Skip to content

sandboxd: a missing state for host-only env, kept off disk behind host_env_memory_only - #499

Merged
CMGS merged 7 commits into
mainfrom
fix/host-env-at-rest
Nov 7, 2026
Merged

CMGS merged 7 commits into
mainfrom
fix/host-env-at-rest

Conversation

@CMGS

@CMGS CMGS commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Closes #492
Closes #493
Closes #494
Closes #495
Closes #496
Closes #498

Part of #489.

What changes

Missing state (#492), always on

  • An env entry gains missing, which only the node sets.
  • While an entry is missing, it fails closed: an inject sends nothing and it blocks the node's secret of the same name; a missing upstream entry falls back to the class or pool upstream.
  • GET /v1/sandboxes/{id}/env shows "missing": true on such an entry, and the index row (GET /v1/sandboxes and the root by-id GET /v1/sandboxes/{id}) carries env_missing.
  • A caller write that carries missing, or a guest: false entry with an empty value, answers 400. A GET sent back as a PUT therefore fails instead of blanking secrets.
  • PATCH with a value clears an entry's missing.

host_env_memory_only (#493, #494, #496), off by default, restart only

  • claims.json and the archive and replica rows store guest: false entries without their values, marked missing.
  • A hibernating claim drops its values from memory.
  • After a restart, a wake from hibernate or the archive, or an adoption, the entries stay missing until the control plane sends them again with PATCH.
  • A live move still carries the values to its target.
  • The first start with the flag on rewrites claims.json without the values.

LimitCORE=0 (#495)

  • The shipped unit sets it. deploy.md says to run sandboxd hosts with swap off or encrypted.

Docs (#498)

  • Prefer a claim's own guest: false entry over node-level secrets[].value_env.
  • sandboxd-api.md, deploy.md, egress.md, security.md and sdk.md describe the missing state and the flag.

Go SDK

  • EnvVar.Missing and SandboxSummary.EnvMissing.
  • The Python SDK returns raw dicts and needs no change.

Compatibility

  • Breaking: a guest: false entry with an empty value now answers 400. egress.md documented "" as a way to suppress the node's value for a claim; that form is gone. A missing entry blocks the node's value for its secret.
  • Everything else is unchanged while host_env_memory_only is off.

Deployment order

  1. Release with host_env_memory_only off. Only the write validation changes.
  2. Deploy the control plane's re-push of entries reported as env_missing (cocoonbox final review #223) to production.
  3. Turn host_env_memory_only on per node and restart. Every host-only entry on that node is then missing until re-pushed.

Do not turn the flag on before step 2, or a restart or wake leaves boxes without their credentials.

Hot path

  • Proxy: one extra boolean check per lookup of a host-only value, and none per request otherwise.
  • Journal and row writes: one env map copy per write, only with the flag on.

Tests

New tests:

  • TestDroppedHostValuesAreMissingAndUnpublished
  • TestEnvValidate (2 new cases)
  • TestAMissingEntryInjectsNothingAndBlocksTheNodeSecret
  • TestRouteTakesTheClaimThenClassThenPoolUpstream (missing upstream case)
  • TestEnvVerbsForRootOrTheTenant and TestEnvPatchVerb (empty and missing writes answer 400)
  • TestHostEnvMemoryOnlyKeepsValuesOffDiskAndARestartReportsThemMissing
  • TestTurningHostEnvMemoryOnlyOnDropsTheValuesAJournalStillHolds
  • TestHostEnvMemoryOnlyDropsValuesWhenAClaimHibernates
  • TestHostEnvMemoryOnlyDropsValuesWhenAnUnconfirmedHibernateIsAdopted
  • TestFailoverRowsHoldNoHostOnlyValueWhenMemoryOnly
  • SDK decode tests

The flag tests run with the flag both off and on.

Negative controls: removing each of these makes its test fail (12 checks):

  • the inject skip, checked at the types and the outbound level;
  • the hidden-value skip;
  • each of the two write rejections;
  • the journal drop;
  • the row drop;
  • the hibernate drop on both commit paths;
  • the boot drop;
  • the summary flag;
  • missing kept through redaction.

Gates

Modules sandboxd and sdk/go, GOWORK=off, pinned golangci-lint v2.13.2:

  • golangci-lint run on linux and darwin: 0 issues for each module.
  • golangci-lint fmt --diff: clean.
  • asl -forwarder=false on linux and darwin: no findings.
  • go test -race -count=1 ./...: all packages ok (macOS; CI runs Linux).
  • go vet on e2e, mcp and protocol/wire: ok.

@CMGS
CMGS merged commit 2abab46 into main Nov 7, 2026
1 check passed
@CMGS
CMGS deleted the fix/host-env-at-rest branch November 7, 2026 07:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant