Skip to content

Commit 7b79fcb

Browse files
committed
feat(gateway): add operation interceptors
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
1 parent f4a5005 commit 7b79fcb

26 files changed

Lines changed: 5954 additions & 85 deletions

File tree

Cargo.lock

Lines changed: 42 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
[workspace]
55
resolver = "2"
6-
members = ["crates/*"]
6+
members = ["crates/*", "examples/policy-governance-interceptor"]
77

88
[workspace.package]
99
version = "0.0.0"

architecture/gateway.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,31 @@ Domain objects use shared metadata: stable server-generated IDs, human-readable
107107
names, creation timestamps, and labels. Crate-level details live in
108108
`crates/openshell-core/README.md`.
109109

110+
## Interceptors
111+
112+
Gateway interceptors are an optional operation-review boundary for deployments
113+
that need organization-specific controls outside the gateway binary. They are
114+
disabled unless configured in gateway TOML. At startup, the gateway connects to
115+
each configured gRPC or Unix-socket service, calls `Describe`, validates the
116+
returned manifest, applies any local narrowing overrides, and builds a
117+
deterministically ordered review plan. Invalid manifests or unreachable
118+
interceptors fail gateway startup.
119+
120+
Handlers call the interceptor runtime only after authentication and basic
121+
request validation. The covered write paths are sandbox create and provider
122+
attach/detach, provider and provider-profile writes, policy/config updates, and
123+
the driver-facing sandbox create shape before compute-driver validation. The
124+
runtime supports `pre_request`, `modify_object`, `validate_object`,
125+
`validate_driver`, and `post_commit` phases. Modification phases are available
126+
only where the gateway owns explicit protobuf-to-JSON round-trip adapters;
127+
validation phases may deny but cannot patch.
128+
129+
Provider credentials are treated as secret-bearing fields. Review payloads
130+
redact credential values, and patches that read or write provider credential
131+
paths are rejected before they can modify persisted state. Interceptor denials
132+
and security-relevant failures are visible through structured tracing, gateway
133+
OCSF finding events, and metrics.
134+
110135
## Persistence
111136

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

178+
User-supplied labels are validated with Kubernetes label-value limits at API
179+
boundaries. Trusted gateway extensions, such as interceptors, may attach longer
180+
stored metadata values when those values are not projected to compute-platform
181+
labels.
182+
153183
The SQLite adapter tightens the on-disk database file to mode `0o600` on every
154184
connect so that provider API keys, SSH session tokens, and sandbox metadata are
155185
not readable by other local users on shared hosts. The same restriction is
@@ -422,6 +452,11 @@ Driver implementation settings live in the TOML driver tables. See
422452
`docs/reference/gateway-config.mdx` for worked per-driver examples and RFC
423453
0003 for the full schema.
424454

455+
Gateway interceptors are configured under
456+
`[[openshell.gateway.interceptors]]`. They do not inherit into driver tables.
457+
Interceptor service manifests are validated at startup before the gateway
458+
accepts traffic.
459+
425460
`database_url` is env-only and rejected when present in the file
426461
(`OPENSHELL_DB_URL` / `--db-url`).
427462

crates/openshell-cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ workspace = true
8686

8787
[features]
8888
bundled-z3 = ["openshell-prover/bundled-z3"]
89+
gh-release-z3 = ["openshell-prover/gh-release-z3"]
8990
dev-settings = ["openshell-core/dev-settings"]
9091

9192
[dev-dependencies]

crates/openshell-core/src/proto/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,19 @@ pub mod inference {
7979
}
8080
}
8181

82+
#[allow(
83+
clippy::all,
84+
clippy::pedantic,
85+
clippy::nursery,
86+
unused_qualifications,
87+
rust_2018_idioms
88+
)]
89+
pub mod interceptor {
90+
pub mod v1 {
91+
include!(concat!(env!("OUT_DIR"), "/openshell.interceptor.v1.rs"));
92+
}
93+
}
94+
8295
pub use datamodel::v1::*;
8396
pub use inference::v1::*;
8497
pub use openshell::*;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
[package]
5+
name = "openshell-interceptors"
6+
description = "Gateway interceptor config, planning, transport, and review runtime"
7+
version.workspace = true
8+
edition.workspace = true
9+
rust-version.workspace = true
10+
license.workspace = true
11+
repository.workspace = true
12+
13+
[dependencies]
14+
openshell-core = { path = "../openshell-core", default-features = false }
15+
16+
tokio = { workspace = true }
17+
tonic = { workspace = true, features = ["channel", "tls-native-roots"] }
18+
prost-types = { workspace = true }
19+
hyper-util = { workspace = true, features = ["tokio"] }
20+
tower = { workspace = true }
21+
22+
metrics = { workspace = true }
23+
serde = { workspace = true }
24+
serde_json = { workspace = true }
25+
toml = { workspace = true }
26+
thiserror = { workspace = true }
27+
tracing = { workspace = true }
28+
url = { workspace = true }
29+
json-patch = "1.4"
30+
31+
[dev-dependencies]
32+
tokio = { workspace = true, features = ["full"] }
33+
34+
[lints]
35+
workspace = true

0 commit comments

Comments
 (0)