hive-c0re: scrub host-integration cookies (#715 batch 8)
This commit is contained in:
parent
6bdfe52386
commit
dd07ca946e
3 changed files with 57 additions and 60 deletions
|
|
@ -34,21 +34,18 @@ const TOKEN_NAME_PREFIX: &str = "hyperhive";
|
|||
/// creation, future webhook setup, etc.). Root-only.
|
||||
const CORE_TOKEN_PATH: &str = "/var/lib/hyperhive/forge-core-token";
|
||||
/// Marker that records whether `ensure_core_avatar` has successfully
|
||||
/// uploaded the hyperhive logo as `core`'s avatar (issue #320). One-shot:
|
||||
/// the upload runs once, the marker is written, subsequent startups skip
|
||||
/// uploaded the hyperhive logo as `core`'s avatar. One-shot: the
|
||||
/// upload runs once, the marker is written, subsequent startups skip
|
||||
/// the call. Delete to force re-upload.
|
||||
const CORE_AVATAR_MARKER: &str = "/var/lib/hyperhive/forge-core-avatar-set";
|
||||
/// Sibling marker for the `agent-configs` org avatar (#424). Same one-
|
||||
/// shot semantics — delete to force the upload to re-run.
|
||||
/// Sibling marker for the `agent-configs` org avatar. Same one-shot
|
||||
/// semantics — delete to force the upload to re-run.
|
||||
const CONFIG_ORG_AVATAR_MARKER: &str = "/var/lib/hyperhive/forge-agent-configs-avatar-set";
|
||||
// Avatar PNGs are loaded at runtime from
|
||||
// `$HIVE_ASSETS_DIR/branding/{hyperhive,agent-configs}.png` via the
|
||||
// helpers in `hive_sh4re::assets` (#555 — was `include_bytes!` of an
|
||||
// in-source path and an OUT_DIR-rendered sibling, both of which
|
||||
// invalidated the crane src cache on any branding edit). The
|
||||
// `agent-configs.png` is rendered from its SVG during the
|
||||
// `hyperhive-assets` derivation's build (was `hive-c0re/build.rs`
|
||||
// + `rsvg-convert` on PATH; both gone now).
|
||||
// helpers in `hive_sh4re::assets`. The `agent-configs.png` is
|
||||
// rendered from its SVG during the `hyperhive-assets` derivation's
|
||||
// build.
|
||||
/// Forgejo org grouping every agent's applied config repo. Core is a
|
||||
/// site admin and reads + writes every repo here; agents are NOT
|
||||
/// members and the repos are private, so no agent — not even the one
|
||||
|
|
@ -84,7 +81,7 @@ const TOKEN_SCOPES: &str = "read:user,write:user,read:notification,write:notific
|
|||
/// membership alone isn't enough — the token's own scope gate runs
|
||||
/// 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 (#646).
|
||||
/// 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";
|
||||
|
||||
/// Token file inside the agent's bind-mounted state dir (visible as
|
||||
|
|
@ -199,8 +196,7 @@ async fn forge_http(
|
|||
/// account password: `None` uses `--random-password` (the existing
|
||||
/// agent provisioning shape — the password is never read, agents auth
|
||||
/// by token); `Some(pw)` uses `--password <pw>` so the operator path
|
||||
/// in `hivectl` can set a real password for matrix-style web-UI login
|
||||
/// (#663).
|
||||
/// in `hivectl` can set a real password for matrix-style web-UI login.
|
||||
async fn ensure_user_exists(name: &str, admin: bool, password: Option<&str>) -> Result<()> {
|
||||
let email = agent_email(name);
|
||||
let mut args = vec!["user", "create", "--username", name, "--email", &email];
|
||||
|
|
@ -257,11 +253,11 @@ async fn change_user_password(name: &str, password: &str) -> Result<()> {
|
|||
///
|
||||
/// Uses the admin REST API (`PATCH /api/v1/admin/users/{name}`) rather
|
||||
/// than `forgejo admin user edit` because the CLI dropped the `edit`
|
||||
/// subcommand somewhere between forgejo 8 and current — see #574 for
|
||||
/// the "flag provided but not defined: -username" error this fix
|
||||
/// replaces. Body sets `source_id = 0` (local auth, the default for
|
||||
/// users hive-c0re creates) which forgejo's PATCH validator requires
|
||||
/// even when the only thing changing is the email.
|
||||
/// subcommand somewhere between forgejo 8 and current (the bare CLI
|
||||
/// surfaced as "flag provided but not defined: -username"). Body sets
|
||||
/// `source_id = 0` (local auth, the default for users hive-c0re
|
||||
/// creates) which forgejo's PATCH validator requires even when the
|
||||
/// only thing changing is the email.
|
||||
async fn ensure_user_email(name: &str) {
|
||||
let Some(token) = core_token() else {
|
||||
tracing::debug!(%name, "forge: skipping ensure_user_email — no core token yet");
|
||||
|
|
@ -276,13 +272,13 @@ async fn ensure_user_email(name: &str) {
|
|||
}
|
||||
Ok(status) if status == reqwest::StatusCode::FORBIDDEN => {
|
||||
// Almost certainly an existing-deployment migration case:
|
||||
// pre-#646 the core token was minted without admin scope, so
|
||||
// /admin/users/* now returns 403 even though `core` is a
|
||||
// site admin. Tell the operator how to fix it inline (#646).
|
||||
// an older core token may have been minted without admin
|
||||
// scope, so /admin/users/* now returns 403 even though
|
||||
// `core` is a site admin. Tell the operator how to fix it.
|
||||
tracing::warn!(
|
||||
%name, %email, %status,
|
||||
"forge: PATCH user email forbidden — core token likely missing admin scope. \
|
||||
Delete {CORE_TOKEN_PATH} and restart hive-c0re to re-mint with the new scopes (#646)."
|
||||
Delete {CORE_TOKEN_PATH} and restart hive-c0re to re-mint with the new scopes."
|
||||
);
|
||||
}
|
||||
Ok(status) => {
|
||||
|
|
@ -357,15 +353,15 @@ pub async fn ensure_user_for(name: &str) -> Result<()> {
|
|||
/// disk — the caller is responsible for storing it. Used by `hivectl
|
||||
/// forge create-user` for human (non-agent) accounts so we don't create
|
||||
/// stray `/var/lib/hyperhive/agents/<name>/` directories for users that
|
||||
/// aren't agents (#662).
|
||||
/// aren't agents.
|
||||
///
|
||||
/// `password` picks the account password. `None` keeps the existing
|
||||
/// random-throwaway shape (caller doesn't need web UI access — token
|
||||
/// alone is enough). `Some(pw)` sets `pw` as the password, including
|
||||
/// running `forgejo admin user change-password` if the account already
|
||||
/// exists, so the operator can log into the forge web UI afterwards
|
||||
/// (#663). Idempotent: re-running with the same `Some(pw)` lands on
|
||||
/// the same final state.
|
||||
/// exists, so the operator can log into the forge web UI afterwards.
|
||||
/// Idempotent: re-running with the same `Some(pw)` lands on the same
|
||||
/// final state.
|
||||
pub async fn provision_user_token(name: &str, password: Option<&str>) -> Result<String> {
|
||||
if !is_present().await {
|
||||
anyhow::bail!(
|
||||
|
|
@ -385,9 +381,9 @@ pub async fn provision_user_token(name: &str, password: Option<&str>) -> Result<
|
|||
}
|
||||
|
||||
/// Set `core`'s Forgejo avatar to the hyperhive logo once, then
|
||||
/// remember it so subsequent startups don't re-upload (issue #320).
|
||||
/// Best-effort — any non-2xx is logged at the caller; the project
|
||||
/// runs fine with the default hash identicon.
|
||||
/// remember it so subsequent startups don't re-upload. Best-effort
|
||||
/// — any non-2xx is logged at the caller; the project runs fine
|
||||
/// with the default hash identicon.
|
||||
async fn ensure_core_avatar(token: &str) -> Result<()> {
|
||||
let marker = std::path::Path::new(CORE_AVATAR_MARKER);
|
||||
if marker.exists() {
|
||||
|
|
@ -415,7 +411,7 @@ async fn ensure_core_avatar(token: &str) -> Result<()> {
|
|||
}
|
||||
|
||||
/// Set the `agent-configs` org's Forgejo avatar to the
|
||||
/// configs-stack glyph once (#424). Sibling to `ensure_core_avatar`:
|
||||
/// configs-stack glyph once. Sibling to `ensure_core_avatar`:
|
||||
/// one-shot, marker-guarded, best-effort. Forgejo's per-org avatar
|
||||
/// endpoint is `POST /api/v1/orgs/{org}/avatar` with a base64-PNG
|
||||
/// JSON body — same shape as the admin user endpoint above.
|
||||
|
|
|
|||
Loading…
Reference in a new issue