Generate sandbox security policies from plain-language requirements and optional REST API documentation. At minimum, takes API host:port endpoints and intent to produce preset-based or L4 policies. With full API docs (OpenAPI, Swagger, markdown), generates fine-grained per-endpoint L7 rules. Trigger keywords - generate policy, create policy, update policy, change policy, sandbox policy, network policy, API policy, security policy, allow API, restrict API.
Generate YAML sandbox network policies from REST API documentation and natural-language user requirements.
This skill translates a user's plain-language policy intent into a valid sandbox policy. The amount of detail the user provides determines the granularity of the generated policy — from broad L4 or preset-based policies (just a host:port) up to fine-grained per-endpoint L7 rules (full API docs).
The output is a network_policies YAML block (and optionally a full policy file) that conforms to the sandbox policy schema.
The user's input falls into one of three tiers. Work with whatever the user provides — do not require a higher tier than needed.
| Tier | User provides | What you can generate |
|---|---|---|
| Minimal | Host(s) and plain-language intent | L4-only policies, or L7 with access presets (, , ) |
read-onlyread-writefull| Moderate | Host(s) + some known URL paths or resources | L7 with targeted glob rules for known paths, presets for the rest |
| Full | Complete API docs (OpenAPI, Swagger, markdown, URL) | Fine-grained per-endpoint L7 rules with specific method+path combinations |
The user provides API endpoints and a broad intent. No API docs needed.
Examples:
This is sufficient for:
read-only, read-write, full on all paths)For this tier, default to:
access: read-only when the user says "read", "browse", "view", "query", "fetch"access: read-write when the user says "read-write", "create", "update" (but not "delete")access: full when the user says "full access", "everything", "unrestricted"protocol) when the user says "just allow it", "pass through", "no inspection"The user knows some API paths but doesn't have full docs.
Examples:
Generate explicit rules for the known paths. If the user also wants broader access beyond the specific paths, combine with a catch-all rule or suggest a preset instead.
The user provides full API documentation. Accepted formats:
| Format | How to consume |
|---|---|
| URL | Fetch with WebFetch and parse the endpoint list |
| File path | Read the file (OpenAPI JSON/YAML, markdown, etc.) |
| Pasted text | Parse inline from the conversation |
| OpenAPI/Swagger spec | Extract paths object for all method+path combinations |
From the API docs, build an endpoint inventory — a list of (method, path, description) tuples. Group them logically (e.g., by resource or tag). Then generate precise rules that allow only what the user's intent requires.
Regardless of tier, extract (or infer) these from the user's description:
| Aspect | What to identify | Required? |
|---|---|---|
| Scope | Which API host(s) and port(s) | Yes — always needed |
| Access level | Broad intent: read-only, read-write, full, or custom | Yes — ask if unclear |
| Methods | Specific HTTP methods to allow | Only for custom/fine-grained |
| Paths | Specific URL paths or patterns | Only for custom/fine-grained |
| Enforcement | enforce or audit? Default to enforce. | No — has a default |
| Binary | Which binary/process should have access | Yes — ask if not stated |
If the host and access level are clear but binaries are not specified, ask the user which binary or process will be making the requests. Suggest common defaults like /usr/bin/curl, /usr/local/bin/claude, etc.
Before generating the policy, proactively ask clarifying questions to help the user scope the policy down as narrowly as possible. The goal is the most restrictive policy that still satisfies the user's needs.
Always ask about these if the user hasn't already specified them:
| Missing info | Question to ask |
|---|---|
| Binary not specified | "Which binary or process will make these requests? (e.g., /usr/bin/curl, /usr/local/bin/claude)" |
| Port not specified | "Which port does this API use? (443 for HTTPS is typical)" |
| Enforcement not stated | "Should policy violations be blocked (enforce) or just logged for review (audit)? I'll default to enforce if you're not sure." |
Ask these when the user's intent is broad and more specificity is possible:
| User says | Ask to narrow |
|---|---|
| "Full access" / "allow everything" | "Do you actually need DELETE access, or would read-write (everything except DELETE) be enough?" |
| "Allow access to api.example.com" (no method/path detail) | "Do you know which specific API paths or operations you need? If so, I can lock the policy down to just those. Otherwise I'll use a broad preset." |
| L4-only / "just pass it through" | "L4-only means the proxy won't inspect HTTP traffic at all — any method and path will be allowed. Are you sure you don't want at least read-only or read-write restriction?" |
Wildcard binary (/usr/bin/*) | "A wildcard binary pattern means any binary in that directory can use this policy. Can you narrow it to specific binaries?" |
| Multiple hosts in one policy | "Do all of these hosts need the same access level? If some need tighter restrictions, I can split them into separate policies." |
access: full with enforcement: audit | "Full access in audit mode means nothing is actually restricted — all traffic flows through and violations are only logged. Is that intentional, or did you want to enforce restrictions?" |
** path glob on all rules | "Using ** on all paths allows any URL path. Do you know the specific API path prefixes you need (e.g., /api/v1/)?" |
| Private/internal IP destination | "Does this service resolve to a private IP (10.x, 172.16.x, 192.168.x)? If so, you'll need allowed_ips to permit access — what CIDR range should be allowed?" |
When the user mentions a recognizable API host but hasn't provided docs, and the current tier is Minimal, attempt to upgrade to Full by searching for the API documentation online.
When to trigger:
api.github.com, api.anthropic.com, api.openai.com, integrate.api.nvidia.com, api.stripe.com, api.slack.com, api.gitlab.com)How to do it:
WebSearch with a query like "[service name] REST API documentation endpoints" or "[service name] OpenAPI spec"WebFetch and extract the endpoint inventory (method + path pairs)When to skip:
Graceful fallback: If the search doesn't return usable API docs (results are irrelevant, docs are behind authentication, the page is too large to parse), fall back to the current tier without stalling. Say: "I couldn't find usable API docs for [host], so I'll generate the policy using a [preset/L4] approach. You can always provide docs later to tighten it."
If the user confirms the policy must stay broad (they don't know the paths, need genuinely broad access, etc.), accept it but flag the breadth. Do not block policy generation — just make sure the warnings are visible in the output (see Step 6).
You may need to go back and forth a few times. Keep the loop tight:
Do not over-interrogate. If the user has given a clear, specific request, skip clarification and go straight to generation. Only ask when there is genuine ambiguity or an opportunity to meaningfully reduce the attack surface.
Read the full policy schema reference:
Read architecture/security-policy.md
Key sections to reference:
network_policies — rule structureNetworkEndpoint fields — host, port, protocol, tls, enforcement, access, rules, allowed_ipsL7Rule / L7Allow — method + path matchingread-only, read-write, fullallowed_ips — CIDR allowlist for private IP spaceAlso read the example policy for real-world patterns. The default policy is baked into the community base image (ghcr.io/nvidia/openshell-community/sandboxes/base:latest). For reference, consult the policy schema documentation:
Read architecture/security-policy.md
Follow this decision tree based on the detail tier and user intent:
Is L7 inspection needed?
├─ No (user wants pass-through / "just allow it")
│ └─ Generate L4-only policy (no protocol, no tls, no rules/access)
│
└─ Yes (user wants method/path control)
│
├─ Does a preset match the intent exactly?
│ ├─ Read-only (GET, HEAD, OPTIONS) → access: read-only
│ ├─ Read-write (no DELETE) → access: read-write
│ └─ Everything → access: full
│
└─ No preset fits (specific paths, mixed broad+narrow, exclude certain paths)
└─ Build explicit rules list
└─ Requires either known paths from the user or full API docs
Principle: always choose the simplest representation that satisfies the intent. A preset is preferable to explicit rules when it covers the use case.
| API host port | TLS setting |
|---|---|
| Port 443 (HTTPS) and L7 rules/preset needed | tls: terminate (required for inspection) |
| Port 443 (HTTPS) and L4-only | Omit tls (passthrough, no L7) |
| Non-443 (HTTP) | Omit tls |
Critical: protocol: rest on port 443 without tls: terminate will not work — the proxy cannot inspect encrypted traffic. Always set tls: terminate when combining port 443 with L7 rules.
Only needed for the Moderate and Full tiers. Translate API path parameters to glob patterns:
| API path | Glob pattern |
|---|---|
/repos/{owner}/{repo} | /repos/*/* |
/repos/{owner}/{repo}/issues | /repos/*/issues |
/repos/{owner}/{repo}/issues/{id} | /repos/*/issues/* |
/api/v1/models/{model_id}/versions/{version} | /api/v1/models/*/versions/* |
All sub-paths under /api/v1/ | /api/v1/** |
Remember: * does not cross / boundaries. Use ** for recursive matching across path segments.
For each allowed operation, create an allow entry: