kolm  /  integrations  /  GitLab CI

kolm in GitLab CI.

Three reference .gitlab-ci.yml snippets: verify-on-MR, release-with-binder, scheduled quarterly re-verify. Each one wires kolm into your existing GitLab project, blocks merges on K-score regression, posts receipts as MR notes, and ships signed artifacts to GitLab releases. Works on GitLab.com and self-managed.

Runner image node:20Verifier offlineMin minutes 2

Workflow 1 . verify on MR

Block merges on K-score regression.

Drop this in .gitlab-ci.yml. When a merge request touches a recipe, the pipeline compiles, signs, verifies, and posts a receipt as an MR note. The merge button is blocked if any artifact misses its K-score floor (the compile step exits non-zero).

Add a project CI/CD variable named KOLM_API_KEY (Settings → CI/CD → Variables; masked, protected). Add GITLAB_API_TOKEN as a project access token with api scope so the MR-note step can post.

stages: [verify]

verify:
  stage: verify
  image: node:20
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      changes: ["recipes/**/*"]
  variables:
    KOLM_BACKEND: local_cpu
  script:
    - npm install -g kolm
    - mkdir -p artifacts
    - |
      for r in recipes/*.recipe.json; do
        name=$(basename "$r" .recipe.json)
        kolm compile --from "$r" --out "artifacts/${name}.kolm"
        kolm verify "artifacts/${name}.kolm"
      done
    - |
      # post a single MR note with the receipts
      BODY=""
      for rc in artifacts/*.receipt.json; do
        K=$(node -e "console.log(require('./'+process.argv[1]).k_score)" "$rc")
        C=$(node -e "console.log(require('./'+process.argv[1]).cid)" "$rc")
        BODY="${BODY}\n**$(basename $rc)** . K=${K} . CID \`${C}\`"
      done
      curl -sf -X POST \
        -H "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \
        -H "Content-Type: application/json" \
        -d "{\"body\":\"${BODY}\"}" \
        "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/notes"
  artifacts:
    when: always
    paths: ["artifacts/*.kolm", "artifacts/*.receipt.json"]
    expire_in: 30 days
CheckpointThe MR is auto-blocked when the compile fails its K-score gate. The reviewer sees a single note listing each artifact, its K-score, and its CID. No noise.

Workflow 2 . release with binder

Ship a one-page audit PDF with every tag.

On a tag push, attach the .kolm, the receipt, and a single-page binder PDF that lists CID + recipe + base model + K-score to a GitLab release. The PDF is what your auditor signs.

stages: [build, release]

build_release:
  stage: build
  image: node:20
  rules:
    - if: '$CI_COMMIT_TAG'
  script:
    - npm install -g kolm
    - mkdir -p out
    - |
      for r in recipes/*.recipe.json; do
        name=$(basename "$r" .recipe.json)
        kolm compile --from "$r" --out "out/${name}.kolm"
        kolm verify "out/${name}.kolm" --binder "out/${name}.binder.pdf"
      done
  artifacts:
    paths: ["out/*.kolm", "out/*.receipt.json", "out/*.binder.pdf"]
    expire_in: never

publish_release:
  stage: release
  image: registry.gitlab.com/gitlab-org/release-cli:latest
  needs: [build_release]
  rules:
    - if: '$CI_COMMIT_TAG'
  script:
    - echo "Publishing release ${CI_COMMIT_TAG}"
  release:
    tag_name: '$CI_COMMIT_TAG'
    name: 'Release $CI_COMMIT_TAG'
    description: 'Signed kolm artifacts + binder PDFs. Verify with `kolm verify *.kolm`.'
    assets:
      links:
        - name: 'kolm artifacts (zip)'
          url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/download'
          link_type: package
CheckpointThe release-cli image is the official GitLab-published one. Tags trigger; branches and MRs do not. The binder PDF is what your auditor signs five years from now.

Workflow 3 . scheduled re-verify

Re-verify last-quarter's artifacts on a schedule.

Quarterly pipeline that re-runs kolm verify against every artifact in releases/. If a verifier-side change ever rejects an artifact you previously shipped, you find out before your auditor does. Configure the schedule in GitLab UI: Build → Pipeline schedules → New schedule, cron 0 4 1 */3 *, ref main.

stages: [reverify]

reverify:
  stage: reverify
  image: node:20
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
  script:
    - npm install -g kolm
    - |
      fails=0
      for art in releases/**/*.kolm; do
        if ! kolm verify "$art"; then
          echo "FAIL: $art" >&2
          fails=$((fails+1))
        fi
      done
      if [ "$fails" -gt 0 ]; then
        echo "$fails artifact(s) failed re-verify" >&2
        exit 1
      fi
  artifacts:
    when: on_failure
    paths: ["releases/**/*.receipt.json"]
    expire_in: 90 days
CheckpointIf the verifier rejects an old artifact, that is the moment to investigate before the artifact ever reaches an auditor or a customer. Schedule this. Forget it. Get paged on the day it matters.