OXYGENHUB

Identities instead of tokens: agents as the owner's Oxygen delegates, signed requests over a Unix socket, ownership shown issue #4 closed: completed andymccall opened this · 1 comment

andymccall

Nobody is trusted for where they connect from: loopback proves nothing, since any process of any user on the machine can reach the socket or port (spec §5, §8, §21). Instead, every principal is an Oxygen identity and every request is signed.

  • spectra init: reads the owner's identity (oxy identity export from their OXY_HOME) into the ledger as identity.owner; makes the instance identity (keys/instance.secret, 0600; identity.instance in the ledger) and prints the oxy identity delegate add for the owner to run.
  • spectra agent add NAME --kind K --project P --home DIR [--identity FILE] [--uid N]: makes the agent's key pair in its own OXY_HOME through oxy-core, prints the oxy identity delegate add DIR/identity --scope changes --expires 8h for the owner, and refuses to finish until the owner's current identity delegates to the key. Records agent.added with the identity, the owner and the delegation. There is no agent without an owner.
  • Ownership shown everywhere: claude-oxygen · Andy McCall's agent in Radar, the CLI and every tool result's text, from the owner identity's name (§8.1).
  • Authentication (§8.5): the Unix socket <data>/spectra.sock (0660) with SO_PEERCRED; the loopback TCP port for Radar. Signed requests: Spectra-Key, Spectra-Time, Spectra-Nonce, Spectra-Signature (a composite signature with the domain spectra1 request over method || BLAKE3(body) || time || nonce); a five-minute window, a nonce cache, and the owner's delegation to the key checked at every request, so an expired --expires 8h stops the agent by itself. The signature is the resulting events' auth.proof.
  • Assurance levels on every event: 1 token, 2 key on disk, 3 passkey. Tokens exist only behind [security] allow_tokens (spectra agent add --token) and are level 1. The owner's CLI signs with the owner's key (level 2). The passkey and the [policy] classes are issue #19, in 0.2; until then Radar signs the owner in through spectra serve --open's one-time link signed by the CLI key, a level-2 session with a banner.
  • Key to uid: --uid or --learn-uid binds the key; a request with that key from another uid is refused and logged as guard.impersonation; one key on two connections under one uid is guard.key_shared.
  • spectra identity show|refresh (a successor identity of the owner; a removed delegation disables the agent and verify marks its past events valid but revoked).
  • Constant-time checks; ten failed authentications a minute from one address or uid pause it, logged.

Done when a test shows: an unsigned request refused on every interface; a request signed by a key the owner has not delegated to refused; one signed by an expired delegation refused; a key from the wrong uid refused and logged; and two agents under different uids each attributed to their own owner-delegated key in the ledger. After issue #3.

andymccall set labels feature, security ·

andymccall set milestone Sprint 1 ·

andymccall edited ·

andymccall set labels feature, security ·

andymccall edited ·

andymccall referenced by change 09752034b5a8 on main ·

andymccall

Done: spectra init records the owner's Oxygen identity (proven by signing with it) and makes the instance key; spectra agent add makes the agent's key in its own OXY_HOME, prints the oxy identity delegate add to run, waits, and records the agent only once the owner's identity delegates to it (checked against the real oxy, expiry included). Ownership is shown as 'claude-oxygen · Andy McCall's agent'. spectra agent list|disable, spectra identity show|refresh (a successor is accepted only with the same key pair and a signature by it). spectra admin verify now replays identities and delegations in ledger order and checks every signed event; tests cover an agent without delegation, an agent naming another agent or the owner as its actor (a gap found and fixed here), a forged successor, expiry, disable, and a swapped proof. spectra-core's Authenticator checks signature, method, body, a five-minute window, single-use nonces and the uid binding; issue #7 mounts it on the Unix socket with SO_PEERCRED, which is where the 'every interface' test lands. One process writes a ledger at a time (spectra.lock). Spec 0.3a records the decisions.

andymccall closed ·