ci: push tag via ANVIL_TOKEN URL, not clone-token origin #11

merged colechristensen cole.christensen@gmail.com wants to merge ci/git-push-via-anvil-token into main
No CI

Problem

The last release run failed at the final step:

fatal: Authentication failed for 'https://anvil.fangorn.io/fangorn/ex_git_objectstore.git/'

The runner clones the repo via an auto-embedded URL that has the clone token baked into the userinfo. Clone tokens are legacy-read-only per `git_http_controller` — the catch-all `authorize_service(:job_token, _, _, _)` returns `:unauthorized` for anything other than `git-upload-pack`. `git push origin` always 401s.

Fix

Don’t push via origin. Instead push via an explicit URL that embeds `$ANVIL_TOKEN` — the per-job API token injected by the runner, which goes through the new `authenticate_api_job_token` path in `git_http_auth` and checks `contents: :write` in the effective scope map.

git push \\
\"https://x-token:\${ANVIL_TOKEN}@anvil.fangorn.io/fangorn/ex_git_objectstore.git\" \\
\"\$VERSION\"

This is a two-line functional change (plus a four-line comment block explaining the why). No other parts of the release step move.

Prerequisites

  • `fangorn/anvil#46` (design) — filed
  • `fangorn/anvil#57` (unified CI token backend) — merged + deployed
  • `fangorn/anvil#58` (CI permissions UI) — merged + deployed (assumed; needed for admins to configure)
  • `fangorn/anvil#59` (git HTTP accepts API tokens for push)must land before this PR
  • `contents: :write` granted on this repo — already done

If this PR lands before #59 is deployed, the push still fails — but with a proper `ci_scope_exceeded` error instead of the cryptic shell-syntax / HTML-not-binary / not-logged-in errors we’ve been chasing. Strictly better than the status quo.

Test plan

There’s no unit test I can write in this repo that exercises the full push flow against a real server — that’s what the tests in `fangorn/anvil#59` are for. The real test is: merge #59, deploy, merge this PR, watch the next main CI run actually cut `2026.4.1`.

If it fails yet again, I owe you a very careful explanation.

🤖 Generated with Claude Code

Created Apr 13, 2026 at 23:42 UTC | Merged Apr 14, 2026 at 00:02 UTC by colechristensen cole.christensen@gmail.com