docs: add token scopes section to forge.md, trim forge.rs module doc + scope comments
This commit is contained in:
parent
88cdab411e
commit
5522d65074
2 changed files with 43 additions and 46 deletions
|
|
@ -8,6 +8,37 @@ handling live in [`docs/gateway.md`](gateway.md); this file owns the
|
||||||
per-agent integration story and the notification pump that wakes
|
per-agent integration story and the notification pump that wakes
|
||||||
each agent on relevant activity.
|
each agent on relevant activity.
|
||||||
|
|
||||||
|
## Token scopes
|
||||||
|
|
||||||
|
Two scope sets live in `hive-c0re::forge`:
|
||||||
|
|
||||||
|
**`TOKEN_SCOPES`** (per-agent tokens):
|
||||||
|
|
||||||
|
| Scope | Why |
|
||||||
|
|-------|-----|
|
||||||
|
| `write:repository` | Create, clone, push, delete repos; merge PRs. |
|
||||||
|
| `write:issue` | Open / comment / review issues **and** pull requests (Forgejo namespaces PR conversation under issues). |
|
||||||
|
| `write:user` | Edit own profile, create repos under own user. |
|
||||||
|
| `write:organization` | Create + manage orgs (lets agents share a forge namespace). |
|
||||||
|
| `read:user` | Token-owner endpoint used for self-identification at harness startup. |
|
||||||
|
| `write:misc` | Hooks, attachments, the rest of the long tail. |
|
||||||
|
| `read:notification` | Poll `GET /notifications` for unread events. |
|
||||||
|
| `write:notification` | Mark notifications read via `PATCH /notifications/threads/{id}`. |
|
||||||
|
|
||||||
|
**`CORE_TOKEN_SCOPES`** (hive-c0re's own `core` user): everything in
|
||||||
|
`TOKEN_SCOPES` plus `read:admin` and `write:admin`. Site-admin
|
||||||
|
membership alone isn't sufficient — Forgejo's token scope gate runs
|
||||||
|
before the user-permission check, so `/api/v1/admin/*` returns
|
||||||
|
`403 Forbidden` for any token without the admin scope bits, even when
|
||||||
|
the bearer is a site admin.
|
||||||
|
|
||||||
|
**Migration note**: if `PATCH /api/v1/admin/users/{name}` returns 403
|
||||||
|
on an existing deploy, the core token predates the admin-scope
|
||||||
|
addition. Delete `/var/lib/hyperhive/forge-core-token` and restart
|
||||||
|
hive-c0re to re-mint with the new scopes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Per-agent forge accounts
|
## Per-agent forge accounts
|
||||||
|
|
||||||
Each agent gets its own Forgejo user + access token, provisioned at
|
Each agent gets its own Forgejo user + access token, provisioned at
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,6 @@
|
||||||
//! Optional Forgejo wiring. When the `hive-forge` nixos-container is
|
//! Optional Forgejo wiring — per-agent user + token provisioning,
|
||||||
//! present and running, hive-c0re ensures every agent (and the
|
//! config-repo mirroring, meta read-access grants. No-op when
|
||||||
//! manager) has a corresponding forgejo user with an API token
|
//! `hive-forge` isn't running. Full design: `docs/forge.md`.
|
||||||
//! written to `<agent-state>/forge-token` — visible inside the
|
|
||||||
//! container as `/state/forge-token`. Idempotent: skips creation
|
|
||||||
//! when the user already exists, skips token issuance when the file
|
|
||||||
//! is already there.
|
|
||||||
//!
|
|
||||||
//! It also mirrors each agent's hive-c0re-owned *applied* config repo
|
|
||||||
//! into the private `agent-configs` org (`push_config`), so every
|
|
||||||
//! deploy / approval tag core plants is visible on the forge. Each
|
|
||||||
//! agent is a read-only collaborator on `core/meta` (the meta flake)
|
|
||||||
//! so they can fetch their deployment context; the `agent-configs`
|
|
||||||
//! repos remain core-only.
|
|
||||||
//!
|
|
||||||
//! No-op when `hive-forge` isn't enabled (detected via
|
|
||||||
//! `nixos-container list`), so operators who don't run the bundled
|
|
||||||
//! forge pay nothing.
|
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
|
@ -56,32 +41,15 @@ const CONFIG_ORG: &str = "agent-configs";
|
||||||
/// Forgejo orgs hive-c0re ensures on startup. The meta repo lives at
|
/// Forgejo orgs hive-c0re ensures on startup. The meta repo lives at
|
||||||
/// `core/meta` (the `core` user's own namespace — no org needed).
|
/// `core/meta` (the `core` user's own namespace — no org needed).
|
||||||
const SEEDED_ORGS: &[&str] = &[CONFIG_ORG];
|
const SEEDED_ORGS: &[&str] = &[CONFIG_ORG];
|
||||||
/// Forgejo scopes the agent's token gets. Broad-but-not-admin: every
|
/// Per-agent token scopes (broad-but-not-admin). See
|
||||||
/// repo / PR / issue thing an agent needs day-to-day, no admin
|
/// `docs/forge.md::Token scopes` for the per-scope rationale.
|
||||||
/// surface.
|
|
||||||
/// - `write:repository` — create, clone, push, delete repos in the
|
|
||||||
/// user's own namespace; merge PRs.
|
|
||||||
/// - `write:issue` — open / comment / review issues *and* pull
|
|
||||||
/// requests (forgejo namespaces PR conversation under issues).
|
|
||||||
/// - `write:user` — edit own profile, create repos under own user.
|
|
||||||
/// - `write:organization` — create + manage orgs (lets agents share
|
|
||||||
/// a forge namespace).
|
|
||||||
/// - `read:user` — token-owner endpoint clients call to introspect.
|
|
||||||
/// - `write:misc` — hooks, attachments, the rest of the long tail.
|
|
||||||
/// - `read:notification` — required by `forge_notify` to poll
|
|
||||||
/// `GET /notifications` for unread PR/review events.
|
|
||||||
/// - `write:notification` — required by `forge_notify` to mark
|
|
||||||
/// notifications as read via `PATCH /notifications/threads/{id}`.
|
|
||||||
const TOKEN_SCOPES: &str = "read:user,write:user,read:notification,write:notification,write:repository,write:issue,write:organization,write:misc";
|
const TOKEN_SCOPES: &str = "read:user,write:user,read:notification,write:notification,write:repository,write:issue,write:organization,write:misc";
|
||||||
|
|
||||||
/// Scopes for the bootstrap `core` token used by hive-c0re itself.
|
/// Bootstrap `core` token scopes — adds `read:admin,write:admin` on
|
||||||
/// Adds `read:admin,write:admin` on top of `TOKEN_SCOPES` so the host
|
/// top of `TOKEN_SCOPES` so the host daemon can drive
|
||||||
/// daemon can drive `/api/v1/admin/*` endpoints (PATCH user email on
|
/// `/api/v1/admin/*`. Site-admin membership alone isn't enough: the
|
||||||
/// agent provision, future webhook + org admin work). Site-admin
|
/// token's own scope gate runs before the user-permission check.
|
||||||
/// membership alone isn't enough — the token's own scope gate runs
|
/// See `docs/forge.md::Token scopes`.
|
||||||
/// before the user-permission check, so `403 Forbidden` comes back
|
|
||||||
/// for any `/admin/users/*` call from a non-admin-scoped token
|
|
||||||
/// even if the bearer is an admin user.
|
|
||||||
const CORE_TOKEN_SCOPES: &str = "read:admin,write:admin,read:user,write:user,read:notification,write:notification,write:repository,write:issue,write:organization,write:misc";
|
const CORE_TOKEN_SCOPES: &str = "read:admin,write:admin,read:user,write:user,read:notification,write:notification,write:repository,write:issue,write:organization,write:misc";
|
||||||
|
|
||||||
/// Token file inside the agent's bind-mounted state dir (visible as
|
/// Token file inside the agent's bind-mounted state dir (visible as
|
||||||
|
|
@ -271,10 +239,8 @@ async fn ensure_user_email(name: &str) {
|
||||||
tracing::debug!(%name, %email, "forge: user email aligned");
|
tracing::debug!(%name, %email, "forge: user email aligned");
|
||||||
}
|
}
|
||||||
Ok(status) if status == reqwest::StatusCode::FORBIDDEN => {
|
Ok(status) if status == reqwest::StatusCode::FORBIDDEN => {
|
||||||
// Almost certainly an existing-deployment migration case:
|
// Core token missing admin scope — see
|
||||||
// an older core token may have been minted without admin
|
// `docs/forge.md::Token scopes` migration note.
|
||||||
// scope, so /admin/users/* now returns 403 even though
|
|
||||||
// `core` is a site admin. Tell the operator how to fix it.
|
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
%name, %email, %status,
|
%name, %email, %status,
|
||||||
"forge: PATCH user email forbidden — core token likely missing admin scope. \
|
"forge: PATCH user email forbidden — core token likely missing admin scope. \
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue