The SDK proto check and sync dashboard jobs pinned the CI container to
image tag 37072ee8, which predates several mise.lock updates. Tools
baked into that image no longer satisfied the lockfile, so every run
re-downloaded go and yq from the GitHub release CDN and failed whenever
that CDN returned a transient error.
Repin to 5b9daab9, the current CI image build, so mise install resolves
entirely from the baked toolchain. The pin stays an explicit tag to keep
the zizmor unpinned-images rule satisfied.
Signed-off-by: Ignas Baranauskas <ibaranau@redhat.com>
Add automated proto drift detection for Go and TypeScript SDKs with
issue-based notifications when SDK builds break due to proto changes.
Signed-off-by: Ignas Baranauskas <ibaranau@redhat.com>
- Replace BSD-incompatible in-place sed calls with portable temp-file rewrites.
- Remove test-only shell interception and capture generated gateway config
directly.
- Allow parity tests to use supplied supervisor binaries without resolving a
Linux target.
- Normalize temporary-directory paths and use portable RPM config installation.
- Set a valid setuptools-scm version for Python protobuf generation in Jujutsu
checkouts.
Signed-off-by: Kris Hicks <khicks@nvidia.com>
* fix(ci): restore Windows test portability
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* fix(tasks): skip Unix lockfile check on Windows
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* fix(tasks): use buf shim on Windows
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
---------
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
forward_handler_preserves_ssrf_response_and_denial_stage's ssrf_denied
check was the only assertion in the test without a failure message,
unlike its sibling assertions. This test has failed intermittently in
CI with no way to see what response was actually returned, since the
message is where that gets surfaced.
Signed-off-by: politerealism <burdcat17@gmail.com>
* feat(helm): scope ClusterRole/ClusterRoleBinding names by release namespace
The chart creates cluster-scoped ClusterRole and ClusterRoleBinding
resources with a fixed name derived from the release name. When
multiple Helm releases coexist on the same cluster (multi-tenant),
only one release can own these resources due to Helm ownership
annotations -- the second install fails with a conflict.
Append .Release.Namespace to the ClusterRole and ClusterRoleBinding
names so each release gets its own cluster-scoped resources. The
duplication is harmless (the rules are identical and small) and
eliminates multi-tenant conflicts entirely without requiring external
RBAC management.
Signed-off-by: Brandon Squizzato <bsquizza@redhat.com>
* test(helm): add regression tests for namespace-scoped ClusterRole names
Assert the generated ClusterRole name, ClusterRoleBinding name, and
roleRef all include the release namespace suffix so multi-namespace
installations cannot silently regress to conflicting fixed names.
Signed-off-by: Brandon Squizzato <bsquizza@redhat.com>
---------
Signed-off-by: Brandon Squizzato <bsquizza@redhat.com>
* feat(mxc): ETW->OCSF audit consumer + Windows OCSF JSONL parity (cp6 P1)
Add a Windows MXC ETW->OCSF audit trail in openshell-driver-mxc: a real-time
Sandboxing-provider ETW consumer that decodes events (TDH), attributes each to
an OpenShell sandbox_id, and maps them to OCSF (lifecycle 6002, config 5019,
process 1007, finding 2004).
cp6 Phase 1 - durable OCSF JSONL audit-file parity with Linux:
- openshell-ocsf: add emit_ocsf_event_routed (populates the event-bridge
thread-local AND stamps sandbox_id+message in one dispatch) plus public
set/clear_current_event; OS-aware device (Device::windows/for_current_os) so
device.os.name reflects the host instead of a hardcoded Linux stub.
- etw_consumer: emit via the routed emit (previously fired a bare info! that
never populated the bridge, so the structured event was dropped).
- openshell-server: install OcsfJsonlLayer over a synchronous daily-rotated
appender (durable under force-kill), gated by OPENSHELL_OCSF_JSON, path via
%PROGRAMDATA%\OpenShell\logs (override OPENSHELL_OCSF_LOG_DIR).
- device.hostname now resolves to the real gateway machine name.
Box-proven on 7F203-MXC-001: JSONL lines == shorthand OCSF rows, all valid
OCSF JSON, per-sandbox attribution intact, disabled state writes nothing.
Signed-off-by: Akber Raza <akberr@nvidia.com>
* feat(mxc): map remaining Sandboxing ETW events to OCSF
Close the last three ETW->OCSF gaps so the audit trail covers the full
set of events the Sandboxing provider emits (12/12):
- ProcessLaunched -> Process Activity [1007] "Launch" (confirmed start;
carries the real processId/threadId, the twin of CreateProcessInSandbox
which only has the request + command line).
- SandboxProxyConfigured -> Device Config State Change [5019] (the one
network-plane setup event; surfaces proxyPort, "no proxy" when 0).
- SandboxConsoleReferencePlumbed -> Device Config State Change [5019]
(console-handle plumbing).
map_config_state now handles the full config/hardening/setup family and
carries proxyPort/hasConsoleReference/creationFlags as unmapped fields.
Verified on 7F203-MXC-001: 11/12 event types emit OCSF without a proxy
(SandboxProxyConfigured requires proxy config to fire).
Signed-off-by: Akber Raza <akberr@nvidia.com>
* fix(mxc): seed ETW attribution under registry lock + Device tests
Address CodeRabbit review on !31:
- Prevent stale ETW attribution on a delete/launch race: register the
wxc-exec pid while holding the registry lock, and bail if the sandbox
entry is already gone. Previously the attribution key could be seeded
after `delete` had removed the sandbox, leaving a stale key that could
misroute later Sandboxing ETW events to a dead sandbox_id. Lock order
(registry -> attribution) matches the delete path, so no deadlock.
- Add unit tests for the new Device::windows and Device::for_current_os
constructors to harden Windows/Linux OCSF device parity.
Signed-off-by: Akber Raza <akberr@nvidia.com>
* fix(mxc-etw): buffer+replay racing events and harden attribution keys
Addresses two ETW->OCSF attribution review items (Shailendra #1, #2).
#2 early-event loss: ETW delivers the sandbox create/config burst the instant wxc-exec starts, which can beat the driver's register_launch (now under the registry lock post-Ready). process_event previously dropped anything unresolved, losing the racing burst. Add a bounded, time-bounded pending buffer (PENDING_MAX=4096, PENDING_TTL=5s): unresolved events are held and replayed once attribution lands, aged-out ones dropped. Consumer switched to a timed recv_timeout(200ms) so the buffer is re-driven after each event and on a tick. Emit path factored into shared emit_resolved().
#1 attribution collisions: a Windows PID is recycled after exit and a command line is commonly identical across sandboxes. register_launch now rebinds by_pid on reuse and clears the stale last_pid_sid hint (warns if the PID still pointed at a different, leaked sandbox); command line is held in by_cmd only while unique and demoted to a new ambiguous_cmds set on a second owner, so a duplicate command refuses to resolve rather than misroute.
Unit tests: buffer replay (direct + cross-link), buffer bound, PID-reuse rebind, duplicate-cmd non-resolution. Box-verified on 7F203-MXC-001 (5 sandboxes, identical cmd -> 5 isolated sandbox_ids, 50/50 OCSF/JSONL, BuffersLost=0).
Signed-off-by: Akber Raza <akberr@nvidia.com>
* docs(mxc-etw): note cmd_line is captured raw with no privacy filtering
Review item #3 (Shailendra): add a PRIVACY NOTE on map_process_launch stating cmd_line is copied verbatim into OCSF process.cmd_line with no redaction, so secrets/PII on a command line land unredacted in the durable audit trail (deliberate audit-fidelity trade-off; treat the log as sensitive). Redaction is owned by an upstream privacy layer, not this path; no general audit-output PII scrubber exists today (openshell_core::secrets [CREDENTIAL] redaction is scoped to the proxy HTTP-target logging, a separate egress path).
Signed-off-by: Akber Raza <akberr@nvidia.com>
* fix(mxc-etw): open ETW trace on caller thread so start_session reports real status
Review item #4 (Shailendra): start_session previously returned Ok(EtwSession) as soon as the pump thread was spawned, but OpenTraceW ran later inside that thread; if it failed we still handed back a live-looking session and logged 'consumer started' (silent failure = false audit coverage).
Split the two Win32 calls instead of adding a channel handshake (avoids any lost-wakeup/hang risk): the quick, synchronous OpenTraceW now runs on the caller thread (open_trace), and only the blocking ProcessTrace runs on the pump thread (run_trace). start_session returns Err if OpenTraceW fails (reclaiming the boxed Sender so the consumer disconnects, stopping the session, joining the consumer) and returns Ok/logs 'started' only once capture is genuinely open. Opened handle + LoggerName buffer + boxed Sender are carried to the pump via a Send OpenedTrace so they outlive ProcessTrace.
Box-verified on 7F203-MXC-001: consumer started=True, failed-to-start=False, 50 OCSF rows / 50 JSONL, BuffersLost=0 (no regression to capture/emit).
Signed-off-by: Akber Raza <akberr@nvidia.com>
* fix(mxc-etw): guard pending-event replay against PID recycling
CodeRabbit flagged that drain_resolved() re-resolved buffered events
against the live by_pid map, so if Windows recycled a wxc-exec PID within
PENDING_TTL a stale event from the dead sandbox could be emitted under the
new owner.
Stamp each by_pid registration with its Instant and add resolve_replay(),
used only on the buffered/replay path. It (a) never falls back to the
recycle-/ambiguity-prone by_cmd or last_pid_sid keys, and (b) trusts a PID
match only when the registration is not newer than the buffered event by
more than REPLAY_PID_GRACE (2s) - a recycled PID's registration lands well
outside that window, so the stale event ages out instead of misattributing.
The legitimate #2 seed race (registration lands ~immediately) still replays.
Adds unit tests for the recycle-refusal, in-grace acceptance, and
weak-fallback exclusion.
Signed-off-by: Akber Raza <akberr@nvidia.com>
* fix(mxc-etw): surface unexpected ProcessTrace termination (review #4)
start_session already returns Err on OpenTraceW failure (runs on the
caller thread since e41a7701), closing the first half of Shailendra's #4.
This closes the second half: ProcessTrace's result was discarded, so if
capture died mid-run the backend had no way to know.
Add a shared CaptureHealth (stopped/stopping/exit_code) between the pump
thread and EtwSession. run_trace now records ProcessTrace's WIN32_ERROR
and, when the pump returns without a deliberate stop, logs at ERROR that
MXC OCSF capture is no longer running. EtwSession::stop() sets `stopping`
before teardown so a normal shutdown isn't misreported, and
EtwSession::is_capture_alive() exposes the state for status/diagnostics.
Box-verified on 7F203-MXC-001: 5 sandboxes, 50 attributed OCSF rows,
JSONL parity 50/50, BuffersLost=0, clean start/stop (no false failure).
Signed-off-by: Akber Raza <akberr@nvidia.com>
* feat(mxc-ocsf): add ETW->OCSF audit-trail example kit; fix proxy-configured message
Add a runnable OCSF audit-trail example under examples/ (run-ocsf-audit.ps1,
mxc-ocsf-audit.toml, ocsf-audit.yaml, README) that spins up sandboxes with the
in-process ETW consumer and egress proxy on, emitting a full OCSF JSONL audit
trail across all four classes (6002/5019/1007/2004).
Fix SandboxProxyConfigured mapping to log "MXC sandbox proxy configured" instead
of a misleading "(no proxy)" when the provider reports proxyPort=0; the event's
presence already indicates proxy configuration. Verified on-box: 26 events, all
mapped ETW event types present.
Signed-off-by: Akber Raza <akberr@nvidia.com>
* feat(mxc-ocsf): clearer audit report + client-safe run-ocsf-audit.ps1
Improve the ETW to OCSF audit-trail example output and make it safe to ship.
Report:
- Add an event-type coverage count ("N of M expected event types fired");
the denominator auto-adjusts (8 with proxy on, 7 with -NoProxy).
- Split the checklist into expected event types vs anomaly findings
(ActivityError/FallbackError), which are reported separately and not
counted toward coverage (a clean run may emit none).
- Verdict is now coverage-based (all expected types must fire) instead of
the looser "at least 3 OCSF classes".
- Call out the absolute path to the durable OCSF JSONL log prominently.
Client-safety:
- Default -ShareOut to empty (no auto-copy); pass -ShareOut a UNC path to
opt in. Removes a hardcoded internal share path from a published example.
- Drop internal-team wording ("Hand that zip back for evaluation", "BUNDLE:")
in favor of neutral "Results bundle:".
- Update README-ocsf-audit.txt to match the opt-in -ShareOut behavior.
Verified on both MXC boxes: 7F203-MXC-001 (base-container) -> PASS, 8 of 8
event types, 26 OCSF events across 4 classes; 7F203-MXC-003 (AppContainer
fallback) -> reduced set as expected, clean output.
Signed-off-by: Akber Raza <akberr@nvidia.com>
* fix(mxc): configure OCSF audit workloads per sandbox
- remove unsupported gateway-scoped workload fields from the shipped MXC audit example.
- build the command, working directory, and filesystem grant from each run's ShareDir
- pass the workload through --driver-config-json.
- preserve the host CONNECT proxy configuration and conditional audit coverage for the future host_connect_proxy merge
- require the workload output when determining the audit verdict.
Signed-off-by: Akber Raza <akberr@nvidia.com>
* fix(mxc): omit command arguments from OCSF audit logs
- record only the executable basename for MXC CreateProcessInSandbox audit events
- leave process.cmd_line unset so workload arguments cannot reach shorthand or JSONL logs
- cover tokens, passwords, signed URLs, and PII with a secret-leak regression test
- update the audit example, architecture guidance, and published logging documentation
- preserve ETW attribution and future host_connect_proxy enforcement behavior
Signed-off-by: Akber Raza <akberr@nvidia.com>
* feat(etw): enhance ETW session management with distinct naming for concurrent gateways
* fix(etw): bound the audit queue during overload
- replace the unbounded ETW callback channel with count- and byte-bounded buffering
- keep the ETW callback non-blocking and count records rejected during overload
- emit immediate, rate-limited warnings that identify resulting audit coverage gaps
- make the audit example fail when queue overload causes dropped ETW records
- cover stalled consumers, oversized events, and warning throttling with unit tests
Signed-off-by: Akber Raza <akberr@nvidia.com>
* fix(etw): harden sandbox audit attribution
- remove command-line and persistent per-PID fallback keys from live and replay resolution
- retire the driver-owned wxc-exec PID before publishing child completion
- retain established identity, activity, and correlation-vector links only for the five-second late-event window
- prevent buffered records from crossing rapid PID retirement and reuse boundaries
- add resolver and lifecycle coverage and document the attribution trust boundary
Signed-off-by: Akber Raza <akberr@nvidia.com>
* chore(mxc): address rebase follow-ups
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* fix(mxc): align OCSF audit example with driver config
- remove unsupported egress proxy settings
- stop requiring the unavailable proxy audit event
- update example documentation for supported event coverage
Signed-off-by: Akber Raza <akberr@nvidia.com>
* fix(etw): redact command-line secrets in DecodedEtwEvent summary
* fix(etw): enhance PID resolution and event attribution logic for ETW records
* fix(ocsf): restrict gateway-local JSONL sink to Windows/MXC path with opt-in configuration
* address rebase issues
* fix(mxc): address ETW audit review feedback
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* fix(mxc): fail closed across ambiguous PID reuse
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
* fix(mxc): bind ETW attribution to process generation
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
---------
Signed-off-by: Akber Raza <akberr@nvidia.com>
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
Co-authored-by: Jamie King <jamiek@nvidia.com>
Co-authored-by: Drew Newberry <anewberry@nvidia.com>
* docs(rfc): RFC 0012 Isolation Backend interface
Introduces RFC 0012, the runtime-selectable Isolation Backend contract: a
pluggable component that establishes and enforces an agent's isolation
boundary across network, filesystem, syscall, and identity, while the
supervisor stays the policy authority (proxy, policy, audit) and the agent's
only egress.
Includes the supporting topology matrix and codebase-grounding notes.
Signed-off-by: Jordan Ganoff <jordan.ganoff@docker.com>
* docs(rfc): complete RFC 0012 contract detail and corrections
Tighten RFC 0012 for review without changing its structure or tone:
- Remove the undefined `BoundaryIntent` from `attach`, and state that `claim`
is the only transition that binds sandbox identity, policy, agent, and
resources; an attached boundary holds no claimed or untrusted workload.
- Add the runtime interface definitions (`BoundaryExec`/`ExecSession`,
`BoundaryPortForward`, `EventSource`) and their semantics: owned distinct
stdio, PTY resize, placement-neutral exit and signals, stable repeated
`wait`, validated loopback targets, and single-consumer events.
- Make boundary confirmation mandatory (`MUST`) and lifetime-long, and state
retry, termination, and cleanup semantics (only attach is auto-retryable; a
lost `start_agent` returns the existing process; descendants are owned;
`wait_terminated` and an idempotent `shutdown`).
- Require trusted admission to supply the expected backend id, contract
version, policy digest, and capabilities that a backend cannot lower; add the
no-silent-weakening policy invariant; mark `VerifiedBoundaryDescriptor`
privately constructed and distinguish envelope from contract version; make
`ResourceBinding` driver-issued, bound, and non-wideable.
- Make the rollout executable and forbid a silent default backend.
topology-matrix: rename "sidecar proxy" to sidecar-assisted (the proxy stays
with the supervisor), frame sidecar and node as composite backends, move the
single-pod outer sandbox to the shared-kernel cell, and note a node enforcer
alone is not `restricted`-compatible.
codebase-grounding: re-pin anchors to the RFC's parent ba21bb32 (driver.rs and
proxy.rs line numbers refreshed) and add a permalink base; correct the event
wording so a denial carries `Evidence` plus request-specific L7 data.
Set state: review and link PR #2048.
Signed-off-by: Jordan Ganoff <jordan.ganoff@docker.com>
* docs(rfc): RFC 0012 cleanup
Contract completion: add MediationIngress/MediatedConnection so the proxy
receives connections placement-neutrally; complete the runtime types
(BoundaryExitStatus/BoundarySignal, BoundaryTerminal::resize, IdentitySource
Send+Sync) and a machine-readable BackendErrorKind; name the AdmittedBoundary-
Requirements admission block retained by VerifiedBoundaryDescriptor; show
claim_id/generation in ClaimContext; require a canonical bounded descriptor
encoding; define capability comparison. Mark MediationIngress, the admission
block, and claim generation as contract additions the in-pod POC does not yet
implement.
Security semantics: make confirmation mandatory and lifetime-long, but correct
the enforcement model: Landlock/seccomp are monotonic while netns/nftables are
mutable, so require the mutation authority fenced from the workload, atomic
default-deny updates, and fail-closed on lease loss rather than calling the
boundary irreversible. "Confirms effective enforcement", not "reads rules
back". Bind Attested identity to sandbox and claim id/generation. Tighten the
execution-domain invariant (admission-visible named capability + audit, whole
descendant trees). Distinguish structural pre-Running ordering from dynamic
post-termination rejection; note adoption must remove legacy bypass paths.
Lifecycle: drop the "establishes before supervisor boot" contradiction; add
shutdown to the supervisor sequence; rewrite the in-pod migration appendix
(policy-free attach, netns/rules at claim/bind, agent().wait(), wait_terminated,
idempotent shutdown). The RFC is implemented only after the in-pod backend
passes its release gates.
Topology: narrow node-enforcer claims to "network-setup capabilities off the
pod"; nuance NetworkPolicy (coarse L3/L4 defense in depth, not a proxy
replacement); drop the proxy-policy-reprograms-boundary claim; label the
containment table a kernel-compromise ceiling.
Grounding: re-pin to the RFC's parent a5161d0 (process.rs and proxy.rs line
numbers refreshed; others unchanged and reverified).
Signed-off-by: Jordan Ganoff <jordan.ganoff@docker.com>
* docs(rfc): simplify isolation backend contract
This removes a lot of detail to keep the RFC succinct.
* removed POC and intermediate stage references
The RFC should describe the end state, and not intermediate milestones or POCs.
* revised based on feedback:
- Introduced topology nomenclature to align with how we've been talking about this in other conversations
- Simplified the explanation in the proposal section
- Clarified binary identity
- Simplified the initial contract to require the minimal interface necessary to satisfy all known topologies
- Confirmed this will work with the proposed mxc (RFC 0013) proposal
* docs(rfc): update RFC 0012 supporting docs for sidecar topology
- Repin codebase-grounding.md to 8eacb477 (sidecar supervisor topology,
#2076); update capabilities line numbers (1534→2538, 1540→2544), init
container line numbers (191→423, 993→1506, 1185→2113), and remove the
stale "no native sidecars today" claim. Add openshell-network-init and
openshell-supervisor-network sidecar entries and expand the rg pattern.
- Add Implementation column to topology-matrix.md; mark Co-located/in-pod
and Same-pod composite as implemented (original topology and #2076
respectively); remaining patterns noted as proposed.
Signed-off-by: Jordan Ganoff <jordan.ganoff@docker.com>
* docs(rfc): fully reground RFC 0012 codebase references to 8eacb477
All line numbers and function names verified against the post-sidecar
state of the codebase (commit 8eacb477, #2076).
Changes:
- process.rs: ProcessHandle::spawn 440→527, netns param 446→535;
drop_privileges call sites 603/700→710/812, enforcement 613/705→721/818-819;
enter_netns_and_sandbox now documented at ssh.rs:1245
- CLONE_NEWNET call sites: process.rs:589→695, ssh.rs:619/1186→653/1262,
supervisor_session.rs:610→735, netns/mod.rs:363→342 (226 unchanged)
- CLONE_NEWNS: was one unshare at :393; now unshare at :449 and a new
setns at :480 added for sidecar mount-namespace entry
- nft fail-open: line 264→265, return Ok(()) range 272-277→277; note
that the sidecar path (netns/mod.rs:477) requires nft and returns an
error if absent, fixing the invariant bug for the sidecar topology
- nft_ruleset.rs: policy accept 41→53; accept rules 43-49→56-92;
reject rules now at 106+
- VM driver MASQUERADE: runtime.rs:417/436→418/437
- Agent command: main.rs:331→601; sleep infinity driver.rs:1886→2937,
clarify it is set via SANDBOX_COMMAND env var
- OPA evaluation: proxy.rs:1611 / evaluate_opa_tcp renamed to
authorize_egress_intent at proxy.rs:1955; NetworkInput built at :2032
- openshell.proto: clarify no lifecycle Attach; note AttachSandboxProvider
(provider record attachment, not isolation lifecycle)
- README.md appendix: update pinned commit reference a5161d0→8eacb477
Signed-off-by: Jordan Ganoff <jordan.ganoff@docker.com>
* docs(rfc): address feedback and clean ups
Signed-off-by: Jordan Ganoff <jordan.ganoff@docker.com>
* docs(rfc): preserve binary identity semantics
Keep RFC 0012 focused on placing binary-aware enforcement behind the Isolation Backend contract instead of requiring a new connection-initiation capture mechanism. Define identity as trusted resolution for an accepted connection before policy evaluation, retain fail-closed attribution requirements, and document the current authorization-time procfs behavior. This preserves RFC 0002's binary gating baseline while allowing future backends to provide stronger identity resolution without changing the contract.
Signed-off-by: Jordan Ganoff <jordan.ganoff@docker.com>
* docs(rfc): simplify isolation backend proposal
Addresses PR feedback: Removed the implementation plan and codebase grounding,
renamed the forwarding primitive to BoundaryLoopbackConnector, and clarified
that conformance tests exercise the deployed topology, including delegated
components and their transport.
---------
Signed-off-by: Jordan Ganoff <jordan.ganoff@docker.com>
* fix(supervisor): canonicalize L7 protocols before OPA
Normalize recognized protocol spellings before supervisor validation and Rego authorization so mixed-case MCP policies cannot take the REST rule path. Reject null MCP configuration instead of silently defaulting it, and cover both behaviors with regression tests.
Signed-off-by: Shiju <shiju@nvidia.com>
* test(policy): cover normalization for every supported protocol
Exercise TCP, REST, WebSocket, GraphQL, SQL, JSON-RPC and MCP through YAML and protobuf loading with lowercase, uppercase and mixed-case names.
Assert canonical names in raw OPA data and returned L7 configuration, preserve TCP L4 behavior, and verify that normalization leaves unrelated data unchanged and is idempotent.
Signed-off-by: Shiju <shiju@nvidia.com>
---------
Signed-off-by: Shiju <shiju@nvidia.com>
Previously, every event from a sandbox reused the sandbox ID as its event
ID. Consumers deduplicating security records could mistake separate events
for the same record, and missing device types or empty image objects could
prevent schema validation.
Give each event its own ID, retain the sandbox association separately, and
classify the environment as Other/Sandbox while keeping the OS separate.
Omit unknown container details instead of emitting empty objects.
Security tooling can now distinguish events from the same sandbox and read
their identity consistently after serialization.
Refs #1055
Signed-off-by: Kris Hicks <khicks@nvidia.com>
* chore(nix): unify native and cross-compilation toolchains
Replace the separate GNU and musl development shells with one shell that
provides explicit toolchains for x86_64 and aarch64 Linux, plus native
Darwin on macOS. Cargo selects the compiler, assembler, archiver, and
linker through target-specific environment variables.
Build GNU targets against a glibc 2.28 sysroot with static GCC runtimes
and use the musl toolchains for static Linux executables. Build Z3 and
AWS-LC with each target's stdenv and expose AWS-LC libraries and Rust
bindings through its target-specific system directory.
Keep Darwin system libraries on the unprocessed Apple SDK and prevent
the Rust toolchain from propagating replacement libraries into the shell.
Include the compiler and libc fixes needed for Darwin-to-Linux builds.
Share dependency and environment wiring through mkToolchain, keep compiler
wrappers in the Linux and Darwin modules, and group the pinned GNU build
environment under glibc-2.28. Document the toolchain boundaries in the build
architecture overview.
Validation: actionlint and nix fmt pass. The toolchain refactor preserves
the shell derivations for x86_64 Linux, aarch64 Linux, and aarch64 Darwin.
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
* ci(nix): use the default shell for binary builds
Remove the dev-shell input and its matrix and workflow plumbing.
Use the host default shell for builds and cache hashing.
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
* ci(nix): build release binaries with explicit Cargo targets
Use target-specific artifact paths and rely on the Nix toolchains for
linkage. Remove post-link rewriting, platform linkage checks, and the
unused interpreter input. Update the build architecture documentation.
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
* refactor(nix): reuse glibc and GCC build recipes
Use a pinned historical Nixpkgs recipe for glibc 2.28 and rebuild GCC 15
against it instead of maintaining separate runtime builds. Keep only
compatibility adjustments needed by the current build tools.
Assemble the sysroot from glibc outputs and static native libraries. Use
standard ELF interpreters and resolve Rust's explicit gcc_s dependency
through the static GCC archives.
Allow 90 minutes for Rust branch checks to accommodate cold toolchain
builds. Validate the Linux release matrix locally; Darwin remains for CI.
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
* fix(nix): disable obsolete RPC tools in glibc
Avoid building rpcgen against the Darwin SDK, which does not expose stat64.
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
---------
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
* feat(docs): add version availability labels
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* fix(docs): use supported Python for sync
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* feat(docs): publish versioned docs from releases
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* fix(docs): format dev version label
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* chore(docs): upgrade Fern CLI to 5.112.0
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* fix(docs): make release publishing monotonic
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* fix(docs): preserve snapshot release identity
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* docs(fern): document versioned publishing
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* test(docs): cover explicit snapshot rollback
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* refactor(docs): use Fern refs for versions
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* fix(docs): bundle components for ref versions
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* revert(docs): keep complete version copies
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
* fix(docs): publish latest and dev channels
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
---------
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
Keep watching briefly when a compute driver reports ContainerExited without a canonical main-process result. This prevents --no-keep cleanup from deleting the sandbox before the supervisor publishes the authoritative exit status.
Signed-off-by: Shiju <shiju@nvidia.com>
* refactor(inference): remove managed inference routes
Closes#3172
Remove the inference route control plane, inference.local data path, built-in router crate, and SDK surface. Move inference workloads to explicitly imported provider profiles and native endpoints, with migration cleanup and updated tests and documentation.
Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>
* fix(policy): preserve alternate upstream isolation
Restore the provider policy activation guard so legacy OpenAI and Anthropic providers configured for alternate base URLs do not grant egress to the built-in public vendor endpoints.
Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>
---------
Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>
* chore(deps): replace ring with AWS-LC
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
* fix(lint): address warnings after dependency upgrades
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
* fix(tls): limit provider initialization to reqwest clients
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
---------
Signed-off-by: Simon Scatton <sscatton@nvidia.com>
Introduce a single generic applier, options.Apply[T any, O ~func(*T)],
in a new leaf package openshell/v1/internal/options, and route all
option-application sites through it. Nil option entries are now ignored
uniformly instead of panicking; non-nil options still apply in order,
and each site keeps its existing pre-seeding and defaulting.
- Add internal/options package with Apply and unit tests
- Route the 15 application sites (root, types, oidc, fake, gateway, edge)
through options.Apply; exported types.Apply*Options keep their
signatures and delegate to it
- Add one nil-handling test per affected package
- Document the nil-option rule in README.md and the docs book
No public API signature changes.
Closes#3213
Signed-off-by: Roland Huß <rhuss@redhat.com>
* feat(sandbox): support rootfs tar as --from source for VM driver
Accept flat rootfs tar archives (.tar, .tar.gz, .tgz) via the --from
flag for VM-backed gateways. The CLI detects the archive extension,
validates that the gateway uses the VM compute driver, and passes the
tar path through driver_config. The VM driver copies the tar into its
staging area and feeds it into the existing rootfs extraction and ext4
disk creation pipeline, skipping the container image pull/export steps.
Closes#2175
Signed-off-by: Philippe Martin <phmartin@redhat.com>
* fix(sandbox): validate rootfs tar path at the VM driver boundary
The rootfs_tar_path field in driver_config was passed from the API
caller directly to tokio::fs::copy without validation. An authenticated
user bypassing the CLI could supply arbitrary host paths (e.g.
/dev/zero for disk exhaustion, or readable host files for data
exfiltration).
Introduce a trusted staging directory that the VM driver creates on
startup and advertises via GetCapabilities. The CLI now copies the tar
into the staging directory before creating the sandbox, and the driver
validates that the received path is a regular file inside the staging
root and within a configurable size limit (default 10 GiB) before any
I/O.
New VmDriverConfig options:
- rootfs_tar_staging_dir: override the staging directory
(default: <state_dir>/rootfs-tar-staging)
- rootfs_tar_max_bytes: override the size limit (default: 10 GiB)
Addresses GATOR-28b5152e-01.
Signed-off-by: Philippe Martin <phmartin@redhat.com>
* fix(sandbox): request-scoped staging, size pre-check, and cleanup for rootfs tar
Tighten the rootfs tar staging flow to address the remaining GATOR-01
obligations:
- Request-scoped staging: the CLI creates a unique per-request
subdirectory (req-<pid>) under the staging root instead of placing
files directly in the shared directory. The driver enforces that the
tar path is at depth 2 (staging_root/<subdir>/<file>), preventing
cross-request path selection.
- Size pre-check: the driver advertises rootfs_tar_max_bytes via
GetCapabilities. The CLI reads this limit and rejects oversized files
before copying, avoiding disk exhaustion in the staging directory.
- Cleanup: the driver removes the request staging subdirectory after
consuming the tar (on cache hit, copy success, or copy failure),
ensuring staged data does not persist beyond the request.
Signed-off-by: Philippe Martin <phmartin@redhat.com>
* fix(vm): restore rootfs-tar sandboxes from persisted image identity
On restore or restart, the one-shot staged tar archive has already been
cleaned up. Reading the persisted image identity from the sandbox state
directory and resolving the cached disk path directly avoids re-accessing
the deleted staging path.
Addresses GATOR-168b9210-01.
Signed-off-by: Philippe Martin <phmartin@redhat.com>
* fix(cli): use random staging dirs and enforce byte limit during rootfs tar copy
Replace PID-based request staging directories with tempfile-generated
random names to prevent collisions and make paths unpredictable.
Replace bare tokio::fs::copy with a streaming copy loop that enforces
the advertised max_bytes limit during transfer, closing the TOCTOU gap
between the pre-copy size check and the actual copy.
Signed-off-by: Philippe Martin <phmartin@nvidia.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
* fix(sandbox): issue rootfs tar staging slots from the gateway
A caller could name any host path in `driver_config.vm.rootfs_tar_path`,
which the privileged VM driver then read. The CLI-side locality check did
not apply to direct API requests.
The gateway now owns staging. `BeginRootfsTarStaging` allocates a
request-scoped directory under the driver-advertised staging root and
returns an opaque single-use token; `CreateSandbox` carries the token, and
the gateway substitutes the path it allocated before dispatching to the
driver. `template.driver_config.<driver>.rootfs_tar_path` is rejected
outright in request validation, so a caller-supplied path never reaches
privileged I/O.
Tokens are bound to the issuing workspace and subject, consumed once, and
expire after 30 minutes. Outstanding slots are capped per caller and
overall, so one caller can neither exhaust the staging filesystem nor
starve others. An RAII guard reclaims the directory on every failure path
after consumption, and an age-gated sweep runs at startup and on each
reconcile pass for directories whose driver died before its own cleanup.
The token is stripped from the public sandbox before persistence: the
stored copy is returned verbatim by GetSandbox, ListSandboxes and
WatchSandbox to every member of the workspace.
Also fixes two defects this exposed:
- The CLI wrote `rootfs_tar_path` at the top level of `driver_config`, but
the gateway forwards only `driver_config.<driver_name>`, silently
dropping unmatched keys. The archive never reached the VM driver, so the
documented `--from ./rootfs.tar` flow did not work at all. Config is now
nested under `vm` and deep-merged, so a caller's existing VM settings
survive instead of being clobbered by a shallow extend.
- Staging previously required `GetGatewayInfo`, which is restricted to
`platform_admin`, making the feature unusable for ordinary users on any
RBAC-enabled gateway. The new RPC matches CreateSandbox at
`sandbox:write` / `workspace_role: user`.
`compute_driver.proto` is unchanged; the gateway reads the staging root
from the capabilities it already stores.
Refs #2175
Signed-off-by: Philippe Martin <phmartin@redhat.com>
* fix(vm): derive rootfs tar cache identity from archive contents
The prepared-disk cache key combined the archive's full path with an mtime
truncated to seconds, then mapped punctuation to `-`. Distinct paths such as
`/tmp/a/b.tar` and `/tmp/a-b.tar` collapsed onto the same key and reused each
other's disk, a rewrite within the same second kept stale contents, and a long
path could exceed filesystem component limits.
Identity is now a SHA-256 of the archive contents. This is also what makes the
cache work at all now that the gateway allocates a fresh staging directory per
request: a path-derived key would miss on every create.
The archive is hashed, the cache checked, and only on a miss copied — so a hit
skips writing a multi-gigabyte file. The copy is hashed as it is written and
rejected if the digest differs from the first pass, which closes the window
where the source changes during staging rather than approximating it with a
re-stat.
Refs #2175
Signed-off-by: Philippe Martin <phmartin@redhat.com>
* fix(vm): decompress gzip rootfs tar archives during staging
`--from` accepts `.tar.gz` and `.tgz`, but the driver staged whatever bytes
it was given and the guest image-prep VM extracts the staged file with a
plain `tar -xpf`. Compressed sources therefore depended on the guest tar
auto-detecting gzip, and the prepared disk was sized from the compressed
length, which is far too small for the expanded rootfs.
Staging now detects gzip from the archive's magic bytes -- the driver only
ever sees a gateway-issued staging path, never the caller's file name -- and
writes an uncompressed tar. The digest still covers the source bytes, so the
"archive changed while staging" check is unaffected, and expansion is bounded
by `rootfs_tar_max_bytes` so a compression bomb cannot fill the host disk.
`extract_rootfs_archive_to` sniffs gzip as well, so the host-side extraction
path matches.
Adds unit coverage for gzip staging, bounded expansion, and gzip extraction,
plus an e2e sandbox created from a gzip-compressed export.
Signed-off-by: Philippe Martin <phmartin@redhat.com>
---------
Signed-off-by: Philippe Martin <phmartin@redhat.com>
Signed-off-by: Philippe Martin <phmartin@nvidia.com>