Skip to content

docker-sbx: sbx's own secrets, per sandbox, and teardown - #38

Merged
czpython merged 1 commit into
mainfrom
dru-460-docker-sbx-secrets
Sep 7, 2026
Merged

czpython merged 1 commit into
mainfrom
dru-460-docker-sbx-secrets

Conversation

@czpython

@czpython czpython commented Sep 6, 2026 •

Copy link
Copy Markdown
Owner

What changes

The docker-sbx side of the seam, finished on the bed, with teardown.

  • Host deletion calls delete_secrets for the box before the VM goes. Docker Sandboxes keeps a per-sandbox secret after the sandbox is removed, so nothing else would remove it. A provider failure there keeps the row for a retry, like a VM failure does.
  • The seam gets the box alone. Teardown never reads the host row, so a row whose secrets no longer decrypt still goes, VM and all. A test rotates the key and deletes.
  • On docker-sbx, delete_secrets removes the github secret by service name and every custom secret by the placeholder sbx lists for it, then the value files. Removal can run again after a partial teardown: sbx answers a missing secret with success.
  • sbx's own github secret applies only to the catalog's github service. A custom entry named github with a host of its own is a custom secret on that host.
  • The deploy doc says which sbx secret each service is, that deletion removes the sandbox's scope, and that no global sbx secret may name a destination drukbox manages.

Where this differs from the ticket

  • The seam removes a box's secrets as one call, delete_secrets(vm), not one secret by its placeholder. The host row keeps only a fingerprint of the placeholder, by design, so teardown cannot replay it. sbx lists the placeholders of a sandbox's custom secrets, so the sbx implementation reads them there. sbx secret ls has no JSON and sbx secret rm without a name prompts, so the table is parsed, with a test on a captured listing.
  • Teardown wiring is listed under the lifecycle ticket. It lands here because this ticket's done-when needs it, and the bed showed that a removed sandbox keeps its scoped secrets.
  • The sbx github secret and the custom secrets both read their value through --command cat <file>, as the seam PR set up, since sbx secret set has no stdin path.

Names

New names, open to change: delete_secrets on the seam, SbxCLI.custom_placeholders.

Gates

uv run ruff check, uv run ruff format --check, uv run pyright, and uv run pytest are green.

Acceptance

docker-sbx on the KVM bed, with a host that carries a github secret and an anthropic secret:

  • sbx held the github service secret and a custom secret for api.anthropic.com, both scoped to the sandbox. No global secret was made.
  • The value files were 0600 beside the workspaces, not inside one.
  • A plain session saw both placeholders. claude -p answered through sbx's swap.
  • gh api, gh pr list, a clone, a push, and a branch deletion worked against a private repository.
  • Neither value was anywhere in the box.
  • After DELETE /hosts, the sandbox scope listed no secret, and no value file and no workspace remained.

15 of 15 checks passed on this commit. An earlier run, before the review changes, failed one check of the kit's own: it looked for the phrase No secrets found in the unscoped listing while the sandbox still existed, and that listing shows every scope. The check now reads the scope column.

Review

The adversarial review reported two findings. Both are applied:

  • Host deletion read the row's secrets, so a rotated key blocked every teardown, the janitor's too. The seam now gets the box alone and teardown never reads the row.
  • A custom entry named github with a host of its own went to sbx's native github secret, and its host was ignored. Native applies only to the catalog's github service now. This defect was on the base branch too.

@czpython
czpython force-pushed the dru-460-docker-sbx-secrets branch from 1c1b268 to 082831d Compare September 6, 2026 15:29
@czpython
czpython force-pushed the dru-454-github-through-the-proxy branch 2 times, most recently from 4a1a0a7 to 762ecae Compare September 7, 2026 05:25
Docker Sandboxes keeps a per-sandbox secret after the sandbox is removed,
so a host that goes must take its secrets with it. Host deletion now calls
delete_secrets for the box before the VM goes. A provider failure there
keeps the row for a retry, like a VM failure does.

The seam gets the box alone. Teardown never reads the host row, so a row
whose secrets no longer decrypt still goes. On docker-sbx, delete_secrets
removes the github secret by service name and every custom secret by the
placeholder sbx lists for it, since the CLI has no JSON and no way to clear
a scope. Removal can run again after a partial teardown: sbx answers a
missing secret with success. The value files go with the secrets.

sbx's own github secret now applies only to the catalog's github service.
A custom entry named github with a host of its own is a custom secret on
that host, so the value reaches that host and never public GitHub.

The deploy doc says which sbx secret each service is, that deletion
removes the sandbox's scope, and that no global sbx secret may name a
destination drukbox manages, since sbx applies the global one first.
@czpython
czpython force-pushed the dru-460-docker-sbx-secrets branch from 082831d to c51e946 Compare September 7, 2026 05:27
@czpython
czpython changed the base branch from dru-454-github-through-the-proxy to main September 7, 2026 05:27
@czpython
czpython merged commit 3d82716 into main Sep 7, 2026
6 of 12 checks passed
@czpython
czpython deleted the dru-460-docker-sbx-secrets branch September 7, 2026 05:29
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