Skip to content

Commit e06ec57

Browse files
committed
feat(examples): govern provider profiles in interceptor
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
1 parent b21e104 commit e06ec57

8 files changed

Lines changed: 932 additions & 320 deletions

File tree

examples/governance-interceptor/Cargo.lock

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

examples/governance-interceptor/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ base64 = "0.22"
1515
jsonwebtoken = "9"
1616
openshell-core = { path = "../../crates/openshell-core", default-features = false }
1717
openshell-policy = { path = "../../crates/openshell-policy" }
18+
openshell-providers = { path = "../../crates/openshell-providers" }
1819
prost-types = "0.14"
1920
rcgen = { version = "0.13", features = ["crypto", "pem"] }
2021
serde = { version = "1", features = ["derive"] }
2122
serde_json = "1"
23+
serde_yml = "0.0.12"
2224
sha2 = "0.10"
2325
tokio = { version = "1.43", features = ["macros", "rt-multi-thread", "fs", "signal"] }
2426
tonic = { version = "0.14", features = ["transport"] }

examples/governance-interceptor/README.md

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,31 @@ This standalone example implements the
55
extend OpenShell to provide advanced governance over sandbox policies.
66

77
- every new sandbox receives `policy.yaml` sourced from this examples folder
8-
- every new sandbox is attached to exactly `github` and `gitlab`
8+
- every new sandbox is attached to exactly `github` and `slack`
9+
- `github` must use the `github` provider profile
10+
- `slack` must use the custom `slack` provider profile
11+
- governed provider network policy lives in `profiles/*.yaml`, not in the
12+
signed baseline sandbox policy
913
- every new sandbox gets an `openshell.nvidia.com/policy-signature` metadata annotation
1014
that is used to verify the policy
1115
- every sandbox creation evaluation adds a `correlation_id` log annotation so the
1216
gateway log can be correlated with interceptor-side decisions
1317
- users cannot attach or detach other providers after sandbox creation
1418
- users cannot replace or merge sandbox policy after sandbox creation
15-
- users cannot create provider records other than `github` and `gitlab`
16-
- users cannot update or delete the governed `github` or `gitlab` provider records
19+
- users cannot create provider records other than `github` and `slack`
20+
- users cannot update or delete the governed `github` or `slack` provider records
21+
- users cannot import or update provider profiles other than `github` and
22+
`slack`
23+
- provider profile deletion is blocked by the interceptor
1724

1825
Run the interceptor:
1926

2027
```shell
2128
cargo run -- \
2229
--listen 127.0.0.1:18081 \
23-
--policy policy.yaml
30+
--policy policy.yaml \
31+
--profiles profiles \
32+
--gateway-endpoint http://127.0.0.1:8080
2433
```
2534

2635
At startup the example parses `policy.yaml`, converts it to the protobuf JSON
@@ -30,6 +39,22 @@ sandbox under `metadata.annotations["openshell.nvidia.com/policy-signature"]` an
3039
verifies the JWT against the sandbox policy during the `CreateSandbox` validate
3140
phase.
3241

42+
Provider profile YAML files are loaded by the interceptor from `--profiles`
43+
(default: this example's `profiles/` directory). The interceptor names each
44+
profile from its filename without the extension: `profiles/github.yaml` becomes
45+
profile ID `github`, and `profiles/slack.yaml` becomes profile ID `slack`. The
46+
YAML files do not need an `id` field; if one is present, the filename still wins.
47+
48+
When `--gateway-endpoint` is set, the interceptor reconciles the loaded profiles
49+
through the gateway's normal provider profile APIs. GitHub is already a built-in
50+
read-only profile, so the interceptor accepts the exported built-in `github`
51+
profile as present; the gateway still rejects importing or updating that
52+
built-in ID. Slack is a custom profile: the interceptor uses
53+
`ImportProviderProfiles` for first-time vending and `UpdateProviderProfiles` for
54+
ongoing changes. It exports the current profile to read `resource_version`,
55+
injects that version into the loaded YAML payload, and submits
56+
`UpdateProviderProfiles`. It never deletes governed profiles.
57+
3358
The signing key is generated in memory on each interceptor start. This keeps the
3459
example self-contained. Production governance services should load managed
3560
signing keys, publish verifier keys, and define a rotation process.
@@ -45,7 +70,7 @@ Gateway TOML snippet:
4570

4671
```toml
4772
[[openshell.gateway.interceptors]]
48-
name = "source-control-governance"
73+
name = "provider-governance"
4974
grpc_endpoint = "http://127.0.0.1:18081"
5075
order = 10
5176
failure_policy = "fail_closed"

examples/governance-interceptor/policy.yaml

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,4 @@ process:
1515
run_as_user: sandbox
1616
run_as_group: sandbox
1717

18-
network_policies:
19-
github:
20-
name: github-api-readonly
21-
endpoints:
22-
- host: api.github.com
23-
port: 443
24-
protocol: rest
25-
enforcement: enforce
26-
access: read-only
27-
binaries:
28-
- { path: /usr/bin/git }
29-
- { path: /usr/bin/curl }
30-
gitlab:
31-
name: gitlab-api-readonly
32-
endpoints:
33-
- host: gitlab.com
34-
port: 443
35-
protocol: rest
36-
enforcement: enforce
37-
access: read-only
38-
binaries:
39-
- { path: /usr/bin/git }
40-
- { path: /usr/bin/curl }
18+
network_policies: {}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
display_name: GitHub
5+
description: GitHub API and Git operations
6+
category: source_control
7+
credentials:
8+
- name: api_token
9+
description: GitHub token
10+
env_vars: [GITHUB_TOKEN, GH_TOKEN]
11+
required: true
12+
auth_style: bearer
13+
header_name: authorization
14+
discovery:
15+
credentials: [api_token]
16+
endpoints:
17+
- host: api.github.com
18+
port: 443
19+
protocol: rest
20+
access: read-only
21+
enforcement: enforce
22+
- host: api.github.com
23+
port: 443
24+
path: /graphql
25+
protocol: graphql
26+
access: read-only
27+
enforcement: enforce
28+
- host: github.com
29+
port: 443
30+
protocol: rest
31+
access: read-only
32+
enforcement: enforce
33+
binaries: [/usr/bin/gh, /usr/local/bin/gh, /usr/bin/git, /usr/local/bin/git]
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
display_name: Slack
5+
description: Read-only Slack Web API access for governed sandbox agents
6+
category: messaging
7+
credentials:
8+
- name: api_token
9+
description: Slack bot or user token
10+
env_vars: [SLACK_BOT_TOKEN, SLACK_TOKEN]
11+
required: true
12+
auth_style: bearer
13+
header_name: authorization
14+
discovery:
15+
credentials: [api_token]
16+
endpoints:
17+
- host: slack.com
18+
port: 443
19+
protocol: rest
20+
enforcement: enforce
21+
rules:
22+
- allow:
23+
method: GET
24+
path: /api/team.info
25+
- allow:
26+
method: GET
27+
path: /api/users.info
28+
- allow:
29+
method: GET
30+
path: /api/conversations.info
31+
- allow:
32+
method: GET
33+
path: /api/conversations.history
34+
binaries:
35+
- /usr/bin/curl
36+
- /usr/local/bin/curl

0 commit comments

Comments
 (0)