publish-kdl-write CI job 401s: CI_RELEASE_TOKEN lacks write:package scope, so #501's internal channel is empty #550

Open
opened 2026-07-03 06:48:36 +00:00 by coilysiren · 1 comment
Owner

Symptom

The publish-kdl-write job added by #501 (commit 31281f1a, "give ward-kdl-write an internal channel so the broker survives ward#455") fails in CI with HTTP 401:

Publish ward-kdl-write to the internal package registry (not the release page)
curl: (22) The requested URL returned error: 401   # DELETE (|| true, non-fatal)
curl: (22) The requested URL returned error: 401   # PUT  (-f, fails the job)

Run: https://forgejo.coilysiren.me/coilyco-flight-deck/ward/actions/runs/799/jobs/2/attempt/1

Consequence (why this matters, not just red CI)

The generic package registry for ward-kdl-write is empty - confirmed via GET /api/v1/packages/coilyco-flight-deck?type=generic returns []. So the broker's INTERNAL channel that #501 built has nothing in it. The ward#455 goal is not actually satisfied: the write tier never lands in the internal channel, and a broker that stopped reading release assets has nowhere to fetch from. #501 shipped functionally broken and was closed on the code merge, not on a green publish.

Root cause

The job authenticates the packages API with CI_RELEASE_TOKEN:

base="${FORGEJO_BASE_URL}/api/packages/${PKG_OWNER}/generic/ward-kdl-write/${TAG}"
curl -fsSL -X PUT -H "Authorization: token ${TOKEN}" --data-binary @"dist/${file}" "${base}/${file}"

CI_RELEASE_TOKEN carries release-asset scope (the release job uses it fine against /api/v1/repos/.../releases) but not write:package. The Forgejo generic package registry (/api/packages/...) requires package write scope, so both the DELETE and PUT 401. The job's own comment already flags the requirement: "CI_RELEASE_TOKEN must carry package write scope." That precondition is unmet in the deployed secret.

Fix - a credential action, plus an optional code tidy

Required (only a Forgejo admin can do this - not an engineer container):

  • Either regenerate CI_RELEASE_TOKEN to add the write:package (+ read:package/delete) scope and update the Actions secret, or
  • add a dedicated PKG_WRITE_TOKEN Actions secret scoped to packages only, mirroring how bump-tap-formula uses a dedicated TAP_WRITE_TOKEN instead of overloading the release token.

Optional code change (dispatchable once the secret decision is made):

  • If we go the dedicated-secret route, point the publish-kdl-write step at ${{ secrets.PKG_WRITE_TOKEN }} with the same up-front -z guard the other jobs use, and update the comment. Purely mechanical once the secret exists.

