hyperhive/frontend/packages/dashboard/src/credentials.html
iris dbf880ac66 extra-forges: fully dashboard-provisioned, no host config
Per mara's feedback on PR #2407 ("better: you can also provide url in
dashboard, same as with matrix, no host config"), drops
services.hyperhive.extraForges and the admin-API mint/revoke flow
entirely. The operator now creates a token on the external forge
themselves and pastes a label + base URL + access token into the
dashboard's FORGES tab, the same shape as the GitHub PAT flow plus the
base-URL field from the matrix extra-account flow. hive-c0re only ever
writes/deletes two local files per account (forge-<label>-token,
forge-<label>.json sidecar for the URL) via hive-priv — no remote
account creation, no admin token, no revoke-on-the-remote-side, no nix
config to enumerate.

- nix/host-modules/hive-forge/default.nix: removed the extraForges
  option, its label-format assertion, and the HYPERHIVE_EXTRA_FORGES
  env forwarding.
- hive-c0re/src/forge/extra.rs: deleted (REST admin-API provisioning,
  no longer needed).
- hive-c0re/src/dashboard/extra_forges.rs: GET /api/extra-forges?
  agent= lists an agent's stored forges by scanning its state dir
  (mirrors matrix_accounts.rs's filename-scan listing), POST
  /api/extra-forge-account (agent/label/base_url/token/
  action=add|remove) stores or removes an account.
- hive-sh4re/priv_proto.rs + hive-priv/main.rs: new
  WriteAgentExtraForgeAccount/DeleteAgentExtraForgeAccount priv
  requests (adds base_url, writes/deletes a JSON sidecar alongside the
  token).
- hive-c0re/src/priv_client.rs: matching wrapper functions.
- frontend/packages/dashboard/src/credentials.{html,js}: FORGES tab is
  a per-agent list + add-account paste form (label/base_url/token), no
  grant/revoke-from-catalog UI.
- docs/web-ui/dashboard.md: FORGES tab section rewritten.

Supersedes the design in PR #2407 (already approved+green on the old
admin-API model) — opening as a fresh PR against the same issues
rather than force-pushing over the approved one.
2026-07-14 18:38:55 +02:00

