Skip to content

refactor(policy): extract shared L7 endpoint validation - #4

Draft
gracesmith6504 wants to merge 1 commit into
mainfrom
fix/1714-shared-l7-validation
Draft

refactor(policy): extract shared L7 endpoint validation#4
gracesmith6504 wants to merge 1 commit into
mainfrom
fix/1714-shared-l7-validation

Conversation

@gracesmith6504

@gracesmith6504 gracesmith6504 commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Summary

Extract 9 L7 endpoint semantic checks into a shared validate_l7_endpoint_semantics() function in openshell-policy. Both profile lint (openshell-providers) and the runtime validator (openshell-supervisor-network) now call the shared function via a lightweight L7EndpointFields field bag, eliminating duplication and preventing drift. Also consolidates the L7Protocol enum into a single definition in openshell-policy.

Related Issue

Fixes NVIDIA#1714

Changes

  • New shared validation module crates/openshell-policy/src/l7_validate.rs with L7Protocol enum, L7EndpointFields struct, validate_l7_endpoint_semantics() function, and 15 unit tests
  • Re-export shared validation types from crates/openshell-policy/src/lib.rs
  • Add openshell-policy dependency to crates/openshell-providers/Cargo.toml
  • Replace inline L7 checks with shared function call in crates/openshell-providers/src/profiles.rs; add 5 integration tests
  • Delete duplicate L7Protocol enum from crates/openshell-supervisor-network/src/l7/mod.rs, import and re-export from openshell-policy; replace 9 duplicated checks with shared function call; align rules_would_deny_all computation
  • Fix 4 test fixtures in crates/openshell-server/src/grpc/policy.rs and provider.rs: add access: "full" to endpoints with protocol

Testing

  • mise run pre-commit passes
  • Unit tests added/updated
  • E2E tests added/updated (if applicable)

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated (if applicable)

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 805200c5-1be3-4299-8e6b-ac4794140e62

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds shared L7 endpoint semantic validation to the policy crate, integrates it into provider profile and supervisor validation, and updates affected endpoint test fixtures with explicit access values.

Changes

L7 Semantic Validation

Layer / File(s) Summary
Shared validator contract and rules
crates/openshell-policy/src/*
Defines public protocol and endpoint validation types, implements consistency checks, re-exports the API, and tests each major validation rule.
Provider profile validation integration
crates/openshell-providers/Cargo.toml, crates/openshell-providers/src/profiles.rs
Maps profile endpoints into shared validation inputs, emits endpoint-scoped diagnostics, and updates profile round-trip and linting tests.
Supervisor validation migration and endpoint fixtures
crates/openshell-supervisor-network/src/l7/mod.rs, crates/openshell-server/src/grpc/*
Delegates supervisor endpoint semantics to the shared validator and adds explicit access: "full" values to affected server test fixtures.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ProfileSet
  participant validate_profile_set
  participant validate_l7_endpoint_semantics
  participant ProfileValidationDiagnostic
  ProfileSet->>validate_profile_set: validate endpoint shape
  validate_profile_set->>validate_l7_endpoint_semantics: pass L7EndpointFields
  validate_l7_endpoint_semantics-->>validate_profile_set: return semantic messages
  validate_profile_set->>ProfileValidationDiagnostic: emit endpoint-scoped errors
Loading

Possibly related PRs

  • gracesmith6504/OpenShell#2: Implements overlapping L7 endpoint semantic constraints before this PR centralizes them in the policy crate.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: extracting shared L7 endpoint validation into the policy crate.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/1714-shared-l7-validation

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
crates/openshell-policy/src/l7_validate.rs (1)

117-126: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate diagnostic for json-rpc without rules.

For protocol == "json-rpc" with no rules and no access, both rule 4 (requires explicit rules with allow.method) and rule 5 (protocol requires rules or access) fire — the same root cause reported twice. Rule 5 already excludes mcp from this double-count; json-rpc isn't excluded, producing redundant diagnostics that mcp doesn't suffer from.

♻️ Suggested fix
-    // 5. Non-MCP protocol requires rules or access
-    if !protocol.is_empty() && protocol != "mcp" && !ep.has_rules && ep.access.is_empty() {
+    // 5. Non-MCP, non-JSON-RPC protocol requires rules or access (JSON-RPC's
+    // dedicated message is emitted by rule 4).
+    if !protocol.is_empty() && protocol != "mcp" && protocol != "json-rpc" && !ep.has_rules && ep.access.is_empty() {
         errors.push("protocol requires rules or access to define allowed traffic".to_string());
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/openshell-policy/src/l7_validate.rs` around lines 117 - 126, Update
the rule-5 validation condition in the surrounding protocol validation logic to
exclude json-rpc when it has no rules, allowing rule 4 to remain the sole
diagnostic for that case while preserving rule 5 for other non-MCP protocols
without rules or access.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/openshell-policy/src/l7_validate.rs`:
- Around line 25-35: The MCP and JSON-RPC validation branches currently compare
the raw protocol string despite L7Protocol::parse being case-insensitive. Update
the checks in the surrounding validation logic to compare the parsed l7_protocol
enum against L7Protocol::Mcp and L7Protocol::JsonRpc, preserving correct
handling for mixed-case valid configurations.

In `@crates/openshell-supervisor-network/src/l7/mod.rs`:
- Around line 1039-1058: Update the rules_would_deny_all calculation in the
L7EndpointFields mapping to return true when the rules array is empty or when
every rule entry lacks an allow clause. Preserve the existing raw-JSON handling
and ensure the condition matches the L7EndpointFields contract and profiles.rs
mapping.

---

Nitpick comments:
In `@crates/openshell-policy/src/l7_validate.rs`:
- Around line 117-126: Update the rule-5 validation condition in the surrounding
protocol validation logic to exclude json-rpc when it has no rules, allowing
rule 4 to remain the sole diagnostic for that case while preserving rule 5 for
other non-MCP protocols without rules or access.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5d96a109-9f7a-49d3-a3e0-7807af1b4ff3

📥 Commits

Reviewing files that changed from the base of the PR and between 9a4f8a8 and d9510ee.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • crates/openshell-policy/src/l7_validate.rs
  • crates/openshell-policy/src/lib.rs
  • crates/openshell-providers/Cargo.toml
  • crates/openshell-providers/src/profiles.rs
  • crates/openshell-server/src/grpc/policy.rs
  • crates/openshell-server/src/grpc/provider.rs
  • crates/openshell-supervisor-network/src/l7/mod.rs

Comment thread crates/openshell-policy/src/l7_validate.rs
Comment thread crates/openshell-supervisor-network/src/l7/mod.rs
@gracesmith6504
gracesmith6504 force-pushed the fix/1714-shared-l7-validation branch from d9510ee to 4f07c2d Compare July 20, 2026 14:20
@gracesmith6504

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@gracesmith6504
gracesmith6504 force-pushed the fix/1714-shared-l7-validation branch from 4f07c2d to 4288256 Compare July 20, 2026 15:27
@gracesmith6504

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

let mut errors = Vec::new();
let protocol = ep.protocol;
let l7_protocol = if protocol.is_empty() {
None

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to check if protocol.is_empty() and return None if L7Protocol::parse(protocol) has match arm for it?

}

#[cfg(test)]
mod tests {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only testing lowercase, so case normalization is never tested

Comment on lines +86 to +87
let is_mcp = l7_protocol == Some(L7Protocol::Mcp);
let is_jsonrpc = l7_protocol == Some(L7Protocol::JsonRpc);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use matches! here wdyt?

Comment on lines +309 to +311
has_rules: false,
has_deny_rules: false,
rules_would_deny_all: true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible for this case to happen?

Comment on lines +101 to +122
// 3. JSON-RPC family cannot use access presets
if jsonrpc_family && !ep.access.is_empty() {
if is_mcp {
errors.push(format!(
"protocol {protocol} does not support access presets; \
use rules/deny_rules or set mcp.allow_all_known_mcp_methods: true \
for an allow-all MCP policy"
));
} else {
errors.push(format!(
"protocol {protocol} does not support access presets; \
use explicit rules with allow.method such as \"*\""
));
}
}

// 4. json-rpc requires explicit rules
if is_jsonrpc && !ep.has_rules {
errors.push(format!(
"protocol {protocol} requires explicit rules with allow.method"
));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor said:
Rule 4 fires redundantly when access is already set. For json-rpc + access: full + no rules, both rule 3 ("does not support access presets") and rule 4 ("requires explicit rules") fire — two errors pointing at
the same fix.

Rule 6 (MCP) already handles this correctly by gating on ep.access.is_empty(). Rule 4 should match:

  • if is_jsonrpc && !ep.has_rules {
  • if is_jsonrpc && !ep.has_rules && ep.access.is_empty() {

@gracesmith6504
gracesmith6504 force-pushed the fix/1714-shared-l7-validation branch from 4288256 to 73f81c6 Compare July 21, 2026 11:04
@gracesmith6504

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@gracesmith6504
gracesmith6504 force-pushed the fix/1714-shared-l7-validation branch 9 times, most recently from 1cac830 to 3be623a Compare July 23, 2026 07:19
Move L7 endpoint semantic checks into the openshell-policy crate so both
profile lint and the runtime validator share one implementation. This
eliminates drift between the two validation paths.

The shared validator covers 9 checks: unknown protocol, rules/access
mutual exclusivity, JSON-RPC family access rejection, json-rpc requires
rules, non-JSON-RPC protocol requires rules or access, MCP requires
rules when allow_all is false, rules-would-deny-all detection,
deny_rules require protocol, and deny_rules require base allow set.

Changes rules/deny_rules fields to Option<Vec<...>> so absent vs empty
is distinguishable at lint time. Adds is_effectively_empty() to
L7AllowProfile for deny-all detection of allow: {} objects. Makes
rules_would_deny_all MCP-aware by checking tool/params.name selectors
before classifying a rule as deny-all. Adds params field to
L7AllowProfile so MCP tool selectors survive proto round-trip.

Signed-off-by: Grace Smith <gsmith@redhat.com>
Signed-off-by: Grace Smith <grasmith@redhat.com>
@gracesmith6504
gracesmith6504 force-pushed the fix/1714-shared-l7-validation branch from 3be623a to 8bdd502 Compare July 24, 2026 10:22
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.

bug(providers): provider v2 profile lint does not validate L7 endpoint constraints (protocol/access/rules)

2 participants