Skip to content

Commit cb40667

Browse files
committed
docs(policy): add network recipes and update command reference
Signed-off-by: Johnny Greco <jogreco@nvidia.com>
1 parent 7d4c9f9 commit cb40667

2 files changed

Lines changed: 822 additions & 0 deletions

File tree

‎docs/reference/policy-updates.mdx‎

Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
---
2+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
title: "Incremental Policy Update Reference"
5+
sidebar-title: "Policy Updates"
6+
description: "Command grammar, scope requirements, merge behavior, previews, and revision status for incremental sandbox policy updates."
7+
keywords: "Generative AI, Cybersecurity, Policy, CLI, Incremental Update, Hot Reload"
8+
position: 4
9+
---
10+
11+
`openshell policy update` merges explicit operations into a sandbox's current
12+
`network_policies` map. It does not edit filesystem, Landlock, process, or
13+
middleware sections. Use `policy set` with an exported base policy for those
14+
broader changes.
15+
16+
This reference describes the command's flags, input formats, and update
17+
behavior. For the policy lifecycle and editing workflow, see
18+
[Configure Sandbox Policies](/sandboxes/policies). Examples use `my-sandbox`
19+
for an existing sandbox; adapt rule names, executable paths, and destinations
20+
to its current base policy.
21+
22+
## Command Flags
23+
24+
One command can contain several compatible operations. The gateway applies the
25+
batch atomically and persists at most one new revision.
26+
27+
| Flag | Purpose |
28+
|---|---|
29+
| `--add-endpoint <SPEC>` | Add or merge one endpoint and its declared binary scope. Repeat for multiple endpoints. |
30+
| `--remove-endpoint <HOST:PORT>` | Remove the host and port match from every authored network rule. A multi-port endpoint keeps its other ports. |
31+
| `--remove-rule <NAME>` | Remove a complete named `network_policies` entry. |
32+
| `--add-allow <SPEC>` | Append a REST or WebSocket method and path allow rule. |
33+
| `--add-deny <SPEC>` | Append a REST or WebSocket method and path deny rule. |
34+
| `--binary <PATH>` | Add binaries with endpoints, or declare the complete stored binary scope for an L7 append. Repeat as needed. |
35+
| `--rule-name <NAME>` | Name one new endpoint rule or select the existing rule for an L7 append. Required for `--add-allow` and `--add-deny`. |
36+
| `--any-binary` | Declare that the existing L7 target stores an empty binary scope. Cannot be combined with `--binary`. |
37+
| `--endpoint-path <PATH>` | Select one existing endpoint by its exact stored path. Pass `''` to select no path. |
38+
| `--dry-run` | Fetch the current policy and preview the local merge without saving a revision. |
39+
| `--wait` | Poll for the submitted revision's result. Cannot be combined with `--dry-run`. |
40+
| `--timeout <SECONDS>` | Set the `--wait` timeout. Defaults to 60 seconds. |
41+
42+
`--any-binary` describes the target rule's stored merge scope. It is not an
43+
independent claim that every runtime identity mode admits every process. Prefer
44+
explicit binary paths in authored rules and introductory workflows.
45+
46+
## Endpoint Specification
47+
48+
`--add-endpoint` uses this grammar:
49+
50+
```text
51+
host:port[:access[:protocol[:enforcement[:options]]]]
52+
```
53+
54+
| Segment | Accepted values and behavior |
55+
|---|---|
56+
| `host` | Required destination hostname. |
57+
| `port` | Required integer from 1 through 65535. |
58+
| `access` | `read-only`, `read-write`, or `full` for inspected endpoints. |
59+
| `protocol` | `tcp`, `rest`, `websocket`, or `sql`. Use full policy YAML for GraphQL, MCP, and JSON-RPC. |
60+
| `enforcement` | `enforce` or `audit`. Omission selects audit for inspected requests. |
61+
| `options` | Comma-separated options listed below. |
62+
63+
Endpoint options are:
64+
65+
| Option | Effect |
66+
|---|---|
67+
| `allowed-ip=<CIDR-or-IP>` | Add a destination IP allowance. Repeat the option in the comma-separated list for multiple values. |
68+
| `request-body-credential-rewrite` | Rewrite supported credential placeholders in inspected REST text bodies. |
69+
| `websocket-credential-rewrite` | Rewrite supported placeholders in client WebSocket text messages on REST compatibility or WebSocket endpoints. |
70+
| `allow-uninspected-credentials` | Accept the security-sensitive exposure of provider credentials on an uninspected traffic path. |
71+
72+
Read-only HTTP access for curl:
73+
74+
```shell
75+
openshell policy update my-sandbox \
76+
--rule-name github_readonly \
77+
--binary /usr/bin/curl \
78+
--add-endpoint api.github.com:443:read-only:rest:enforce \
79+
--wait
80+
```
81+
82+
Native PostgreSQL access for psql:
83+
84+
```shell
85+
openshell policy update my-sandbox \
86+
--rule-name postgres \
87+
--binary /usr/bin/psql \
88+
--add-endpoint db.internal.example:5432::tcp \
89+
--wait
90+
```
91+
92+
Read-only access to an internal HTTP API with an explicit destination IP allowance:
93+
94+
```shell
95+
openshell policy update my-sandbox \
96+
--rule-name private_api \
97+
--binary /usr/bin/curl \
98+
--add-endpoint 'api.internal.example:443:read-only:rest:enforce:allowed-ip=10.20.0.0/16' \
99+
--wait
100+
```
101+
102+
The empty access segment before `tcp` is required by the positional grammar.
103+
`protocol: tcp` rejects access, enforcement, and application-inspection options.
104+
The standard runtime initializes policy DNS and transparent capture before the
105+
workload starts, so a live update can add the first TCP endpoint. An alternate
106+
backend must advertise the required capability and a ready substrate.
107+
108+
An inspected REST or WebSocket endpoint needs an allow shape. For incremental
109+
creation, supply an access preset. Create the endpoint in one command, then add
110+
explicit allow or deny rules in a separate command.
111+
112+
## L7 Rule Specification
113+
114+
`--add-allow` and `--add-deny` use this grammar:
115+
116+
```text
117+
host:port[,port...]:METHOD:path_glob
118+
```
119+
120+
The host, complete port set, rule name, complete binary set, and optional
121+
endpoint path identify one existing REST or WebSocket endpoint. These flags do
122+
not create an endpoint or change its scope.
123+
124+
Quote specifications that contain `*`, `**`, `?`, or bracket classes. Request
125+
path globs are not shell path globs. Both `*` and `**` can cross `/` boundaries,
126+
`?` matches one character, and bracket classes are supported.
127+
128+
The following examples target an existing `github_api` rule whose only binary
129+
is `/usr/bin/gh` and whose REST endpoint is `api.github.com:443`. An allow append
130+
permits POST requests to issue-creation paths:
131+
132+
```shell
133+
openshell policy update my-sandbox \
134+
--rule-name github_api \
135+
--binary /usr/bin/gh \
136+
--add-allow 'api.github.com:443:POST:/repos/*/issues' \
137+
--wait
138+
```
139+
140+
A deny append blocks POST requests to administration paths on that endpoint:
141+
142+
```shell
143+
openshell policy update my-sandbox \
144+
--rule-name github_api \
145+
--binary /usr/bin/gh \
146+
--add-deny 'api.github.com:443:POST:/admin/**' \
147+
--wait
148+
```
149+
150+
For an existing `realtime` rule with only `/usr/bin/node` and a WebSocket
151+
endpoint at `realtime.example.com:443`, a text-message deny uses the
152+
`WEBSOCKET_TEXT` method. The path matches the stored upgrade request path, not
153+
message content:
154+
155+
```shell
156+
openshell policy update my-sandbox \
157+
--rule-name realtime \
158+
--binary /usr/bin/node \
159+
--add-deny 'realtime.example.com:443:WEBSOCKET_TEXT:/v1/admin/**' \
160+
--wait
161+
```
162+
163+
Use `--endpoint-path` when a rule contains multiple endpoints with the same host
164+
and ports. This selector identifies the endpoint. It is separate from the
165+
request path appended by `--add-allow` or `--add-deny`.
166+
167+
## Complete Scope Requirements
168+
169+
A network rule grants each listed binary access to each listed endpoint and
170+
port, subject to application rules and other checks. A rule with two binaries
171+
and two endpoints therefore includes four connection pairs:
172+
173+
| Binary | Endpoint |
174+
|---|---|
175+
| `/usr/bin/curl` | `api.example.com:443` |
176+
| `/usr/bin/curl` | `uploads.example.com:443` |
177+
| `/usr/bin/python3` | `api.example.com:443` |
178+
| `/usr/bin/python3` | `uploads.example.com:443` |
179+
180+
If Python should reach only `api.example.com`, put that binary and endpoint in a
181+
separate rule. Adding Python to the original rule would also authorize the
182+
uploads endpoint.
183+
184+
The CLI requires complete affected scope for L7 appends and for endpoint merges
185+
that could create new pairs. For example, an endpoint that stores ports 443 and
186+
8443 must be targeted with `443,8443`, even if the new method was observed only
187+
on 443. Likewise, repeat every stored binary path or use `--any-binary` only
188+
when the stored rule actually has an empty binary list.
189+
190+
Inspect the stored base before composing an append:
191+
192+
```shell
193+
openshell policy get my-sandbox --base
194+
```
195+
196+
Copy the rule name, binary paths, endpoint path, and complete port set from that
197+
view. Do not derive merge scope from `--full` when provider-owned rules are
198+
present; those rules are not part of the sandbox base you can incrementally
199+
edit.
200+
201+
The gateway rejects incomplete or ambiguous declarations before revision
202+
persistence. Read the reported expected scope and correct the command. Do not
203+
fill scope mechanically without confirming that the broader effect matches your
204+
intent.
205+
206+
## Remove Permissions
207+
208+
Preview endpoint removal before applying it because `--remove-endpoint` is not
209+
scoped by `--rule-name`. It removes the matching host and port from every
210+
authored network rule:
211+
212+
```shell
213+
openshell policy update my-sandbox \
214+
--remove-endpoint api.example.com:443 \
215+
--dry-run
216+
217+
openshell policy update my-sandbox \
218+
--remove-endpoint api.example.com:443 \
219+
--wait
220+
```
221+
222+
To remove one named rule instead:
223+
224+
```shell
225+
openshell policy update my-sandbox \
226+
--remove-rule github_readonly \
227+
--wait
228+
```
229+
230+
Removing an endpoint from a multi-port endpoint removes only the named port.
231+
When removal leaves an endpoint with no ports, OpenShell removes that endpoint.
232+
When a rule loses its final endpoint, OpenShell removes the rule instead of
233+
retaining an empty entry. Use `--remove-rule` when you intend to remove one
234+
specific map entry, and inspect the resulting base policy after either command.
235+
236+
## Preview a Merge
237+
238+
`--dry-run` shows the proposed policy without saving it. For example, this
239+
command previews a request-rule change to an existing `github_api` rule with
240+
only `/usr/bin/gh` and a REST endpoint at `api.github.com:443`:
241+
242+
```shell
243+
openshell policy update my-sandbox \
244+
--rule-name github_api \
245+
--binary /usr/bin/gh \
246+
--add-allow 'api.github.com:443:GET:/repos/**' \
247+
--dry-run
248+
```
249+
250+
The command validates argument shapes, connects to the gateway, fetches the
251+
current sandbox configuration, and applies the merge locally. It creates no
252+
revision. An unavailable gateway therefore causes a connection failure. The
253+
preview does not establish that a later submission will pass every effective
254+
policy, provider, credential, or runtime validation.
255+
256+
## Merge and Concurrency Behavior
257+
258+
All compatible flags in one command form one atomic batch. They succeed or fail
259+
together and persist at most one revision. `--add-endpoint` cannot share a batch
260+
with `--add-allow` or `--add-deny` because their scope flags have different
261+
meanings.
262+
263+
Concurrent writers use optimistic retry. The gateway reapplies the complete
264+
operation batch to the latest revision and validates the result again. A no-op
265+
merge reports an unchanged version and creates no revision.
266+
267+
Rule names identify stored map entries for update and removal. The optional
268+
human-readable `name` inside a YAML rule is not the `--rule-name` selector when
269+
the two differ. Use the map key shown by `policy get --base`.
270+
271+
Incremental updates are unavailable while a gateway-global policy is active.
272+
Delete the global override through the operator workflow before changing a
273+
sandbox policy.
274+
275+
## Wait and Status Semantics
276+
277+
Without `--wait`, success means the gateway accepted the submission. It does not
278+
mean the supervisor activated it.
279+
280+
With `--wait`, the CLI polls until it observes a terminal outcome or timeout. A
281+
zero exit can represent a loaded revision, a no-op, or a revision superseded by
282+
another update. Always inspect current state before relying on the change:
283+
284+
```shell
285+
openshell policy list my-sandbox
286+
openshell policy get my-sandbox --full
287+
```
288+
289+
A wait timeout means the CLI stopped polling. It does not establish whether the
290+
revision later loaded or failed. Inspect revision status and sandbox readiness
291+
before resubmitting, because an automatic retry can race with a late result.
292+
293+
## Full Replacement
294+
295+
`openshell policy set` handles middleware changes, advanced protocol shapes, and complete
296+
replacement. Start from the current base and preserve sections you do not intend
297+
to change. Follow [Replace the
298+
Policy](/sandboxes/policies#replace-the-policy) to prepare an editable
299+
YAML file using the CLI's readable output.
300+
301+
For automation, the following alternative uses `jq` on the host to extract the
302+
base policy without display metadata or provider-owned rules:
303+
304+
```shell
305+
set -o pipefail
306+
openshell policy get my-sandbox --base --output json \
307+
| jq -e '.policy' > base-policy.json
308+
```
309+
310+
Edit `base-policy.json`, then submit the complete policy:
311+
312+
```shell
313+
openshell policy set my-sandbox --policy base-policy.json --wait
314+
```
315+
316+
Refer to [Inspect the Current Policy](/sandboxes/policies#inspect-the-current-policy)
317+
for effective export, and use
318+
[Troubleshoot Sandbox Policies](/sandboxes/troubleshoot-policies) when submission
319+
and activation results differ.

0 commit comments

Comments
 (0)