Skip to content

feat(policy): add deny rules to network policy schema#822

Merged
johntmyers merged 2 commits intomainfrom
feat/565-deny-rules/jomyers
Apr 15, 2026
Merged

feat(policy): add deny rules to network policy schema#822
johntmyers merged 2 commits intomainfrom
feat/565-deny-rules/jomyers

Conversation

@johntmyers
Copy link
Copy Markdown
Collaborator

🏗️ build-from-issue-agent

Summary

Add L7 deny rules to the network policy schema, enabling the "allow everything except these specific operations" pattern. Deny rules mirror the full capability set of allow rules (method, path, query params, SQL command) and take precedence -- if a request matches any deny rule, it is blocked regardless of allow rules.

Related Issue

Closes #565

Changes

  • proto/sandbox.proto: Add L7DenyRule message (mirrors L7Allow) and deny_rules repeated field on NetworkEndpoint
  • crates/openshell-policy/src/lib.rs: Add L7DenyRuleDef serde struct with full parity (method, path, command, query), add deny_rules field to NetworkEndpointDef, wire up bidirectional to_proto/from_proto conversions
  • crates/openshell-sandbox/src/opa.rs: Pass deny_rules (including query matchers) through to Rego in proto_to_opa_data_json
  • crates/openshell-sandbox/src/l7/mod.rs: Validate deny_rules in validate_l7_policies -- require protocol, validate method/path/command/query, check glob syntax, reject empty lists
  • crates/openshell-sandbox/data/sandbox-policy.rego: Add deny_request rule that reuses existing matchers (method_matches, path_matches, query_params_match, command_matches). Modify allow_request to check not deny_request. Add deny-specific request_deny_reason. Separate deny_query_params_match for deny-side query evaluation
  • docs/reference/policy-schema.mdx: Document deny rules -- add to endpoint object table, add Deny Rule Object section with field table and example
  • .agents/skills/generate-sandbox-policy/SKILL.md: Add deny rules section with guidance on when to use deny rules vs explicit allow rules

Deviations from Plan

None -- implemented as planned.

Testing

  • cargo fmt --check passes
  • cargo clippy passes (no new warnings)
  • Unit tests added/updated
  • E2E tests: N/A (policy schema change, fully testable via unit tests)

Tests added:

  • Unit (openshell-policy): 4 tests -- parse deny rules from YAML, round-trip preserves deny rules (including query matchers), parse deny rules with query.any, reject unknown fields in deny rule
  • Unit (openshell-sandbox, Rego): 10 tests -- deny rule blocks allowed method+path, allows non-matching requests, allows same method on different path, blocks wildcard method, blocks PUT to protection, deny reason populated, deny with query blocks matching params, deny with query allows non-matching params, deny without matching query key allows

Checklist

  • Follows Conventional Commits
  • Architecture docs updated (docs + skill)

Closes #565

Add L7 deny rules that block specific requests even when allowed by
access presets or explicit allow rules. Deny rules mirror the full
capability set of allow rules (method, path, query params, SQL command)
and take precedence -- if a request matches any deny rule, it is blocked
regardless of allow rules.

This enables the "allow everything except these specific operations"
pattern without enumerating every allowed endpoint. For example, granting
read-write access to GitHub while blocking PR approvals, branch
protection changes, and ruleset modifications.
@johntmyers johntmyers requested a review from a team as a code owner April 13, 2026 19:47
@johntmyers johntmyers self-assigned this Apr 13, 2026
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented Apr 13, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions
Copy link
Copy Markdown

…dation

Addresses PR review findings P1 and P3:

P1: Deny-side query matching now uses fail-closed semantics. If ANY
value for a query key matches the deny matcher, the deny fires. The
previous implementation reused allow-side "all values must match"
logic which allowed ?force=true&force=false to bypass a deny on
force=true.

P3: Deny-side query validation now mirrors the full allow-side checks:
empty any lists, non-string matcher values, glob+any mutual exclusion,
glob type checks, and glob syntax warnings are all validated.
@johntmyers johntmyers merged commit 28e1ff7 into main Apr 15, 2026
10 checks passed
@johntmyers johntmyers deleted the feat/565-deny-rules/jomyers branch April 15, 2026 04:52
ericksoa pushed a commit to NVIDIA/NemoClaw that referenced this pull request Apr 23, 2026
## Summary
Bumps the pinned OpenShell version range from `0.0.29` → `0.0.32` so
fresh NemoClaw installs pick up sandbox hardening and TLS improvements
from the last three OpenShell releases.

## Notable upstream changes

**0.0.30**
([NVIDIA/OpenShell@v0.0.29...v0.0.30](NVIDIA/OpenShell@v0.0.29...v0.0.30))
- Network policy deny rules
([OpenShell#822](NVIDIA/OpenShell#822))
- Preserve ownership on existing `read_write` paths
([OpenShell#827](NVIDIA/OpenShell#827))
- Disable child core dumps
([OpenShell#821](NVIDIA/OpenShell#821))
- Escape control characters in SSE error formatting
([OpenShell#842](NVIDIA/OpenShell#842))
- Fix silent truncation of large streaming inference responses
([OpenShell#834](NVIDIA/OpenShell#834))

**0.0.31**
([NVIDIA/OpenShell@v0.0.30...v0.0.31](NVIDIA/OpenShell@v0.0.30...v0.0.31))
- Inference routed-request header allowlist
([OpenShell#826](NVIDIA/OpenShell#826))

**0.0.32**
([NVIDIA/OpenShell@v0.0.31...v0.0.32](NVIDIA/OpenShell@v0.0.31...v0.0.32))
- **Load system CA certificates for upstream TLS connections**
([OpenShell#862](NVIDIA/OpenShell#862))
- Publish standalone `openshell-gateway` binaries
([OpenShell#853](NVIDIA/OpenShell#853))

## Changes
- `nemoclaw-blueprint/blueprint.yaml`: `min_openshell_version` and
`max_openshell_version` → `0.0.32`
- `scripts/install-openshell.sh`: `MIN_VERSION` and `MAX_VERSION` →
`0.0.32` (`PIN_VERSION` follows `MAX`)
- `scripts/brev-launchable-ci-cpu.sh`: default `OPENSHELL_VERSION` →
`v0.0.32`
- `src/lib/onboard.ts`: blueprint-fallback min version → `0.0.32`
- `test/onboard.test.ts`,
`test/install-openshell-version-check.test.ts`: fixtures updated; "above
MAX" test case moved from `0.0.30` to `0.0.33`

Historical `m-dev` comments referencing `0.0.29` left in place — they
describe a self-report quirk the sidecar fallback still handles.

## Why not 0.0.33+?
`0.0.34` introduced incremental sandbox policy updates and L7
request-target canonicalization — changes with larger surface area
against how NemoClaw delivers policy via gRPC. Worth a follow-up PR
rather than bundling here. `0.0.35` released hours before this PR was
cut — too fresh.

## Type of Change
- [x] Code change for a new feature, bug fix, or refactor.

## Testing
- [x] `npx vitest run test/install-openshell-version-check.test.ts` — 9
passed
- [x] pre-commit hooks (prek) clean: shellcheck, commitlint, gitleaks,
YAML validator, CLI test suite
- [ ] Nightly E2E on this branch — will be kicked off after PR opens

## Notes
- No user-facing CLI behavior changes — just the pinned version range.
- Two pre-existing failures in `test/onboard.test.ts` reproduce on clean
`main` and are unrelated to this bump.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Updated OpenShell version constraints and default pinned version to
v0.0.32 across configuration, install, and onboarding flows.

* **Tests**
* Updated test fixtures and expectations to match the new OpenShell
version (v0.0.32).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

deny rules in network policy schema

2 participants