Run 350 cleared platform init (/user 200, /version 200, /repos 200), then stopped at GET /api/v1/orgs/Home-Network with Gitea's own 403: token does not have at least one of required scope(s), required=[read:organization], token scope=read:package,write:repository,read:user The workflow's header listed only those three scopes, and the operator minted exactly that. Renovate's initRepo -> isOrg needs read:organization, and Gitea files /issues and /labels under the issue scope, which the dashboard and PR labels need: write:issue. - renovate.yaml: corrects the scope list (read:user, read:organization, write:repository, write:issue, read:package), with the call each serves. A new preflight step probes them with GETs, the token passed to curl on stdin, and names a missing scope instead of Renovate's bare "Authentication failure". - ci/lint.sh: rejects workflow `uses:` lines that need a Docker daemon (docker://, renovatebot/github-action, docker/*-action), the class fixed in #84. Co-Authored-By: Claude Opus 5.5 <[email protected]>
6.0 KiB
date, branch, title
| date | branch | title |
|---|---|---|
| 2026-10-30 | fix/renovate-auth | Renovate's token needs five scopes, not three; the workflow documented the wrong list, and now probes it |
What changed
The fix is operator-side. RENOVATE_TOKEN lacks read:organization, and it will next lack
write:issue. The operator must re-mint it with five scopes:
read:userread:organizationwrite:repositorywrite:issueread:package
The git half fixes the two things that sent the operator round this loop twice.
.gitea/workflows/renovate.yaml:
- The header's scope list is corrected, with the call each scope serves. The old list named
only
write:repository,read:userandread:package, and the operator minted exactly that. The preflight's "TO FIX" text is corrected the same way. - A new step, "Preflight - the token has every scope Renovate needs".
- It probes read-only GETs:
/userfor read:user,/orgs/Home-Networkfor read:organization,/repos/{repo}for read:repository,/repos/{repo}/labelsfor read:issue, and registry/v2/tokenfor read:package. - It reads the token's own scope list out of Gitea's 403 from
/admin/orgs(names only), and requireswrite:repositoryandwrite:issuein it. - It says what a failure means: 401 is the value; a Gitea 403 is a scope, and the probe prints Gitea's message; an "Access denied" 403 is a Cilium/Envoy denial.
- The token is fed to curl on stdin (
--config -), never in argv.
- It probes read-only GETs:
ci/lint.sh: a new guard rejects any non-comment uses: in .gitea/workflows that needs a
Docker daemon: docker://, renovatebot/github-action and Docker's daemon-bound
docker/*-actions. That is the class of bug fixed in #84.
Root cause, with evidence
Run 350 (task 567, 06:49 UTC) got further than 348 and 349. Gitea's router log, filtered to
the act-runner pod 10.0.0.38:
06:49:31 GET /api/v1/user 200 OK
06:49:31 GET /api/v1/version 200 OK
06:49:31 GET /api/v1/repos/Home-Network/home-network-k3s-impl 200 OK
06:49:31 GET /api/v1/orgs/Home-Network 403 Forbidden
There were no /v2/ requests: Renovate stopped before extraction. From the job log, verbatim:
ERROR: Repository has unknown error (repository=Home-Network/home-network-k3s-impl)
"url": "https://gitea.home.keithjackson.dev/api/v1/orgs/Home-Network",
"message": "token does not have at least one of required scope(s), required=[read:organization], token scope=read:package,write:repository,read:user"
"x-envoy-upstream-service-time": "27", "server": "envoy"
INFO: Repository finished ... "result": "unknown-error", "exitCode": 8
This is not Cilium. The body is Gitea's JSON scope message, Gitea logged the request, and
x-envoy-upstream-service-time shows that Envoy forwarded it upstream.
The secret WAS updated. Runs 348 and 349 got GET /user 403 from tokenRequiresScopes. Run 350
got /user 200, and its token scope list now includes read:user.
Why read:organization is needed. Renovate 44.167.0, lib/modules/platform/gitea/index.ts
initRepo, calls helper.isOrg → GET /orgs/{owner} and rethrows on error. Gitea 1.24.3,
routers/api/v1/api.go, puts /orgs/{org} behind
tokenRequiresScopes(AccessTokenScopeCategoryOrganization).
Why write:issue is needed next. In the same api.go, /repos/{o}/{r}/issues…, /labels
and /milestones sit in a group with tokenRequiresScopes(AccessTokenScopeCategoryIssue)
(lines 1466–1582). Renovate's gitea-helper uses /issues, /issues/{n}/labels, /labels and
/issues/{n}/comments, for the dependency dashboard (:dependencyDashboard is extended) and for
PR labels. A dry run only reads them; a scheduled run writes them.
The other causes the coordinator listed are ruled out:
- Schedule window and dry-run. The run never reached branch processing.
- Repository config. The run never reached the clone (
"cloned": undefined). - The Summary step. It is not involved; the failure is Renovate's own exit 8.
What I verified
- I read the whole run 350 job log (204 lines), and the router lines above. Runs 348 and 349 are
as recorded in
decisions/2026-10-30-renovate-first-run.md's follow-up:/usergot 403 fromtokenRequiresScopes. - The probe step, in the pinned image. I extracted the step body from the YAML and ran it in
ghcr.io/renovatebot/renovate:44.167.0(curl8.5.0 andjqare present) with a deliberately bogus token. Every probe reported 401 with the "token VALUE" diagnosis, the scope-list read fell back to a warning, and the step exited 1. - The scope-list parser. Against run 350's exact message format it reports
write:issueMISSING. Against a five-scope list it reports both OK. Againstallit reports both OK. - The lint guard. It flags
renovatebot/github-actionin the pre-#84renovate.yaml(dfc432c, line 152). It reports nothing on the current workflows, and it ignores commented lines.bash -n ci/lint.shpasses. - Account facts, read-only.
renovate-botis a collaborator withwrite, and the org is public.
What I did NOT verify
- The probe with a real token. UNVERIFIED. I never had the token. In particular, I have not
observed that
GET /api/v1/admin/orgsgives renovate-bot's token a 403 with atoken scope=list. The source says the scope check runs beforereqSiteAdmin. If the message format differs, the step warns and does not fail. - That five scopes are enough for a full non-dry run. They cover every helper endpoint Renovate 44.167.0 calls, mapped to Gitea 1.24.3's route categories by reading source. Branch pushes go over git-over-HTTPS with the token; I believe that needs write:repository, but I have not observed it.
- Registry reads as renovate-bot.
read:packageon a public org is expected to work. The new probe is the first real test of it. - Sensitive paths.
.gitea/**andci/**are both sensitive. CI'sapproval-policywill block until the operator posts/approve-overrideas a PR review.