Unify forge-token secret prefix: FORGEJO_TOKEN_* → FORGE_TOKEN_* #867

Closed
opened 2026-05-05 05:39:47 +00:00 by claude-desktop · 4 comments
Collaborator

As a maintainer, I want every per-type Forgejo PAT in the secret table renamed to a forge-neutral FORGE_TOKEN_<TYPE> prefix, so that the multi-forge story (#29) doesn't carry a Forgejo-specific name for what is now a generic forge credential and so the dashboard stops accumulating two parallel sets of token rows whenever a re-seed runs.

Context

Live secret table on the desktop today carried two parallel sets of forge-token rows for every agent type:

  • FORGEJO_TOKEN_<TYPE> — seeded 2026-05-01 from token files; the live name (defaults.ts:95 references ${SECRET:FORGEJO_TOKEN_$$TYPE_UPPER$$}, onboarding-apply.ts:363 writes under this prefix).
  • FORGE_TOKEN_<TYPE> — written 2026-05-03 by the TOK-1 (#757/#764) one-shot env→DB migration. Orphaned: no code path reads them; the cleanup got dropped when the Drizzle nuke (#854) deleted the 17 hand-rolled migrations.

The 6 stale FORGE_TOKEN_* rows were deleted manually 2026-05-05. This issue prevents recurrence by collapsing onto one canonical prefix — and the forge-neutral FORGE_TOKEN_* is the one to keep, lined up with the env var name FORGE_TOKEN already injected into agent containers (render-for-instance.ts:200).

Acceptance criteria

Code rename

  • apps/server/src/domain/agent-config/defaults.ts:95 — flip the FORGE_TOKEN env-var template from ${SECRET:FORGEJO_TOKEN_$$TYPE_UPPER$$} to ${SECRET:FORGE_TOKEN_$$TYPE_UPPER$$}.
  • apps/server/src/http/handlers/onboarding-apply.ts:363secretNameForType returns FORGE_TOKEN_<TYPE> (update the JSDoc on line 358-359 too).
  • apps/server/src/infrastructure/container/container.ts:34 — comment block updated to reference FORGE_TOKEN_<TYPE>.
  • No remaining FORGEJO_TOKEN_<TYPE> references in apps/ or packages/ outside of (a) the legacy-rename literals in db.ts:688-689 (those are migration breadcrumbs, see next section) and (b) test fixtures pinned to the legacy literal.

Migration

  • On boot, copy every FORGEJO_TOKEN_<TYPE> row in secret to a same-value FORGE_TOKEN_<TYPE> row, then delete the FORGEJO_TOKEN_<TYPE> row. Idempotent — re-running on a fresh boot is a no-op.
  • The legacy-rename pairs in db.ts:688-689 are extended (or renamed) so the boss→code-lead and foreman→architect literal renames still apply against the new prefix. Equivalent rows for both prefixes are accepted (operator may have either).

Tests

  • New unit test: seed table with FORGEJO_TOKEN_DEV='abc' + FORGEJO_TOKEN_REVIEWER='xyz' → run migration → expect rows under FORGE_TOKEN_DEV='abc' + FORGE_TOKEN_REVIEWER='xyz', with the original rows gone.
  • Coexistence test: seed BOTH FORGEJO_TOKEN_DEV='old' + FORGE_TOKEN_DEV='new' → migration leaves FORGE_TOKEN_DEV='new' (target row wins; legacy row dropped without overwriting). Logs the conflict.
  • Idempotency test: second migration run is a no-op (returns 0 rows touched).
  • onboarding-apply.ts test fixture asserts the new prefix.

Docs

  • docs/credentials.md updated to reference the canonical FORGE_TOKEN_<TYPE> name.

Out of scope

  • Multi-forge token routing (#29FORGE_TOKENS JSON env var) — already in place; this is just a rename of the per-type secret row.
  • Per-instance overrides (FORGE_TOKEN_INSTANCE_<NAME>) — already on the new prefix; nothing to rename.
  • Webhook secret (WEBHOOK_SECRET_FORGEJO) — forge-specific by design (different webhook secrets per forge).
  • OAuth client secret (FORGEJO_OAUTH_CLIENT_SECRET) — also per-forge by design (the operator_oauth_tokens table will eventually carry a client_secret_ref per forge, see PR D series).

References

  • defaults.ts:95 — current env-var template.
  • onboarding-apply.ts:358-363 — current secret-name builder.
  • db.ts:688-689 — legacy-rename pairs (boss→code-lead, foreman→architect).
  • render-for-instance.ts:200FORGE_TOKEN env var (forge-neutral) injected at dispatch.
  • TOK-1 (#757 / #764) — original env→DB migration that wrote FORGE_TOKEN_<TYPE>.
  • Drizzle nuke (#854) — dropped the migration ladder; this issue restores the prune step under the new naming.
  • Cleanup of stale rows on 2026-05-05 — manual DELETE against 6 orphan FORGE_TOKEN_* rows.
**As a** maintainer, **I want** every per-type Forgejo PAT in the `secret` table renamed to a forge-neutral `FORGE_TOKEN_<TYPE>` prefix, **so that** the multi-forge story (#29) doesn't carry a Forgejo-specific name for what is now a generic forge credential and so the dashboard stops accumulating two parallel sets of token rows whenever a re-seed runs. ## Context Live `secret` table on the desktop today carried two parallel sets of forge-token rows for every agent type: - `FORGEJO_TOKEN_<TYPE>` — seeded 2026-05-01 from token files; **the live name** (`defaults.ts:95` references `${SECRET:FORGEJO_TOKEN_$$TYPE_UPPER$$}`, `onboarding-apply.ts:363` writes under this prefix). - `FORGE_TOKEN_<TYPE>` — written 2026-05-03 by the TOK-1 (#757/#764) one-shot env→DB migration. Orphaned: no code path reads them; the cleanup got dropped when the Drizzle nuke (#854) deleted the 17 hand-rolled migrations. The 6 stale `FORGE_TOKEN_*` rows were deleted manually 2026-05-05. This issue prevents recurrence by collapsing onto **one canonical prefix** — and the forge-neutral `FORGE_TOKEN_*` is the one to keep, lined up with the env var name `FORGE_TOKEN` already injected into agent containers (`render-for-instance.ts:200`). ## Acceptance criteria ### Code rename - [ ] `apps/server/src/domain/agent-config/defaults.ts:95` — flip the `FORGE_TOKEN` env-var template from `${SECRET:FORGEJO_TOKEN_$$TYPE_UPPER$$}` to `${SECRET:FORGE_TOKEN_$$TYPE_UPPER$$}`. - [ ] `apps/server/src/http/handlers/onboarding-apply.ts:363` — `secretNameForType` returns `FORGE_TOKEN_<TYPE>` (update the JSDoc on line 358-359 too). - [ ] `apps/server/src/infrastructure/container/container.ts:34` — comment block updated to reference `FORGE_TOKEN_<TYPE>`. - [ ] No remaining `FORGEJO_TOKEN_<TYPE>` references in `apps/` or `packages/` outside of (a) the legacy-rename literals in `db.ts:688-689` (those are migration breadcrumbs, see next section) and (b) test fixtures pinned to the legacy literal. ### Migration - [ ] On boot, copy every `FORGEJO_TOKEN_<TYPE>` row in `secret` to a same-value `FORGE_TOKEN_<TYPE>` row, then delete the `FORGEJO_TOKEN_<TYPE>` row. Idempotent — re-running on a fresh boot is a no-op. - [ ] The legacy-rename pairs in `db.ts:688-689` are extended (or renamed) so the boss→code-lead and foreman→architect literal renames still apply against the new prefix. Equivalent rows for both prefixes are accepted (operator may have either). ### Tests - [ ] New unit test: seed table with `FORGEJO_TOKEN_DEV='abc'` + `FORGEJO_TOKEN_REVIEWER='xyz'` → run migration → expect rows under `FORGE_TOKEN_DEV='abc'` + `FORGE_TOKEN_REVIEWER='xyz'`, with the original rows gone. - [ ] Coexistence test: seed BOTH `FORGEJO_TOKEN_DEV='old'` + `FORGE_TOKEN_DEV='new'` → migration leaves `FORGE_TOKEN_DEV='new'` (target row wins; legacy row dropped without overwriting). Logs the conflict. - [ ] Idempotency test: second migration run is a no-op (returns 0 rows touched). - [ ] `onboarding-apply.ts` test fixture asserts the new prefix. ### Docs - [ ] `docs/credentials.md` updated to reference the canonical `FORGE_TOKEN_<TYPE>` name. ## Out of scope - Multi-forge token routing (#29 — `FORGE_TOKENS` JSON env var) — already in place; this is just a rename of the per-type secret row. - Per-instance overrides (`FORGE_TOKEN_INSTANCE_<NAME>`) — already on the new prefix; nothing to rename. - Webhook secret (`WEBHOOK_SECRET_FORGEJO`) — forge-specific by design (different webhook secrets per forge). - OAuth client secret (`FORGEJO_OAUTH_CLIENT_SECRET`) — also per-forge by design (the operator_oauth_tokens table will eventually carry a `client_secret_ref` per forge, see PR D series). ## References - `defaults.ts:95` — current env-var template. - `onboarding-apply.ts:358-363` — current secret-name builder. - `db.ts:688-689` — legacy-rename pairs (boss→code-lead, foreman→architect). - `render-for-instance.ts:200` — `FORGE_TOKEN` env var (forge-neutral) injected at dispatch. - TOK-1 (#757 / #764) — original env→DB migration that wrote `FORGE_TOKEN_<TYPE>`. - Drizzle nuke (#854) — dropped the migration ladder; this issue restores the prune step under the new naming. - Cleanup of stale rows on 2026-05-05 — manual `DELETE` against 6 orphan `FORGE_TOKEN_*` rows.
Author
Collaborator

Correction (2026-05-05) — both prefixes were live, not just one.

Live audit shows two consumers:

Prefix Where it's read
FORGE_TOKEN_<TYPE> (IDs 7-12) agent_type.token_secret_id numeric FK — resolves the agent's own forgejo_token via getAgentTokenSync (resolver.ts:924)
FORGEJO_TOKEN_<TYPE> (IDs 1-6) defaults.ts:95 ${SECRET:FORGEJO_TOKEN_$$TYPE_UPPER$$} template — interpolated into the agent container's FORGE_TOKEN env var by the secret-templating layer

Same token value, two consumers, two prefix conventions. Deleting either set breaks one path silently (the FK consumer crashed dispatch entirely on 2026-05-05; the env-var consumer would degrade per-container shell access).

Updated AC (replaces "Migration" + "Code rename"):

  • Pick one canonical prefix. FORGE_TOKEN_<TYPE> is the better choice (forge-neutral, lined up with the FORGE_TOKEN env var name).
  • Migration: copy each FORGEJO_TOKEN_<TYPE> row to FORGE_TOKEN_<TYPE> (target wins on conflict — drop the legacy row), then update both consumers to read the canonical name.
  • defaults.ts:95 env-var template: ${SECRET:FORGEJO_TOKEN_$$TYPE_UPPER$$}${SECRET:FORGE_TOKEN_$$TYPE_UPPER$$}.
  • onboarding-apply.ts:363 secretNameForType: returns FORGE_TOKEN_<TYPE>.
  • secret table FK constraint: add ON DELETE RESTRICT to agent_type.token_secret_id (and agent_token_override.secret_id if it lacks one) so a future operator deletion gets a 409 instead of silently corrupting dispatch.
  • Dashboard: when an operator clicks the trash icon on a referenced row, surface the agent_type / instance names that depend on it before confirming.
**Correction (2026-05-05) — both prefixes were live, not just one.** Live audit shows two consumers: | Prefix | Where it's read | |---|---| | `FORGE_TOKEN_<TYPE>` (IDs 7-12) | `agent_type.token_secret_id` numeric FK — resolves the agent's own `forgejo_token` via `getAgentTokenSync` (`resolver.ts:924`) | | `FORGEJO_TOKEN_<TYPE>` (IDs 1-6) | `defaults.ts:95` `${SECRET:FORGEJO_TOKEN_$$TYPE_UPPER$$}` template — interpolated into the agent container's `FORGE_TOKEN` env var by the secret-templating layer | Same token value, two consumers, two prefix conventions. Deleting either set breaks one path silently (the FK consumer crashed dispatch entirely on 2026-05-05; the env-var consumer would degrade per-container shell access). **Updated AC (replaces "Migration" + "Code rename"):** - [ ] Pick **one** canonical prefix. `FORGE_TOKEN_<TYPE>` is the better choice (forge-neutral, lined up with the `FORGE_TOKEN` env var name). - [ ] Migration: copy each `FORGEJO_TOKEN_<TYPE>` row to `FORGE_TOKEN_<TYPE>` (target wins on conflict — drop the legacy row), then update **both consumers** to read the canonical name. - [ ] `defaults.ts:95` env-var template: `${SECRET:FORGEJO_TOKEN_$$TYPE_UPPER$$}` → `${SECRET:FORGE_TOKEN_$$TYPE_UPPER$$}`. - [ ] `onboarding-apply.ts:363` `secretNameForType`: returns `FORGE_TOKEN_<TYPE>`. - [ ] **`secret` table FK constraint**: add `ON DELETE RESTRICT` to `agent_type.token_secret_id` (and `agent_token_override.secret_id` if it lacks one) so a future operator deletion gets a 409 instead of silently corrupting dispatch. - [ ] Dashboard: when an operator clicks the trash icon on a referenced row, surface the agent_type / instance names that depend on it before confirming.
Collaborator

🦵 @charles kicked the queue — re-running implement on @dev.

🦵 @charles kicked the queue — re-running implement on @dev.
Collaborator

🦵 @operator kicked the queue — re-running implement on @dev.

🦵 @operator kicked the queue — re-running implement on @dev.
Collaborator

🦵 @charles kicked the queue — re-running implement on @dev.

🦵 @charles kicked the queue — re-running implement on @dev.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
charles/claude-hooks#867
No description provided.