168 lines
8.1 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>hyperhive // CR3D3NTIALS</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="stylesheet" href="/static/colors.css">
<link rel="stylesheet" href="/static/theme.css">
<link rel="stylesheet" href="/static/common.css">
<link rel="stylesheet" href="/static/credentials.css">
</head>
<body class="cred-shell">
<!-- Minimal chrome: back link + sub-tab strip, same pattern as
logs.html (MATRIX / GITHUB instead of AGENT/SYSTEM/AUDIT). Back
link points to the H0M3 hub (served at /). -->
<header class="page-header">
<a class="page-back" href="/">← home</a>
<nav class="hive-tabbar cred-tabbar" id="cred-tabbar" role="tablist">
<a class="hive-tab" id="cred-tab-matrix" href="#matrix" role="tab"
aria-controls="cred-pane-matrix" data-tab="matrix">
<span class="cred-tab-label">MATRIX</span>
</a>
<a class="hive-tab" id="cred-tab-github" href="#github" role="tab"
aria-controls="cred-pane-github" data-tab="github">
<span class="cred-tab-label">GITHUB</span>
</a>
<a class="hive-tab" id="cred-tab-forges" href="#forges" role="tab"
aria-controls="cred-pane-forges" data-tab="forges">
<span class="cred-tab-label">FORGES</span>
</a>
</nav>
</header>
<main class="cred-main">
<!-- Agent picker: shared across both tabs (one agent selected at a
time drives both the matrix account list and the github status). -->
<h3>◇ agent</h3>
<label class="ma-field">
<span>agent</span>
<select id="ma-agent"></select>
</label>
<!-- MATRIX tab: unchanged from the old /matrix-accounts.html, just
moved under a tab pane. -->
<section class="cred-pane" id="cred-pane-matrix" data-tab-pane="matrix"
role="tabpanel" aria-labelledby="cred-tab-matrix">
<p class="meta">provision or log in an <strong>external</strong> matrix account for an agent and store its access token. the token is written to the agent's <code>matrixAccounts.&lt;account&gt;.tokenFile</code> by the host coordinator &mdash; it is never displayed back on this page.</p>
<h3>◇ provisioned accounts</h3>
<p class="meta">accounts that have a stored token (provision one below to add it here); a config-declared account that hasn't been provisioned yet won't appear until it has a token. status reflects whether a <em>token is stored</em>, not a live session &mdash; a true online/offline indicator is a follow-up that needs the daemon's account registry.</p>
<div id="ma-list" class="ma-list"><p class="meta">select an agent to see its matrix accounts.</p></div>
<h3>◇ provision / log in</h3>
<form id="ma-form" class="ma-form" autocomplete="off">
<label class="ma-field">
<span>account name</span>
<input type="text" name="account" placeholder="e.g. public" required>
</label>
<label class="ma-field">
<span>homeserver</span>
<input type="text" name="homeserver" placeholder="https://matrix.org" required>
</label>
<fieldset class="ma-mode">
<legend>login method</legend>
<label><input type="radio" name="mode" value="password" checked> password</label>
<label><input type="radio" name="mode" value="token"> existing token</label>
</fieldset>
<div id="ma-pw-fields" class="ma-modefields">
<label class="ma-field">
<span>user id</span>
<input type="text" name="user_id" placeholder="@user:matrix.org" autocomplete="username">
</label>
<label class="ma-field">
<span>password</span>
<input type="password" name="password" autocomplete="new-password">
</label>
</div>
<div id="ma-token-fields" class="ma-modefields" hidden>
<label class="ma-field">
<span>access token</span>
<input type="password" name="token" autocomplete="off">
</label>
<label class="ma-field">
<span>user id <span class="meta">(optional &mdash; derived via whoami)</span></span>
<input type="text" name="user_id" placeholder="@user:matrix.org">
</label>
</div>
<button type="submit" class="btn btn-spawn">log in &amp; store token</button>
<p id="ma-result" class="ma-result" aria-live="polite"></p>
</form>
</section>
<!-- GITHUB tab: single-account PAT paste. No login flow — the
operator pastes an existing PAT for a dedicated bot account.
Security-warning banner + a link to generate a PAT. -->
<section class="cred-pane" id="cred-pane-github" data-tab-pane="github"
role="tabpanel" aria-labelledby="cred-tab-github" hidden>
<div class="cred-warning">
⚠ use a <strong>dedicated bot account</strong>, not a human's &mdash;
and a <strong>minimally-scoped</strong> personal access token (only
the repos/scopes the agent actually needs, e.g. <code>repo</code> +
<code>workflow</code>). the container boundary is the enforcement:
anything within the token's scopes is reachable if the agent is
ever compromised. the token is injected into the agent's state dir
and is <strong>never displayed back</strong> on this page.
</div>
<h3>◇ status</h3>
<div id="gh-status" class="gh-status"><p class="meta">select an agent to see its github credential status.</p></div>
<h3>◇ provision</h3>
<p class="meta">generate a token at
<a href="https://github.com/settings/tokens" target="_blank" rel="noopener">github.com/settings/tokens</a>
and paste it below. one account per agent &mdash; pasting a new token replaces the stored one.</p>
<form id="gh-form" class="ma-form" autocomplete="off">
<label class="ma-field">
<span>personal access token</span>
<input type="password" name="token" autocomplete="off" required>
</label>
<button type="submit" class="btn btn-spawn">store token</button>
<p id="gh-result" class="ma-result" aria-live="polite"></p>
</form>
</section>
<!-- FORGES tab: external Forgejo/Gitea/Codeberg-compatible forges.
Entirely dashboard-provisioned, no host-side nix config &mdash; same
shape as GITHUB plus a base-URL field (like MATRIX's homeserver).
The operator creates a token on the external forge themselves
(however that forge lets them) and pastes label + URL + token
below. No remote account minting/revoking &mdash; purely local. -->
<section class="cred-pane" id="cred-pane-forges" data-tab-pane="forges"
role="tabpanel" aria-labelledby="cred-tab-forges" hidden>
<p class="meta">store a <strong>label + base URL + access token</strong> for an external Forgejo/Gitea/Codeberg-compatible forge, per agent. no account is created on the remote forge &mdash; create the token there yourself first. the token is never displayed back on this page.</p>
<h3>◇ provisioned forges</h3>
<div id="ef-list" class="ef-list"><p class="meta">select an agent to see its forge accounts.</p></div>
<h3>◇ add forge account</h3>
<form id="ef-form" class="ma-form" autocomplete="off">
<label class="ma-field">
<span>label</span>
<input type="text" name="label" placeholder="e.g. codeberg" required>
</label>
<label class="ma-field">
<span>base url</span>
<input type="text" name="base_url" placeholder="https://codeberg.org" required>
</label>
<label class="ma-field">
<span>access token</span>
<input type="password" name="token" autocomplete="off" required>
</label>
<button type="submit" class="btn btn-spawn">store account</button>
<p id="ef-result" class="ma-result" aria-live="polite"></p>
</form>
</section>
</main>
<script type="module" src="/static/credentials.js" defer></script>
</body>
</html>