fix(ssh): persist sandbox host identities - #4094
quocanh261997 wants to merge 2 commits into
Conversation
Store each sandbox's Ed25519 host key in the gateway credential store and deliver it only to the supervisor. Preserve identity across restarts, delete owned credentials with the sandbox, and expose the public SHA256 fingerprint through sandbox and SSH-session APIs and client SDKs. Cover credential ownership, cancellation, deletion retries, client compatibility, and pinned SSH connections through lifecycle transitions. Closes NVIDIA#3835 Signed-off-by: Mike Nguyen <miken@nvidia.com>
Local verification evidenceThe saved local run passed all six Docker CLI conformance scenarios and the SSH identity E2E test. This report covers the working-tree implementation subsequently committed as Environment: macOS on ARM64, Docker Desktop. Live test run: October 1, 2026. The excerpts below come from the saved test output. What the live SSH test verified
The test source at this commit contains these assertions. The gateway restart branch ran; its skip message is absent from the saved output. Actual SSH test output: Supporting checks
Actual SSH credential test outputReproduction and scopeThe standard focused Docker command is: OPENSHELL_E2E_DOCKER_TEST=ssh_host_identity mise run e2e:dockerOn this Mac, the stock launcher's container-side if [ "$(uname -s)" = "Darwin" ]; then
GATEWAY_BIND_IP="0.0.0.0"
SUPERVISOR_GATEWAY_HOST="host.docker.internal"
fiThe gateway still used mTLS. The successful local invocation was: LIBRARY_PATH=/opt/homebrew/lib \
OPENSHELL_E2E_DOCKER_TEST=ssh_host_identity \
OPENSHELL_CONFORMANCE_BIN="$PWD/target/debug/openshell-conformance" \
mise exec -- bash plans/3835-with-docker-gateway-macos.sh \
bash e2e/rust/e2e-docker.sh __openshell_run_docker_e2eThe launcher adjustment is excluded from the PR. This evidence covers local Docker verification; Kubernetes pod rescheduling and other driver E2E lanes were not exercised. GitHub runner validation is still pending. |
drew
left a comment
There was a problem hiding this comment.
gator-agent
PR Review Status
Thanks @quocanh261997 for documenting the current-head Docker and SSH verification. I checked the full patch and the creation/cleanup paths those tests exercise; one PR-owned failure path can leave a sandbox record and its host-key credential behind after create reports an error.
Action required: make every post-commit identity failure either fully remove the sandbox and key or durably leave the sandbox in a retryable deletion state.
Blocking findings:
GATOR-e5de0a89-01: see the inline Warning on the post-commit identity preparation call.
Carried findings:
- None
Gator metadata
- Validation: project-valid through linked, validated issue #3835
- Docs: sandbox identity behavior is documented under
docs/; related operating skills are updated - Checks: DCO and vouch gates are green; required branch workflows have not been dispatched for this head
- E2E:
test:e2eis required for sandbox lifecycle and credential-flow changes, but dispatch waits until blocking review feedback is resolved - Head SHA:
e5de0a892813408bf08a36d93ab33b66a9929d18 - Base SHA:
76cfd0e31d5e1633db7ccd86ad9023ef7a2461b2 - Merge base SHA:
021400be8af471f8669369e679de3e18cf0bd672 - Patch ID:
accf65c51eed8be52b1848efb2eb9bfbfe089f99 - Gator payload:
10 - Review mode:
initial - Previous reviewed SHA: none
- Review budget exhausted: no
- Maintainer decision required: no
- Next state:
gator:in-review
Signed-off-by: Mike Nguyen <miken@nvidia.com>
Local verification after the failed-create fixTested the working tree now committed as The six new regression tests all passed. They inject failures to check that:
Full E2E Test AttestationGateway mode: Docker. Every live test/scenario executed by the focused launcher passed:
The SSH test checks the published fingerprint against the key actually presented, workload read restrictions, a pinned OpenSSH connection after stop/start and a managed gateway restart, and a different key after delete/recreate. The gateway restart branch ran; no SSH test was skipped. Command used: LIBRARY_PATH=/opt/homebrew/lib \
OPENSHELL_E2E_DOCKER_TEST=ssh_host_identity \
OPENSHELL_CONFORMANCE_BIN="$PWD/target/debug/openshell-conformance" \
mise exec -- bash plans/3835-with-docker-gateway-macos.sh \
bash e2e/rust/e2e-docker.sh __openshell_run_docker_e2eAs in the earlier evidence, the ignored launcher copy uses |
|
Label |
|
/ok to test a645d9f |
drew
left a comment
There was a problem hiding this comment.
gator-agent
PR Review Status
Thanks @quocanh261997. I checked your cleanup update against the prior failed-create finding: post-commit identity failures and driver-create rejections now share compensation that removes the sandbox and key when possible, retains a durable Deleting record when cleanup must retry, and continues cleanup after caller cancellation. The added regressions cover the requested credential-store and key-deletion failures. No blocking code-review findings remain.
Blocking findings:
- No blocking findings remain
Carried findings:
GATOR-e5de0a89-01: resolved by this head; the Gator-owned thread has been closed
Required test dispatch is not complete yet. Gator applied test:e2e and posted /ok to test for the current head; the contributor mirror must be created before the E2E label can be re-applied and the required workflows confirmed queued.
Gator metadata
- Validation: project-valid through linked, validated issue #3835
- Docs: sandbox identity behavior is documented under
docs/; no additional docs change is required for this cleanup-only delta - Checks: DCO is green; required current-head branch workflows are awaiting contributor-mirror dispatch
- E2E:
test:e2eis required; mirror creation was requested with/ok to test a645d9fd5d61993ed8c8f3d848955e38f0e81be5and workflow queue confirmation remains pending - Head SHA:
a645d9fd5d61993ed8c8f3d848955e38f0e81be5 - Base SHA:
76cfd0e31d5e1633db7ccd86ad9023ef7a2461b2 - Merge base SHA:
021400be8af471f8669369e679de3e18cf0bd672 - Patch ID:
3b6a5b4b21488f22e5a5a68154f7db415e0e635c - Gator payload:
10 - Review mode:
follow_up - Previous reviewed SHA:
e5de0a892813408bf08a36d93ab33b66a9929d18 - Review budget exhausted: no
- Maintainer decision required: no
- Next state:
gator:in-review
|
/ok to test a645d9f |
Summary
Sandbox SSH host keys currently change when the supervisor restarts, so clients cannot reliably recognize the same sandbox. Give each sandbox ID one Ed25519 host key and expose its public SHA256 fingerprint. Keep the private key in the configured gateway credential store and deliver it only to the supervisor.
Related Issue
Closes #3835
Replaces #4027, which the vouch check closed before contributor approval. The contributor is now vouched.
Changes
Testing
mise run pre-commitpasses.mise run ci— passed, including workspace and gateway Rust tests, Python tests, Go checks, TypeScript tests, formatting, lint, and compile checks.mise run sdk:ts:ci— passed, including 142 tests, coverage, and build validation.mise run go:ci— passed.ssh_host_identity— passed.Rust checks used
LIBRARY_PATH=/opt/homebrew/libfor Homebrew Z3 on macOS. Installede2fsprogsfor the existing VM filesystem tests.The stock Docker E2E launcher failed locally because its container-side
127.0.0.1endpoint cannot reach the macOS gateway. The successful conformance run uses an ignored copy of the launcher withhost.docker.internalas the supervisor endpoint and the temporary mTLS gateway bound on all interfaces. This local launcher adjustment is excluded from the PR.Six additional failed-create tests cover a failed credential save and name reuse, failed key deletion after each driver rejection, failed fingerprint publication, failed backend cleanup, and caller cancellation during deletion or while waiting for the cleanup lock.
Added identity tests cover credential-store reconstruction, concurrent candidates, interrupted preparation, deletion retries, failed candidate cleanup, inconsistent published identity, secret redaction, older bootstrap bundles, client conversion, fingerprint responses, and real SSH handshakes with direct and relayed streams after listener restart. A live sandbox test checks Get/List fingerprints, a remembered OpenSSH host key through stop/start and gateway restart, workload access restrictions, and recreation under the same name.
The live test uses the Docker driver. Kubernetes pod rescheduling and other compute-driver lanes have not been exercised locally.
Checklist