Skip to content

feat(sandbox): persist startup command across gateway stop/start cycles#753

Open
drew wants to merge 1 commit intomainfrom
persist-sandbox-command/an
Open

feat(sandbox): persist startup command across gateway stop/start cycles#753
drew wants to merge 1 commit intomainfrom
persist-sandbox-command/an

Conversation

@drew
Copy link
Copy Markdown
Collaborator

@drew drew commented Apr 4, 2026

Summary

The user-provided command from sandbox create -- <command> was previously ephemeral — executed via SSH on first connect but lost when the sandbox pod was recreated after a gateway restart. This change persists the command in the SandboxSpec so it survives gateway stop/start cycles.

Related Issue

N/A — discovered during testing of sandbox pod resumption behavior.

Changes

  • proto/datamodel.proto: Added repeated string command = 10 field to SandboxSpec to persistently store the user's startup command
  • crates/openshell-cli/src/run.rs: Pass the CLI's trailing -- <command> args into the SandboxSpec.command field on CreateSandboxRequest. Since the command now runs as the sandbox entrypoint, the post-create flow opens an interactive shell instead of SSH-exec'ing the command a second time
  • crates/openshell-server/src/sandbox/mod.rs: Thread the command through sandbox_to_k8s_specsandbox_template_to_k8sbuild_env_listapply_required_env. When a command is present, OPENSHELL_SANDBOX_COMMAND is set to the user's command instead of sleep infinity
  • crates/openshell-cli/src/ssh.rs: Suppressed dead-code warning on sandbox_exec_without_exec (no longer called from the create flow)
  • Added two new unit tests: apply_required_env_uses_sleep_infinity_when_no_command and apply_required_env_uses_user_command_when_provided

Testing

  • mise run pre-commit passes
  • Unit tests added/updated
  • E2E tests added/updated (if applicable)

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated (if applicable)

The user-provided command from `sandbox create -- <command>` was
previously ephemeral—executed via SSH on first connect but lost when the
sandbox pod was recreated after a gateway restart.

This change persists the command in the SandboxSpec protobuf, stores it
in both SQLite and the Kubernetes CRD, and sets it as
OPENSHELL_SANDBOX_COMMAND in the pod spec. When the CRD controller
recreates the pod after a gateway stop/start, the supervisor re-executes
the stored command instead of falling back to `sleep infinity`.
@drew drew self-assigned this Apr 4, 2026
@drew drew requested a review from a team as a code owner April 4, 2026 02:02
} else {
sandbox_command.join(" ")
};
upsert_env(env, "OPENSHELL_SANDBOX_COMMAND", &command_value);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we run a risk of accidentally mangling the command when we retrieve it for execution and split on whitespace?

i.e. "python -c print('hello world')". => ["python", "-c", "print('hello", "world')"] due to

} else if let Ok(c) = std::env::var("OPENSHELL_SANDBOX_COMMAND") {
    // Simple shell-like splitting on whitespace
    c.split_whitespace().map(String::from).collect()

We basically only had sleep infinity as the sandbox entrypoint I think?

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.

2 participants