Skip to content

fix(sandbox): acknowledge initial policy load and expose SDK labels #2159

Description

@KyleZheng1284

Summary

Two OpenShell lifecycle/API gaps block the policy-bound per-job sandbox integration in NVIDIA-AI-Blueprints/aiq#298 for AI-Q 2.2:

  1. A newly created sandbox can reach Ready and expose an effective policy while the same revision remains Pending indefinitely.
  2. The public Python SDK cannot send gateway-object labels or list sandboxes by label selector, although the protobuf supports both.

AI-Q intentionally fails closed instead of exposing execution without authoritative policy attestation.

Confirmed policy-state behavior

Reproduced on macOS/Apple Silicon with Docker Desktop:

OpenShell Creation path Result
0.0.72 clean gateway diagnostic Ready; effective policy present; matching revision remains Pending; current_policy_version=0
0.0.77 CLI directly, without AI-Q Ready; revision 2 is Effective via policy get; revision 2 remains Pending via policy list; revision 1 is Superseded

The state remained stable rather than transitioning to LOADED. The policy itself was successfully constructed and applied. landlock.compatibility: best_effort is therefore not an attestation bypass or explanation; it controls filesystem-enforcement compatibility.

Linux has not yet been reproduced. The observed behavior is confirmed on the macOS/Docker Desktop path; source inspection suggests shared lifecycle logic, but a Linux run is required to establish platform scope.

Minimal reproduction

  1. Create a sandbox with an explicit policy.
  2. Wait until the sandbox reaches Ready.
  3. Compare policy get <sandbox> -o json, policy list <sandbox>, and the sandbox's current_policy_version.
  4. Observe an effective positive revision while that same revision remains Pending.
  5. Delete the sandbox and verify it is absent.

Expected contract

After initial policy construction:

  • report the exact sandbox-scoped revision as LOADED;
  • report FAILED with a load error when construction fails;
  • never leave a successfully applied initial revision permanently Pending;
  • continue reporting later hot-reload revisions normally.

Suspected source path

Inspection of v0.0.72 and v0.0.74 found:

  • load_policy() constructs the initial OpaEngine;
  • the first run_policy_poll_loop() iteration records config_revision and policy_hash;
  • ReportPolicyStatus(LOADED) is sent only from the later policy_changed branch;
  • an unchanged initial hash never enters that branch.

The same runtime symptom is present in 0.0.77; its exact source path should be confirmed against that tag.

Python SDK label/selector gap

CreateSandboxRequest supports request-level labels and ListSandboxes supports label_selector, but the public Python lifecycle API does not expose them:

  • SandboxClient.create(), create_session(), and Sandbox(...) cannot forward gateway labels;
  • SandboxClient.list() cannot forward a selector;
  • SandboxRef does not retain gateway metadata labels.

Template labels reach Docker/runtime resources, but gateway selectors inspect gateway-object metadata. Consequently, a Python-created AI-Q sandbox is not returned by:

openshell sandbox list --selector aiq=deep-research

Proposed fix

Initial policy acknowledgement

  • Preserve the fetched sandbox policy version/source through initial construction.
  • Report initial success or failure exactly once.
  • Track the acknowledged version so later polling does not duplicate it.
  • Preserve existing hot-reload behavior.

Python SDK

Add optional, source-compatible parameters:

  • name and labels for creation/session/Sandbox;
  • label_selector for listing;
  • immutable gateway labels on SandboxRef.

The lifecycle and SDK fixes may land separately, but AI-Q requires both in a tagged release.

Acceptance criteria

  • Initial success and failure acknowledgement tests.
  • Later policy-revision/hot-reload regression tests.
  • Python request-label and selector-forwarding tests.
  • Docker E2E: create → ReadyLOADED → selector membership → execute → delete.
  • Direct lookup and selector both confirm deletion.
  • Tagged release with compatible CLI, Python SDK, and gateway versions.
  • AI-Q macOS demo validation with explicit best_effort.
  • AI-Q Linux production validation with hard_requirement.

Downstream impact

This issue blocks AI-Q #298. It blocks only the OpenShell-specific live acceptance for stacked artifact-lifecycle PR AI-Q #305; #305's provider-independent artifact-storage implementation can be restacked onto develop and proceed separately. AI-Q will not treat Pending as success, weaken attestation, or pin an unreleased fork.

A focused implementation PR can be prepared after maintainer triage and the repository's human state:agent-ready gate.

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:triage-neededOpened without agent diagnostics and needs triage

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions