Tags give the ability to mark specific points in history as being important
-
v6.1.0
protectedRelease: pipeline v6.1.073d65143 · ·Catalog v6.1.0 ci-go toolchain refresh: Go 1.26.4 -> 1.26.5, clearing GO-2026-5856 (CVE-2026-42505, a crypto/tls Encrypted Client Hello pre-shared-key identity disclosure), and golangci-lint v2.4.0 -> v2.12.2, whose predecessor panicked analyzing Go 1.26 code and kept consumer CI lint gates disabled. Consumers pinning ci-go can restore blocking audit gates and re-enable golangci-lint in CI at this tag. Instance fix behind work item #5; the Go-patch release cadence it proposes remains open.
-
v6.0.1
protectedRelease: pipeline v6.0.18e55eabd · ·Catalog v6.0.1 Fail-loud sweep across every template whose script block could mask a failure behind a trailing echo. binary's publish-to-package-registry and sign-blob loops, container's :latest/:TAG push blocks, and verify's :latest/:TAG verification blocks -- the highest-stakes instance, since verify exists solely to assert signature integrity -- now run under `set -euo pipefail`. A failed upload, sign, push, or verification now fails the job instead of shipping a green pipeline with a missing or unverified artifact. Also carries the Renovate delivery work merged since v6.0.0: automerge for lockfile/pin/digest updates, catalog bumps exempt from the concurrent-MR cap, the renovate-fleet-audit delivery gate, lab projects moved to dashboard approval, and token-rotation survival.
-
v6.0.0
protectedRelease: pipeline v6.0.05661aa6b · ·Catalog v6.0.0 BREAKING: automerge-gate's `required-checks` input is renamed `required_checks`. A consumer passing the old name gets `unknown input arguments` at include resolution. The component has no consumers in this estate, so the blast radius is zero today and grows with every consumer it gains. The hyphen was never a design decision: `required_checks` was the original name and a July commit renamed it with no rationale, so this reverts to the convention. FIXED, and the reason this release exists now rather than later: `container` and `registry-cleanup` shipped v5.0.0 with an `image:` that resolves to nothing. The job fell back to the runner's default image, which carries no buildah, and died on `buildah: command not found` (exit 127) after a clean pipeline start. v4.0.2 hardcoded the image and worked, so a bump to v5.0.0 is what broke it. Any consumer on v5.0.0 that builds containers should move to v6.0.0. The cause was a duplicate YAML key: the v5.0.0 cut added a second `variables:` block to a job that already had one, so the block defining the image name was silently discarded. Three layers missed it independently. The linter used yaml.safe_load, which applies last-key-wins in silence. GitLab's own /ci/lint reports such a config valid and returns merged YAML with the block already gone. And no sim covers `container`, the most-included component in the catalog. Two blocking lint rules close that class: 13 rejects duplicate mapping keys via a strict loader, and 14 requires an `image:` naming a variable to define that variable in the same job. Both were verified able to fail against the shape that shipped. Also in this release: 28 README rows and worked-example lines that documented inputs which do not exist, fixed across nine components, with five further blocking lint rules and an advisory tier so the class cannot return. verify's `needs_job` removal is now recorded as breaking in the 5.0.0 notes, where a consumer bumping from v4 will look. KNOWN LIMITATION: `container` still has no sim. Its only coverage is consumer pipelines, which is how the v5.0.0 regression reached a tag. The new rules catch the static shape; nothing yet builds an image and asserts the job ran on a buildah image.
-
v5.0.0
protectedRelease: pipeline v5.0.0ea515e08 · ·pipeline v5.0.0 **Major because the release is lockstep and one component's contract broke.** `automerge-gate` no longer exits nonzero for a customer-shipping class whose checks are green (see BREAKING below). That component has no consumers today, so the practical blast radius is nil -- but semver is a promise about the contract, not a function of how many people currently hold it, and every template ships at the same catalog tag. Cutting this as a minor would have put a breaking change behind Renovate's non-major grouped MR, which is automerge-eligible for some classes. A major routes it to its own MR with a human, which is what a contract change should get. Everything else here is a fix, and the vale work in particular changes behaviour without changing any input contract. - **Six defects found by a systematic audit, not incidentally.** Every earlier fix in this release surfaced because something broke or a consumer had patched around it. This pass instead checked all 21 templates mechanically against the failure shapes this estate has actually hit: runtime network fetches, floating refs, `component.version` in a spec default, inputs declared but unused, inputs used but undeclared, README/template input drift, jobs that cannot gate, missing `interruptible`, `cosign` without `id_tokens`, and ordering that rests on an `optional` `needs:`. - `container` and `registry-cleanup` **documented an `image` input neither template declared.** A consumer following the README got `unknown input arguments: image` -- the same failure the `vale` sim hit. Both now declare it, using the variable-name idiom this release established. - `verify` declared **`needs_job` and referenced it nowhere.** A consumer setting it expecting ordering got nothing. Removed; removing an input is breaking, which is what this major is for. - `release` ran a job on **`curlimages/curl:latest`**, an unpinned third-party image in the release path, the least reproducible place in the catalog to float. `ci-tools` already carries curl and ships in lockstep. - `binary` and `paper` **defaulted their image to `:latest`** instead of pairing with the component version. `pipeline.just`'s header claims version skew is "unrepresentable"; these two made it representable. - `vale`'s README still documented **fetching styles from `master` on every run**, which this release removed. The audit's other 50 findings were triaged as false positives and are recorded rather than silently dropped: `:latest` discussed in prose rather than used, SLSA `buildType` spec URLs matching a `/main/` pattern, `options:` values documented in a README table and read as input rows, and `curl` invocations whose pinned version sits on the next line of a shell continuation. Six components do order on an `optional` `needs:`, which is the same shape as the `container-sbom`/`container-attest` attestation race; that needs a sim reproducing the race and is deliberately not in this release. - **A vale that could not run was indistinguishable from a clean one, because `allow_failure: true` swallowed exit 2 along with exit 1.** v5.0.0 already removes the runtime failure mode by baking vale and its styles into `ci-tools`, but the signal itself was still unreadable by the pipeline. The job now emits `allow_failure: { exit_codes: $[[ inputs.tolerated_exit_codes ]] }`, defaulting to `[1]`: prose findings advise, a check that could not run blocks. This is the estate's exit-code taxonomy finally enforced rather than merely documented -- 0 pass, 1 the-checked-thing-failed, 2 the-check-could-not-run, and only the middle one is a matter of taste. **The input contract is unchanged, so this is a minor.** `allow_failure` is still a boolean; `tolerated_exit_codes` derives its default from it via `spec:inputs:rules:` and resolves to `[0]` when `allow_failure` is false. `[0]` expresses "tolerate nothing" because exit 0 never fails, chosen over an empty array so the behaviour does not rest on GitLab's handling of `exit_codes: []`. Behaviour DOES change: a vale job that silently passed while linting nothing will now go red. That is the fix, not a regression. `CONTRIBUTING.md` rule 9 also documented an input shape that does not compose: it showed a top-level `default:` alongside `rules:`, and GitLab rejects that outright (`config these keys cannot be used together: default, rules`). The rule was written from upstream documentation rather than from a pipeline that ran, and the first component to actually use the idiom failed to create a pipeline because of it. Corrected, with the requirement that the rules be exhaustive over the deciding input, since an input with rules and no matching branch becomes required and breaks consumers. Proven by `sim-vale-exit-codes`, two arms covering both branches of the rule. `exit_codes` appeared nowhere in this catalog before now, and deriving an array default from another input is likewise new here; both failure modes are config failures, so an invalid shape means the pipeline does not create. - **`mode: project` did not disable the rules its own description claimed, and three separate consumers had patched around it.** The input said project mode disables `InternalLink*`; the emitted `.vale.ini` never disabled `InternalLinkFormat`. Sweeping every catalog consumer's `.gitlab-ci.yml` found `gitlab_docs.InternalLinkFormat` hand-disabled in **3 of 3** vale consumers, `gitlab_base.Offerings` in 3, and `gitlab_base.LatinTerms` in 3. All three are now off by default in project mode. A rule every consumer disables is not a standard, it is a papercut with a default: `InternalLinkFormat` enforces docs.gitlab.com link shape and means nothing in a README, and `Offerings` and `LatinTerms` enforce docs product voice on prose that is not product docs. A project that wants the full ruleset still has `mode: docs`. `Substitutions` and `SubstitutionWarning` deliberately stay on, because the mechanical discipline they carry is correct everywhere. After this ships, `reference`, `gitlab-contribution` and `gitlab-simulation` can each drop those entries from their `disable_rules`. - **`templates/paper/README.md` taught `@~latest` in three places** -- a floating ref in the one document a new consumer copies from. Now pinned. `lab/project-lattice/paper` pins `@main`, which components cannot resolve at all since they resolve from tags only, and is almost certainly downstream of this. - **`validate:templates:syntax` broke every MR in the catalog, from an unpinned `pip3 install yq`.** python-yq depends on `argcomplete`; a new `argcomplete` release annotates `Final[Mapping[str, str | bytes]]` at class creation, and PEP 604 unions need Python 3.10 while the job's pinned UBI9 image ships 3.9. Nothing in this repository changed. Someone else's release did, and three unrelated MRs went red at once. The job now uses `python3-pyyaml` from the distro, so the version is whatever the pinned base image carries and there is no network install in the job at all. `yq` was never needed here: the job asserts each template parses as a two-document YAML stream, which PyYAML does directly. It also now checks the document count rather than only that parsing succeeds. This is the defect `mise.toml` already records for the template linters -- "imported PyYAML from wherever it happened to be: present on one machine, absent on another, and pip-installed inline and unpinned by one CI job". This was that job. - **`vale` had stopped linting anything, and the job's own red square hid it.** On 2026-08-04 the job failed three pipelines in a row on `reference` with HTTP 429, exhausting its retries while asking gitlab.com to archive the `gitlab-org/gitlab` monorepo at `master` for `doc/.vale`. It examined zero files each time. Because the component is normally included with `allow_failure: true` so prose findings advise rather than block, "the styles download was rate-limited so nothing ran" was indistinguishable from "the prose is clean" and from "there are 313 findings" -- one ignored red job standing for three different states. That is why finding counts on this estate kept moving between sessions. `vale` and a **pinned** snapshot of the GitLab docs styles now ship inside `ci-tools`, at `/opt/vale-styles` with `VALE_STYLES_PATH` set. The default job path makes **no network call at all**: the binary is no longer pulled from a GitHub release per run, and the styles are no longer archived out of a 3 GB monorepo per run per consumer. A styles failure is now a loud `ci-tools` **build** failure that blocks, instead of a job nobody reads. This also makes the component offline-capable, which the airgapped consumers this catalog exists for actually need. - **The vale ruleset drifted under consumers with no diff in their repository.** `styles_archive` defaulted to `master`, and `master` is not a version. Diffing the pinned tag against `master` on the same day showed a new rule (`BoldEmphasis`), two new style packages, and four changed rule files. A consumer's green pipeline could go red because someone else merged documentation upstream. `VALE_STYLES_REF` pins it (`v18.11.8-ee`) and carries a Renovate annotation, so the ruleset now moves when a maintainer chooses and arrives as a reviewable MR. `vale_version` and `styles_archive` keep working as runtime **overrides**, and both now default to empty (use the image). A failed override fetch, or an image with no styles, exits **2** -- check could not run -- and never falls through to a vale invocation that would report zero findings against zero rules and read as a pass. Verified against all three branches: baked styles present, baked styles missing, and an override URL that 404s. **Not fixed here, and it needs a major.** `allow_failure: true` still swallows exit 2 along with exit 1, so a consumer who wants prose findings advisory cannot yet make could-not-run blocking. The mechanism is `allow_failure: { exit_codes: [1] }`, which means changing the `allow_failure` input's shape: a breaking contract change for the six current consumers, and one whose empty-array semantics should be proven on a lab before shipping. The measured defect above is fixed regardless, because the runtime failure mode is now gone rather than relabelled. - **`$[[ component.version ]]` inside a `spec.inputs` default never interpolated, so two components handed the literal string to the runner.** GitLab does not re-interpolate a default's contents when substituting them into the body; body-level `variables:` does interpolate. `automerge-gate` and `osv-verdict` both defaulted their `image` input to `ci-tools:$[[ component.version ]]`, so any consumer taking the default got an invalid image reference. `reference` carries a hand-written `image:` override and a comment explaining the workaround, which is how this surfaced: a consumer had to discover it the hard way. Both now use the idiom `audit` always used -- the input defaults to a variable NAME (`$GATE_IMAGE`, `$VERDICT_IMAGE`) and the job's `variables:` block builds it, where `component.version` resolves. `audit`'s own description claimed "Same idiom as osv-verdict and automerge-gate", which was not true when written; it is now. **The shape is also linted, so it cannot come back.** `scripts/lint-templates.py` fails any template whose `spec.inputs.*.default` mentions `component.version`, and points at `audit` for the working pattern. Verified by reintroducing the shape and confirming the linter exits non-zero. This is what unblocks wiring `automerge-gate`, which has zero consumers today partly because its default did not work. - **The shared `prConcurrentLimit` was starving the catalog bump, which is the one update class every other conformance property is delivered through.** Measured across the estate on 2026-08-04: 62 catalog includes and **not one on the current tag**, with 20 of them two majors behind on `v3.0.0`. Renovate was not the problem -- it had 22 open catalog MRs across 15 of 17 consuming projects. The queue was. Four consumers (`assay`, `manifold`, `postern`, `reference`) sat at exactly 10 open MRs, the configured limit, and `manifold`'s ten contained **no catalog bump at all** while its `.gitlab-ci.yml` ran two different catalog versions: routine dependency updates had taken every slot, so the bump that would have made it coherent could not be proposed. The catalog `packageRule` now carries `prPriority: 10`, so it is created ahead of every other class regardless of queue depth. Raising the cap was the other option and the wrong one -- it enlarges the review pile without changing what gets proposed first. `automerge` stays `false`: a catalog bump changes consumer CI behaviour and still gets a human. - **The shared Renovate preset stripped the leading `v` from every version it wrote.** `extractVersionTemplate: "^v?(?<version>.+)$"` on the Containerfile ARG manager rewrote `v2.6.3` as `2.6.4`, but the ARG is used as the release TAG in the download URL (the filename gets a separately-stripped copy). Six merge requests across `ci-tools`, `ci-buildah` and `ci-buildkit` proposed URLs that 404: verified against the live API, `gitlab-org/cli` release `1.109.0` returns 404 and `v1.109.0` returns 200. Replaced with `versioningTemplate: "semver-coerced"`. The same line sat on the catalog component-pin manager, where it is worse: that manager's `matchStrings` requires the `v`, so the stripped value fails `confirmIfDepUpdated`, the file reverts, and Renovate throws `update-failure`. That is the errored branch updates, and why no consumer was on the current catalog version. Same root cause, two failure shapes: one writes silently wrong, the other cannot write at all. - **`validate:containers` built nothing and passed.** Its `while read` loop had no input redirect, so it read stdin, which is empty in a CI job. It printed a correct build plan and then `built 0 image(s); Job succeeded`. No pipeline had ever run it, because its rules require a merge request that changes a Containerfile. It now redirects from the plan and asserts built == planned. - **`osv-verdict` was fail-open in merge-request diff mode. Consumers may see MRs newly go red, correctly.** The head scan wrote its findings inside the working tree and `git stash --include-untracked` deleted them; the stash is never popped. `sort` on the missing file exited 2 to stderr, `comm` read an empty stream and exited 0, and the verdict was `pass` no matter what the head introduced. There is no `set -e` in that script, so nothing surfaced. Scan output now lives outside the working tree, the declared `osv-head.json` artifact is restored through an `EXIT` trap covering all five exit paths, and a guard fail-closes when either side of the diff is absent. - **`osv-verdict` treated an unparseable scan as a clean one.** The jq parse ended in `|| : > "$ids_file"`, so any schema change, truncated write or missing file became an empty findings list and a pass. Since `osv_scanner_version` is Renovate-managed, a major bump reshaping the JSON would have silently disarmed the check estate-wide. The parse now fails closed, and a scanner exit of 1 (findings present) that parses to zero findings is treated as schema drift rather than as clean. - **`audit` set `LANG`**, the POSIX locale variable, to the language name. On the vanilla bases every current consumer overrides to, `LANG` is already exported, so the assignment propagated `LANG=go` to every child process (`locale: Cannot set LC_CTYPE to default locale`, collation flipping to C ordering). Renamed to `AUDIT_LANG`. - **`audit`'s `image` input is now optional, derived from `language`.** It had no default, which made it required: the component could not be included without naming an image, and its own error text coached a vanilla base ("add 'image: rust:1.88.0'"). Across all 57 group projects every one of audit's six consumers passes `image:` and five pass a vanilla base, four of them naming a language `ci-tools` already bakes. Conformity was zero by construction. Existing overrides keep working; migration is deleting the line. `rust` resolves to `ci-rust`, `go` to `ci-go`, `node` and `python` to `ci-tools`. Removing the input entirely remains the eventual major. - **`audit` no longer installs audit tooling at job runtime.** The rust arm ran `cargo install --locked cargo-deny --version 0.19.2 2>/dev/null || true`, shadowing the image's Renovate-tracked pin with an unpinned second source of truth and swallowing its own failure. The go arm ran `go install golang.org/x/vuln/cmd/govulncheck@v1.1.4`, which was OLDER than the baked version, so the audit ran an older scanner than the image shipped. The python arm ran an unpinned `pip install pip-audit`, which on this image's pip backtracks to an older release rather than failing. All three now check the baked tool is present and fail pointing at a stale image. - **`ci-tools` bakes `pip-audit`** at a Renovate-tracked `PIP_AUDIT_VERSION`. - **`.image-build` runs on the catalog's own `ci-buildah`** and no longer curl-installs cosign at runtime, which happened on every image build, against this repo's own no-runtime-curl-installs rule, without checksum verification, in the job that signs every catalog image. - **Digest pinning is off.** `pinDigests: false` for the docker datasource, and invariant 1 in `ADOPTION.md` rewritten to match: the semver tag is the pin. Digests rot faster than a review-gated MR can land. - **Containerfile changes are built on the merge request.** No `build:ci-*` job ran on `merge_request_event`, so a Containerfile change was never exercised until after merge, which is why six MRs proposing 404 URLs were all green. `validate:containers` builds the changed images, and their dependents, without pushing or signing. - **BREAKING: `automerge-gate` no longer fails the pipeline for a customer-shipping class whose checks are green.** It reports `GATE_DECISION=human-review` and exits zero. Consumers on the default (`customer_shipping: true`) will see this job go from permanently red to green. That default previously exited nonzero unconditionally, which put "not automerge-eligible" on the same pipeline red/green channel `only_allow_merge_if_pipeline_succeeds` reads to gate *human* merge. The documented adoption shape therefore blocked the human lane rather than routing to it, and the catalog's own sim had to wrap that shape in `allow_failure: true` to stay green. A failing or absent check still exits nonzero on the shipping path. The automerge block itself was never carried by this exit code; it lives in `renovate-config.json` (`platformAutomerge: false` plus `automerge: false` on every rule). - **`automerge-gate` emits a `GATE_DECISION` dotenv** (`automerge-eligible`, `human-review`, `blocked`, `tampered`) with `when: always`, so the decision is auditable and assertable rather than only a log line. - **`automerge-gate` refuses to decide against a tampered floor.** `CUSTOMER_SHIPPING` is a job-level variable and GitLab ranks project and group CI/CD variables above job-level ones, so a Maintainer on a consuming project could set it in Settings and silently send the job down the non-shipping path with no diff in any file. The gate now compares the runtime value against the literal it was compiled with and emits `GATE_DECISION=tampered` with a nonzero exit if they differ. Documentation claiming the floor was "enforced at two layers" has been corrected in `renovate-config.json`, `README.md`, `templates/automerge-gate/README.md` and `ADOPTION.md`; it was one layer plus a report. -
v4.2.0
protectedRelease: pipeline v4.2.0612adc98 · ·pipeline v4.2.0 Added - site-check component. Runs a project's own check command -- type checking, framework diagnostics -- on merge requests. A build is not a check: `astro build` and its equivalents transform sources without type-checking them, so a TypeScript or framework major goes green in CI while breaking types. Four projects in this group each defined `"check": "astro check"` and no pipeline ran it. allow_failure defaults to false, because a check that cannot fail the pipeline is not a gate. - ADOPTION.md -- the adoption profile every consumer of this catalog conforms to, so "deliberately exempt" and "nobody got round to it" stop being indistinguishable. - Inherited Renovate enrollment: the runner injects this catalog's preset as base config for every autodiscovered project, making enrollment opt-out rather than opt-in. - RENOVATE_FORCE cadence normalizer, so the CI cron is the single source of cadence and an inherited schedule cannot silently park updates. - validate:renovate-config job, pinned to the Renovate major the runner runs. - needs: [] on the renovate job, breaking a deadlock where a rotated base-image digest could skip the bumper that would have fixed it. Changed - Evidence is frozen, by path. Files under bench/, archive/, evidence/, experiments/, rig/, receipts/ or results/ are experimental conditions some captured result describes, not dependency choices; bumping them voids the receipt. Keyed on path rather than repository because only 7 of 18 lab projects hold receipts, and a repository-wide freeze both over-freezes the rest and would rot the receipt-bearing labs' own site builds. - TypeScript ceilinged below v7 by upstream limitation, not preference. @astrojs/check peers ^5.0.0 || ^6.0.0 and has no v7-capable release. The ceiling still modernizes: 6.0.3 is stable and compatible, so Renovate proposes the v6 major instead of a v7 that cannot merge. - Renovate scan timeout raised to 3h, sized for a cold run. - Autodiscovery skips purge-pending projects. - Runner preset documents the cadence and enrollment doctrines in its header. Fixed - ci-tools: glab is looked up on the right forge (gitlab-releases, not github-releases). The pin had sat at v1.92.1 while v1.108.0 shipped. - Scheduled runs actually open merge requests. The preset scheduled updates for a window that closed before the cron fired, so every update parked in Awaiting Schedule while the job stayed green. - UBI grouping covers UBI10. - Catalog component pins no longer emit a spurious lookup-failure warning. Closes #2.
-
v4.1.2
protectedRelease: pipeline v4.1.23153dced · ·pipeline v4.1.2 Fixed - pages template: default-branch deploys actually fire. The 4.1.1 fix repaired explicit literal branch inputs but not the default: nested variables inside a variable value do not expand during rules:if evaluation. The branch input default is now the empty string and the rule splits in two: empty input deploys from the project default branch (direct variable-to-variable), an explicit input deploys from exactly that branch. Both paths verified on a live consumer before release. (!82)
-
v4.1.1
protectedRelease: pipeline v4.1.1cfedb89d · ·pipeline v4.1.1 Fixed - pages template: the deploy rule now fires with the default branch input. The rule compared the branch name against the quoted literal $CI_DEFAULT_BRANCH and never matched, silently dropping the pages job from consumer pipelines using defaults. The input now lands in a job variable and the rule compares variable to variable. Consumers that pinned a literal branch as a workaround can drop it. (!81)
-
v4.1.0
protectedRelease: pipeline v4.1.04c97baf3 · ·v4.1.0 Added - automerge-gate template: the terminal, fail-closed Renovate automerge decision job, with a customer-shipping human-signoff floor. Consumes per-check dotenv verdicts over needs: optional and blocks unless every required-check is present and == pass (and blocks if zero checks were evaluated). - osv-verdict template: emits an OSV-scan verdict for automerge-gate. On a merge-request pipeline it fails only on newly-introduced findings, fail-closing if the merge-base is unreachable. - ci-tools ships diffutils (diff + cmp). ubi9-minimal ships neither; a consumer no-op/idempotency check built on them failed command-not-found silently, hiding a real downstream bug. Fixed - automerge-gate fail-open guard: block (exit 1) when zero required-checks were evaluated (empty or typo'd input), ahead of both the customer-shipping floor and the non-shipping path. - osv-verdict shared diff-mode: fail-close on an unreachable merge-base rather than full-scanning and blocking on pre-existing findings; consistent with the sibling estate catalogs. - release reflows the annotated tag body before publishing, so the release page renders wrapped prose as paragraphs. Changed - Standardize the gate input to required-checks (hyphen), matching the sibling catalogs; sim consumers and READMEs updated. - Dependency bumps: UBI9 base image, golang 1.26.4, gitlab-org/cli (glab) 1.102.0, and renovate shared-preset convergence onto the root config. Consumers pin @v4.1.0.
-
v4.0.2
protectedRelease: pipeline v4.0.26e5526c0 · ·v4.0.2 -- fix: verify runs after container-sign (stage-gated) + guards :latest Patch over v4.0.1. verify only needs:ed the build job, so it raced the separate container-sign job -> 'no signatures found'. verify is now stage-gated and guards the :latest digest. Pin @v4.0.2. Full changelog: CHANGELOG.md
-
v4.0.1
protectedRelease: pipeline v4.0.1ff3a8295 · ·v4.0.1 -- fix: catalog images resolve for default consumers Patch over v4.0.0. The image input added in v4.0.0 defaulted to ci-*:$[[ component.version ]], which GitLab does not interpolate inside a resolved input default -- so consumers using the default pulled the literal string and failed with "invalid reference format". Reverted to a body-hardcoded image (which interpolates) and dropped the image input on container, container-sign, vale, and registry-cleanup. No consumer change beyond pinning @v4.0.1. Full changelog: CHANGELOG.md
-
v4.0.0
protectedRelease: pipeline v4.0.05c226ae9 · ·v4.0.0 -- supply-chain decoupling: build/sign split + :latest gating BREAKING. The container supply chain is now composable: build, sign, sbom, attest, and verify are independent components, and :latest tracks the default branch only. Breaking (consumers must act): - container no longer signs -- it builds, pushes, writes container.env. Add a container-sign job per build job to keep signatures: - component: .../pipeline/container-sign@v4.0.0 inputs: { image_name: $CI_REGISTRY_IMAGE, container_job: container-build } - :latest is pushed/signed on the default branch + tags only, never on MR pipelines (:SHA always; :TAG on tags). - build-container-buildah removed -- use container + container-sign. Added: - container-sign -- cosign-signs pushed digests from container.env. - registry-cleanup -- container_expiration_policy with a cosign .sig carve-out (protects latest/semver/signatures, prunes stale SHA tags). - image input on container / container-sign / vale. Changed: - container-sbom drops artifacts:reports:cyclonedx -- Ultimate Container Scanning owns GitLab-side SBOM ingestion; component keeps its cosign-attested external SBOM. - ci-tools expanded (make/node/npm/python3/yq); vale gains disable_rules. - shape linter conforms to GitLab input-name convention. - reference-check relocated to public-sector/reference; reference examples moved to examples/. Full changelog: CHANGELOG.md -
v3.3.2
protectedRelease: pipeline v3.3.20306e4fa · ·**Patch release.** Includes the backtick fix from v3.3.1 plus the `GOVULNCHECK_VERSION` pin fix that was blocking the v3.3.1 tag pipeline from completing. - **Backtick fix (was: v3.3.1).** Dropped the GitLab `release:` keyword in favor of an explicit `glab release create --notes-file` invocation. The `release:` keyword routed `${CI_COMMIT_TAG_MESSAGE}` through shell `eval`, treating backticks as command substitution and stripping every `code span` from the release page. The replacement reads the tag annotation directly from `git tag -l --format='%(contents)'` into a file, then passes that file to `glab` — no shell expansion of the description body. Re-runs are idempotent: `glab release create` updates an existing release in place rather than failing. - **`GOVULNCHECK_VERSION` pin fix.** `containers/ci-go.Containerfile` had `ARG GOVULNCHECK_VERSION=1.3.0` (no `v` prefix); Go's module loader rejects bare semver: `invalid version: unknown revision 1.3.0`. Fixed to `v1.3.0` to match the sibling `GOLANGCI_LINT_VERSION=v2.4.0` shape. This was silently blocking every tag pipeline since the pin drifted; surfaced when v3.3.1's tag pipeline couldn't reach its own release stage. - [MR !57](https://gitlab.com/gitlab-com/public-sector/pipeline/-/merge_requests/57) — backtick fix - [MR !58](https://gitlab.com/gitlab-com/public-sector/pipeline/-/merge_requests/58) — pin fix - Lab evidence: [kaniko test-catalog-rc1](https://gitlab.com/gitlab-com/public-sector/kaniko/-/releases/test-catalog-rc1) — pre-merge validation of the backtick fix against a real consumer; 32-backtick parity from source tag to rendered release page - [CHANGELOG](https://gitlab.com/gitlab-com/public-sector/pipeline/-/blob/main/CHANGELOG.md) -
v3.3.1
protectedeef303cf · ·**Patch release.** Fixes the `templates/release` catalog component so backtick-delimited content in tag annotations renders correctly on the release page, and makes tag-pipeline re-runs idempotent. - **Backtick fix.** Dropped the GitLab `release:` keyword in favor of an explicit `glab release create --notes-file` invocation. The `release:` keyword routed `${CI_COMMIT_TAG_MESSAGE}` through shell `eval`, treating backticks as command substitution and silently stripping every `code span` from the release page. The replacement reads the tag annotation directly from `git tag -l --format='%(contents)'` into a file, then passes that file to `glab` — no shell expansion of the description body. - **Re-run idempotency.** `glab release create` updates an existing release in place rather than failing with `--no-update flag was specified`. Force-pushed tags, Renovate re-runs, and operator-initiated re-tags all succeed. - [CHANGELOG anchor](https://gitlab.com/gitlab-com/public-sector/pipeline/-/blob/main/CHANGELOG.md#v331) - [MR !57](https://gitlab.com/gitlab-com/public-sector/pipeline/-/merge_requests/57) - Lab evidence: [kaniko test-catalog-rc1](https://gitlab.com/gitlab-com/public-sector/kaniko/-/releases/test-catalog-rc1) — pre-merge validation against the branch SHA, 32 backticks in source tag, 32 backticks in rendered release page (parity) -
v3.2.0
protectedRelease: pipeline v3.2.023a0e12f · ·v3.2.0 -- expose runner_tag input on compliance/container-attest/container-sbom/vale templates. Default saas-linux-large-amd64 (one tier up from previous implicit small). Backward-compatible; consumers that don't set the input get the new default.
-
v3.1.0
protectedRelease: pipeline v3.1.0588c2d3e · ·v3.1.0 -- container component auto-injects OCI image-metadata build-args (OCI_VERSION / OCI_REVISION / OCI_CREATED) sourced from CI predefined variables. Additive, backward-compatible with v3.0.0 consumers. Pairs with the forthcoming container-image standard in reference.
-
v3.0.0
protectedRelease: pipeline v3.0.010d48aee · ·v3.0.0 — namespace migration to gitlab-com/public-sector First release at the new path gitlab-com/public-sector/pipeline. Every catalog image, cosign OIDC identity, and SLSA provenance subject moves to the new namespace. Hard break from v2.x. Consumers must update include lines: $CI_SERVER_FQDN/gitlab-com/public-sector/pipeline/<name>@v3.0.0 Removed: posture-verify component (divested to GitLab compliance product). Deferred: ci-kaniko image (returns when kaniko ships at the new path). Bootstrap: image-build runs under quay.io/buildah/stable:v1.43.0 with runtime cosign install. v3.1.0+ uses the just-published ci-buildah image.
-
v2.7.0
protectedRelease: pipeline v2.7.04682fe69 · ·v2.7.0 - validation cleanup + pipeline-self-validates roll-up
-
v2.6.0
protectedRelease: pipeline v2.6.0dfa79dbc · ·v2.6.0 - catalog IS the Renovate runner (presets/renovate-runner.gitlab-ci.yml + self-include)
-
v2.5.0
protectedRelease: pipeline v2.5.03d2528e4 · ·v2.5.0 - declare artifacts.reports.cyclonedx for GitLab Dependency List ingestion