fix(supervisor-network): L7 endpoint validation edge cases - #2464
fix(supervisor-network): L7 endpoint validation edge cases#2464andrewwhitecdw wants to merge 5 commits into
Conversation
…orts validate_l7_policies assumed every endpoint entry was a JSON object and used ep.as_object_mut().unwrap() in expand_access_presets. A non-object endpoint would panic. Add an object-shape validation error and replace the unwraps with safe pattern matching. Also filter zero values out of the ports array to match the scalar port validation (which already rejects port == 0). Signed-off-by: Andrew White <andrewh@cdw.com>
…arser network_endpoint_from_json accepted port 0 from the ports array without filtering, creating an endpoint with no usable ports. Drop zero entries so the array behaves consistently with the scalar port field. Signed-off-by: Andrew White <andrewh@cdw.com>
|
I have read the DCO document and I hereby sign the DCO. |
johntmyers
left a comment
There was a problem hiding this comment.
gator-agent
PR Review Status
Validation: This is project-valid small, concentrated work in supervisor network-policy handling: it replaces a malformed-input panic with fail-closed validation and attempts to make zero-port handling consistent. No duplicate work was found.
Head SHA: 583f62ef7019a4c54b23fe91e6ef289c2ca02d4a
Review findings:
- One correctness issue is anchored inline: the raw-policy zero-port filter does not normalize the policy data later supplied to OPA, so mixed arrays still retain zero.
- Focused regression coverage is missing for all three changed contracts. Please add unit tests showing that a non-object endpoint reports the expected validation error and preset expansion remains panic-free; raw-policy
[0]and[0, 443]follow the intended contract; and agent proposals reject an all-zero array while retaining only positive entries from mixed arrays, including scalar fallback.
Docs: Fern docs are not needed for this malformed-input robustness fix; the existing policy reference already describes endpoint objects and concrete MCP ports.
E2E: The changed network-policy path requires test:e2e after review findings are resolved.
Next state: gator:in-review pending an author update.
| |arr| { | ||
| arr.iter() | ||
| .filter_map(serde_json::Value::as_u64) | ||
| .filter(|p| *p > 0) |
There was a problem hiding this comment.
gator-agent
Warning: This filters only a temporary vector whose sole consumer already checks any(|port| *port > 0). Consequently, [0] was already rejected, while [0, 443] still passes and the zero remains in the JSON supplied to OPA. Please either reject any zero-valued ports member or remove zeros during endpoint normalization/proto serialization, then cover all-zero and mixed arrays with regression tests.
There was a problem hiding this comment.
I will get to these later today thanks for raising this issue.
|
@andrewwhitecdw Several of your PRs are awaiting feedback, please let us know if you plan on looking so we can plan accordingly |
…ion tests Addresses gator-agent review feedback on NVIDIA#2464: - Filter zero values from endpoint ports arrays in normalize_endpoint_ports so OPA never sees a zero port. - Promote positive scalar port to ports array; leave all-zero arrays empty. - Skip non-object endpoints during normalization instead of panicking. - Add regression tests for non-object endpoint validation, zero-port filtering, and scalar fallback. Signed-off-by: Andrew White <andrewh@cdw.com>
johntmyers
left a comment
There was a problem hiding this comment.
gator-agent
PR Review Status
Validation: This remains project-valid small, concentrated robustness work in supervisor network-policy handling.
Head SHA: 200ecd2f0444b5ef60d33c2332990c546e521dc5
Thanks @andrewwhitecdw. I checked the update you pushed after the earlier zero-port normalization and test feedback. The raw-YAML mixed-array case is now normalized and the added helper tests cover that path, but the production proto load/reload path still bypasses the new normalizer.
Review findings:
- One critical correctness/security-boundary issue is anchored inline: zero ports still reach OPA through
OpaEngine::from_proto. - One warning is anchored inline: the separate agent-proposal parser behavior still needs focused regression coverage.
Docs: Fern docs are not needed because this hardens malformed input without changing supported policy syntax or commands.
E2E: The network-policy path still requires test:e2e after review findings are resolved.
Next state: gator:in-review pending an author update.
| // If "ports" already exists, filter out zero values so OPA never | ||
| // sees a zero port. An all-zero array becomes empty and falls back | ||
| // to scalar "port" promotion below. | ||
| if let Some(ports) = ep_obj.get_mut("ports").and_then(|v| v.as_array_mut()) { |
There was a problem hiding this comment.
gator-agent
Critical (CWE-20): This normalizer runs only from preprocess_yaml_data; production OpaEngine::from_proto loads proto_to_opa_data_json without calling it. validate_l7_policies filters only a temporary vector, so a CLI policy with ports: [0, 443] still reaches OPA containing zero during normal sandbox load/reload. Please filter in proto_to_opa_data_json or apply shared normalization to proto-generated JSON, then add an OpaEngine::from_proto regression test.
| } | ||
|
|
||
| let mut ports = endpoint.ports; | ||
| ports.retain(|p| *p > 0); |
There was a problem hiding this comment.
gator-agent
Warning (CWE-20): This changes the untrusted agent-proposal parser without testing that path. Please add proposal_chunks_from_body cases for mixed [0, 443], zero-only [0] rejection, and [0] with positive scalar fallback, asserting the resulting proto port and ports. The new OPA helper tests cannot protect this separate parser.
|
Thanks for the nudge — I’ve gone through all five open PRs:
All relevant test suites pass. Please re-review when you have a chance. |
…arser tests proto_to_opa_data_json cloned e.ports unfiltered, so a policy with ports: [0, 443] still reached OPA with the zero even though the YAML preprocess path normalized it. Filter zero ports in the production path the same way (mixed arrays drop zeros, zero-only arrays fall back to a positive scalar port, zero scalar port is not promoted). Add tests: - proto_to_opa_data_json_filters_zero_ports_in_production_path - proposal_chunks_from_body_filters_mixed_zero_ports - proposal_chunks_from_body_rejects_zero_only_ports - proposal_chunks_from_body_zero_ports_falls_back_to_scalar_port cargo test -p openshell-supervisor-network --lib: 977 passed. Signed-off-by: Andrew White <andrewh@cdw.com>
|
Both review items addressed:
Verified: |
johntmyers
left a comment
There was a problem hiding this comment.
gator-agent
PR Review Status
Validation: This remains project-valid small, concentrated robustness work in supervisor network-policy handling.
Head SHA: ed4a4b63649a5857e2405a8f72bbb62f99a93282
Thanks @andrewwhitecdw. I checked your update about filtering zero ports in the production proto-to-OPA path and adding focused proposal-parser coverage. Those prior gaps are addressed, but the independent review found two remaining normalization cases that can reinterpret malformed or zero-only authorization input as a scalar-port allow; both are anchored inline. A focused preset-expansion regression gap is also anchored inline.
Review findings:
- Two blocking CWE-20 warnings are anchored inline: malformed JSON array elements can be discarded before scalar fallback, and zero-only proto arrays can activate a shadowed scalar despite documented
portsprecedence. - One focused test gap is anchored inline for the removed
expand_access_presetsunwraps.
Docs: Fern docs are not needed for the intended malformed-input robustness fix. If scalar fallback for an explicitly present zero-only ports array is intentional, the schema and proto precedence contract would need updating.
E2E: The network-policy path still requires test:e2e after review findings are resolved.
Next state: gator:in-review pending an author update.
| // sees a zero port. An all-zero array becomes empty and falls back | ||
| // to scalar "port" promotion below. | ||
| if let Some(ports) = ep_obj.get_mut("ports").and_then(|v| v.as_array_mut()) { | ||
| ports.retain(|p| p.as_u64().is_some_and(|n| n > 0)); |
There was a problem hiding this comment.
gator-agent
Warning (CWE-20): retain removes every value that is not a positive JSON u64, not only zero. In local-file mode, ports: ["443"] plus port: 8443 therefore becomes ports: [8443], silently converting malformed authorization input into an allow. Please reject non-integer entries before normalization, or remove exactly numeric zero (p.as_u64() != Some(0)) so malformed arrays remain fail-closed. Add a regression case.
| // never sees them, then ports takes precedence over a | ||
| // single promoted port. Rego always sees "ports". | ||
| let filtered: Vec<u32> = e.ports.iter().copied().filter(|&p| p > 0).collect(); | ||
| let ports: Vec<u32> = if !filtered.is_empty() { |
There was a problem hiding this comment.
gator-agent
Warning (CWE-20): This changes the documented proto precedence: {port: 8080, ports: [0]} now permits 8080, although a present ports array previously took precedence and matched nothing. Malformed or zero-only authorization data should not activate a shadowed scalar port. Branch on the original e.ports.is_empty() state and filter inside the ports branch, or reject the proto explicitly; then update the scalar-fallback test.
| use super::*; | ||
|
|
||
| #[test] | ||
| fn validate_l7_policies_rejects_non_object_endpoint() { |
There was a problem hiding this comment.
gator-agent
Suggestion: This test verifies validation, but not expand_access_presets, where the unwraps were removed. Please add a direct expansion test containing a non-object endpoint and a valid preset endpoint, asserting the invalid entry remains unchanged and the valid preset expands. It would also be stronger to assert indexed errors for both malformed entries.
Author Follow-Up NudgeThis PR has been in @andrewwhitecdw, please respond to the two blocking review comments about malformed array elements and zero-only proto-array precedence, or push an update. If this is no longer planned, please say so and a maintainer can close it out. |
1 similar comment
Author Follow-Up NudgeThis PR has been in @andrewwhitecdw, please respond to the two blocking review comments about malformed array elements and zero-only proto-array precedence, or push an update. If this is no longer planned, please say so and a maintainer can close it out. |
…zation - Preserve proto precedence: a present "ports" array takes precedence over scalar "port", even when filtering leaves only zeros. - Keep non-numeric "ports" entries intact during YAML normalization so malformed arrays fail closed instead of being silently dropped. - Add regression tests for mixed/zero-only port arrays, malformed entries, and expand_access_presets with non-object endpoints. Signed-off-by: Andrew White <andrewwhitecdw@users.noreply.github.com>
96d1085 to
805f189
Compare
|
/ok to test 805f189 |
johntmyers
left a comment
There was a problem hiding this comment.
gator-agent
PR Review Status
Validation: This remains project-valid small, concentrated robustness work in supervisor network-policy handling.
Head SHA: 805f189c9a35f241bcbf3395bbd0cea1bfaa5d7a
Base SHA: 0c7e59a95355cabc15ccaddb86fcbe6a1d30eaaa
Merge base SHA: 21da343c9f838bd9ac85dc61bf44889de1a72873
Patch ID: d8044cf19d18d7dd4ad2547d4467f81feea7a843
Gator payload: 3
Review mode: follow_up
Previous reviewed SHA: ed4a4b63649a5857e2405a8f72bbb62f99a93282
Thanks @andrewwhitecdw. I checked the update pushed after the malformed-array and zero-only proto-array feedback. The raw-policy normalizer now preserves malformed non-numeric entries for fail-closed validation, the proto conversion preserves explicit ports precedence, and focused regression coverage now exercises both cases plus preset expansion with a non-object endpoint.
Blocking findings:
- No blocking findings remain.
Carried findings:
gator-inline-3679152284: resolved by preserving non-numeric array entries through normalization.gator-inline-3679152285: resolved by branching on whether the original protoportsarray is present.
Docs: Fern docs are not needed because this hardens malformed input without changing supported policy syntax or user workflows.
E2E: test:e2e is applied. The mirror was absent, so an authorized maintainer command /ok to test 805f189c9a35f241bcbf3395bbd0cea1bfaa5d7a was posted.
Next state: gator:watch-pipeline
|
Label |
|
/ok to test 805f189 |
Summary
Two small robustness fixes in L7 network policy handling:
validate_l7_policiesassumed every entry innetwork_policies.<name>.endpointswas a JSON object, andexpand_access_presetscalledep.as_object_mut().unwrap(). A malformed non-object endpoint caused a panic. This change adds an object-shape validation error and replaces the unwraps with safe pattern matching.portfield was already validated to be> 0, but theportsarray accepted0values silently. The same inconsistency existed in the agent-proposal endpoint parser. Both paths now filter out zero ports.Related Issue
N/A — small fixes found during code review.
Changes
l7/mod.rs: validate endpoint is an object; replaceas_object_mut().unwrap()with safe matching; filterportsarray to> 0policy_local.rs: filter zero entries fromendpoint.portsTesting
mise run pre-commitpasses (mise unavailable in this environment; ran equivalentcargo fmt+cargo clippy -p openshell-supervisor-network --all-targets— clean)cargo test -p openshell-supervisor-network --lib— 969 passed)Checklist