Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c292819
feat: isolate and attest OpenShell jobs
KyleZheng1284 Jul 1, 2026
ec3ab69
test: add live OpenShell isolation smoke
KyleZheng1284 Jul 1, 2026
4f16702
fix: harden OpenShell cleanup lifecycle
KyleZheng1284 Jul 1, 2026
ad13192
fix: drop nonexistent /app from generated OpenShell read_only policy
KyleZheng1284 Jul 2, 2026
f06c326
drop /app from the policy and and also fix for non-sandbox jobs
KyleZheng1284 Jul 2, 2026
3227a2b
fix: sanitize sandbox teardown failures
KyleZheng1284 Jul 2, 2026
790ce5f
fix: attest effective OpenShell policy
KyleZheng1284 Jul 6, 2026
a010e9a
fix: make sandbox cleanup outcome truthful
KyleZheng1284 Jul 6, 2026
5e7e04f
refactor: separate OpenShell gateway lifecycle
KyleZheng1284 Jul 6, 2026
312a232
fix: validate OpenShell 0.0.72 live attestation
KyleZheng1284 Jul 6, 2026
423586c
fix lint issue
KyleZheng1284 Jul 6, 2026
7d0508d
test: move OpenShell live acceptance under pytest
KyleZheng1284 Jul 7, 2026
2f8981d
docs: add canonical OpenShell operator guide
KyleZheng1284 Jul 7, 2026
aa5c432
fix(sandbox): enforce OpenShell readiness capabilities
KyleZheng1284 Jul 7, 2026
c3f83f5
docs: clarify OpenShell readiness acceptance
KyleZheng1284 Jul 7, 2026
e335c9b
fix(sandbox): rebaseline OpenShell runtime on 0.0.80
KyleZheng1284 Jul 10, 2026
76ad559
docs(sandbox): update OpenShell 0.0.80 operations guidance
KyleZheng1284 Jul 10, 2026
d144465
fix(artifacts): make chart capture and references deterministic
KyleZheng1284 Jul 10, 2026
ddc1b6d
fix(writer): retry missing report output once
KyleZheng1284 Jul 10, 2026
d74c86c
fix(sandbox): harden OpenShell setup and readiness
KyleZheng1284 Jul 10, 2026
0284a2a
fix(sandbox): address OpenShell review findings
KyleZheng1284 Jul 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 26 additions & 20 deletions configs/config_openshell.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# EXPERIMENTAL: AI-Q deep research over a local, single-operator OpenShell sandbox.
# Run ./scripts/setup_openshell.sh first to provision the gateway and named sandbox.
# Jobs attach to that shared sandbox; per-job directories prevent filename collisions
# but are not a security boundary. Do not run mutually untrusted jobs concurrently.
# EXPERIMENTAL: one policy-bound OpenShell sandbox per deep-research job.
# Canonical operator guide: docs/source/deployment/openshell.md

general:
use_uvloop: true
Expand Down Expand Up @@ -52,16 +50,6 @@ llms:
chat_template_kwargs:
enable_thinking: true

gpt_oss_llm:
_type: nim
model_name: openai/gpt-oss-120b
base_url: https://integrate.api.nvidia.com/v1
temperature: 1.0
top_p: 1.0
max_tokens: 256000
api_key: ${NVIDIA_API_KEY}
max_retries: 10

summary_llm:
_type: nim
model_name: nvidia/nemotron-mini-4b-instruct
Expand Down Expand Up @@ -139,13 +127,31 @@ functions:
deep_research_sandbox:
_type: deep_research_sandbox
provider: openshell
sandbox_name: ${AIQ_OPENSHELL_SANDBOX_NAME:-aiq-openshell-demo}
openshell_image: ${AIQ_OPENSHELL_IMAGE:-aiq-openshell-demo:latest}
policy: ${AIQ_OPENSHELL_POLICY_FILE:-configs/openshell/generated/aiq-openshell-policy.yaml}
workdir: /sandbox
network: blocked
# The OpenShell policy is authoritative. This declaration is an upper bound:
# startup fails if the policy grants a hostname not listed here.
network: allowlist
network_allow:
- api.github.com
- github.com
- integrate.api.nvidia.com
- api.tavily.com
- google.serper.dev
- pypi.org
- files.pythonhosted.org
- huggingface.co
- cdn-lfs.huggingface.co
- export.arxiv.org
- api.semanticscholar.org
- registry.npmjs.org
timeout: 1200
idle_timeout: 1800
delete_on_exit: false
policy_load_timeout_seconds: 30
delete_on_exit: true
attest: true
require_hard_landlock: ${AIQ_OPENSHELL_REQUIRE_HARD_LANDLOCK:-true}
artifact_capture:
enabled: true
max_file_bytes: 50000000
Expand All @@ -154,11 +160,11 @@ functions:
deep_research_agent:
_type: deep_research_agent
enable_citation_verification: true
orchestrator_llm: gpt_oss_llm
orchestrator_llm: nemotron_super_llm
source_router_llm: nemotron_super_llm
researcher_llm: nemotron_super_llm
planner_llm: gpt_oss_llm
writer_llm: gpt_oss_llm
planner_llm: nemotron_super_llm
writer_llm: nemotron_super_llm
exclude_tools:
- web_search_tool
verbose: true
Expand Down
15 changes: 15 additions & 0 deletions configs/openshell/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# OpenShell Policies

`aiq-research-policy.yaml` is the checked-in, production-oriented policy sample
used by schema and regression tests. It is not the runtime default.

Run `scripts/openshell/setup_openshell.sh` to generate the canonical runtime policy at:

```text
configs/openshell/generated/aiq-openshell-policy.yaml
```

The generated file reflects the selected network preset and Landlock mode and is
the default consumed by `configs/config_openshell.yml`, the strict gateway probe,
and the live acceptance suite. Do not commit environment-specific generated
policies or credentials.
14 changes: 7 additions & 7 deletions configs/openshell/aiq-research-policy.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Generated by scripts/setup_openshell.sh.
# Generated by scripts/openshell/setup_openshell.sh.

version: 1

Expand All @@ -11,21 +11,21 @@ filesystem_policy:
- /usr
- /lib
- /etc
- /app
- /var/log
- /proc/self
- /proc
- /dev/urandom
read_write:
- /sandbox
- /workspace
- /tmp
- /dev/null

# best_effort lets the sandbox start on hosts without Landlock (e.g. Docker Desktop on
# macOS), but there filesystem confinement is silently dropped. Acceptable only for the
# local single-operator demo; production must use `hard_requirement` (fail closed).
# Fail closed when the host cannot enforce Landlock filesystem confinement. Local demo
# environments that intentionally accept weaker isolation must generate a separate policy
# with `scripts/openshell/setup_openshell.sh --landlock-compatibility best_effort` and configure
# `require_hard_landlock: false` explicitly.
landlock:
compatibility: best_effort
compatibility: hard_requirement

process:
run_as_user: sandbox
Expand Down
2 changes: 1 addition & 1 deletion deploy/openshell/Dockerfile.aiq-demo
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ENV DEBIAN_FRONTEND=noninteractive

