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
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