feat(images): build, verify and publish the three images in CI; Renovate carries the digests
Operator rule 2026-10-29: image creation, hosting and lifecycle belong to CI/CD, never to a workstation build/push. Nothing had ever been pushed to the Gitea registry. - .gitea/workflows/images.yaml + scripts/images.sh: PRs build+verify (no credential); main builds, verifies and pushes toolbox, agent-runner (FROM toolbox) and conformance-runner as sha-<commit> + main, reading the digest back from the registry. Only changed images build. - Each image's own build-image.sh does the build and in-image verification, now engine-neutral (DinD: no podman-only calls, probe over stdin not a bind mount). New toolbox build-image.sh. - Digest references carry `# renovate-digest:` markers; renovate.json5 gains a custom.regex manager for them. The worker Job template is deliberately untracked (it would loop). - renovate.yaml pins renovate-version 44.167.0: the action's default (39.264.0) rejects the current config's managerFilePatterns, so every run would have died at CONFIG_VALIDATION. - Push credential: REGISTRY_PUSH_TOKEN secret; the Actions token has no package scope in Gitea 1.24.3 (container.go Authenticate). Retention: infra/gitea/registry-retention.sh. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
1301af9a4c
commit
0da34ddbc6
24 files changed
+1280
-210
No files matched your search
+90
-5
@@ -22,9 +22,28 @@
|
||||
// podman run --rm -v "$PWD/renovate.json5:/tmp/renovate.json5:ro,Z" \
|
||||
// ghcr.io/renovatebot/renovate renovate-config-validator /tmp/renovate.json5
|
||||
//
|
||||
// NOTE on what was NOT wrong: `enabledManagers` containing bare `regex` was suspected of needing to
|
||||
// be `custom.regex`. The validator accepts `regex`, so that suspicion was unfounded and nothing
|
||||
// here changes it.
|
||||
// CORRECTION (2026-10-29): THE VALIDATOR ABOVE WAS NOT THE RENOVATE THE WORKFLOW RUNS. The bare
|
||||
// `ghcr.io/renovatebot/renovate` tag is `latest` (44.167.0 when this was measured), while
|
||||
// renovatebot/[email protected] defaults `renovate-version` to `39` (its action.yml), i.e.
|
||||
// 39.264.0. Validated against THAT, this file failed with five errors — every
|
||||
// `managerFilePatterns` key ("Custom Manager contains disallowed fields", "Invalid configuration
|
||||
// option: flux.managerFilePatterns", ...), because 39.x only knows `fileMatch`; the rename landed
|
||||
// in 40.2.0. So even after the workflow found this file, every run would have stopped at
|
||||
// CONFIG_VALIDATION. renovate.yaml now pins `renovate-version` to the exact release this file is
|
||||
// validated against. VALIDATE WITH THAT SAME TAG:
|
||||
// podman run --rm -v "$PWD/renovate.json5:/tmp/renovate.json5:ro,Z" \
|
||||
// ghcr.io/renovatebot/renovate:<renovate-version from renovate.yaml> \
|
||||
// renovate-config-validator /tmp/renovate.json5
|
||||
// (Not `--strict`: that also fails on a pending migration of the pre-existing top-level
|
||||
// `"docker": {"enabled": true}` block at the bottom, which is a warning, not an error.)
|
||||
//
|
||||
// `regex` vs `custom.regex` in enabledManagers, RESOLVED FROM SOURCE (Renovate 39.264.0 and
|
||||
// later): both work. lib/config/migrations/custom/enabled-managers-migration.ts rewrites
|
||||
// `regex` -> `custom.regex`, and that migration runs on every real repository run
|
||||
// (lib/workers/repository/init/merge.ts -> migrateAndValidate), not only in the validator;
|
||||
// lib/modules/manager/index.ts getEnabledManagersList accepts either spelling. `custom.regex` is
|
||||
// the canonical name (introduced in 37.51.1, renovatebot/renovate#24079), so it is used below and
|
||||
// nothing depends on the migration any more.
|
||||
{ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
// Renovate config — Phase 4 automated updates (ADR-0009, R-UPD-01/02). AS OF 2026-10-17
|
||||
// RENOVATE OWNS BOTH HALVES: Helm chart/dependency bumps AND per-service container image tags.
|
||||
@@ -51,7 +70,7 @@
|
||||
"labels": ["dependencies", "automated-update"],
|
||||
"ignoreUnstable": true,
|
||||
"respectLatest": true,
|
||||
"enabledManagers": ["flux", "kustomize", "helmv3", "kubernetes", "regex", "github-actions"],
|
||||
"enabledManagers": ["flux", "kustomize", "helmv3", "kubernetes", "custom.regex", "github-actions"],
|
||||
"flux": {
|
||||
"managerFilePatterns": [
|
||||
"/(^|/)platform/.+\\.ya?ml$/",
|
||||
@@ -93,6 +112,42 @@
|
||||
"#\\s*renovate:\\s*datasource=(?<datasource>\\S+)\\s+depName=(?<depName>\\S+)(?:\\s+versioning=(?<versioning>\\S+))?\\s*\\n.*?(?<currentValue>v?[0-9]+\\.[0-9]+\\.[0-9]+)"
|
||||
],
|
||||
"versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}"
|
||||
},
|
||||
// ADDED 2026-10-29 — THIS REPO'S OWN IMAGES (toolbox, agent-runner, conformance-runner).
|
||||
// CI publishes them (.gitea/workflows/images.yaml) under an immutable `sha-<commit>` tag and a
|
||||
// moving `main` tag, and never writes to git. Every reference to them is DIGEST-ONLY
|
||||
// (`<repo>@sha256:<hex>`, no tag), because the admission policies
|
||||
// (platform/kyverno/admission/pm-agent-job-shape.yaml, conformance-trigger-job-shape.yaml)
|
||||
// admit exactly that form. A digest alone gives Renovate nothing to follow, so the tag to
|
||||
// follow rides in a marker comment on the line ABOVE the reference:
|
||||
//
|
||||
// # renovate-digest: image=<registry>/<namespace>/<image> tag=main
|
||||
// <anything>sha256:<64 hex>
|
||||
//
|
||||
// `main` is not a version, so Renovate skips the release lookup and proposes a `digest`
|
||||
// update whenever the tag's digest moves (lib/workers/repository/process/lookup/index.ts:
|
||||
// an unversioned currentValue WITH a currentDigest yields updateType `digest`). The
|
||||
// `sha256:` prefix is INSIDE currentDigest on purpose: Renovate replaces that capture
|
||||
// verbatim with the new digest, which carries the prefix.
|
||||
//
|
||||
// DELIBERATELY NOT TRACKED: infra/agent/worker-job-template.yaml. It is baked INTO
|
||||
// agent-runner, so bumping it would rebuild agent-runner and loop forever; pm-dispatch
|
||||
// overwrites that field from PM_WORKER_IMAGE at runtime anyway.
|
||||
// REGISTRY AUTH: the Gitea registry answers 401 to anonymous reads, and the platform token is
|
||||
// scoped to hostType `gitea`, which a docker lookup never matches
|
||||
// (lib/util/host-rules.ts find). renovate.yaml supplies a hostType `docker` rule.
|
||||
{
|
||||
"customType": "regex",
|
||||
"description": "This repo's own CI-published images, pinned by digest, following the tag named in a `# renovate-digest:` marker on the previous line.",
|
||||
"managerFilePatterns": [
|
||||
"/(^|/)versions\\.env$/",
|
||||
"/(^|/)platform/pm-agent/.+\\.ya?ml$/"
|
||||
],
|
||||
"matchStrings": [
|
||||
"#\\s*renovate-digest:\\s*image=(?<depName>\\S+)\\s+tag=(?<currentValue>\\S+)\\s*\\n[^\\n]*?(?<currentDigest>sha256:[a-f0-9]{64})"
|
||||
],
|
||||
"datasourceTemplate": "docker",
|
||||
"versioningTemplate": "docker"
|
||||
}
|
||||
],
|
||||
"packageRules": [
|
||||
@@ -151,6 +206,26 @@
|
||||
"needs-review",
|
||||
"blast-radius"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "ADDED 2026-10-29. This repo's own images are followed ONLY through the `# renovate-digest:` markers above. The `kubernetes` manager also sees platform/pm-agent/deployment.yaml and infra/agent/worker-job-template.yaml, where the image has a digest and no tag; left on, it would look those up as `latest` (a tag CI never pushes) and, for the template, re-open the self-referential loop the custom manager deliberately avoids.",
|
||||
"matchManagers": ["kubernetes"],
|
||||
"matchPackageNames": [
|
||||
"gitea.home.keithjackson.dev/home-network/toolbox",
|
||||
"gitea.home.keithjackson.dev/home-network/agent-runner",
|
||||
"gitea.home.keithjackson.dev/home-network/conformance-runner"
|
||||
],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"description": "ADDED 2026-10-29. Digest bumps for this repo's own images: the image was built and verified by CI before it was published, so these auto-merge on a green gate like any digest (rule 1). Labelled so they are easy to find. NOTE: the conformance-runner bump edits conformance/versions.env, a sensitive path (infra/gitea/approval-policy.json), so it will wait for an administrator's /approve-override regardless of this rule.",
|
||||
"matchManagers": ["custom.regex"],
|
||||
"matchPackageNames": [
|
||||
"gitea.home.keithjackson.dev/home-network/toolbox",
|
||||
"gitea.home.keithjackson.dev/home-network/agent-runner",
|
||||
"gitea.home.keithjackson.dev/home-network/conformance-runner"
|
||||
],
|
||||
"addLabels": ["own-image"]
|
||||
}
|
||||
],
|
||||
// WHAT RENOVATE STILL CANNOT FIX, so nobody mistakes a working bot for full coverage. A
|
||||
@@ -168,10 +243,20 @@
|
||||
// shape, not software to keep current. `conformance/**` was already ignored for the same
|
||||
// reason; this closes the matching hole that enabling the `kubernetes` manager would otherwise
|
||||
// have opened.
|
||||
// conformance/** NARROWED 2026-10-29 to its subdirectories: ignorePaths applies to custom
|
||||
// managers too (lib/workers/repository/extract/file-match.ts getMatchingFiles ->
|
||||
// filterIgnoredFiles), so the blanket glob also hid conformance/versions.env, which now carries
|
||||
// the conformance-runner digest Renovate must maintain. Everything else under conformance/
|
||||
// stays ignored, for the original reason (test fixtures with deliberately fixed shapes).
|
||||
"ignorePaths": [
|
||||
"**/*.example",
|
||||
"**/*.sops.yaml",
|
||||
"conformance/**",
|
||||
"conformance/config/**",
|
||||
"conformance/incluster/**",
|
||||
"conformance/lib/**",
|
||||
"conformance/requirements/**",
|
||||
"conformance/runs/**",
|
||||
"conformance/tests/**",
|
||||
"platform/image-automation/per-service/**",
|
||||
"platform/kyverno/tests/**"
|
||||
],
|
||||
|
||||
Reference in new issue
Block a user