mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-16 05:20:22 +08:00
pull-request/2184
57
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
34fd3cbf64 |
feat(inference): inference interception and routing (!38)
Closes #67 ## Summary Implements transparent inference interception and routing for sandboxed AI agents. The sandbox proxy intercepts outbound AI SDK calls (OpenAI, Anthropic) and reroutes them through the gateway to policy-controlled backends — enabling organizations to redirect inference traffic to local or self-hosted models without modifying agent code. **Decision model** — a tri-state OPA evaluation for every CONNECT request: 1. Binary + endpoint explicitly allowed in `network_policies` → **allow** (pass through) 2. Not explicitly allowed + `inference.allowed_routes` configured → **inspect for inference** (TLS intercept, detect API patterns, route through gateway) 3. Otherwise → **deny** No endpoint declarations or binary lists needed for inference routing. Just configure `inference.allowed_routes`. ## Key Changes ### Sandbox (interception) - **OPA policy**: New `network_action` Rego rule with three outcomes (`allow`, `inspect_for_inference`, `deny`). New `NetworkAction` enum replaces `PolicyDecision.allowed` bool for the proxy's main decision path. - **Proxy**: New `InspectForInference` path — TLS-terminates client, parses HTTP, detects inference API patterns (`POST /v1/chat/completions`, `/v1/completions`, `/v1/messages`), strips auth headers, forwards via gRPC. - **New module**: `l7/inference.rs` — `InferenceApiPattern`, `detect_inference_pattern()`, HTTP request/response parsing. - **gRPC client**: New `proxy_inference()` for sandbox→gateway forwarding. - **Sandbox init**: Creates OPA engine when inference is configured, even without `network_policies`. ### Gateway (dispatch) - **InferenceService**: `ProxyInference` RPC loads sandbox policy, resolves allowed routes, dispatches to router. Full CRUD for inference routes. - **Proto**: `InferenceRoute`, `InferenceRouteSpec`, `ProxyInferenceRequest/Response`, Inference gRPC service. ### Router (backend proxying) - **New crate**: `navigator-router` with `Router`, `proxy_with_candidates()`, protocol-based route selection, backend HTTP proxying with auth header rewriting. - **Mock support** for testing (`mock://` scheme). ### CLI - `nav inference create/update/delete/list` commands for route management. ### Python SDK - Updated protobuf bindings. Removed old `inference.py` client (replaced by transparent interception). ### Documentation - New `architecture/inference-routing.md` — end-to-end system documentation. - Updated `architecture/sandbox.md` — proxy, OPA, and source index sections. - Updated `architecture/README.md` — new subsystem overview and diagram. ## Addendum: Chunked Transfer Compatibility This branch now also fixes intercepted SDK requests that send chunked request bodies: - `inspect_for_inference` now accepts `Transfer-Encoding: chunked` and decodes chunked request bodies before forwarding to the gateway - Removed the prior `411 Length Required` response for chunked intercepted requests - Added request/response header sanitization for framing and hop-by-hop headers (`content-length`, `transfer-encoding`, `connection`, etc.) to keep forwarded requests and returned responses valid - Added unit tests for chunked parsing and header sanitization Note: this improves compatibility for streaming-style SDK request patterns; true token-by-token passthrough response streaming is still a separate follow-up. ## Minimal Policy for Inference Routing ```yaml inference: allowed_routes: - local ``` Any outgoing connection from a binary not explicitly allowed in `network_policies` will be intercepted and checked for inference API patterns. ## Test Plan - [x] `cargo test --workspace` — all tests pass - [x] `mise run pre-commit` — all checks pass - [x] E2E: OpenAI chat completions routed through gateway - [x] E2E: Anthropic messages routed through gateway - [x] E2E: Python OpenAI SDK from sandbox (`examples/inference/inference.py`) - [x] E2E test: `e2e/python/test_inference_routing.py` |
||
|
|
6dc97171ed |
feat(sandbox): add image build/push and fix cluster deploy (!34)
Closes #44 ## Summary - Add `nav sandbox image push --dockerfile <path>` command to build and push custom container images into the cluster - Fix sandbox Docker build failure caused by OpenClaw installer TTY access - Fix sandbox proxy crash when network namespace is unavailable (fall back to loopback) - Add e2e test for the full custom image build and sandbox creation flow - Rename and rewrite BYOC architecture doc to reflect current state ## Changes ### `navigator-bootstrap` - New `build` module (`src/build.rs`) with `build_and_push_image()` public API - Builds via bollard `Docker::build_image()`, streams output to caller - `.dockerignore` support with glob matching, 8 unit tests ### `navigator-cli` - Added `SandboxImageCommands::Push` subcommand with `--dockerfile`, `--tag`, `--context`, `--build-arg` flags - Added `test:e2e:custom-image` mise task ### `navigator-sandbox` - Proxy now falls back to `127.0.0.1:3128` when no network namespace or explicit bind address is available, instead of erroring out ### Docker / Infra - Sandbox Dockerfile: replaced OpenClaw native installer (`curl | bash`) with `npm install -g openclaw` to avoid `/dev/tty` failures in Docker build ### Documentation - Renamed `architecture/sandbox-byoc.md` to `sandbox-custom-containers.md` - Rewrote doc to describe current behavior (CLI usage, push pipeline, supervisor behavior, design decisions) instead of listing implementation changes ### Tests - Added `e2e/bash/test_sandbox_custom_image.sh` covering image push + sandbox create with custom image |
||
|
|
82e6b81324 |
fix(security): reject CONNECT to internal IPs (SSRF defense-in-depth) (!37)
> **🔧 security-fix-agent** Closes #62 ## Security Fix ### Summary The CONNECT proxy accepted hostnames from clients and connected to whatever IP they resolved to, with no validation against internal address ranges. While the OPA policy is default-deny, a misconfigured or overly permissive policy could allow SSRF to cloud metadata (169.254.169.254), localhost, or RFC1918 services. This fix adds DNS resolution before connecting and rejects any host that resolves to an internal IP. ### Severity Assessment - **Impact:** Medium — if exploited, could reach cloud metadata (IAM creds), cluster-internal services, or host-local services - **Exploitability:** Very low — requires OPA policy misconfiguration or DNS rebinding attack - **Affected components:** `crates/navigator-sandbox/src/proxy.rs` — `handle_tcp_connection` ### Changes Made - `crates/navigator-sandbox/src/proxy.rs`: Added `is_internal_ip()` helper that checks IPv4 loopback/private/link-local, IPv6 loopback/link-local, and IPv4-mapped IPv6. Added `resolve_and_reject_internal()` that resolves DNS and rejects internal IPs. Inserted check between OPA allow and `TcpStream::connect`, with control plane endpoints exempt. - `architecture/security-policy.md`: Added SSRF Protection section with blocked ranges table and flow diagram - `architecture/sandbox.md`: Updated proxy connection flow diagram and added SSRF protection subsection - `architecture/README.md`: Added internal IP rejection step to proxy description ### Tests Added - **Unit:** 17 tests in `proxy::tests` — covers IPv4 loopback/private/link-local, IPv6 loopback/link-local, IPv4-mapped IPv6, public IPs, DNS resolution of localhost/127.0.0.1/169.254.169.254, and DNS failure handling - **Integration/E2E:** N/A — the proxy runs inside a Linux network namespace; unit tests for IP checking and DNS resolution cover the security boundary ### Documentation Updated - `architecture/security-policy.md`: New SSRF Protection section with blocked IP ranges and Mermaid flowchart - `architecture/sandbox.md`: Updated proxy flow diagram and added SSRF protection subsection - `architecture/README.md`: Added step 4 to proxy description ### Verification All 85 sandbox tests pass including 17 new proxy SSRF tests. Pre-commit (fmt, clippy, full test suite) passes clean with zero warnings. |
||
|
|
1c939a255a | feat(sandbox): enable port forwarding and setup openclaw (!33) | ||
|
|
f1439727b9 |
feat(sandbox): L7 protocol-aware inspection with TLS termination (!29)
## Summary Implements L7 (application-layer) protocol-aware policy enforcement for the sandbox proxy, enabling per-request allow/deny decisions based on HTTP method and path — not just host:port. ### Phase 1: HTTP/REST L7 Inspection (plaintext) - New `l7/` module with provider trait, REST parser, and relay loop - Parses HTTP/1.1 requests inside CONNECT tunnels, evaluates method+path against OPA/Rego policy - Supports `access` presets (`full`, `read-only`, `read-write`) and explicit `rules` with glob path matching - `enforcement` modes: `enforce` (deny with 403 JSON) vs `audit` (log only, forward traffic) - Structured logging for every L7 decision (`L7_REQUEST` with protocol, action, target, decision) ### Phase 2: MITM TLS Termination for HTTPS - Ephemeral CA generated at sandbox startup (`rcgen`) - Per-hostname leaf certificate cache (256 cap) for dynamic cert presentation - Client-side TLS termination (sandbox trusts ephemeral CA via `SSL_CERT_FILE`, `NODE_EXTRA_CA_CERTS`, etc.) - Upstream TLS connection with `webpki-roots` verification - Endpoints with `tls: terminate` get full L7 inspection; others remain passthrough ### Additional - Benign TLS/connection errors (close_notify, handshake EOF, reset) downgraded from WARN to DEBUG - Generic `AsyncRead + AsyncWrite` bounds throughout L7 module (works with both `TcpStream` and `TlsStream`) - Proto schema extended with `protocol`, `tls`, `enforcement`, `access`, `rules` fields on `NetworkEndpoint` - CLI `nav sandbox run` wired with `--rego-policy`/`--rego-data` flags and L7 policy display ### E2E Test Coverage - 7 L4 tests: no-matching-policy deny, wildcard binary, binary-restricted, wrong port, cross-policy isolation, non-CONNECT 405, structured log fields - 7 L7 TLS tests: full access allow, read-only deny POST, audit mode, explicit path rules, CA trust store injection, deny response JSON format, structured log fields ## Key Files | Area | Files | |------|-------| | L7 core | `l7/mod.rs`, `l7/provider.rs`, `l7/relay.rs`, `l7/rest.rs` | | TLS termination | `l7/tls.rs` | | Proxy integration | `proxy.rs`, `lib.rs`, `main.rs` | | Env/process | `process.rs`, `ssh.rs` | | OPA policy | `opa.rs`, `dev-sandbox-policy.rego` | | Proto schema | `proto/sandbox.proto` | | CLI | `navigator-cli/src/run.rs` | | E2E tests | `e2e/python/test_sandbox_policy.py` | ## Test plan - [x] 67 unit tests pass (`cargo test --workspace`) - [x] `cargo clippy --workspace --all-targets` clean - [x] 16 e2e policy tests pass (`mise run test:e2e:sandbox`) - [x] Manual smoke test: sandbox with `tls: terminate` on `api.anthropic.com:443` Closes #25 |
||
|
|
89a6e04c8c |
feat(providers): inject provider credentials into sandbox child processes at runtime (!26)
## Summary - Add `GetSandboxProviderEnvironment` gRPC endpoint so the sandbox supervisor can fetch provider credentials at runtime instead of embedding them in the pod spec - Sandbox supervisor (`navigator-sandbox`) fetches credentials on startup and injects them as environment variables into both entrypoint processes and SSH shell sessions via `Command::env()` - Remove credential injection from sandbox creation-time pod spec in `navigator-server` - Update `architecture/providers.md` to document the full runtime credential injection flow, discovery engine details, trait definitions, and end-to-end diagram ## Changes - **proto**: Add `GetSandboxProviderEnvironment` RPC and request/response messages, add `providers` field to `SandboxSpec` - **navigator-server**: Implement `GetSandboxProviderEnvironment` handler and `resolve_provider_environment()` with env var key validation and first-wins dedup; remove old creation-time credential injection from `sandbox/mod.rs` - **navigator-sandbox**: Fetch provider env via gRPC on startup (`grpc_client.rs`), thread `provider_env` HashMap through to `process.rs` (entrypoint) and `ssh.rs` (shell sessions), inject via `cmd.env()` - **navigator-cli**: Adjust sandbox create flow to set provider names in `SandboxSpec.providers` - **e2e**: Add `test_sandbox_providers.py` end-to-end tests - **docs**: Rewrite `architecture/providers.md` with implementation details ## Test Plan - Unit tests for `resolve_provider_environment` in `grpc.rs` - Integration tests updated in `provider_commands_integration.rs`, `mtls_integration.rs`, `multiplex_integration.rs`, `multiplex_tls_integration.rs` - New e2e test suite `test_sandbox_providers.py` |
||
|
|
d2f3ca71d4 |
feat(sandbox): add callable python exec API and refresh e2e coverage (!19)
Closes #13 ## Summary - add Python sandbox execution APIs for command and callable workflows - consolidate sandbox policy fixtures and expand e2e test coverage for policy and Python exec paths - update CI/build config and images for sandbox e2e execution dependencies ## Test Plan - mise run pre-commit |