Commit Graph
62 Commits
Author SHA1 Message Date
John T. MyersandJohn Myers dfd5238d0d fix(gator): make supervised lifecycle sandbox-native (#3343)
* fix(gator): run supervisor as sandbox main process

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* feat(gator): persist supervised state history

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* refactor(gator): remove obsolete background launch mode

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

---------

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>
Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
2026-09-15 19:04:13 +00:00
Mrunal Patel b799fccb8b fix(auth): harden OIDC trust root retrieval (#3332)
* fix(auth): harden OIDC trust root retrieval

Signed-off-by: Mrunal Patel <mrunalp@gmail.com>

* fix(e2e): pass OIDC HTTP acknowledgement value

Signed-off-by: Mrunal Patel <mrunalp@gmail.com>

---------

Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
2026-09-15 17:00:45 +00:00
alangou 9b4b63ec69 fix(deps): update DOMPurify and runtime image packages (#3276)
Signed-off-by: Adrien Langou <alangou@nvidia.com>
2026-09-11 10:45:29 +00:00
John T. Myers f4dc6be4b2 refactor(inference): remove managed inference routes (#3195)
* 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>
2026-09-09 18:47:22 +00:00
alangou 3693b32841 ci(trivy): add artifact and PR configuration scans (#3185)
* ci(trivy): add artifact and PR configuration scans

Signed-off-by: Adrien Langou <alangou@nvidia.com>

* fix(ci): harden Trivy gate detection and finding diff

Signed-off-by: Adrien Langou <alangou@nvidia.com>

* feat(ci): scan released artifacts in release pipelines

Signed-off-by: Adrien Langou <alangou@nvidia.com>

* fix(ci): harden and simplify Trivy scans

Signed-off-by: Adrien Langou <alangou@nvidia.com>

* fix(ci): consolidate Trivy reports and prevent collisions

Signed-off-by: Adrien Langou <alangou@nvidia.com>

---------

Signed-off-by: Adrien Langou <alangou@nvidia.com>
2026-09-09 13:58:06 +00:00
Evie Howard 6e6b3c8905 refactor(cli): remove local Dockerfile image builds (#3214)
Signed-off-by: Evie Howard <evhoward@redhat.com>
2026-09-09 13:28:17 +00:00
John T. MyersandJohn Myers 2aa6a5f420 chore(gator): adopt authoritative provider profiles (#3108)
Signed-off-by: John Myers <johntmyers@users.noreply.github.com>
Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
2026-09-02 00:48:01 +00:00
John T. MyersandJohn Myers 07df822090 feat(providers): make profiles authoritative (#2962)
* feat(providers): make profiles authoritative

Closes #1988

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* docs(providers): move profiles into provider navigation

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* docs(providers): clarify provider attachment lifecycle

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* fix(tui): scroll provider profile picker

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* fix(providers): honor profile credential semantics

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* fix(providers): prefer exact profile IDs

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* fix(providers): harden authoritative profile adoption

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* test(oidc): align provider fixtures with profiles

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* fix(providers): preserve authoritative profile lifecycle

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

---------

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>
Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
2026-09-01 19:22:07 +00:00
Simon Scatton 981606d2f8 ci: build release binaries with Nix (#2977)
* ci: build release binaries with Nix

Refs #1683

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: build VM artifacts with Nix

Refs #1683

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: build images from Nix artifacts

Refs #1683

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* fix(nix): prevent host header leakage

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: parallelize artifact builds

Refs #1683

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: build external driver test artifacts

Refs #1683

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* fix(nix): disable mold in musl shells

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: key Rust cache by Nix shell derivation

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: refactor end-to-end workflows

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: split platform binary workflows

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: remove obsolete native build workflows

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: replace disallowed mise action

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: fix refactored e2e lanes

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: check out local result action

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: cache mise installations

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: run docker builds on host runners

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* ci: disable unstable kubernetes e2e lanes

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* fix(ci): scope binary builds to cargo packages

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* fix(ci): address zizmor template injection findings

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

* fix(ci): resolve remaining zizmor annotations

Signed-off-by: Simon Scatton <sscatton@nvidia.com>

---------

Signed-off-by: Simon Scatton <sscatton@nvidia.com>
2026-08-27 17:25:06 +00:00
John T. MyersandJohn Myers 4d16a2a6f4 feat(gator): improve review output and launch compatibility (#2896)
* feat(gator): render human-readable review findings

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* feat(gator): collapse operational review metadata

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* fix(gator): support canonical sandbox startup

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* fix(gator): preserve credential placeholder identity

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* feat(gator): resolve addressed review threads

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* fix(agents): preserve provider profile revisions

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

---------

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>
Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
2026-08-25 19:59:04 +00:00
Max DubrinskyandDrew Newberry 35fb27ef14 feat(sdk): add TypeScript SDK (@nvidia/openshell-sdk) (#2122)
* feat(sdk): add TypeScript SDK (@nvidia/openshell-sdk)

First native, per-language SDK for the OpenShell gateway: a thin, idiomatic
TypeScript client over proto-generated gRPC stubs (connect-es), no FFI. Covers
the v0.1 surface — sandbox lifecycle (create/get/list/delete + waitReady/
waitDeleted), health, and streamed exec.

- sdk/typescript/: package, client/transport/errors, protoc + protoc-gen-es
  codegen (gen/ gitignored, absorbed into dist/ at build), committed lockfile.
- tasks/typescript.toml: sdk:ts install/proto/typecheck/build/ci/publish;
  sdk:ts:typecheck wired into `check`; sdk-typescript job in branch-checks
  (typecheck, build, and a --dry-run publish that validates the release path).
- Enforce SPDX headers on .ts/.tsx/.mts/.cts (skip node_modules and gen/);
  back-fill docs/_components/jsx.d.ts and fern/components/CustomFooter.tsx.
- release.py gains an npm version format; release-tag.yml publishes to
  GitHub Packages on tag, stamping the version (0.0.0 placeholder in git);
  prerelease builds publish under the `next` dist-tag, not `latest`.

Ships as @nvidia/openshell-sdk on GitHub Packages pre-GA; public npm
(@openshell/sdk) follows at GA with an unchanged public API.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* chore(sdk): adopt TypeScript 6, tidy @types/node range

- typescript ^5.7.2 -> ^6.0.3 (6.0 is now `latest`; the old caret capped at 5.x)
- @types/node ^24.0.0 -> ^24 (same range, tidier)

No source changes; codegen, typecheck, and build pass on 6.0.3. Verified the
emitted d.ts still type-check for downstream consumers on TypeScript 5.0.4
through 5.9.3, so this does not raise the SDK's consumer TS floor.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* refactor(sdk): group operations under a composable SandboxClient

Reshape the client from flat methods (createSandbox, listSandboxes, exec) to a
scoped SandboxClient reached as `client.sandbox.create/get/list/delete/exec`
(+ waitReady/waitDeleted), mirroring the CLI's noun-verb model and the Python
SDK's SandboxClient.

SandboxClient is also usable standalone via SandboxClient.connect();
OpenShellClient composes it over a single shared transport, so future
service/provider clients reuse one connection. health() stays top-level as a
gateway call. No behavior change; types are unchanged.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* chore(sdk): generate TypeScript SDK stubs with buf

Replace the protoc gen.sh with `buf generate` + buf.gen.yaml. `buf`
(@bufbuild/buf) is a package devDependency and self-compiles the protos, so
the TS SDK no longer depends on the mise-pinned protoc; it drives the same
connect-es plugin. Generation stays limited to the client-surface closure
(openshell/sandbox/datamodel) via the input paths.

Output is byte-identical to the previous protoc + protoc-gen-es pipeline. Lays
the groundwork for a shared buf.yaml (lint/breaking/LSP) as a follow-up.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* build(proto): add repo-level buf module with lint

Declare proto/ as a single buf v2 module in a root buf.yaml so buf
generate, lint, breaking, and the editor LSP resolve imports the same
way. Lint uses STANDARD with six documented exceptions for deviations
the current protos intentionally make: the flat proto/ layout with
nested packages (DIRECTORY_SAME_PACKAGE, PACKAGE_DIRECTORY_MATCH) and
the established API shape with unsuffixed services and reused
request/response messages (RPC_REQUEST_RESPONSE_UNIQUE,
RPC_REQUEST_STANDARD_NAME, RPC_RESPONSE_STANDARD_NAME, SERVICE_SUFFIX).
Every other STANDARD rule now enforces on future protos. Breaking uses
FILE.

Code generation stays package-scoped in sdk/typescript/buf.gen.yaml
since it binds to that package's connect-es plugin and output dir;
its inputs are unchanged and regeneration is byte-identical.

Wire the check in via a proto:lint mise task that runs buf from the
SDK devDependencies. It is a dependency of both sdk:ts:ci (so the
TypeScript SDK CI job enforces it) and the top-level lint aggregate
(so local pre-commit covers it).

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* chore(sdk): publish as unscoped openshell-sdk on public npm

Rename the package from @nvidia/openshell-sdk to the unscoped
openshell-sdk and target public npm (registry.npmjs.org) instead of
GitHub Packages. GitHub Packages requires a scope matching the owning
org, and the @openshell scope is blocked by an unrelated existing
package, so an unscoped name on public npm is the lowest-friction
distribution path and needs no org approval.

Rework the release-tag publish job to auth against registry.npmjs.org
with NPM_TOKEN (the job now only needs packages: read to pull the CI
image). Update the README install instructions and usage imports.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* chore(sdk): publish @nvidia/openshell-sdk to GitHub Packages

Revert the unscoped-name switch. GitHub Packages only accepts scoped
names matching the owning org, so shipping there first (which needs no
external npm org or NPM_TOKEN, just the repo's GITHUB_TOKEN) requires
the @nvidia scope. Keeping the @nvidia/openshell-sdk name also lets a
later public-npm release use the same install specifier, so adding
public npm becomes a second publish step rather than a rename.

Restore the GitHub Packages publish auth in the release-tag job and the
scoped install instructions in the README (keeping the buf codegen
note).

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* feat(sdk-ts): add streaming exec, forward, ssh, provider, and config methods

Grow SandboxClient to the surface the first two consumers need. execStream
yields stdout/stderr chunks as they arrive and exec now drains it, keeping its
buffered ExecResult and signature unchanged. execInteractive is the TTY + stdin
transport primitive (start-first framing, output/write/resize/close/done, no
terminal glue). forward binds a local TCP listener that tunnels each accepted
connection into the sandbox for the process lifetime, minting and revoking a
per-socket SSH session token around a forwardTcp bidi. Adds createSshSession /
revokeSshSession, attach/detach/listProviders, and getConfig / setPolicy /
setSetting (sandbox-scoped, network-policy-only, with an optional wait poll).

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* build(sdk-ts): add Biome and Vitest tooling

The TypeScript SDK had no formatter or linter and no test runner. Add Biome
(format + lint, generated src/gen excluded) enforcing 2-space indent, single
quotes, semicolons, and a 120-column width, and reformat the existing
hand-written sources accordingly. Add Vitest for unit tests. Wire sdk:ts:format,
sdk:ts:lint, and sdk:ts:test mise tasks into the fmt/lint aggregates, the root
test suite, and sdk:ts:ci so they run in CI.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* test(sdk-ts): cover the sandbox surface with in-memory transport tests

Exercise SandboxClient against an in-memory OpenShell service built with
createRouterTransport: request assembly and id resolution, u64/int64 rendered as
strings, enum lowercasing, fromConnect code mapping, the exec/execStream drain
plus a backward-compat check on exec, execInteractive start-first ordering and
done resolution, and a forward() byte relay against a loopback echo with close()
teardown.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* docs(sdk-ts): document the new surface and connect/upload/download boundaries

Document execStream, execInteractive, forward, ssh sessions, providers, and
config/policy in the SDK README, and record the intentional boundaries:
interactive connect / PTY ownership, upload/download (no file-transfer RPC), and
detached forwards stay out of scope. Note the Biome/Vitest dev commands.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* feat(sdk-ts): support mTLS client authentication

Add clientCert and clientKey to ConnectOptions so the SDK can
authenticate to the default local gateway, which uses mTLS user
authentication. Without a client certificate and key the SDK could
verify the server but never authenticate the caller, so it could not
connect to the standard Docker, VM, Homebrew, or Linux-package gateway.

Validate the pair as both-or-neither and pass cert and key through to
the Node TLS options for https gateways. The h2c path is unchanged.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* chore(sdk-ts): drop the demo script and its tsx dependency

Remove src/demo.ts, the demo npm script, the tsx devDependency, and the
tsconfig build exclude for the demo. The demo was never part of the
published package, and dropping it also removes the only place that
logged part of an SSH session token.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* fix(sdk-ts)!: harden exec streaming, waits, SSH, and forwarding

Address review feedback on the sandbox surface.

- Make the streamed command exit code observable from idiomatic
  for-await: the terminal exit is now an in-band ExecStreamEvent
  ({ type: 'exit', exitCode }) rather than the async generator return
  value, which for-await discards. A stream that ends without an exit
  event now throws instead of reporting success.
- Bound waitReady, waitDeleted, and the setPolicy wait by their timeout:
  each poll RPC carries a per-iteration deadline and the waits accept an
  AbortSignal, so a stalled call can no longer leave a wait pending
  forever. Add waitTimeoutSecs to SetPolicyOptions.
- Validate the CreateSshSession response against the proto charset and
  range contract before returning it or using its token, since the
  values feed an OpenSSH ProxyCommand.
- Respect socket backpressure when relaying forwarded responses: pause
  reading the gRPC stream when the local socket buffer is full and
  resume on drain so memory stays bounded.
- Expose create-time sandbox policy: add policy and an advanced rawSpec
  passthrough to SandboxSpec so the safety boundary is expressible at
  creation and new spec fields do not require an SDK change.

BREAKING CHANGE: execStream and the interactive exec output now yield a
terminal { type: 'exit', exitCode } event; consumers iterating the
stream must handle that arm. The exit code is no longer the async
generator return value.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* feat(sdk-ts): export error contract, enum unions, and caller cancellation

Address Tier-1 review feedback on the TypeScript SDK public surface (PR #2122).

- Errors: export SdkError and SdkErrorCode so callers can use instanceof and
  exhaustively switch on .code. fromConnect preserves the originating
  ConnectError as .cause and its status as .connectCode, maps Aborted to a new
  'aborted' code for optimistic-concurrency conflicts, and maps Canceled and
  DeadlineExceeded to 'canceled'. errorCode() behavior is unchanged.
- Enums: replace the string-typed phase, status, scope, and policySource fields
  with lowercase literal unions (SandboxPhaseName, HealthStatus,
  SettingScopeName, PolicySourceName) backed by exhaustive Record maps. The
  unions are a hand-maintained mirror of the generated proto enums; a new drift
  test pins each literal to its generated member name.
- Cancellation: accept an optional AbortSignal on exec, execInteractive, and
  forward, threaded into both sandbox resolution and the streaming RPC. forward
  tears down its local listener on abort.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* feat(sdk-ts): add raw escape hatch for uncurated gateway RPCs

The curated sub-clients reduce proto messages to ergonomic subsets (for
example get() drops created_at_ms, the full spec, conditions, runtime
endpoints, and current_policy_version), and not every gateway RPC has a
typed helper yet. Rather than ship methods that exist but throw, expose a
generated client for the full surface.

OpenShellClient.raw and SandboxClient.raw are generated clients covering
every gateway RPC, returning the verbatim wire messages so proto
distinctions the curated types smooth over are preserved. .transport
exposes the shared connection for building extra clients over one socket.
Generated request/response types are published at the new
@nvidia/openshell-sdk/raw subpath. Curated methods stay the default;
raw is the always-available floor.

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* fix(sdk-ts): address review feedback on exec, forward, and auth transport

Settle exec's `done` promise before yielding the exit event so a consumer
that breaks on exit no longer leaves it pending forever, and give it a lone
rejection handler plus a finally-settle so a stream error or early abandon
can never surface as an unhandled rejection or a hang.

Attach an 'error' listener to each accepted forward socket synchronously,
before forwardConnection awaits CreateSshSession; a peer reset in that
window previously emitted an unhandled 'error' and crashed the process.

Reject ambiguous or unsafe transport configs at buildTransport: oidcToken
and edgeToken together (silently OIDC-only), and any auth token sent over
plaintext http:// to a non-loopback host unless allowInsecureAuth is set.

Wrap versionPin so a non-u64 expectedResourceVersion raises
SdkError('invalid_config') instead of a raw BigInt SyntaxError, and raise
the Node engine floor to >=20.3 for AbortSignal.any().

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>

* fix(sdk-ts): address review feedback

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* docs(sdk-ts): defer published sdk guide

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

---------

Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
Co-authored-by: Drew Newberry <anewberry@nvidia.com>
2026-08-13 20:50:38 +00:00
John T. MyersandJohn Myers d22859c22d fix(gator): separate review budget from approval gate (#2704)
Signed-off-by: John Myers <johntmyers@users.noreply.github.com>
Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
2026-08-12 16:07:41 +00:00
2f96c53b8c feat(gateway,cli): windows compilation support (#2496)
* chore(windows): gate Unix-only workspace code for MSVC

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* feat(windows): stub unsupported compute drivers

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* ci(windows): add MSVC mise build lane

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* docs(windows): document MSVC build-only design

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* docs(agent): add Windows MSVC build skill

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* feat(windows): add Windows build support

Signed-off-by: Akber Raza <akberr@nvidia.com>

* refactor(windows): consolidate Windows-specific dependencies and improve build logic

Signed-off-by: Akber Raza <akberr@nvidia.com>

* feat(windows): add libclang path resolution and update cargo commands with bundled Z3 features

Signed-off-by: Akber Raza <akberr@nvidia.com>

* chore(tooling): lock Windows tool artifacts

Signed-off-by: Giedrius Burachas <gburachas@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* feat(windows): enhance libclang path resolution to support architecture-specific subdirectories

Signed-off-by: Akber Raza <akberr@nvidia.com>

* Fix Windows dependency gating after sync merge

Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(z3): update Z3 header path requirements in Windows build documentation and scripts

Signed-off-by: Akber Raza <akberr@nvidia.com>

* docs(windows): relocate Windows MSVC build design to architecture/

Why: windows-msvc-build-design.mdx is a design document ("design decisions for
the native Windows MSVC build lane"), but it lived in the published, user-facing
docs/reference/ tree. Per AGENTS.md (Documentation) and architecture/README.md
("rfc/ vs architecture/"), design content belongs in architecture/ (or rfc/),
not in published reference. It also shared Fern sidebar "position: 6" with the
MXC compute-driver design page, colliding in the Reference nav ordering.

What:
- Move docs/reference/windows-msvc-build-design.mdx ->
  architecture/windows-msvc-build.md.
- Strip the Fern publish frontmatter and add a plain H1, matching the other
  architecture docs.
- Register it in the architecture doc index in architecture/README.md.
- Repoint the inbound references (build-openshell-mxc-windows skill + reference,
  implement-openshell-mxc-driver skill) to the new path.

With both design pages moved out of docs/reference/, the duplicate position-6
sidebar collision is resolved.

Signed-off-by: Akber Raza <akberr@nvidia.com>

* remove openshell-supervisor-network from unsupported driver package test exclusion list

Signed-off-by: Akber Raza <akberr@nvidia.com>

# Conflicts:
#	tasks/scripts/windows-msvc.ps1

* fix(interceptors): gate unix-only imports so the crate builds on Windows

openshell-gateway-interceptors failed to compile on Windows (E0432: no UnixStream in tokio::net), breaking any Windows build of openshell-server (which depends on it unconditionally). The connect_unix_endpoint fn was already #[cfg(unix)]-gated, but the imports it uses (UnixStream, TokioIo, Uri, service_fn) were left ungated. Gate those four imports with #[cfg(unix)] too. No behavior change on unix; Windows now compiles (no errors, no unused-import warnings).

Signed-off-by: Akber Raza <akberr@nvidia.com>

* feat(windows): add native ARM64 test support

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(mise): skip Skaffold on Windows

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(windows): harden ARM64 toolchain discovery

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(windows): scope ARM64 toolchain preflight

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(windows): restore compatibility after GitHub sync

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(windows): avoid rate-limited Z3 source lookup

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(mise): skip Helm checks on Windows

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(windows): support repository pre-commit checks

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(windows): stabilize native MSVC validation

Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(windows): harden shared Z3 source cache

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>

* fix(windows): avoid leaking MSVC flags into clang-cl

Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(windows): complete ARM64 migration audit

Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(windows): restore ARM64 Ninja discovery

Signed-off-by: Akber Raza <akberr@nvidia.com>

* refactor(windows): separate platform crate roots

Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(windows): restore proto include cfg gating

Signed-off-by: Akber Raza <akberr@nvidia.com>

* refactor: address lint errors

* fix(windows): add preflight check for proxy auth file path

* docs(windows): update GitHub checkout guidance

Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(windows): restore CI after dependency updates

Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(mise): repair Windows sccache lock entry

Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(windows): reconcile validation after rebase

Signed-off-by: Akber Raza <akberr@nvidia.com>

* refactor(server): exclude unsupported drivers on Windows

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>

* refactor(server): isolate platform driver config

Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>

* fix(windows): repair unsupported driver contract test

Signed-off-by: Akber Raza <akberr@nvidia.com>

* fix(sandbox): remove stale dependencies

Signed-off-by: Akber Raza <akberr@nvidia.com>

* ci(windows): pin x64 workflow actions

Signed-off-by: Akber Raza <akberr@nvidia.com>

* ci(windows): align x64 Rust toolchain

Signed-off-by: Akber Raza <akberr@nvidia.com>

* ci(windows): align ARM64 workflow setup

Signed-off-by: Akber Raza <akberr@nvidia.com>

* refactor(windows): exclude unsupported runtime crates

Signed-off-by: Akber Raza <akberr@nvidia.com>

* refactor(windows): exclude unsupported crates at workspace boundary

Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>

* refactor(server): gate builtin driver config by platform

Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>

* fix(sandbox): restore crate documentation

Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>

* ci(windows): make build workflow manual

Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>

* ci(windows): temporarily enable pull request builds

Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>

* ci(windows): cache Rust dependencies

Signed-off-by: Akber Raza <akberr@nvidia.com>

* refactor(windows): remove unnecessary platform changes

Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>

* ci(windows): make build workflow manual

Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>

* fix(ci): synchronize mise lockfile

Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>

* fix(ci): normalize mise provenance metadata

Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>

* refactor(python): isolate Windows atomic replace retry

Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>

* fix(python): type Windows permission test errors

Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>

---------

Signed-off-by: Shailendra Singh <shailendras@nvidia.com>
Signed-off-by: Akber Raza <akberr@nvidia.com>
Signed-off-by: Giedrius Burachas <gburachas@nvidia.com>
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
Signed-off-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>
Co-authored-by: Shailendra Singh <shailendras@nvidia.com>
Co-authored-by: Giedrius Burachas <gburachas@nvidia.com>
Co-authored-by: Jamie King <jamiek@nvidia.com>
Co-authored-by: Piotr Mlocek <pmlocek@nvidia.com>
Co-authored-by: Piotr Mlocek <1116309+pimlock@users.noreply.github.com>
2026-08-11 21:00:36 +00:00
John T. MyersandJohn Myers 3ebed4e796 fix(gator): allow same-sha state nudges (#2681)
* fix(gator): allow same-sha state nudges

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* chore(gator): default to medium reasoning

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* chore(gator): default to gpt-5.6-sol

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* docs(gator): document same-sha nudge exception

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

---------

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>
Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
2026-08-10 16:42:37 +00:00
alangou 0c7e59a953 fix(deps): bump russh, jsonwebtoken, tar and npm lint deps (#2617)
Signed-off-by: Adrien Langou <alangou@nvidia.com>
2026-08-06 09:39:43 +00:00
alangou 5541398ccb fix(deps): update russh dompurify and base image of the gateway (#2575)
Signed-off-by: Adrien Langou <alangou@nvidia.com>
2026-07-31 12:54:03 +00:00
Drew Newberry 7f53f78bdb fix(gator): preserve resolved review feedback (#2533)
* fix(gator): preserve resolved review feedback

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(gator): make follow-up reviews pragmatic

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(gator): enforce review convergence

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

---------

Signed-off-by: Drew Newberry <anewberry@nvidia.com>
2026-07-30 02:27:07 +00:00
Derek Carr 9c019a93f5 Wire authorization into workspace model (#2445)
* feat(auth): implement RFC 0011 Phase 2 workspace authorization

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(auth): address PR review feedback on workspace authorization

- Docker e2e: add --health-port and switch readiness probe from
  `openshell status` to `curl /healthz`, fixing a false-positive
  readiness check in OIDC mode where the CLI exited 0 without
  actually contacting the gateway

- ListWorkspaces: move membership filtering from post-query N+1
  lookups into a SQL EXISTS subquery so pagination applies to the
  visible set, not the global ordering. Add generic
  list_with_membership to the persistence layer.

- Descriptor validator: reject role/scope fields on unauthenticated
  and sandbox auth modes, and allow-list workspace_role as
  user/admin and global_role as platform_admin to catch typos at
  startup

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(server): use authed request in delete telemetry test

The workspace authorization added by the Phase 2 auth changes requires
a Principal on every delete request. The delete-telemetry test was still
using a bare Request::new, so extract_principal failed before the handler
could acquire the delete gate, causing a 5-second timeout flake.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(auth): address gator review findings for workspace authorization

- Inject unauthenticated-local-dev principal in no-auth gateway mode so
  handlers that call extract_principal() always find one.
- Cap label-selector membership query at MAX_PAGE_SIZE instead of
  u32::MAX to bound the in-memory read.
- Authorize workspace membership before resolving workspace existence in
  all sandbox RPCs to prevent workspace-name enumeration by non-members.
- Remove dead_code allow on AuthorizedWorkspace.workspace now that
  callers use the normalized name from the authz result.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(auth): close workspace-name oracle and label-selector truncation

Swap authorize-before-resolve ordering in 27 handlers across
provider.rs, service.rs, policy.rs, and workspace.rs to prevent
CWE-203 workspace-name enumeration by non-members.

Add combined membership+label SQL query (list_with_membership_and_selector)
to both persistence backends so ListWorkspaces with label selectors no
longer silently drops results beyond the first page of membership matches.

Signed-off-by: Derek Carr <decarr@redhat.com>

* test(auth): add non-member rejection and membership+label persistence tests

Add comprehensive test coverage for workspace authorization changes:
- Non-member rejection tests across all 44 workspace-scoped handlers
  (sandbox, provider, service, policy, workspace, inference) verifying
  PERMISSION_DENIED is returned instead of NOT_FOUND to prevent
  CWE-203 workspace-name oracle
- Persistence test for list_with_membership_and_selector verifying
  SQL-level membership EXISTS + label filtering, multiple predicates,
  no-match cases, and pagination

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(auth): format merged import line in sandbox tests

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(auth): address gator re-review findings on workspace authorization

- Fix TUI unconditionally setting providers_v2_enabled after provider
  refresh; read the actual gateway setting via GetGatewayConfig at
  startup instead
- Fix SQLite json_extract with dotted label keys (e.g. example.com/env)
  by quoting the key in the JSON path
- Add authed_request wrappers to upstream OCI identity tests that were
  missing a principal after rebase
- Add test proving GetGatewayConfig is accessible without Platform Admin
- Add test for dotted/prefixed Kubernetes-style label key filtering

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(auth): address second gator re-review findings

- Loosen GetGatewayConfig from platform_admin to scope-only so workspace
  users can discover providers_v2_enabled during sandbox creation with
  inferred-provider commands; update proto descriptor, descriptor
  validation, and RFC 0011 access table
- Add validate_label_selector to handle_list_workspaces and escape
  single quotes in SQLite json_extract interpolation (CWE-89
  defense-in-depth)
- Re-fetch providers_v2_enabled after TUI gateway switch so the new
  gateway's capability is reflected
- Add e2e test for workspace user with inferred-provider command
- Add persistence test for adversarial label keys with SQL injection
  attempts
- Add handler test for invalid label selector rejection in
  ListWorkspaces

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(auth): address third gator review findings

- Cap label selector pairs at 64 (CWE-400) to bound SQLite dynamic SQL
- Add SCOPE_ONLY_METHODS allowlist for scope-without-role RPCs (CWE-863)
- Normalize ID-based data-plane handlers to return NOT_FOUND for
  unauthorized sandboxes, closing the cross-workspace oracle (CWE-203)
- Fix TUI provider profile cache lookup key mismatch for legacy
  providers with empty profile_workspace
- Add whoami to CLI skill reference command tree
- Update TUI skill doc with workspace, provider, and settings coverage
- Document scope/workspace orthogonality on GetGatewayConfig proto

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(auth): extend CWE-203 normalization to policy.rs sandbox handlers

GetSandboxConfig and GetSandboxLogs in policy.rs had the same
fetch-before-authorize pattern that leaked cross-workspace sandbox
existence. Promote fetch_and_authorize_sandbox to pub(super) and
use it from both sandbox.rs and policy.rs handlers.

Signed-off-by: Derek Carr <decarr@redhat.com>

* test(auth): update assertions for CWE-203 sandbox ID normalization

Cross-workspace sandbox access via ID-based handlers now returns
NOT_FOUND instead of PERMISSION_DENIED to prevent existence inference.
Update the unit test and OIDC e2e assertion to match.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(auth): narrow CWE-203 error mapping and correct whoami output formats

Only remap PERMISSION_DENIED to NOT_FOUND in fetch_and_authorize_sandbox
and RevokeSshSession, letting INTERNAL and UNAUTHENTICATED propagate
as-is. Fix whoami --output format values in cli-reference.md to match
the actual CLI (table/json/yaml, not text/json).

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(ci): share network namespace with Keycloak in containerized CI

In GitHub Actions job containers, Docker port publishing lands on the
host, not inside the job container. Detect this environment and attach
Keycloak to the job container's network namespace instead, with
hardened defaults (cap-drop ALL, no-new-privileges, loopback-only
listener).

Signed-off-by: Derek Carr <decarr@redhat.com>

---------

Signed-off-by: Derek Carr <decarr@redhat.com>
2026-07-30 00:31:32 +00:00
Evan Lezar 7b444bd88d fix(agents): make baked payload readable (#2419)
Signed-off-by: Evan Lezar <elezar@nvidia.com>
2026-07-22 18:59:10 +00:00
Jesse Jaggars bdd1ce87ed fix(cli): respect CARGO_TARGET_DIR in openshell wrapper script (#2391)
The scripts/bin/openshell wrapper hardcoded the binary path to
$PROJECT_ROOT/target/debug/openshell. When CARGO_TARGET_DIR is set
(e.g. via .bashrc or mise), cargo places the binary elsewhere and the
wrapper fails with 'No such file or directory'.

Use ${CARGO_TARGET_DIR:-$PROJECT_ROOT/target} so the wrapper finds
the binary regardless of where the build artifacts live.

Signed-off-by: Jesse Jaggars <jjaggars@jjaggars-kubevirt.rht.csb>
Signed-off-by: Jesse Jaggars <jjaggars@redhat.com>
2026-07-21 17:03:45 +00:00
Derek Carr 5952a5a23f feat(workspace): add workspace resource model with scoping, membershi… (#2243)
* feat(workspace): implement workspace model (Phase 1 of RFC 0011)

Implements workspace and membership model providing hard isolation
boundaries for multi-player OpenShell deployments.

Workspace CRUD with Kubernetes-style Terminating phase for graceful
deletion. All resources scoped by workspace via ObjectMeta. Membership
RPCs for workspace access control. Persistence migration shifts name
uniqueness to (object_type, workspace, name). Provider profiles support
platform and workspace scoping. Service routing uses workspace-prefixed
DNS labels. Inference routes renamed and workspace-scoped with
DeleteInferenceRoute RPC. Python SDK with WorkspaceClient, two-method
list pattern (workspace-scoped and for_all_workspaces), and workspace
parameter on all methods. CLI workspace flags, TUI workspace cycling.
K8s driver filters unmanaged CRs and uses delete preconditions. Podman
driver uses immutable container IDs. Label serialization fixed across
all put_if call sites.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(cli): delegate sandbox upload command to existing upload function

The standalone `sandbox upload` command reimplemented upload logic
inline with two bugs: it used `Path::exists()` which follows symlinks
(rejecting dangling symlinks), and it ran git-aware filtering on
symlink sources. The `run::sandbox_upload()` function already handles
both cases correctly via `sandbox_upload_plan()`. Replace the inline
logic with a call to the existing function.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(e2e): shorten sandbox names and fix test compatibility

Shorten the sandbox name in initial_sparse_policy_is_acknowledged_as_loaded
from 'e2e-2159-sparse-enrich' (22 chars) to 'e2e-sparse-enrich' (17 chars)
to comply with MAX_ROUTABLE_NAME_LEN (19 chars).

Also capture stderr in create_keep_with_args so future sandbox creation
failures include the actual CLI error instead of reporting empty output.

Signed-off-by: Derek Carr <decarr@redhat.com>

* test(workspace): add test coverage for workspace CRUD and persistence isolation

Add unit tests for workspace create happy path, get round-trip, get
not-found, get empty-name rejection, already-exists error, and
resolve_workspace not-found. Add persistence test proving cross-workspace
name uniqueness (same name in different workspaces produces separate
records). Add workspace name max-length boundary tests. Fix e2e harness
to include stderr in name-parse-failure error path. Align Python e2e
test_workspace_crud with try/finally pattern. Document provider profile
catalog workspace scoping gap in RFC 0011.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(examples): update examples for workspace model compatibility

Shorten sandbox names in demo scripts to fit the 19-character
MAX_ROUTABLE_NAME_LEN limit: policy-demo prefix to pd-, multi-agent
notepad derives a short SANDBOX_TAG from the run ID, governance
interceptor uses gs-PID-RANDOM. Update vscode-remote-sandbox.md SSH
host aliases from openshell-{name} to openshell-{name}.{workspace}
format.

Signed-off-by: Derek Carr <decarr@redhat.com>

* feat(sdk): add workspace-scoped client and workspace CRUD

Add WorkspaceScopedClient modeled after kube::Api::namespaced — captures
workspace once and injects it into every sandbox request. Add workspace
CRUD methods (create, get, list, delete) and list_sandboxes_all_workspaces
on OpenShellClient. Extend SandboxRef with workspace field and add
WorkspaceRef type. Include mock tests for all new operations.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(lint): resolve clippy warnings in workspace test assertions

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(docs): convert indented code blocks to fenced in RFC 0011

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(lint): resolve clippy warnings and apply cargo fmt across workspace

Auto-format with cargo fmt and fix clippy warnings exposed by the
reformat: unnecessary qualifications, map_unwrap_or, identical match
arms, unused variable prefix, dead code annotations, and let-unit-value
in e2e harness.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(workspace): address workspace scoping issues from review

- Add workspace field to settings JSON output (CLI)
- Skip Podman containers missing workspace label instead of defaulting
  to empty string, matching K8s driver behavior
- Add resource_version to list_by_scope SELECT in both SQLite and
  Postgres backends, with regression test
- Gate PolicyLocalContext proposal/lookup routes on workspace readiness,
  returning 503 when workspace is not yet discovered
- Block sandbox and provider creation in TUI all-workspaces mode
- Clear workspace vectors in TUI reset_sandbox_state

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(workspace): make provider profile catalog workspace-aware

Thread workspace through snapshot_catalog so the
EffectiveProviderProfileCatalog enforces workspace boundaries on both
read and write paths. UserProviderProfileSource now loads platform-scoped
profiles (workspace "") plus the target workspace's profiles, preventing
cross-workspace duplicate profile ID collisions that previously caused
global catalog failures.

Update RFC 0011 to reflect catalog scoping is implemented in Phase 1
rather than deferred to future work.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(persistence): include workspace column in atomic policy revision INSERT

put_policy_revision_atomic omitted the workspace column from the INSERT
into the objects table in both SQLite and Postgres backends, causing
atomically-written policy revisions to lose their workspace association.
Add workspace field to AtomicPolicyRevisionWrite and thread it through
both backend INSERT statements, matching the non-atomic put_policy_revision
path which already included it.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(proxy): skip ancestor walk when socket owner is the entrypoint

collect_ancestor_identities walked the entire process tree above the
entrypoint when the connecting process was the entrypoint itself,
SHA256-hashing every ancestor binary (IDE, shell, container runtime).
On dev machines with large binaries in the ancestor chain this exceeded
the 30-second test timeout. When start_pid == stop_pid there are no
intermediate ancestors to verify, so return an empty list immediately.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(workspace): make provider profile catalog scope-aware

Allow the same profile ID at platform and workspace scopes by
introducing layered catalog entries where workspace profiles shadow
platform profiles. Add source and scope fields to the ProviderProfile
proto and CLI output. Migrate List/Get handlers to the catalog,
fixing divergence with runtime profile resolution.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(e2e): align podman e2e labels with centralized driver constants

The podman driver moved its container labels to the centralized
openshell.ai/ prefix, but the e2e test harness and cleanup script
still referenced the old openshell.sandbox-* keys, causing the
local_driver_token_restart test to fail on container lookup.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(e2e): align python profile isolation test with scope-aware catalog

Platform profiles are now visible in workspace listings as fallbacks
per the layered catalog design. Update the assertion to match.

Signed-off-by: Derek Carr <decarr@redhat.com>

* fix(workspace): honor profile_workspace in runtime profile resolution

Runtime profile lookups now consult provider.profile_workspace via
get_type_profile_for_scope. Providers created with --global-profile
(profile_workspace="") resolve to the platform profile even when a
workspace profile shadows the same ID. All 6 runtime call sites
updated; type-only call sites remain scope-agnostic.

Signed-off-by: Derek Carr <decarr@redhat.com>

---------

Signed-off-by: Derek Carr <decarr@redhat.com>
2026-07-21 00:59:18 +00:00
John T. MyersandJohn Myers 06062027e6 docs(gator): require inline review comments (#2346)
Signed-off-by: John Myers <johntmyers@users.noreply.github.com>
Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
2026-07-17 10:26:19 -07:00
Simon Scatton 008193a2e7 fix: remove mentions of bundled-z3 in CI and wheel builds (#2322) 2026-07-16 16:58:53 +00:00
John T. MyersandJohn Myers 9ad53b3f36 fix(gator): retry review after draft blocker clears (#2200)
Signed-off-by: John Myers <johntmyers@users.noreply.github.com>
Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
2026-07-13 09:04:16 -07:00
Ignas Baranauskas a72711697d chore: remove deprecated --keep flag from docs, scripts, and e2e tests (#2126)
* docs: remove deprecated --keep flag from tutorials and examples

The --keep flag is deprecated, hidden, and a no-op since sandboxes
are kept by default. Remove references from tutorial docs and example
READMEs that explain it as a real feature.

- Remove --keep from sandbox create commands
- Remove --keep explanation text
- Clarify that sandboxes are kept by default

Signed-off-by: Ignas Baranauskas <ibaranau@redhat.com>

* chore: remove deprecated --keep usage from scripts and e2e tests

The --keep flag is a deprecated no-op since sandboxes are kept by
default. Stop passing it in internal scripts, e2e test scripts,
and example demo scripts.

Signed-off-by: Ignas Baranauskas <ibaranau@redhat.com>

---------

Signed-off-by: Ignas Baranauskas <ibaranau@redhat.com>
2026-07-07 14:36:25 +02:00
45060f4492 feat(agents): add manifest-driven gator agent (#1826)
* chore(gator): add gator gate skill

* chore(gator): add sandbox launcher scaffold

* chore(gator): add codex image and docs checks

* chore(gator): fold approved provider policy rules

* chore(gator): add deterministic reviewer runner

* chore(gator): clarify ok-to-test comments

* chore(gator): structure launcher harnesses

* chore(gator): require e2e for dependabot

* chore(gator): add codex refresh profile

* chore(gator): wip manifest agent launcher

* feat(agents): supervise watch cycles in sandbox

* fix(agents): preserve gateway refresh state

* fix(gator): continue human response threads

* fix(agents): keep watch supervisor retrying

* fix(agents): use refreshed Codex credential aliases

* fix(gator): avoid misleading gh auth checks

* docs(agents): remove architecture build update

* fix(gator): use REST-backed GitHub writes

* fix(agents): bake immutable agent payloads

* fix(agents): upload writable agent workspace

* fix(agents): surface gator watch progress

* fix(agents): prevent codex stdin hang

* fix(agents): align codex subagent input

* fix(agents): heartbeat during active cycles

* fix(agents): clean up heartbeat sleep

* fix(agents): disable gh telemetry in codex harness

* fix(agents): reconcile closed gator PRs

* fix(agents): query closed gator PR labels separately

* fix(agents): tolerate rotated credential placeholders

* fix(agents): enforce gator same-sha comment guard

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* docs(agents): scope gator trusted commentary

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* fix(gator): treat reviewer failures as transient

Signed-off-by: Evan Lezar <elezar@nvidia.com>

* feat(agents): refine gator supervised workflow

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* fix(agents): stream codex prompts via stdin

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* docs(agents): clarify trusted gator responses

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

* refactor(agents): scope gator PR to scripts

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>

---------

Signed-off-by: John Myers <johntmyers@users.noreply.github.com>
Signed-off-by: Evan Lezar <elezar@nvidia.com>
Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
Co-authored-by: Evan Lezar <elezar@nvidia.com>
2026-07-01 10:22:40 -07:00
Mesut Oezdil 863d2a2ea9 chore(helm): add missing SPDX header to gateway-config template (#1545)
* chore(helm): add missing SPDX header to gateway-config template

* chore(scripts): remove helm templates from license header exclusions

The bypass had no known rationale. Removing it ensures the header
script covers deploy/helm/openshell/templates uniformly going forward.

Signed-off-by: mesutoezdil <mesudozdil@gmail.com>

---------

Signed-off-by: mesutoezdil <mesudozdil@gmail.com>
2026-05-25 12:28:47 -07:00
Drew Newberry f5b546e41b Revert "perf(build): speed up local CLI rebuilds (#1387)" (#1395)
This reverts commit 668c712b63.
2026-05-14 17:45:37 -07:00
John T. Myers 668c712b63 perf(build): speed up local CLI rebuilds (#1387) 2026-05-14 11:44:36 -07:00
Drew Newberry 70a0f6c547 refactor(cli): remove gateway lifecycle management (#1221) 2026-05-07 09:54:13 -07:00
Derek Carr d45c1a704e fix(scripts): eliminate xargs subshell dependency in docker-cleanup.sh (#1207)
Replace xargs usage with native docker/podman multi-argument inspect calls.
The previous implementation failed because xargs spawns subshells that
don't inherit the ce() function from container-engine.sh.

Instead of piping container IDs through xargs, collect them into an array
and pass them directly to `ce inspect`, which accepts multiple IDs. This
eliminates the subshell issue entirely and simplifies the code.

Fixes the docker:cleanup mise task that was failing with:
  xargs: ce: No such file or directory

Signed-off-by: Derek Carr <decarr@redhat.com>
2026-05-06 18:15:53 -07:00
Drew Newberry 4d388d2677 ci(vm): cleanup vm build infra (#1186) 2026-05-06 08:58:02 -07:00
Taylor Mutch 5116cc27b7 feat(helm): add kubernetes local-dev environment (#1158) 2026-05-05 13:42:21 -07:00
Drew Newberry 2e0afeabe1 feat(vm): derive guest rootfs from sandbox images (#957) 2026-05-03 23:23:30 -07:00
Mrunal Patel 084505425b feat(auth): add OIDC/Keycloak authentication with RBAC and scope-based permissions (#935)
* feat(auth): add OIDC/Keycloak authentication with RBAC

Add OAuth2/OIDC authentication to the gateway server with role-based
access control, CLI login flows, and full deployment plumbing.

Server: JWT validation against configurable OIDC issuer (oidc.rs),
JWKS key caching with TTL and rotation handling, method classification
(unauthenticated/sandbox-secret/dual-auth/bearer), identity extraction
with provider-agnostic Identity type, and RBAC enforcement via
AuthzPolicy with configurable admin/user roles and auth-only mode.

CLI: browser-based Authorization Code + PKCE flow, Client Credentials
flow for CI/automation, token storage with refresh, gateway add/login/
logout commands, OIDC bearer token injection over mTLS transport,
discovery endpoint for auto-configuration.

Security: sandbox-secret scope restriction on UpdateConfig (policy
sync only), anti-spoofing header stripping, dual-auth fallthrough
from sandbox-secret to Bearer token.

Deployment: OIDC config wired through DeployOptions, Docker env vars,
Helm values/templates, HelmChart manifest, cluster-entrypoint.sh, and
bootstrap scripts. Keycloak dev server script with pre-configured
realm (test users, roles, PKCE client, CI client).

Tested with Keycloak. The roles claim path and role names are
configurable to support other OIDC providers.

* feat(auth): add OAuth2 scope-based fine-grained permissions

Add opt-in scope enforcement on top of existing OIDC role-based access
control. When --oidc-scopes-claim is set, the server extracts scopes
from the JWT and checks them per-method against an exhaustive scope map.

Scopes: sandbox:read, sandbox:write, provider:read, provider:write,
config:read, config:write, inference:read, inference:write, and
openshell:all (wildcard). Methods not in the scope map require
openshell:all. Scopes layer on top of roles and cannot escalate
privilege. Auth-only mode (empty role names) still enforces scopes
when enabled.

Server: scopes_claim in OidcConfig, scope extraction from JWT
(space-delimited and JSON array formats), standard OIDC scope
filtering, scope check in AuthzPolicy after role check.

CLI: --oidc-scopes on gateway add/start stored in metadata and
consumed by gateway login, --oidc-scopes-claim on gateway start
forwarded to server, scopes parameter in browser and client
credentials OAuth2 flows with openid deduplication.

Deployment: oidc_scopes_claim wired through DeployOptions, docker.rs,
Helm, bootstrap scripts, and cluster entrypoint.

Keycloak: realm config updated with built-in OIDC scopes and 9
OpenShell client scopes as optional on openshell-cli and openshell:all
as default on openshell-ci.

* fix(auth): address branch review findings

Add GetInferenceBundle to sandbox-secret methods so sandbox inference
route refresh works under OIDC. Make GetSandboxConfig dual-auth so CLI
users can read sandbox settings with Bearer tokens.

Preserve OIDC gateway metadata on restart — a bare gateway start
without --oidc-* flags no longer erases the stored OIDC registration.

Document CI client ID requirement (openshell-ci vs openshell-cli) in
the testing guide. Add security note about auth-only mode blast radius
for GitHub Actions.

* fix(auth): complete review findings for OIDC auth boundary

Move OpenShell/GetSandboxConfig from sandbox-secret-only to dual-auth
so CLI users can read sandbox settings with Bearer tokens while sandbox
supervisors continue using the shared secret.

Add sandbox secret interceptor to the inference bundle fetch path so
GetInferenceBundle works under OIDC-enabled gateways. Extract shared
interceptor constructor to avoid duplication.

Add GetSandboxConfig to the config:read scope map so scope enforcement
applies consistently when scopes are enabled.

Refactor OIDC metadata preservation into apply_oidc_gateway_metadata()
with explicit resume semantics — only preserve existing OIDC metadata
on real resume paths, not on fresh deployments.

Update architecture docs and testing guide to reflect the corrected
method classifications and add new test coverage for interceptor
injection, scope requirements, metadata preservation, and dual-auth
classification.

* refactor(auth): use oauth2 crate for CLI OIDC flows

Replace hand-written PKCE generation, authorization URL construction,
token exchange, client credentials, and token refresh with the oauth2
crate's typed API.

Eliminates sha2, hex, and getrandom dependencies from the CLI. The
custom urlencoded() helper and manual form POST logic are replaced by
BasicClient methods with proper type-state safety.

Discovery and the callback server remain custom since the oauth2 crate
does not provide OIDC discovery or a localhost redirect listener.

* refactor(auth): move server auth modules into auth/ directory

Group oidc.rs, authz.rs, identity.rs, and the auth HTTP endpoints
under src/auth/ module directory. No behavioral changes.

  auth/mod.rs      — module root, re-exports HTTP router
  auth/oidc.rs     — JWT validation, JWKS caching, method classification
  auth/authz.rs    — role and scope authorization policy
  auth/identity.rs — provider-agnostic Identity type
  auth/http.rs     — /auth/connect and /auth/oidc-config endpoints

* fix(auth): use RequestBody auth type for client credentials flow

The oauth2 crate defaults to BasicAuth (HTTP Basic header) but Keycloak
and most OIDC providers expect client_secret_post (credentials in the
request body). Set AuthType::RequestBody explicitly to match the
pre-refactor behavior.

Also re-export Identity, IdentityProvider, and JwksCache from the auth
module so ServerState's public API remains nameable by external consumers.

* fix(auth): forward OPENSHELL_OIDC_SCOPES through cluster bootstrap

Pass --oidc-scopes to gateway start so the metadata includes requested
scopes after cluster bootstrap. Without this, users had to manually
edit metadata.json to set scopes for gateway login.

Usage: OPENSHELL_OIDC_SCOPES="openshell:all" mise run cluster

* test(auth): add OIDC e2e tests for RBAC, scopes, and client credentials

Add 10 end-to-end tests covering OIDC authentication against a live
K3s cluster with Keycloak:

RBAC (5 tests): admin can create providers, user cannot, user can list
sandboxes, unauthenticated requests rejected, health probe works
without auth.

Scopes (4 tests): sandbox-scoped token can list sandboxes but not
providers, openshell:all grants full access, no-scopes token denied.

Client credentials (1 test): CI token via client_credentials grant.

Tests are opt-in via OPENSHELL_E2E_OIDC=1 and OPENSHELL_E2E_OIDC_SCOPES=1
env vars. They derive the Keycloak URL from gateway metadata to match
the server's configured issuer.

Run with:

  OPENSHELL_E2E_OIDC=1 OPENSHELL_E2E_OIDC_SCOPES=1 \
  PYTHONPATH=python uv run pytest e2e/python/oidc/ -v

* fix(docs): fix markdown lint errors in OIDC architecture docs

Add blank lines before lists and fenced code blocks to satisfy
markdownlint MD031 and MD032 rules.
2026-04-30 10:37:23 -07:00
Derek Carr f8fb382146 fix(scripts): handle docker cleanup when no containers are running (#977)
The docker-cleanup.sh script failed when no containers were running because
grep -v returned exit code 1 on empty input, causing the script to abort
due to set -euo pipefail.

Add || true to the volume detection pipeline so the script succeeds when
there are no running containers (in_use_volumes will be empty, which is
the correct behavior).

Signed-off-by: Derek Carr <decarr@redhat.com>
2026-04-26 23:02:40 -07:00
John T. Myers bb5bdb483e fix(ci): ignore local artifacts in license checks (#974)
Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>
2026-04-24 15:07:41 -07:00
Piotr Mlocek df38d1f66f feat(ci): add Markdown and Mermaid linting (#933) 2026-04-24 11:27:02 -07:00
Adam Miller d44d8a1e27 feat: Openshell driver podman (#904)
* feat(podman): add Podman compute driver for rootless sandbox management

Adds openshell-driver-podman, a new compute driver that manages OpenShell
sandboxes as rootless Podman containers via the Podman REST API over a
Unix socket. Enables local workstation sandboxes without Kubernetes.

Driver features:
- Bridge networking with ephemeral host-port mapping for rootless SSH reachability
- Named volumes for workspace storage, Podman native health checks, GPU via CDI
- Supervisor binary sideloaded via image volume mount (BYOC-compatible)
- SSH handshake secret injected via Podman secrets API (not plaintext env)
- Typed ContainerSpec structs, input validation, and path-traversal guards
- Cgroups v2 required; fails fast on v1 hosts
- Bounded event stream buffer; watch stream reconnection handled by server watch_loop
- Graceful shutdown and standalone driver binary with gRPC bridge

Rootless-specific fixes:
- Skip drop_privileges when user namespace lacks SETUID/SETGID/DAC_READ_SEARCH caps
- Add /run/netns tmpfs mount for ip netns in rootless containers
- Use secret_env map (not secrets array) for env-var injection in libpod API
- Resolve SSH endpoint to 127.0.0.1:<host_port> instead of unreachable bridge IP

Server/sandbox hardening:
- Split loopback and link-local SSRF gates; Podman/VM drivers allow loopback
- Close SSRF bypass in SSH tunnel Host path by resolving DNS before connecting
- Prevent OPENSHELL_* env var override by user-supplied spec environment maps
- Disable SQLite pool idle_timeout/max_lifetime for in-memory databases
- Emit deleted_event on 404-during-inspect instead of regressing sandbox phase
- Key delete cleanup by stable sandbox_id to survive container label drift

CLI fixes:
- Restore --name as a named flag on sandbox create (not positional)
- Fix exec command arg parsing to not consume sandboxed-command flags
- Propagate SSH verbosity via OPENSHELL_SSH_LOG_LEVEL

Build tooling:
- Add tasks/scripts/container-engine.sh: auto-detects Podman or Docker, exposes
  unified ce_* helpers; all build/cluster/VM scripts updated to use it
- Add docker:build:supervisor mise task for standalone supervisor image
- Add openshell-driver-podman to Dockerfile.images pre-fetch/build stages
- Add e2e/rust/e2e-podman.sh and e2e:podman mise task for full lifecycle testing

Signed-off-by: Adam Miller <admiller@redhat.com>

* fix(driver-podman): derive grpc endpoint from server bind port

When a user starts the gateway on a non-default port (e.g. --port 8081),
sandbox containers were receiving OPENSHELL_ENDPOINT pointing at the
default port 8080. The driver's auto-detection fallback read
OPENSHELL_BIND_ADDRESS from the environment, which was stale or unset,
and fell back to DEFAULT_SERVER_PORT.

Add gateway_port to PodmanComputeConfig and thread config.bind_address.port()
from the server into the driver so the fallback uses the actual listening
port. Remove the OPENSHELL_BIND_ADDRESS env var read and the
extract_port_from_bind_address helper which are no longer needed.

Add --gateway-port / OPENSHELL_GATEWAY_PORT to the standalone driver
binary for parity when the driver is run outside the embedded server path.

Signed-off-by: Adam Miller <admiller@redhat.com>

* fix(driver-podman): address PR feedback on env test safety and cluster DNS docs

Replace hand-rolled unsafe TempEnvVar RAII guard with temp_env::with_vars
and a static ENV_LOCK mutex, fixing a data race in parallel test execution.
The prior safety comment incorrectly claimed Cargo runs tests single-threaded.

Update debug-openshell-cluster skill to accurately document the DNS proxy
strategy (setup_dns_proxy + public DNS fallback) and clarify the separation
between cluster DNS and sandbox agent DNS enforcement.

Signed-off-by: Adam Miller <admiller@redhat.com>

* fix(e2e): resolve CI failures in auth timeout, test harness, and formatting

- Short-circuit browser_auth_flow when OPENSHELL_NO_BROWSER=1 instead
  of waiting the full 120s AUTH_TIMEOUT for a callback that never arrives
- Add timeout to SandboxGuard::create() and create_with_upload() to
  prevent indefinite hangs (matches create_keep() which already had one)
- Add missing '--' separator in no_proxy test before command args
- Add #![cfg(feature = "e2e")] gate to sandbox_lifecycle.rs
- Run cargo fmt on openshell-driver-podman
- Refine cluster DNS docs for Podman in debug-openshell-cluster skill

Signed-off-by: Adam Miller <admiller@redhat.com>

* refactor(server): remove allows_loopback_endpoints from ComputeRuntime

SSRF protection is now handled at the network and proxy layers
(openshell-core net.rs, openshell-sandbox proxy.rs) rather than
requiring per-driver flags on ComputeRuntime. Update architecture
docs to reflect supervisor relay SSH transport and add rootless
networking deep-dive.

Signed-off-by: Adam Miller <admiller@redhat.com>

---------

Signed-off-by: Adam Miller <admiller@redhat.com>
2026-04-24 10:30:14 -07:00
jtoelke2 75b880b625 chore(ci): add ARC baseline collector for OS-49 runner migration (#927)
Signed-off-by: Jonas Toelke <jtoelke@nvidia.com>
2026-04-23 16:52:47 -05:00
John T. Myers 3dd6d51c26 fix(cli): use local z3 in dev wrapper (#805)
* fix(cli): use local z3 in dev wrapper

Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>

* fix(docker): add openshell-prover to Dockerfile skeleton stages

---------

Signed-off-by: John Myers <9696606+johntmyers@users.noreply.github.com>
2026-04-10 13:36:19 -07:00
Drew Newberry ddb85b1704 feat(vm): add openshell-vm crate with libkrun microVM gateway (#611) 2026-04-08 22:00:01 -07:00
John T. Myers b7779bdefa feat(sandbox): integrate OCSF structured logging for sandbox events (#720)
* feat(sandbox): integrate OCSF structured logging for all sandbox events

WIP: Replace ad-hoc tracing calls with OCSF event builders across all
sandbox subsystems (network, SSH, process, filesystem, config, lifecycle).

- Register ocsf_logging_enabled setting (defaults false)
- Replace stdout/file fmt layers with OcsfShorthandLayer
- Add conditional OcsfJsonlLayer for /var/log/openshell-ocsf.log
- Update LogPushLayer to extract OCSF shorthand for gRPC push
- Migrate ~106 log sites to OCSF builders (NetworkActivity, HttpActivity,
  SshActivity, ProcessActivity, DetectionFinding, ConfigStateChange,
  AppLifecycle)
- Add openshell-ocsf to all Docker build contexts

* fix(scripts): attach provider to all smoke test phases to avoid rate limits

GitHub's unauthenticated API rate limit (60/hour) causes flaky 403s for
Phases 1, 2, and 4. Fix by attaching the provider to all sandboxes and
upgrading the Phase 1 policy to L7 so credential injection works.

Phase 4 (tls:skip) cannot inject credentials by design, so relax the
assertion to accept either 200 or 403 from upstream -- both prove the
proxy forwarded the request.

* fix(ocsf): remove timestamp from shorthand format to avoid double-timestamp

The display layer (gateway logs, TUI, sandbox logs CLI) already prepends
a timestamp. Having one in the shorthand output too produces redundant
double-timestamps like:

  15:49:11 sandbox INFO  15:49:11.649 I NET:OPEN ALLOWED ...

Now the shorthand is just the severity + structured content:

  15:49:11 sandbox INFO  I NET:OPEN ALLOWED ...

* refactor(ocsf): replace single-char severity with bracketed labels

Replace cryptic single-character severity codes (I/L/M/H/C/F) with
readable bracketed labels: [LOW], [MED], [HIGH], [CRIT], [FATAL].

Informational severity (the happy-path default) is omitted entirely to
keep normal log output clean and avoid redundancy with the tracing-level
INFO that the display layer already provides.

Before: sandbox INFO  I NET:OPEN ALLOWED ...
After:  sandbox INFO  NET:OPEN ALLOWED ...

Before: sandbox INFO  M NET:OPEN DENIED ...
After:  sandbox INFO  [MED] NET:OPEN DENIED ...

* feat(sandbox): use OCSF level label for structured events in log push

Set the level field to 'OCSF' instead of 'INFO' for OCSF events in the
gRPC log push. This visually distinguishes structured OCSF events from
plain tracing output in the TUI and CLI sandbox logs:

  sandbox OCSF  NET:OPEN [INFO] ALLOWED python3(42) -> api.example.com:443
  sandbox OCSF  NET:OPEN [MED] DENIED python3(42) -> blocked.com:443
  sandbox INFO  Fetching sandbox policy via gRPC

* fix(sandbox): convert new Landlock path-skip warning to OCSF

PR #677 added a warn!() for inaccessible Landlock paths in best-effort
mode. Convert to ConfigStateChangeBuilder with degraded state so it
flows through the OCSF shorthand format consistently.

* fix(sandbox): use rolling appender for OCSF JSONL file

Match the main openshell.log rotation mechanics (daily, 3 files max)
instead of a single unbounded append-only file. Prevents disk exhaustion
when ocsf_logging_enabled is left on in long-running sandboxes.

* fix(sandbox): address reviewer warnings for OCSF integration

W1: Remove redundant 'OCSF' prefix from shorthand file layer — the
    class name (NET:OPEN, HTTP:GET) already identifies structured events
    and the LogPushLayer separately sets the level field.

W2: Log a debug message when OCSF_CTX.set() is called a second time
    instead of silently discarding via let _.

W3: Document the boundary between OCSF-migrated events and intentionally
    plain tracing calls (DEBUG/TRACE, transient, internal plumbing).

W4: Migrate remaining iptables LOG rule failure warnings in netns.rs
    (IPv4 TCP/UDP, IPv6 TCP/UDP) to ConfigStateChangeBuilder for
    consistency with the IPv4 bypass rule failure already migrated.

W5: Migrate malformed inference request warn to NetworkActivity with
    ActivityId::Refuse and SeverityId::Medium.

W6: Use Medium severity for L7 deny decisions (both CONNECT tunnel and
    FORWARD proxy paths) to match the CONNECT deny severity pattern.
    Allows and audits remain Informational.

* refactor(sandbox): rename ocsf_logging_enabled to ocsf_json_enabled

The shorthand logs are already OCSF-structured events. The setting
specifically controls the JSONL file export, so the name should reflect
that: ocsf_json_enabled.

* fix(ocsf): add timestamps to shorthand file layer output

The OcsfShorthandLayer writes directly to the log file with no outer
display layer to supply timestamps. Add a UTC timestamp prefix to every
line so the file output matches what tracing::fmt used to provide.

Before: CONFIG:VALIDATED [INFO] Validated 'sandbox' user exists in image
After:  2026-04-01T15:49:11.649Z CONFIG:VALIDATED [INFO] Validated ...

* fix(docker): touch openshell-ocsf source to invalidate cargo cache

The supervisor-workspace stage touches sandbox and core sources to force
recompilation over the rust-deps dummy stubs, but openshell-ocsf was
missing. This caused the Docker cargo cache to use stale ocsf objects
from the deps stage, preventing changes to the ocsf crate (like the
timestamp fix) from appearing in the final binary.

Also adds a shorthand layer test verifying timestamp output, and drafts
the observability docs section.

* fix(ocsf): add OCSF level prefix to file layer shorthand output

Without a level prefix, OCSF events in the log file have no visual
anchor at the position where standard tracing lines show INFO/WARN.
This makes scanning the file harder since the eye has nothing consistent
to lock onto after the timestamp.

Before: 2026-04-01T04:04:13.065Z CONFIG:DISCOVERY [INFO] ...
After:  2026-04-01T04:04:13.065Z OCSF CONFIG:DISCOVERY [INFO] ...

* fix(ocsf): clean up shorthand formatting for listen and SSH events

- Fix double space in NET:LISTEN, SSH:LISTEN, and other events where
  action is empty (e.g., 'NET:LISTEN [INFO]  10.200.0.1' -> 'NET:LISTEN [INFO] 10.200.0.1')
- Add listen address to SSH:LISTEN event (was empty)
- Downgrade SSH handshake intermediate steps (reading preface, verifying)
  from OCSF events to debug!() traces. Only the final verdict
  (accepted/denied) is an OCSF event now, reducing noise from 3 events
  to 1 per SSH connection.
- Apply same spacing fix to HTTP shorthand for consistency.

* docs(observability): update examples with OCSF prefix and formatting fixes

Align doc examples with the deployed output:
- Add OCSF level prefix to all shorthand examples in the log file
- Show mixed OCSF + standard tracing in the file format section
- Update listen events (no double space, SSH includes address)
- Show one SSH:OPEN per connection instead of three
- Update grep patterns to use 'OCSF NET:' etc.

* docs(agents): add OCSF logging guidance to AGENTS.md

Add a Sandbox Logging (OCSF) section to AGENTS.md so agents have
in-context guidance for deciding whether new log emissions should use
OCSF structured logging or plain tracing. Covers event class selection,
severity guidelines, builder API usage, dual-emit pattern for security
findings, and the no-secrets rule.

Also adds openshell-ocsf to the Architecture Overview table.

* fix: remove workflow files accidentally included during rebase

These files were already merged to main in separate PRs. They got
pulled into our branch during rebase conflict resolution for the
deleted docs-preview-pr.yml file.

* docs(observability): use sandbox connect instead of raw SSH

Users access sandboxes via 'openshell sandbox connect', not direct SSH.

* fix(docs): correct settings CLI syntax in OCSF JSON export page

The settings CLI requires --key and --value named flags, not positional
arguments. Also fix the per-sandbox form: the sandbox name is a
positional argument, not a --sandbox flag.

* fix(e2e): update log assertions for OCSF shorthand format

The E2E tests asserted on the old tracing::fmt key=value format
(action=allow, l7_decision=audit, FORWARD, L7_REQUEST, always-blocked).
Update to match the new OCSF shorthand (ALLOWED/DENIED, HTTP:, NET:,
engine:ssrf, policy:).

* feat(sandbox): convert WebSocket upgrade log calls to OCSF

PR #718 added two log calls for WebSocket upgrade handling:

- 101 Switching Protocols info → NetworkActivity with Upgrade activity.
  This is a significant state change (L7 enforcement drops to raw relay).

- Unsolicited 101 without client Upgrade header → DetectionFinding with
  High severity. A non-compliant upstream sending 101 without a client
  Upgrade request could be attempting to bypass L7 inspection.
2026-04-07 13:01:13 -07:00
John T. Myers f37b69b5e5 feat(sandbox): auto-detect TLS and terminate unconditionally for credential injection (#544)
* feat(sandbox): auto-detect TLS and terminate unconditionally for credential injection

Closes #533

The proxy now auto-detects TLS by peeking the first bytes of each
connection. When TLS is detected, it terminates unconditionally —
enabling credential injection and optional L7 inspection without
requiring explicit 'tls: terminate' in the policy.
2026-03-23 18:45:18 -07:00
Drew Newberry a912848217 refactor(build): unify image build graph for cache reuse (#390) 2026-03-18 15:01:04 -07:00
Drew Newberry 19c3230267 feat(ci): add automated release workflow with patch version bumping (#284) 2026-03-13 17:44:22 -07:00
Drew Newberry fbd93a4632 refactor: rename navigator- crate prefix to openshell- (#277) 2026-03-13 02:02:18 -07:00
Drew Newberry 89d21d7852 refactor(sandbox): sandboxes are managed as separate community images (#267) 2026-03-12 22:06:52 -07:00
John T. Myers 454327d890 feat(policy): add policy recommendation plumbing (#204) (#222)
* feat(policy): add policy recommendation plumbing — denial aggregation, transport, approval pipeline, and mechanistic recommendations

Implement the infrastructure layer for automated policy recommendations (#204):

- Proto: 9 new RPCs and messages for draft policy lifecycle (submit, get, approve, reject, approve-all, edit, undo, clear, history)
- Persistence: SQLite/Postgres migrations and store methods for draft_policy_chunks and denial_summaries tables
- Server: Full gRPC handler implementations with mechanistic mapper that auto-generates NetworkPolicyRule proposals from denial summaries
- Sandbox: DenialAggregator with MPSC channel, deduplication, periodic flush to gateway via SubmitPolicyAnalysis
- CLI: 'openshell draft' subcommand with get/approve/reject/approve-all/undo/clear/history operations
- TUI: Draft recommendations panel accessible from sandbox policy view
- Docs: Architecture documentation in architecture/policy-advisor.md

* feat(policy): add L7-aware mechanistic mapper and policy advisor CTF example

Add L7 rule generation to mechanistic mapper (build_l7_rules,
generalise_path, looks_like_id) with 3 new unit tests. Add
examples/policy-advisor/ with a 7-gate CTF script, restrictive
sandbox policy, and walkthrough README.

* fix(policy): use sandbox name for denial flush and add TUI draft badges

Fix denial aggregator passing sandbox UUID instead of name to
SubmitPolicyAnalysis, which caused 'sandbox not found' errors on
flush. Add notification badges to the TUI sandbox list and detail
header showing pending draft recommendation counts.

* fix(policy): deduplicate draft chunks and tolerate overlapping OPA rules

Skip draft chunk creation when a pending/approved chunk already covers
the same host:port endpoint, preventing duplicate rules across denial
aggregator flush cycles.

Rewrite three OPA complete rules (network_policy_for_request,
matched_network_policy, matched_endpoint_config) to tolerate multiple
matching policies without triggering a "complete rule conflict" error.
network_policy_for_request becomes a boolean, matched_network_policy
uses a set comprehension with min(), and matched_endpoint_config uses
an array comprehension with index-0 selection.

* feat(tui): interactive draft actions, highlight bar, and detail popup

Rework the draft recommendations panel to match the logs UX:
- Highlight bar (green accent + background) instead of arrow marker
- Viewport-aware j/k scrolling with g/G for top/bottom
- Enter opens a full-screen detail popup showing endpoints, binaries,
  rationale, security notes, and action hints

Add approve/reject/approve-all draft actions:
- [a] approve selected chunk, [x] reject, [A] approve all pending
- Actions work from both the list view and the detail popup
- gRPC calls run async; result updates status bar and refreshes data
- Nav bar shows all available keybindings

Fix draft count refresh: sandbox_draft_counts now refreshes on every
tick (not just Dashboard), so the detail header badge updates in
real time.

Improve badge labels: show 'N pending' instead of a bare number in
both the dashboard sandbox list and sandbox detail header.

* refactor(policy): DB-level draft chunk dedup with hit counter and timestamps

Replace the in-memory HashSet dedup in SubmitPolicyAnalysis with a
database-level upsert. New denormalized columns on draft_policy_chunks:
- host, port: extracted from proposed_rule at insert time
- hit_count: incremented on conflict (same sandbox + host + port)
- first_seen_ms, last_seen_ms: track when the endpoint was first and
  most recently proposed

A partial unique index (WHERE status IN ('pending','approved')) ensures
only one active chunk per endpoint per sandbox; rejected/superseded
chunks don't block new proposals.

Surface hit_count and first/last_seen in:
- CLI: 'openshell draft get' shows 'Hits: N (first ..., last ...)'
- TUI: detail popup shows hits row; list view shows 'Nx' suffix

* fix(policy): optimistic retry on policy version conflicts + structured logging

merge_chunk_into_policy and remove_chunk_from_policy now retry up to 5
times on UNIQUE constraint violations (version conflicts from concurrent
approvals). Each attempt re-reads the latest policy, re-merges the rule,
and increments the version. This eliminates the race condition where
rapid successive approvals would fail with a DB error.

Add structured tracing to all draft action handlers:
- ApproveDraftChunk: logs rule_name, host, port, hit_count before merge
  and version + policy_hash after success
- RejectDraftChunk: logs rule_name, host, port, reason
- ApproveAllDraftChunks: logs pending_count at start, per-chunk merge
  progress, and final summary with chunks_approved/skipped
- UndoDraftChunk: logs before/after with rule_name and version
- Retry attempts log as warnings with attempt number and conflicting
  version

* wip: forward proxy fix, mapper allowed_ips, TUI polish, CTF rewrite

* fix(tui): use correct --gateway flag for ssh-proxy ProxyCommand

* chore: add Docker cleanup script for stale images, volumes, and build cache

* feat(tui): approve-all confirmation modal and CTF cleanup

Add [A] confirmation popup that snapshots pending chunks, shows a
scrollable list, and approves each chunk individually on confirm.
This prevents approving chunks that arrived after the modal opened.

Remove transient issue #205 reference from CTF victory banner.

* fix(tui): correct import ordering for rustfmt

* wip: stateful toggle model, rename to network rules

Draft chunks now follow a toggle state machine:
  pending -> approved | rejected (initial decision)
  approved <-> rejected (toggle)

One row per (sandbox_id, host, port) via expanded unique index.
Rejecting an approved rule removes it from the active policy.
Re-approving a rejected rule merges it back.

Rename CLI from 'draft' to 'rule', TUI from 'Draft Recommendations'
to 'Network Rules'. State-aware keybindings: approved shows [x] Revoke,
rejected shows [a] Approve. Fix sandbox detail hiding delete confirmation
behind pending message.

* refactor(policy): move mapper sandbox-side, slim schema, per-binary granularity

Move mechanistic mapper from gateway to sandbox so all analysis runs
sandbox-side (N sandboxes = N independent pipelines). Gateway is now a
thin validate + persist + approval layer.

Architectural changes:
- Move mechanistic_mapper.rs from navigator-server to navigator-sandbox
- Sandbox flush flow: aggregator drains -> mapper runs -> proposals sent
- Gateway SubmitPolicyAnalysis: validate + persist only, no mapper
- Drop denial_summaries table (write-only, zero readers)
- Consolidate migrations 003+004+005 into single 003

Schema slimming:
- Drop 5 unused columns from draft_policy_chunks (stage, denial_refs,
  supersedes_chunk_id, analysis_mode, decided_by)
- Add per-binary granularity: binary column, widen unique index to
  (sandbox_id, host, port, binary)
- Mapper groups by (host, port, binary), one proposal per triple
- Merge appends binary to existing rule; revoke removes just that binary

CTF & UX:
- 7-gate CTF: add Gate 3 (curl -> ifconfig.me:80) for per-binary demo
- TUI shows binary short name in list, full path in detail popup
- CLI output shows binary field
- Idempotent rule names, hit_count accumulates real denial counts
- Rationale text no longer bakes in stale denial count
2026-03-12 08:28:26 -07:00
Drew Newberry 95d7ae077e refactor(cli): remove kubeconfig port, add doctor llm-help, update debug docs (#252) 2026-03-11 21:25:25 -07:00