Skip to content

Fleet server: identity route + fleet-token enforcement on data routes #284

Description

@aarontrowbridge

Important

Scope. Slice 1 of Managed Fleet (#283 — read it first for Problem, Approaches Considered, and the cross-cutting risks; not duplicated here). The vendored server gains (a) an unauthenticated identity route answering instance id, role (canonical | standalone), fleet id, and version, and (b) fleet-token enforcement on data routes when a token file is present. A standalone serve with no token configured keeps today's anonymous behavior — the CLI-parity bar (ADR 0002) is preserved.

Acceptance Criteria

  1. The identity route returns the four-field payload; instance id is generated once and persisted across restarts; role is canonical exactly when the server runs fleet-enabled, else standalone.
  2. With a fleet token file present, data routes answer 401 anonymous and 200 with the token; the identity route stays unauthenticated.
  3. With no token file (standalone serve), data routes answer 200 anonymous — no regression for the single-machine default.
  4. Mutation routes still refuse when the server is bound beyond loopback (ADR 0002 graft regression test).
  5. The token file is created 0600 at its fixed per-user path, atomic at birth (ADR 0001 discipline).

Testing Decisions

Route-level tests in the fork server's existing route test harness (reuse the Connections-routes fixtures — same seam, same patterns): identity payload shape + instance-id persistence across restarts; 401/200 token matrix; no-token anonymous parity; beyond-loopback refusal; file-mode assertion at birth. All five ACs map one-to-one to tests; no new test surface needed beyond the route suite.

Key Decisions & Constraints

  • Instance id is minted once at fleet enable and persisted next to the token; it never rotates within a fleet's life (clients pin it — see the parent's Data Contracts).
  • Role is derived from fleet-enabled state, never configured separately (two sources of truth invite the silent-fork class).
  • The identity payload carries no secrets; the token is the only secret and never appears in any response body.
  • Constraints and invariants per the parent; slice-local: the identity route must answer under opencode serve with no extension present.

Source

Part of #283 · Design: docs/adr/0005-managed-fleet.md (PR #282) · No blockers — this is the root slice.

Metadata

Metadata

Assignees

No one assigned

    Labels

    afkImplement + merge unattended — tests decide green

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions