Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

[workspace]
resolver = "2"
members = ["crates/*"]
members = ["crates/*", "examples/policy-governance-interceptor"]

[workspace.package]
version = "0.0.0"
Expand Down
35 changes: 35 additions & 0 deletions architecture/gateway.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,31 @@ Domain objects use shared metadata: stable server-generated IDs, human-readable
names, creation timestamps, and labels. Crate-level details live in
`crates/openshell-core/README.md`.

## Interceptors

Gateway interceptors are an optional operation-review boundary for deployments
that need organization-specific controls outside the gateway binary. They are
disabled unless configured in gateway TOML. At startup, the gateway connects to
each configured gRPC or Unix-socket service, calls `Describe`, validates the
returned manifest, applies any local narrowing overrides, and builds a
deterministically ordered review plan. Invalid manifests or unreachable
interceptors fail gateway startup.

Handlers call the interceptor runtime only after authentication and basic
request validation. The covered write paths are sandbox create and provider
attach/detach, provider and provider-profile writes, policy/config updates, and
the driver-facing sandbox create shape before compute-driver validation. The
runtime supports `pre_request`, `modify_object`, `validate_object`,
`validate_driver`, and `post_commit` phases. Modification phases are available
only where the gateway owns explicit protobuf-to-JSON round-trip adapters;
validation phases may deny but cannot patch.

Provider credentials are treated as secret-bearing fields. Review payloads
redact credential values, and patches that read or write provider credential
paths are rejected before they can modify persisted state. Interceptor denials
and security-relevant failures are visible through structured tracing, gateway
OCSF finding events, and metrics.

## Persistence

The gateway persistence layer is a protobuf object store. Domain services store
Expand Down Expand Up @@ -150,6 +175,11 @@ This keeps the gateway data model portable across storage backends and leaves
room for future stores that can provide the same object, label, version, and
scope semantics.

User-supplied labels are validated with Kubernetes label-value limits at API
boundaries. Trusted gateway extensions, such as interceptors, may attach longer
stored metadata values when those values are not projected to compute-platform
labels.

The SQLite adapter tightens the on-disk database file to mode `0o600` on every
connect so that provider API keys, SSH session tokens, and sandbox metadata are
not readable by other local users on shared hosts. The same restriction is
Expand Down Expand Up @@ -422,6 +452,11 @@ Driver implementation settings live in the TOML driver tables. See
`docs/reference/gateway-config.mdx` for worked per-driver examples and RFC
0003 for the full schema.

Gateway interceptors are configured under
`[[openshell.gateway.interceptors]]`. They do not inherit into driver tables.
Interceptor service manifests are validated at startup before the gateway
accepts traffic.

`database_url` is env-only and rejected when present in the file
(`OPENSHELL_DB_URL` / `--db-url`).

Expand Down
1 change: 1 addition & 0 deletions crates/openshell-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ workspace = true

[features]
bundled-z3 = ["openshell-prover/bundled-z3"]
gh-release-z3 = ["openshell-prover/gh-release-z3"]
dev-settings = ["openshell-core/dev-settings"]

[dev-dependencies]
Expand Down
13 changes: 13 additions & 0 deletions crates/openshell-core/src/proto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,19 @@ pub mod inference {
}
}

#[allow(
clippy::all,
clippy::pedantic,
clippy::nursery,
unused_qualifications,
rust_2018_idioms
)]
pub mod interceptor {
pub mod v1 {
include!(concat!(env!("OUT_DIR"), "/openshell.interceptor.v1.rs"));
}
}

pub use datamodel::v1::*;
pub use inference::v1::*;
pub use openshell::*;
Expand Down
35 changes: 35 additions & 0 deletions crates/openshell-interceptors/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

[package]
name = "openshell-interceptors"
description = "Gateway interceptor config, planning, transport, and review runtime"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true

[dependencies]
openshell-core = { path = "../openshell-core", default-features = false }

tokio = { workspace = true }
tonic = { workspace = true, features = ["channel", "tls-native-roots"] }
prost-types = { workspace = true }
hyper-util = { workspace = true, features = ["tokio"] }
tower = { workspace = true }

metrics = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
toml = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
url = { workspace = true }
json-patch = "1.4"

[dev-dependencies]
tokio = { workspace = true, features = ["full"] }

[lints]
workspace = true
Loading
Loading