GitLab CI
Being rolled out. The interface described here is the one of the next release: it may still change, and may not be enabled on your tenant yet.
This pipeline validates manifests on every branch and applies them on main, without any
secret stored in GitLab. It assumes an OIDC trust declared for the
project.
Prerequisites
sng tenant oidc create gitlab-deploy \
--gitlab-project acme/infra --ref main \
--claim project_id=4242 --claim ref_protected=true
sng tenant policy attach readwrite --oidc-trust gitlab-deploy
For sng validate and sng plan to also run on merge requests, declare a
second read-only trust, all branches:
sng tenant oidc create gitlab-review --gitlab-project acme/infra --ref '*' --claim project_id=4242
sng tenant policy attach readonly --oidc-trust gitlab-review
Install the CLI in the job
As long as binaries are not published, the CLI is built from the sources of the
sng-cli repository. In a pipeline, do it once in a dedicated job and pass the binary as an
artifact:
stages: [tools, verify, deploy]
build-sng:
stage: tools
image: golang:1.27
script:
- git clone --depth 1 "https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/stackngo/sng-cli.git" /tmp/sng-cli
- make -C /tmp/sng-cli build
- mkdir -p bin && cp /tmp/sng-cli/bin/sng bin/sng
artifacts:
paths: [bin/sng]
expire_in: 1 day
cache:
key: sng-cli
paths: [/go/pkg/mod]
The sng-cli repository must be accessible to the project's CI_JOB_TOKEN (same group, or access
granted in its settings). If your team already publishes a binary or an image containing
sng, replace this job with a simple download.
Validate on every branch
.sng:
image: debian:bookworm-slim
needs: [build-sng]
variables:
STNG_TENANT: acme
GIT_DEPTH: "1"
id_tokens:
STNG_OIDC_TOKEN:
aud: https://api.dev.stackngo.fr
before_script:
- export PATH="$CI_PROJECT_DIR/bin:$PATH"
- sng config create >/dev/null
validate:
extends: .sng
stage: verify
script:
- sng validate infra/
- sng plan infra/
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH
id_tokens asks GitLab for an OIDC token with an audience equal to the API URL and places it
in STNG_OIDC_TOKEN. The CLI detects it and opens the session on STNG_TENANT.
On a merge request, the gitlab-review trust (all branches, readonly) opens the
session; on main, gitlab-deploy. If both match, set STNG_OIDC_TRUST
in each job.
Deploy on main
deploy:
extends: .sng
stage: deploy
variables:
STNG_TENANT: acme
STNG_OIDC_TRUST: gitlab-deploy
script:
- sng apply infra/
- sng app describe api
environment:
name: production
url: https://api-api.acme.dev.stackngo.app
rules:
- if: $CI_COMMIT_BRANCH == "main"
apply acme — 3 object(s)
…
Wait for convergence
sng apply returns as soon as the desired state is written. For the job to fail if the application
does not start, loop on the status:
- |
for i in $(seq 1 30); do
ready=$(sng app describe api --json | python3 -c 'import sys,json; print(json.load(sys.stdin).get("ready", False))')
[ "$ready" = "True" ] && exit 0
sleep 10
done
sng app describe api; exit 1
Keep the interval at 10 s: the rate limit is shared by all the jobs of the runner.
Useful variables
| Variable | Role |
|---|---|
STNG_TENANT | Target tenant (required) |
STNG_OIDC_TOKEN | Filled by id_tokens |
STNG_OIDC_TRUST | Disambiguates if several trusts match |
STNG_CLUSTER | Alternative to sng config use-cluster |
No "masked" CI variable is needed: there is no secret.
Troubleshooting
no CI OIDC token: the job has noid_tokensblock, or it is in anextendsthat is not inherited.401 invalid identity token: the token'ssubmatches no trust. On an unprotected branch,ref_protected=trueexcludes the token: this is intended.403 forbiddenonapply: the trust used only hasreadonly. CheckSTNG_OIDC_TRUST.- The
build-sngjob fails on thegit clone: theCI_JOB_TOKENhas no access to thesng-clirepository.