T01 (done): canonical capabilities-based verify pattern in the fleet promotion checklist (catalog-lane-promotion.md) and applied to the railiance-backup and forgejo-admin lane playbooks. Verification proves allow/deny via `bao token capabilities` against the KV v2 data path, never `bao kv get`; a denied default-policy token-create is a pass, not a privileged-fallback trigger. T07 (progress): lessons-learned note for the 2026-07-16 CCR-2026-0004 disclosure (three root causes). Live re-verify + rotation block remain (depend on T06). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
140 lines
No EOL
4.6 KiB
Markdown
140 lines
No EOL
4.6 KiB
Markdown
# Forgejo Admin API Token (PAT)
|
|
|
|
Date: 2026-07-12 (verified 2026-07-13)
|
|
Catalog: `forgejo-admin-api-token` (status `active`, `resolvable: true`)
|
|
Owner: `railiance-platform` (CCR-2026-0006)
|
|
|
|
Forgejo site-admin personal access token for operator and automation tooling.
|
|
Sibling to `forgejo-mailer` (SMTP via ESO); phase 1 is workstation + activity-core
|
|
worker fetch only — no cluster ExternalSecret delivery.
|
|
|
|
---
|
|
|
|
## OpenBao pointers
|
|
|
|
| Field | Value |
|
|
| --- | --- |
|
|
| Mount | `platform` |
|
|
| Path | `platform/workloads/forgejo/forgejo-admin` |
|
|
| Secret field | `API_TOKEN` (PAT value) |
|
|
| Metadata fields | `API_USER`, `API_BASE_URL`, `TOKEN_SCOPES`, `GENERATED_AT` (optional, non-secret) |
|
|
| Policy | `workload-kv-read-forgejo-admin` |
|
|
| OIDC role | `forgejo-admin-workload-kv-read` (`groups=net-kingdom-admins`) |
|
|
|
|
**PAT scopes (minimum for current consumers):** `read:package`, `write:package`,
|
|
`read:repository`, `write:repository`, plus admin scopes as needed for
|
|
`forgejo-operator-bootstrap` (mirror the current admin PAT).
|
|
|
|
**Forgejo account:** `tegwick` (site admin, `coulomb` Owners).
|
|
|
|
---
|
|
|
|
## Worker checklist
|
|
|
|
1. **Login** (caller identity — ops-warden adds no credential):
|
|
|
|
```bash
|
|
bao login -method=oidc -path=netkingdom role=forgejo-admin-workload-kv-read
|
|
```
|
|
|
|
2. **Export for a Forgejo API run** (value streams to your shell — never paste into chat):
|
|
|
|
```bash
|
|
export FORGEJO_ADMIN_TOKEN=$(
|
|
bao kv get -field=API_TOKEN platform/workloads/forgejo/forgejo-admin
|
|
)
|
|
```
|
|
|
|
3. **Or proxy via warden access** (catalog lane is `active`):
|
|
|
|
```bash
|
|
warden access forgejo-admin-api-token --no-policy --fetch --field API_TOKEN
|
|
```
|
|
|
|
4. **Run consumers**:
|
|
|
|
```bash
|
|
# Package prune (railiance-platform)
|
|
make forgejo-package-prune-dry-run
|
|
make forgejo-package-prune
|
|
|
|
# Operator bootstrap / npm smoke / reuse webhook (railiance-apps)
|
|
make forgejo-operator-bootstrap
|
|
make forgejo-npm-smoke
|
|
make reuse-forgejo-webhook
|
|
```
|
|
|
|
5. **Retire workstation file drop** once downstream `load_token()` paths read
|
|
OpenBao when env is unset:
|
|
|
|
- `/tmp/forgejo-tegwick-api-token` — legacy; do not use as steady state
|
|
- `FORGEJO_ADMIN_TOKEN` env — acceptable for one-off sessions after fetch
|
|
|
|
---
|
|
|
|
## Operator provisioning (attended)
|
|
|
|
After CCR approval and policy apply:
|
|
|
|
1. Forgejo UI: `tegwick` → Settings → Applications → Generate New Token
|
|
2. Store in OpenBao (do not echo the value):
|
|
|
|
```bash
|
|
# PAT in a mode-0600 single-line file — never on argv
|
|
install -m 600 /dev/null /tmp/forgejo-admin-pat.input
|
|
# paste token into the file, then:
|
|
~/railiance-platform/scripts/forgejo-admin-pat-provision.sh /tmp/forgejo-admin-pat.input
|
|
shred -u /tmp/forgejo-admin-pat.input
|
|
```
|
|
|
|
3. Verify field presence without printing values:
|
|
|
|
```bash
|
|
bao kv metadata get platform/workloads/forgejo/forgejo-admin
|
|
```
|
|
|
|
---
|
|
|
|
## Verify the lane (capabilities-safe — never read the value)
|
|
|
|
Prove allow/deny with `bao token capabilities`, **not** `bao kv get -field=…`.
|
|
`bao kv metadata get` (above) is fine — it shows versions, not values. Reading the
|
|
data field to "confirm" it is the anti-pattern
|
|
(`wiki/playbooks/catalog-lane-promotion.md#capabilities-safe-lane-verification`).
|
|
|
|
```bash
|
|
# Positive: lane OIDC identity can read the data path
|
|
bao login -method=oidc -path=netkingdom role=forgejo-admin-workload-kv-read
|
|
bao token capabilities "$(bao print token)" platform/data/workloads/forgejo/forgejo-admin
|
|
# → expect: read
|
|
|
|
# Negative: default-only identity is denied
|
|
DEFAULT_TOKEN=$(bao token create -policy=default -field=token) # if denied, that IS the pass — do NOT fall back
|
|
bao token capabilities "$DEFAULT_TOKEN" platform/data/workloads/forgejo/forgejo-admin
|
|
# → expect: deny
|
|
```
|
|
|
|
Confirming the PAT works against Forgejo is a separate, value-using action — fetch
|
|
`--field API_TOKEN` into an env var and call `/api/v1/user`; never paste the token.
|
|
|
|
---
|
|
|
|
## Consumers (downstream wiring — after lane verified)
|
|
|
|
| Consumer | Repo |
|
|
| --- | --- |
|
|
| `tools/cmd/forgejo-package-prune` | `railiance-platform` |
|
|
| `weekly-forgejo-package-prune` activity | `activity-core` |
|
|
| `forgejo-operator-bootstrap`, `forgejo-npm-smoke`, `reuse-forgejo-webhook` | `railiance-apps` |
|
|
|
|
Docs: `railiance-platform/docs/forgejo-package-prune.md`,
|
|
`railiance-apps/docs/forgejo-on-railiance01.md`.
|
|
|
|
---
|
|
|
|
## See also
|
|
|
|
- `railiance-platform/credential-change-requests/CCR-2026-0006-forgejo-admin-api-token-lane.yaml`
|
|
- `railiance-platform/openbao/policies/workload-kv-read-forgejo-admin.hcl`
|
|
- `wiki/playbooks/railiance-backup-offsite-lane.md` (OIDC workstation read pattern)
|
|
- `forgejo-mailer` lane — SMTP only; unchanged |