# Optional OpenShell sandbox log verbosity. Defaults to `warn` (OpenShell's stock
# sandbox level, so default behavior is unchanged). Rebuild with
# `--build-arg OPENSHELL_SANDBOX_LOG_LEVEL=debug` (or `setup_openshell.sh
# `--build-arg OPENSHELL_SANDBOX_LOG_LEVEL=debug` (or `scripts/openshell/setup_openshell.sh
# --sandbox-log-level debug`) to surface process/relay detail (`OCSF PROC:` etc.)
# in the container logs (`/var/log/openshell.*.log`, `openshell logs <name>`).
ARG OPENSHELL_SANDBOX_LOG_LEVEL=warn
Expand Down
2 changes: 1 addition & 1 deletion docs/source/architecture/agents/deep-researcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ an orchestrator using the [`deepagents`](https://docs.langchain.com/oss/python/d

**Location:** `src/aiq_agent/agents/deep_researcher/agent.py`

For optional DeepAgents sandbox execution (Modal) and operational notes, see
For optional DeepAgents sandbox execution (Modal or OpenShell) and operational notes, see
[Deep Research Sandbox](./sandbox.md).

## Purpose
Expand Down
33 changes: 22 additions & 11 deletions docs/source/architecture/agents/sandbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ SPDX-License-Identifier: Apache-2.0
# Deep Research Sandbox Notes

Deep research can optionally run DeepAgents `execute` calls through a sandbox provider
(Modal, OpenShell, or any registered provider). Modal creates a sandbox per job. The
experimental OpenShell path attaches to a pre-created named sandbox shared by its jobs;
job-scoped directories prevent filename collisions but are not a security boundary.
(Modal, OpenShell, or any registered provider). Modal and OpenShell create a fresh physical
sandbox per job. OpenShell binds the configured policy at creation and attests the authoritative
effective policy source, content, hash, and active revision before exposing the execution backend.
On the supported OpenShell `0.0.80` stack, current, active, revision, and effective-config versions
must all be positive and agree with the exact submitted policy/hash; missing capabilities or any
version disagreement fails closed.

The sandbox is an internal execution detail. There are no sandbox-specific API
endpoints, and job-level auth remains responsible for submit, stream, status,
Expand All @@ -17,16 +20,20 @@ runtime (`.../job/{job_id}/artifacts`), which is also auth-scoped to the job.

> **Developer reference:** the full architecture, provider contract, config schema,
> artifact pipeline, and troubleshooting live next to the code in
> [`src/aiq_agent/agents/deep_researcher/sandbox/README.md`](../../../../src/aiq_agent/agents/deep_researcher/sandbox/README.md).
> [`src/aiq_agent/agents/deep_researcher/sandbox/README.md`](https://github.com/NVIDIA-AI-Blueprints/aiq/blob/develop/src/aiq_agent/agents/deep_researcher/sandbox/README.md).
> Operators should use the canonical [OpenShell deployment guide](../../deployment/openshell.md)
> for setup, authenticated gateway lifecycle, supported platforms, acceptance, and cleanup.

## Current Behavior

- Modal uses one sandbox per deep research job. OpenShell currently attaches jobs to
the configured shared sandbox name and is intended for local, single-operator testing.
- Modal and OpenShell use one physical sandbox per deep research job. OpenShell shared
attachment is available only through an explicit debug-only opt-in and is not job-isolated.
- Synchronous sandbox-enabled runs use an internal per-agent runtime ID.
- Providers are selected by config (`sandbox.provider` + `providers.<name>`); the
provider is validated against the registry and gated by its declared capabilities.
OpenShell policy is provisioned externally and is not verified when AI-Q attaches.
OpenShell policy YAML is parsed strictly against the installed SDK schema, applied in the
job's creation spec, checked against the declared network upper bound (hostless/CIDR overrides
are rejected), and attested through the gateway status/config RPCs before use.
- Job IDs must satisfy each provider's object-name rules (Modal: 64 chars or fewer,
alphanumeric plus dash/period/underscore).
- `timeout` bounds individual execution. Other lifecycle controls are provider-dependent.
Expand All @@ -46,16 +53,19 @@ and [Production Considerations](../../deployment/production.md#artifact-storage)

## Operational Notes

- High-concurrency Modal runs create one sandbox per job. OpenShell runs share the named
sandbox and must not be used concurrently for mutually untrusted jobs. Optional submit-path
- High-concurrency Modal and OpenShell runs create one sandbox per job. Optional submit-path
caps (`AIQ_MAX_SANDBOXES_PER_PRINCIPAL` / `AIQ_MAX_SANDBOXES_GLOBAL`, default-off) bound
concurrency/cost but do not provide filesystem isolation.
concurrency and cost.
- Custom client-supplied job IDs must not be reused for a new job.
- Manifest checkpoints preserve completed artifacts after successful sandbox commands. The
terminal finalizer harvests once before cleanup on success/failure; cancellation harvests
only when the provider is idle and otherwise terminates immediately.
- The runtime closes provider sessions on success, failure, cancellation, and timeout.
A named OpenShell sandbox persists when `delete_on_exit` is disabled.
- Per-job OpenShell mode requires `delete_on_exit: true`. A persistent shared sandbox is
possible only through the explicit debug attachment settings.
- OpenShell provisioning and authenticated gateway lifecycle have separate owners. See the
[OpenShell responsibility table](../../deployment/openshell.md#responsibility-and-lifecycle-ownership)
rather than duplicating operational commands here.

## Current Safeguards

Expand All @@ -67,3 +77,4 @@ The following safeguards are in place:
with MIME-from-bytes spoof rejection, SVG sanitization, and an inline-render allowlist.
- Sandbox quota and concurrency controls, and artifact retention via job-expiry cleanup.
- Structured lifecycle logging for sandbox create, reuse, failure, and cleanup.
- Structured `sandbox.attestation` and `sandbox.cleanup` events.
2 changes: 2 additions & 0 deletions docs/source/deployment/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ All containerized deployments run the same three services:

- **[Production Considerations](./production.md)** -- Guidance on managed databases, horizontal scaling, security hardening, monitoring, and resource requirements.

- **[OpenShell](./openshell.md)** -- Optional policy-bound execution for generated deep-research code, including supported platforms, authenticated gateway ownership, policy/config pairing, deterministic live acceptance, and safe cleanup.

## Quick Start

For the fastest path to a running stack:
Expand Down
Loading
Loading