Add ADR-010 (Forgejo integration) and rbw-unlocked pre-flight convention
ADR-010: API tokens as least-privilege managed secrets, declarative-first (no click-ops), automation boundary, planned trunk-based CI. CLAUDE.md/AGENTS.md: check 'rbw unlocked' before vault-dependent tasks (incl. commits) rather than failing partway. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
905bc92b15
commit
37cece9dbd
3 changed files with 84 additions and 0 deletions
|
|
@ -21,3 +21,6 @@ only designed — much of the ADR-described design is not built yet.
|
||||||
- **Check `STATUS.md`** before assuming a role, provider, or pipeline exists.
|
- **Check `STATUS.md`** before assuming a role, provider, or pipeline exists.
|
||||||
- **Git**: `main` must always work; branch for sweeping changes. Commit your work in
|
- **Git**: `main` must always work; branch for sweeping changes. Commit your work in
|
||||||
logical units with imperative ≤72-char subjects and a `Co-Authored-By` trailer.
|
logical units with imperative ≤72-char subjects and a `Co-Authored-By` trailer.
|
||||||
|
- **Vault access**: before a task needing a Vaultwarden secret (`make
|
||||||
|
deploy/check/encrypt/decrypt`, or any `git commit` — the hook decrypts `vault.yml`),
|
||||||
|
run `rbw unlocked`; if locked, ask the user to `rbw unlock` first, don't fail partway.
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,10 @@ Full design rationale: `docs/decisions/`
|
||||||
`vault.grafana.admin_password`); reference as `{{ vault.grafana.admin_password }}`
|
`vault.grafana.admin_password`); reference as `{{ vault.grafana.admin_password }}`
|
||||||
- Vault password comes from Vaultwarden via `rbw` (`scripts/vault-pass-client.sh`,
|
- Vault password comes from Vaultwarden via `rbw` (`scripts/vault-pass-client.sh`,
|
||||||
wired as `vault_password_file`). Unlock once per session: `rbw unlock`
|
wired as `vault_password_file`). Unlock once per session: `rbw unlock`
|
||||||
|
- **Before any vault-dependent task** (`make deploy/check/encrypt/decrypt`, or **any
|
||||||
|
git commit** — the pre-commit ansible-lint hook decrypts `vault.yml`), run `rbw
|
||||||
|
unlocked`; if it exits non-zero, ask the user to `rbw unlock` and wait rather than
|
||||||
|
starting and failing partway. The agent stays unlocked 5h.
|
||||||
- To edit a vault file: `make decrypt FILE=<path>`, edit, `make encrypt FILE=<path>`
|
- To edit a vault file: `make decrypt FILE=<path>`, edit, `make encrypt FILE=<path>`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -165,6 +169,7 @@ Single-contributor, trunk-based (no merge requests / approval gates):
|
||||||
| Network topology | `docs/decisions/007-network.md` |
|
| Network topology | `docs/decisions/007-network.md` |
|
||||||
| Testing methodology | `docs/decisions/008-testing.md` |
|
| Testing methodology | `docs/decisions/008-testing.md` |
|
||||||
| TF ↔ Ansible handoff | `docs/decisions/009-provisioning-handoff.md` |
|
| TF ↔ Ansible handoff | `docs/decisions/009-provisioning-handoff.md` |
|
||||||
|
| Forgejo & CI | `docs/decisions/010-forgejo-ci.md` |
|
||||||
| Adding a new role | `docs/runbooks/new-role.md` |
|
| Adding a new role | `docs/runbooks/new-role.md` |
|
||||||
| Adding a new host | `docs/runbooks/new-host.md` |
|
| Adding a new host | `docs/runbooks/new-host.md` |
|
||||||
| Rotating vault secrets | `docs/runbooks/rotate-secrets.md` |
|
| Rotating vault secrets | `docs/runbooks/rotate-secrets.md` |
|
||||||
|
|
|
||||||
76
docs/decisions/010-forgejo-ci.md
Normal file
76
docs/decisions/010-forgejo-ci.md
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
# ADR-010 — Forgejo integration and CI
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
boma's git host, container registry, and (planned) CI all run on a self-hosted
|
||||||
|
Forgejo instance at `forgejo.nyumbani.baobab.band` (SSH on 7577, HTTPS on 443). Both
|
||||||
|
humans and AI/automation interact with it. This ADR sets the principles so the
|
||||||
|
instance does not become undocumented click-ops drift, and so its credentials are
|
||||||
|
held to the same standard as the rest of the repo's secrets.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What Forgejo provides here
|
||||||
|
|
||||||
|
- **Git hosting** — `origin` (push/pull over SSH; key-based, not token).
|
||||||
|
- **Container registry** — hosts the Molecule test image
|
||||||
|
(`forgejo.nyumbani.baobab.band/sjat/molecule-debian13`); see ADR-008.
|
||||||
|
- **Actions CI** — planned, not yet enabled (`has_actions: false`); trunk-based
|
||||||
|
pipeline per ADR-003 / ADR-008.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
|
||||||
|
### 1. API tokens are managed secrets, least-privilege
|
||||||
|
|
||||||
|
A Forgejo API token (PAT) is a secret and follows ADR-002: stored in **Vaultwarden**,
|
||||||
|
fetched via `rbw`/env, **never** written to a file or pasted into chat. Tokens are
|
||||||
|
**least-privilege** — scoped to their purpose, never admin.
|
||||||
|
|
||||||
|
Note what does *not* need a token: git push/pull (SSH key), and Terraform state
|
||||||
|
(local — ADR-006). A token for CI / registry use needs only:
|
||||||
|
|
||||||
|
- `read:repository`
|
||||||
|
- `read:package`, `write:package` (pull/push the Molecule image)
|
||||||
|
|
||||||
|
### 2. Declarative-first, not click-ops
|
||||||
|
|
||||||
|
Forgejo configuration lives in the repo where possible:
|
||||||
|
|
||||||
|
- Actions workflows in `.forgejo/workflows/` (version-controlled).
|
||||||
|
- Repo/instance settings are codified or documented; changing them ad-hoc via the
|
||||||
|
API or UI is a **documented exception**, recorded when done — not the norm.
|
||||||
|
|
||||||
|
The point: the Forgejo instance must not become the kind of undocumented drift that
|
||||||
|
`/review-repo` exists to catch.
|
||||||
|
|
||||||
|
### 3. Automation boundary
|
||||||
|
|
||||||
|
Automation / AI **may**, via the API or CLI: read repo and CI state, manage the
|
||||||
|
container registry, run and inspect CI. It must **not**, without explicit human
|
||||||
|
direction: change instance/admin settings, delete repos or packages, or rotate
|
||||||
|
credentials.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CI pipeline (planned)
|
||||||
|
|
||||||
|
Trunk-based, matching ADR-003 / ADR-008:
|
||||||
|
|
||||||
|
```
|
||||||
|
push to main → lint + Molecule → deploy staging → [manual gate] → deploy production
|
||||||
|
```
|
||||||
|
|
||||||
|
Runner: `act_runner` on the control node or a dedicated runner VM. Actions is not
|
||||||
|
yet enabled — see STATUS.md.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What was ruled out
|
||||||
|
|
||||||
|
| Option | Reason |
|
||||||
|
|---|---|
|
||||||
|
| Terraform Forgejo HTTP state backend | Forgejo's `/raw/` API is read-only; state can't be written there. Local state instead (ADR-006). |
|
||||||
|
| Admin-scoped automation tokens | Unnecessary privilege; scope to `read:repository` + `read`/`write:package`. |
|
||||||
|
| Ad-hoc UI/API configuration as the norm | Becomes undocumented drift; codify or document instead. |
|
||||||
Loading…
Add table
Reference in a new issue