feat(ci): add self-hosted renovate alongside dependabot#737
Merged
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
Introduces a self-hosted Renovate runner that shadows dependabot during
a soft-launch phase. Renovate replaces and extends dependabot's
coverage by also tracking the tool versions pinned in .settings.yaml
(the project's single source of truth) — something dependabot cannot
do.
## Coverage delta over dependabot
| Source | Manager | Status |
|---|---|---|
| go.mod | gomod | preserved (kubernetes/golang-x/opencontainers groups carried over verbatim) |
| .github/workflows/*, .github/actions/*/action.yml | github-actions | preserved + grouped into one PR/cycle |
| validators/*/Dockerfile | dockerfile | preserved |
| infra/**/*.tf | terraform | preserved + grouped |
| site/package.json | npm | NEW |
| recipes/components/*/values.yaml | helm-values | NEW (partial — auto-detects image.repository/image.tag shape) |
| .settings.yaml (28 tool entries) | custom regex manager | NEW |
| .settings.yaml chainsaw checksums | postUpgradeTasks → tools/update-chainsaw-checksums | NEW |
| .settings.yaml nvkind SHA | dedicated git-refs digest customManager | NEW |
## Key design decisions
- **Self-hosted via renovatebot/github-action** with the built-in
GITHUB_TOKEN. The repo's /ok reviewer-comment policy re-fires CI on
bot PRs, sidestepping GitHub's "GITHUB_TOKEN cannot trigger
workflows" limitation. No PAT/App needed.
- **Custom regex manager for .settings.yaml** — annotations look like
`# renovate: datasource=<DS> depName=<DN> depType=<section>` and
drive the per-section grouping below. Each section in the YAML maps
to its own bundled PR.
- **git-refs digest customManager for nvkind** — uses a distinct
`# renovate-digest:` annotation prefix so the broad regex doesn't
double-extract it. Captures the 40-char SHA into currentDigest.
- **Group consolidation** — section-based bundles for .settings.yaml
(build-tools, linting, security-tools, testing-tools, docs-tools,
test-images, languages); cross-manager bundles for `supply-chain`
(anchore/* + sigstore/* spanning regex + github-actions); single
`docs` bundle merging hugo (.settings.yaml) with site/package.json.
- **Conservative auto-merge** — positive-listed. Only github-actions/
gomod/npm patches plus an explicit allow-list of build/lint/security
tooling auto-merge. Cluster-impacting pins (helm, kubectl, kind,
kwok, chainsaw, karpenter, gpu-operator, kindest/node, CUDA, Go
toolchain, node, hugo, nvkind) require human review.
- **Release cooldown** — `minimumReleaseAge: "3 days"` globally,
raised to "7 days" for auto-merged updates. Defends against
malicious-publish ratchet attacks (event-stream, colors.js,
node-ipc, ...). `internalChecksFilter: "strict"` excludes too-young
releases entirely from the dashboard.
- **Schedule** — workflow cron at `0 5 * * 1-5` (weekdays 05:00 UTC)
is the single source of truth. There is intentionally no
second-layer `schedule:` in renovate.json5 — self-hosted Renovate
runs only when the workflow fires, so a config-side schedule is
redundant and creates an alignment trap.
- **Supply-chain image pinning** — both Renovate runner image
references (Makefile validator + workflow) digest-pinned to
`sha256:00185c0d…` for consistency with the project's GitHub
Actions pinning policy. Lockstep noted in inline comments.
- **Permissions** — explicit `contents: write`, `pull-requests:
write`, `issues: write`, **and `statuses: write`**. The last is
load-bearing: Renovate calls POST /repos/{owner}/{repo}/statuses/
{sha} after each branch creation to write a stability status check
(tied to the cooldown / merge-confidence flow). Without it, the
call 403s and Renovate's error handler maps the failure to
"repository-changed", silently aborting the run.
## CI integration
- `make lint-renovate` validates .github/renovate.json5 against the
same `ghcr.io/renovatebot/renovate:43@sha256:…` image the workflow
uses. NOT part of the `make lint` aggregate (that target stays
Docker-free); invoked directly by CI.
- `verify-renovate` job in `.github/workflows/merge-gate.yaml` runs
`make lint-renovate` only when `.github/renovate.json5` changes
(path-filtered via dorny/paths-filter, mirroring the
verify-licenses pattern). Skip job + aggregate gate wiring keep
the required-status semantics correct.
## Soft-launch plan
See `.github/RENOVATE.md` for the phased Phase A–E rollout. dependabot
config and auto-merge workflow remain in place until Phase D confirms
Renovate is healthy on the live repo end-to-end. Phase E is a
follow-up PR removing them.
This branch was extracted from a soft-launch practice exercise on the
maintainer's fork (njhensley/aicr) where every component was exercised
end-to-end: 4+ Renovate runs producing real PRs across manager types,
verify-renovate gate firing path-filtered, status checks writing
correctly, cooldown filtering young releases, group consolidation
producing single PRs across managers, and the chainsaw post-upgrade
hook validated as idempotent. The thrash from the practice exercise
(several PRs chasing a misleading "repository-changed" error message
that turned out to be a missing statuses:write permission) is squashed
out of this branch — only the converged final state lands here.
fd7d152 to
d10d943
Compare
mchmarny
approved these changes
May 5, 2026
Member
mchmarny
left a comment
There was a problem hiding this comment.
Approving. Substantial, well-documented infra enhancement with a conservative soft-launch posture (Dependabot stays, auto-merge positive-listed + 7-day cooldown, cluster-impacting pins reserved for human review). The inline policy comments and RENOVATE.md make the design decisions reviewable in isolation, and the regression breadcrumbs (the configurationFile: / dual-extraction note, the statuses:write debug story) will save someone hours later.
CI is green on the verify-renovate gate; the GPU jobs in progress are unrelated to the config surface. Three non-blocking inline notes (vendor handling, regex edge case, sed pre/post-check kudos) — none gate merge.
This was referenced May 6, 2026
10 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduces a self-hosted Renovate runner that shadows Dependabot during a soft-launch phase. Renovate replaces and extends Dependabot's coverage by also tracking the tool versions pinned in
.settings.yaml(the project's single source of truth) — something Dependabot cannot do.Motivation / Context
Dependabot covers
gomod,github-actions, Dockerfile-onlydocker, andterraform. It cannot manage the 28 tool versions pinned in.settings.yaml, which currently drift via hand-bumps. Renovate's customManager handles them via# renovate:annotations and bundles updates per top-level YAML section.Dependabot stays in place; Phase E (cutover) is a follow-up PR that removes
dependabot.yml+dependabot-auto-merge.yamlonce Renovate has produced one healthy weekday cycle.Fixes: N/A
Related: pattern modeled on
NVIDIA/gpu-operatorType of Change
Component(s) Affected
Implementation Notes
What's covered
go.modgomod(groups:kubernetes,golang-x,opencontainers).github/workflows/*.yaml,.github/actions/*/action.ymlgithub-actions(digest-pinned, grouped per cycle)validators/*/Dockerfiledockerfileinfra/**/*.tfterraform(grouped)site/package.jsonnpm(bundled withdocs_toolsintodocsgroup)recipes/components/*/values.yamlhelm-values(auto-detectsimage.repository/image.tagonly).settings.yaml(28 tool entries).settings.yamlnvkindSHA.settings.yamlchainsaw_checksumspostUpgradeTasks→tools/update-chainsaw-checksumsDesign decisions
renovatebot/github-actionwith the built-inGITHUB_TOKEN. The repo's/okreviewer-comment policy re-fires CI on bot PRs, sidestepping GitHub's "GITHUB_TOKEN cannot trigger workflows" limitation. No PAT/App needed..settings.yaml— annotations look like# renovate: datasource=<DS> depName=<DN> depType=<section>and drive section-based PR grouping. ThedepTypeis the YAML top-level key (e.g.build_tools,testing_tools). Three matchString shapes cover plain scalars,image:tagstrings, and YAML list items.nvkind(pinned by main-branch SHA) gets a dedicatedgit-refsdigest customManager with a distinct# renovate-digest:annotation prefix so the broad regex doesn't double-extract it..settings.yaml(build-tools, linting, security-tools, testing-tools, docs-tools, test-images, languages); cross-manager bundles forsupply-chain(anchore/* + sigstore/* spanning regex + github-actions); singledocsbundle merging hugo (.settings.yaml) withsite/package.json.github-actions/gomod/npmpatches plus an explicit allow-list of build/lint/security tooling auto-merge. Cluster-impacting pins (helm, kubectl, kind, kwok, chainsaw, karpenter, gpu-operator, kindest/node, CUDA, Go toolchain, node, hugo, nvkind) require human review even on patches.minimumReleaseAge: "3 days"globally, raised to"7 days"for auto-merged updates. Defends against malicious-publish ratchet attacks (event-stream / colors.js / node-ipc style).internalChecksFilter: "strict"keeps the dashboard clean.cron: "0 5 * * 1-5"(weekdays 05:00 UTC) is the single source of truth. Intentionally NOschedule:field inrenovate.json5— self-hosted Renovate runs only when the workflow fires, so a config-side schedule would be redundant and create an alignment trap (mismatched windows would silently hold every PR in "Awaiting Schedule").sha256:00185c0d…for consistency with the project's GitHub Actions pinning policy. Lockstep noted in inline comments.contents: write,pull-requests: write,issues: write, andstatuses: write. The last is load-bearing: Renovate callsPOST /repos/{owner}/{repo}/statuses/{sha}after each branch creation to write a stability status check (tied to the cooldown / merge-confidence flow). Without it, the call 403s and Renovate's error handler maps the failure to a misleading "repository-changed" abort. Worth noting for any future workflows trying to use Renovate with restrictive permissions.CI integration
make lint-renovatevalidates.github/renovate.json5against the sameghcr.io/renovatebot/renovate:43@sha256:…image the workflow uses. Intentionally NOT part ofmake lint(that target stays Docker-free); invoked directly by CI.verify-renovatejob in.github/workflows/merge-gate.yamlrunsmake lint-renovateonly when.github/renovate.json5changes (path-filtered viadorny/paths-filter, mirroring theverify-licensespattern). Skip job + aggregate gate wiring keep the required-status semantics correct.Soft-launch plan
.github/dependabot.ymland.github/workflows/dependabot-auto-merge.yamlare deliberately untouched. Once this PR merges:workflow_dispatchand confirm the dashboard issue + first PRs land cleanly.Testing
The configuration was exercised end-to-end on a fork (
njhensley/aicr) before this PR:verify-renovategate firing exactly when.github/renovate.json5changed and skipping otherwise.statuses:writepermission verified — the stability-status call writes successfully (renovate/stability-daysstatus:Updates have met minimum release age requirement).renovate/supply-chainbundledanchore/*from both.settings.yamlregex andgithub-actionsworkflow files).tools/update-chainsaw-checksumspost-upgrade hook validated as idempotent (zero diff against the currently-pinnedv0.2.14).verify-renovatepath-filter validated by toggling unrelated changes.This is a CI/config-only change — no Go code is touched.
Risk Assessment
Rollout notes: See
.github/RENOVATE.mdfor the full coverage description and the policy choices documented inline inrenovate.json5. Cutover is a follow-up PR removing the Dependabot config; this PR does not delete anything.Checklist
make lint-renovate,actionlinton the new + modified workflows)verify-renovatevalidates it on every PR that touches it).github/RENOVATE.mdis the canonical reference)dorny/paths-filtergating,.settings.yamlas source of truth)git commit -S)