Verify after fix: re-run the release workflow (or a tag re-run), then confirm GET /api/v1/packages/coilyco-flight-deck?type=generic&q=ward-kdl-write lists both ward-kdl-write-linux-amd64 and -arm64 under the release tag, and that the broker fetches the write tier from the internal channel.

  • #501 (source - closed on code merge, feature is publish-broken)
  • ward#455 (the release-asset removal this internal channel was meant to survive)
  • bump-tap-formula / TAP_WRITE_TOKEN - the dedicated-scoped-secret precedent (ward#237, ward#243)
## Symptom The `publish-kdl-write` job added by #501 (commit `31281f1a`, "give ward-kdl-write an internal channel so the broker survives ward#455") fails in CI with **HTTP 401**: ``` Publish ward-kdl-write to the internal package registry (not the release page) curl: (22) The requested URL returned error: 401 # DELETE (|| true, non-fatal) curl: (22) The requested URL returned error: 401 # PUT (-f, fails the job) ``` Run: https://forgejo.coilysiren.me/coilyco-flight-deck/ward/actions/runs/799/jobs/2/attempt/1 ## Consequence (why this matters, not just red CI) The generic package registry for `ward-kdl-write` is **empty** - confirmed via `GET /api/v1/packages/coilyco-flight-deck?type=generic` returns `[]`. So the broker's INTERNAL channel that #501 built has nothing in it. **The ward#455 goal is not actually satisfied**: the write tier never lands in the internal channel, and a broker that stopped reading release assets has nowhere to fetch from. #501 shipped functionally broken and was closed on the code merge, not on a green publish. ## Root cause The job authenticates the packages API with `CI_RELEASE_TOKEN`: ``` base="${FORGEJO_BASE_URL}/api/packages/${PKG_OWNER}/generic/ward-kdl-write/${TAG}" curl -fsSL -X PUT -H "Authorization: token ${TOKEN}" --data-binary @"dist/${file}" "${base}/${file}" ``` `CI_RELEASE_TOKEN` carries release-asset scope (the `release` job uses it fine against `/api/v1/repos/.../releases`) but **not `write:package`**. The Forgejo generic package registry (`/api/packages/...`) requires package write scope, so both the DELETE and PUT 401. The job's own comment already flags the requirement: "CI_RELEASE_TOKEN must carry package write scope." That precondition is unmet in the deployed secret. ## Fix - a credential action, plus an optional code tidy **Required (only a Forgejo admin can do this - not an engineer container):** - Either **regenerate `CI_RELEASE_TOKEN`** to add the `write:package` (+ `read:package`/`delete`) scope and update the Actions secret, **or** - add a **dedicated `PKG_WRITE_TOKEN`** Actions secret scoped to packages only, mirroring how `bump-tap-formula` uses a dedicated `TAP_WRITE_TOKEN` instead of overloading the release token. **Optional code change (dispatchable once the secret decision is made):** - If we go the dedicated-secret route, point the `publish-kdl-write` step at `${{ secrets.PKG_WRITE_TOKEN }}` with the same up-front `-z` guard the other jobs use, and update the comment. Purely mechanical once the secret exists. **Verify after fix:** re-run the release workflow (or a tag re-run), then confirm `GET /api/v1/packages/coilyco-flight-deck?type=generic&q=ward-kdl-write` lists both `ward-kdl-write-linux-amd64` and `-arm64` under the release tag, and that the broker fetches the write tier from the internal channel. ## Related - #501 (source - closed on code merge, feature is publish-broken) - ward#455 (the release-asset removal this internal channel was meant to survive) - `bump-tap-formula` / `TAP_WRITE_TOKEN` - the dedicated-scoped-secret precedent (ward#237, ward#243)
Author
Owner

Root cause confirmed + fix relocated. CI_RELEASE_TOKEN is a scripted/bot-minted PAT, not a hand-edited UI token: infrastructure/scripts/provision-ci-release-token.sh mints it with "scopes":["write:repository"] and stashes it at SSM /forgejo/ci-release-token + the org Actions secret. write:repository covers Releases (why the release job works) but not the package registry, hence the 401.

Corrected fix path (the ward release.yml needs NO change):

  1. Code: add write:package to the mint scope list in provision-ci-release-token.sh -> filed as infrastructure#448, engineer dispatched.
  2. Operator (credential action, Kai): re-run that script to rotate the SSM param + org secret with the new scope.
  3. Re-run the ward release workflow; confirm ward-kdl-write (amd64+arm64) lands in the generic registry.

Supersedes the earlier 'dedicated PKG_WRITE_TOKEN vs rescope' fork - rescope is a clean one-line scope add in the provisioning script.

**Root cause confirmed + fix relocated.** `CI_RELEASE_TOKEN` is a scripted/bot-minted PAT, not a hand-edited UI token: `infrastructure/scripts/provision-ci-release-token.sh` mints it with `"scopes":["write:repository"]` and stashes it at SSM `/forgejo/ci-release-token` + the org Actions secret. `write:repository` covers Releases (why the `release` job works) but **not** the package registry, hence the 401. **Corrected fix path (the ward `release.yml` needs NO change):** 1. Code: add `write:package` to the mint scope list in `provision-ci-release-token.sh` -> filed as **infrastructure#448**, engineer dispatched. 2. Operator (credential action, Kai): re-run that script to rotate the SSM param + org secret with the new scope. 3. Re-run the ward release workflow; confirm `ward-kdl-write` (amd64+arm64) lands in the generic registry. Supersedes the earlier 'dedicated PKG_WRITE_TOKEN vs rescope' fork - rescope is a clean one-line scope add in the provisioning script.
coilyco-ops added
P4
and removed
P2
labels 2026-07-14 06:50:32 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#550
No description provided.