fix(ci): grant statuses:write so renovate can set branch status checks#7
Merged
Merged
Conversation
Root cause of the persistent "Repository has changed during renovation" aborts since PR #4 — Renovate was calling POST /repos/{owner}/{repo}/ statuses/{sha} after each branch creation to write a stability status check (tied to the cooldown / merge-confidence flow). The workflow's permissions block had contents:write, pull-requests:write, issues:write but not statuses:write, so the call 403'd with "integration- unauthorized". Renovate's error handler maps that internally to "repository-changed", which is why every prior debugging attempt (checkout, configurationFile, dry-run env, digest pin) chased the wrong symptom. Confirmed via debug log on run 25346172853: Request failed with status code 403 (Forbidden): POST .../statuses/cf3dc7d1... "x-accepted-github-permissions": "statuses=write" DEBUG: Caught error setting branch status - aborting Error: integration-unauthorized DEBUG: Passing repository-changed error up The earlier hypothesis fixes in PRs #5 and #6 weren't wrong per se (actions/checkout and configurationFile aren't the cause, and RENOVATE_DRY_RUN='' isn't either) — they just couldn't have fixed the underlying permission gap. With statuses:write added, Renovate's post-branch status-check call should succeed and the run should complete normally.
6 tasks
njhensley
added a commit
that referenced
this pull request
May 4, 2026
Confirmed in production run 25346453345: the regex manager stats
showed `"regex": {"fileCount": 4, "depCount": 56}` instead of the
expected 2/28. With `configurationFile: .github/renovate.json5`
passed, the action mounts the file as Renovate's global config AND
Renovate auto-discovers the same file from the cloned working tree;
both loads register the customManagers and every annotation gets
extracted twice. The doubling produced 14 "Cannot find replaceString
in current file content. Was it already updated?" warnings across
the four created branches — Renovate's first pass applied the
replacement, the second pass tried to re-apply but the content no
longer matched.
PR #6 added `configurationFile:` chasing the "repository-changed"
aborts under the wrong hypothesis; PR #7 found and fixed the actual
cause (missing `statuses: write` permission). With #7 in place we
can drop `configurationFile:` cleanly. Earlier dry-run experiments in
RENOVATE_PLATFORM=local mode had already shown this doubling, but I
mis-attributed it to local-mode specifics. Production confirms the
behavior is the same.
`actions/checkout` stays — it's not the cause of any issue we've
seen, and the upstream gpu-operator pattern keeps it.
5 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
One-line permission addition (
statuses: write) that fixes the persistentRepository has changed during renovationaborts every Renovate run has hit since PR #4.Root cause
The error message is misleading. Pulled the debug-level log from run 25346172853:
After Renovate creates each branch, it calls
POST /repos/{owner}/{repo}/statuses/{sha}to write a stability status check (used by the cooldown / merge-confidence pipeline). Our workflow'spermissions:block hadcontents,pull-requests, andissueswrite, but notstatuses. The 403 propagates asintegration-unauthorized, which Renovate's error handler maps internally torepository-changed— a wildly misleading message for what's actually a missing OAuth scope.NVIDIA/gpu-operator's workflow works because they don't set
permissions:at all, so GitHub falls back to defaultwrite-allwhich implicitly includesstatuses: write. We were trying to be principle-of-least-privilege but blocked a required scope.PRs #5 and #6 (drop checkout / restore configurationFile / conditional dry-run) chased symptoms that couldn't have been the cause. Their changes are still defensible on their own merits (PR #6 in particular re-aligns with gpu-operator's pattern), but only this PR addresses the actual abort.
Fixes: persistent
repository-changedaborts since PR #4Related: #5, #6
Type of Change
Implementation Notes
Testing
actionlint .github/workflows/renovate.yaml # cleanPost-merge validation:
renovate/build-toolsbranch (will be re-created by next run with proper status check).gh workflow run renovate.yaml --repo njhensley/aicr.result: "renovate-pr-created"(or similar) instead ofrepository-changed.Risk Assessment
statuses: writelets the GITHUB_TOKEN write status checks on commits in this repo only; matches what gpu-operator's setup gets implicitly via the default permission set.Checklist
actionlint)git commit -S)