Skip to content
31 changes: 25 additions & 6 deletions crates/openshell-supervisor-network/src/l7/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,11 @@ pub fn validate_l7_policies(data_json: &serde_json::Value) -> (Vec<String>, Vec<
};

for (i, ep) in endpoints.iter().enumerate() {
let loc = format!("{name}.endpoints[{i}]");
if !ep.is_object() {
errors.push(format!("{loc}: endpoint entry must be an object"));
continue;
}
let protocol = ep.get("protocol").and_then(|v| v.as_str()).unwrap_or("");
let l7_protocol = L7Protocol::parse(protocol);
let jsonrpc_family = l7_protocol.is_some_and(L7Protocol::is_jsonrpc_family);
Expand All @@ -986,9 +991,13 @@ pub fn validate_l7_policies(data_json: &serde_json::Value) -> (Vec<String>, Vec<
.into_iter()
.collect()
},
|arr| arr.iter().filter_map(serde_json::Value::as_u64).collect(),
|arr| {
arr.iter()
.filter_map(serde_json::Value::as_u64)
.filter(|p| *p > 0)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I will get to these later today thanks for raising this issue.

.collect()
},
);
let loc = format!("{name}.endpoints[{i}]");

if protocol == "mcp" {
if host.trim().is_empty() {
Expand Down Expand Up @@ -1557,7 +1566,13 @@ pub fn expand_access_presets(data: &mut serde_json::Value) -> Vec<String> {
&& !has_rules
&& mcp_allow_all_known_mcp_methods
{
ep.as_object_mut().unwrap().insert(
let Some(obj) = ep.as_object_mut() else {
warnings.push(format!(
"{name}.endpoints[{i}]: endpoint entry is not an object; skipping access preset expansion"
));
continue;
};
obj.insert(
"rules".to_string(),
serde_json::Value::Array(vec![jsonrpc_rule_json("*")]),
);
Expand All @@ -1582,9 +1597,13 @@ pub fn expand_access_presets(data: &mut serde_json::Value) -> Vec<String> {
continue;
};

ep.as_object_mut()
.unwrap()
.insert("rules".to_string(), serde_json::Value::Array(rules));
if let Some(obj) = ep.as_object_mut() {
obj.insert("rules".to_string(), serde_json::Value::Array(rules));
} else {
warnings.push(format!(
"{name}.endpoints[{i}]: endpoint entry is not an object; skipping access preset expansion"
));
}
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/openshell-supervisor-network/src/policy_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,7 @@ fn network_endpoint_from_json(
}

let mut ports = endpoint.ports;
ports.retain(|p| *p > 0);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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.

if ports.is_empty() && endpoint.port > 0 {
ports.push(endpoint.port);
}
Expand Down
Loading