feat(renovate): freeze lab/** by default, carve out build tooling
What
Freezes gitlab-com/public-sector/lab/** by default: reproduction material stops being renovated unattended, while staying fully visible and one checkbox from a thaw.
Why
A lab exists to reproduce a captured scenario, so its pins are the experimental conditions its receipts describe — not choices that should track the moving world. Renovating them does not maintain the lab, it voids the evidence.
This is not hypothetical. Three of the six benchmark subjects in lab/rootless were bumped before this rule existed:
| MR | Change | Files |
|---|---|---|
| !9 (merged) | alpine 3.20 → 3.24 | bench/go-scratch/Dockerfile, archive/pss-matrix/Dockerfile |
| !10 (merged) | golang 1.22 → 1.26 | bench/go-scratch/Dockerfile, archive/pss-matrix/Dockerfile |
| !11 (merged) | spring-boot 3.3.5 → 3.5.16 | bench/java-maven/pom.xml |
| !4 (merged) | flask 3.1.0 → 3.1.3 | bench/python-ubi/requirements.txt |
The drift is undetectable from the receipts. A timing.json reads
{"cell":"buildah-rootless-go-scratch","dockerfile":"go-scratch","wall_seconds":30,"result":"pass"}
— it names its subject only by name and records no versions, so it still claims a pass while the thing it passed on changed underneath it.
How
Implemented with matchRepositories in the shared preset. This needs no inheritConfig, no second runner pass, and no per-group config repo — the mechanism originally sketched for this was considerably heavier.
The glob was checked against real minimatch at both nesting depths, since the project-trustchain and project-lattice labs sit one level deeper than lab/rootless and would otherwise have stayed live:
MATCH gitlab-com/public-sector/lab/rootless
MATCH gitlab-com/public-sector/lab/project-trustchain/architecture
MATCH gitlab-com/public-sector/lab/project-lattice/mcp
no gitlab-com/public-sector/reference
no gitlab-com/public-sector/manifoldThree deliberate choices
-
dependencyDashboardApproval, notenabled: false. Silence would cost visibility — you would stop learning that published evidence sits on a base with a known CVE. The dashboard still lists every available update; nothing is created until a human ticks the box. -
A
.gitlab-ci.ymlcarve-out. Build tooling is not evidence, and letting it rot makes the lab unbuildable, which loses the evidence just as surely. The split is per-path, not per-project: every.gitlab-ci.yml-only lab MR merged so far was harmless, everybench/orarchive/one was not. Rule order is load-bearing — laterpackageRuleswin, so the carve-out follows the freeze. -
A
vulnerabilityAlertsoverride, so a frozen lab still opens an MR for a real advisory. A freeze is not a licence to sit on a vulnerable base, least of all in a lab cited to a customer.
Validation
renovate-config-validator --strictclean across all three config files (pinned torenovate@43.272.0; an unpinnednpxresolves a version predatingmanagerFilePatternsand reports false errors).- Control-tested the validator: a deliberately bogus
matchRepositoriesTYPOin the same position is rejected, so acceptance ofmatchRepositoriesis meaningful rather than a silently-ignored key. - Glob semantics verified against
minimatchdirectly (above). - Diff kept surgical — an earlier pass reformatted every inline array and produced 91 lines of churn for a 20-line change; that was reverted.
Follow-up, not in this MR
Receipts should record their subject's resolved versions/digests, so this class of drift becomes detectable rather than silent. Separately, the four lab/rootless files above need reverting to restore the captured conditions.