Skip to main content

GitLab CI

Beta

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:

.gitlab-ci.yml
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​

VariableRole
STNG_TENANTTarget tenant (required)
STNG_OIDC_TOKENFilled by id_tokens
STNG_OIDC_TRUSTDisambiguates if several trusts match
STNG_CLUSTERAlternative to sng config use-cluster

No "masked" CI variable is needed: there is no secret.

Troubleshooting​

  • no CI OIDC token: the job has no id_tokens block, or it is in an extends that is not inherited.
  • 401 invalid identity token: the token's sub matches no trust. On an unprotected branch, ref_protected=true excludes the token: this is intended.
  • 403 forbidden on apply: the trust used only has readonly. Check STNG_OIDC_TRUST.
  • The build-sng job fails on the git clone: the CI_JOB_TOKEN has no access to the sng-cli repository.

See also​