Skip to content

Ambient box credential: FDE identity for in-container interactive sessions - #174

Merged
udaychandra merged 1 commit into
mainfrom
feat/sail-box-credential
Jul 28, 2026
Merged

Ambient box credential: FDE identity for in-container interactive sessions#174
udaychandra merged 1 commit into
mainfrom
feat/sail-box-credential

Conversation

@udaychandra

Copy link
Copy Markdown
Contributor

Why

sail-agent-principals (v0.16.0) rightly killed the forgeable SAIL_ACTOR, but it defined identity only for sail-launched runs. Every interactive session — an FDE's SSH shell into a project container, an IDE-spawned agent — became nobody, and the in-container spec CLI 401s in every project the moment the host upgrades. Interactive sessions are the dominant mode for spec work.

Trust model: possession of the box is the FDE identity — a container lives on one FDE's devbox and is enterable only with that FDE's SSH key, the same key that already is the Sail CLI identity on the host lane.

What

  • BoxCredentialStore: one hashed single-row credential per devbox (sailbox_<64-hex>); replace atomically retires the old plaintext, resolve maps plaintext → handle. New table rides the post-baseline migration lane.
  • BoxCredentialFile: self-healing reconciler for the plaintext file beside api.sock in the shared bind-mounted dir — ambient in every container with zero per-container work. Missing/tampered/rotated/rebound state all converge on the next server start.
  • LocalApiRouter: sealed Caller (Run | Box); run credentials resolve first (a launched agent is always its principal), then the box credential → the FDE's real roster role (fail closed when the handle left the roster). Spec/content/message writes author as the FDE through the same SpecPolicy; whoami reflects the box identity; events stay run-only (403).
  • spec script: falls back to the ambient file when SAIL_RUN_CREDENTIAL is unset; new staleness marker in the ContainerSailSetup chain.
  • ContainerSetupSweep at server start: best-effort refresh of the socket mount + helper scripts in every running catalog container, so enforcement and provisioning ship in the same hop — recovery from the current fleet-wide 401 is exactly one sail upgrade. (The mount force-refresh also heals reboot-stranded sockets.)

Verification

  • TDD throughout; store/provisioner/router/operations/sweep unit-tested (self-heal matrix, precedence, roster fail-closed, events 403, whoami shape, single-row constraint)
  • Incus IT: a real container authenticates with no injected env by reading box.credential from the mount — whoami as the FDE, posts a spec message attributed to the FDE, forged sailbox_ still 401s
  • mvn -Pintegration -Dsail.it.requireIncus=false clean verify green (all JaCoCo + Spotless gates)

…sions

sail-agent-principals closed the forgeable SAIL_ACTOR hole but defined
identity only for sail-launched runs; every interactive session (an
engineer's SSH shell, an IDE-spawned agent) became nobody and the spec
CLI 401s fleet-wide after upgrade. Possession of the box is the FDE
identity — the container is enterable only with the FDE's SSH key — so
the socket now honors an ambient credential provisioned beside it.

One hashed single-row credential per devbox (BoxCredentialStore),
reconciled with the plaintext file in the shared socket mount by
BoxCredentialFile at server start: missing, tampered, rotated, or
rebound state all self-heal. LocalApiRouter resolves run credentials
first (a launched agent is always its principal), then the box
credential to the FDE's roster role — fail closed when the handle has
left the roster. Events stay run-only. The spec script falls back to
the ambient file when SAIL_RUN_CREDENTIAL is unset, and a best-effort
boot sweep refreshes helpers in every running project container, so
enforcement and provisioning ship in the same hop.
@udaychandra
udaychandra merged commit 58c0782 into main Jul 28, 2026
3 checks passed
@udaychandra
udaychandra deleted the feat/sail-box-credential branch July 28, 2026 19:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant