Skip to content

bug(driver-vm): lifecycle requests fall back to sandbox_name when the supplied sandbox_id is absent #3254

Description

@letv1nnn

User Story

As an operator running sandboxes across multiple workspaces on the VM driver, I want a stop, start, or delete request that carries a sandbox id to either act on that exact sandbox or fail, so that a retried delete never destroys an unrelated sandbox that happens to share its name.

Problem Statement

stop_sandbox, start_sandbox, and delete_sandbox on the VM driver prefer the sandbox_id, but when that id is not present in the registry they fall back to matching on sandbox_name instead of reporting the sandbox as absent.

crates/openshell-driver-vm/src/driver.rs:1392 (stop_sandbox; start_sandbox:1466 and delete_sandbox:1531 are the same shape):

let record_id = {
    let registry = self.registry.lock().await;
    if registry.contains_key(sandbox_id) {
        Some(sandbox_id.to_string())
    } else {
        registry
            .iter()
            .find(|(_, record)| record.snapshot.name == sandbox_name)
            .map(|(id, _)| id.clone())
    }
};

The fallback fires whenever the id is missing — including when the caller supplied a perfectly valid one. Sandbox names are unique per workspace, not globally (crates/openshell-server/src/persistence/tests.rs:684, sqlite_name_unique_scoped_by_workspace), and the VM registry permits same-named entries: create_sandbox rejects duplicates by id only (driver.rs:843), never by name. SandboxRecord.snapshot.workspace is populated (driver.rs:6405) but is not consulted when matching, and HashMap::iter().find(...) selects arbitrarily when several names match.

The gRPC handlers (driver.rs:3923, :3933, :3943) forward sandbox_id and sandbox_name straight through with no id-match post-check. get_sandbox is not affected: it gates the fallback on sandbox_id.is_empty() (driver.rs:1614) and its handler verifies the resolved id afterward (driver.rs:3903).

The most ordinary trigger is a repeated delete. A successful delete_sandbox removes the registry entry, so a retried or duplicate DeleteSandbox carrying the same id and name finds no id, falls through to the name branch, and can delete a same-named sandbox in another workspace. Delete is intended to be idempotent — it returns deleted: false when nothing matches — and that is precisely the path that misfires. Gateway restart is not a reliable trigger: restore_persisted_sandboxes (driver.rs:1645) rehydrates the registry from disk on startup.

Impact / Why This Matters

A retried delete can destroy a live sandbox belonging to a different workspace. The caller receives deleted: true and no error, so the loss is silent, and because the fallback resolves through hash iteration order the outcome is not reproducible. Start and stop carry the same exposure with less severe consequences.

There is no caller-side workaround: the request already carries the correct id and the driver discards it once the id is absent. Avoiding the bug requires never reusing a sandbox name across workspaces on a VM-driver gateway, which contradicts the workspace-scoped naming the rest of the product guarantees.

Related: #3234 and #3240 address the same class of defect in the Docker driver; #3253 covers the MXC driver.

Acceptance Criteria

  • When a lifecycle request supplies a non-empty sandbox_id, stop_sandbox, start_sandbox, and delete_sandbox resolve on that id alone and do not fall back to the name.
  • A repeated delete for an already-removed sandbox reports nothing deleted rather than resolving to a same-named sandbox in another workspace.
  • A name-only request that matches more than one sandbox fails with a deterministic error instead of selecting one by iteration order.
  • Regression tests cover: id-scoped stop/start/delete with two same-named sandboxes in different workspaces affects only the requested one; a repeated delete after successful removal is a no-op; an ambiguous name-only request is rejected.

Reproduction Steps

Code inspection; not reproduced against a running VM-driver gateway.

  1. Create workspaces alpha and beta on a gateway using the VM compute driver.
  2. Create a sandbox named demo in alpha, and another named demo in beta. Both are accepted — names are unique per workspace, and the VM registry rejects duplicates by id only.
  3. Delete the demo in beta. It succeeds and its registry entry is removed.
  4. Repeat the same DeleteSandbox request (retry, duplicate delivery, or a second client call). Its id is no longer in the registry, so the driver falls back to the name demo and may delete the sandbox in alpha, returning deleted: true.

Environment

  • OpenShell: main at a0814443
  • OS: Linux (libkrun-backed VM driver)
  • Runtime, deployment, or integration: VM compute driver, gateway with more than one workspace

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:triage-neededOpened without agent diagnostics and needs triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions