The release bump on GitLab CI
The GitLab equivalent of docs/integrations/github-actions.md. It is the same
command with the same exit code — GitLab has no composite actions, so the job runs
openregs bump directly — and it differs in exactly one place: a merge request is
opened with git push options rather than with a forge CLI, so the job needs no
token to open it.
The pipeline
Section titled “The pipeline”Copy this into your repository’s .gitlab-ci.yml. It is the snippet the test
suite executes; see “What the test harness runs” below for the two lines it
cannot.
stages: - openregs
openregs-bump: stage: openregs image: python:3.12-slim variables: # The mapping is also the pin file: its `release:` field is the pin. OPENREGS_MAP: controls.yaml OPENREGS_OUT: .openregs # $OPENREGS_RELEASE (<regime>@<tag>) comes from the pipeline trigger the # OpenRegs release feed fires; $OPENREGS_REGISTRY is a CI/CD variable naming # the registry to pull it from. GIT_STRATEGY: clone rules: - if: $OPENREGS_RELEASE before_script: - pip install --quiet "openregs==1.0.0" script: - | set -u status=0 # --push-option is what opens the merge request: GitLab reads these off the # push itself, so no token and no API call is needed to get one open. if openregs bump \ --repo "$CI_PROJECT_DIR" \ --to "$OPENREGS_RELEASE" \ --from "$OPENREGS_REGISTRY" \ --map "$OPENREGS_MAP" \ --base "$CI_DEFAULT_BRANCH" \ --out "$OPENREGS_OUT" \ --push-option merge_request.create \ --push-option "merge_request.target=$CI_DEFAULT_BRANCH"; then status=0 else status=$? fi # Exit 2 is "the question could not be asked" — an unbuilt release, a # registry that did not verify, a mapping the validator rejects. Nothing was # pushed, and the job must look like neither a pass nor a reviewed failure. if [ "$status" -eq 2 ]; then echo "openregs: the bump could not be prepared; nothing was pushed" exit 2 fi # The job log is where a GitLab reviewer reads the report, and the artifact is # what the merge request description is filled from. - cat "$OPENREGS_OUT/pull-request.md" - | set -eu if [ "$(cat "$OPENREGS_OUT/verdict.txt")" = fail ]; then echo "openregs: FAIL — an atom mapped to a control changed substantively." echo "openregs: $(cat "$OPENREGS_OUT/branch.txt") must be reviewed by the control" echo "openregs: owners named in the report above before it merges." exit 1 fi echo "openregs: OK — no atom mapped to a control changed substantively." artifacts: when: always paths: - .openregs/ expose_as: OpenRegs impact reportWhat each part is doing
Section titled “What each part is doing”--from "$OPENREGS_REGISTRY"— the release is pulled and verified (signature, trust anchor, digests, provenance, transparency-log inclusion) over a staged copy before a byte of it is read. A release a consumer could not check is not one it may pin itself to.--push-option merge_request.create— GitLab creates the merge request from the push that carries the bump branch.merge_request.targetsets its target branch;merge_request.titleandmerge_request.descriptioncan be set the same way when you would rather not use the artifact.- the exit code — 1 if and only if an atom your mapping maps to a control changed substantively; 0 otherwise; 2 when the question could not be asked. An editorial change to a mapped atom, a change to an atom you have waived and a change to an atom nobody mapped are all reported and none of them fails the job.
artifacts: when: always— the report is most worth keeping on the run that failed.
Make the job required
Section titled “Make the job required”A red job that anyone can merge past is decoration. In GitLab:
- Settings -> Merge requests -> Pipelines must succeed, so the bump merge
request cannot merge while
openregs-bumpis red; and - give the branch
openregs/bump-*no push exception that would let it bypass that.
The check is red on precisely the days it is worth something; see
docs/integrations/github-actions.md for what the owner of the named control is
expected to do about it.
Pushing from a GitLab job
Section titled “Pushing from a GitLab job”The bump pushes to the repository’s own origin, so the job needs a credential
that may write to it — a project access token or a deploy key in
CI_PUSH_TOKEN, wired into the remote the usual way:
git remote set-url origin \ "https://oauth2:${CI_PUSH_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git"CI_JOB_TOKEN cannot push. If your runner clones over SSH with a deploy key that
has write access, nothing needs changing.
What the test harness runs
Section titled “What the test harness runs”tooling/tests/test_downstream_bump.py reads the YAML block above out of this
file and executes the job’s script: for real, against a consuming repository
whose remote is a bare repository under .test-remotes/. That is why the snippet
is written as three plain shell entries: it is a pipeline, not a picture of one.
The test asserts that the branch is pushed with the pin bumped, that
merge_request.create arrives at the remote as a push option, that the report
printed into the job log carries the impact table, and that the job exits 1 for a
mapping the release move impacts.
Two things in the snippet the harness does not execute, and no test here may
claim: image: (a runner image is a container this suite may not pull) and
before_script: (installing from PyPI is a network call). The test puts the CLI
on PATH from the checkout instead. rules: is likewise documentation here —
if: $OPENREGS_RELEASE keeps the job out of every pipeline that is not a release
bump, and GitLab, not this harness, is what evaluates it.
Rendered from openregs/openregs@cbe9615:docs/integrations/gitlab-ci.md