Skip to content

Commit 398979a

Browse files
committed
fix(sandbox): allow HEAD where GET is permitted in L7 policy
RFC 9110 §9.3.2 defines HEAD as identical to GET except no response body. method_matches in sandbox-policy.rego rejected HEAD even when GET was explicitly allowed, breaking package managers that probe with HEAD before fetching. Signed-off-by: mesutoezdil <mesudozdil@gmail.com>
1 parent 1c31764 commit 398979a

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

crates/openshell-sandbox/data/sandbox-policy.rego

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,13 +526,19 @@ graphql_field_matches_any(field, patterns) if {
526526
}
527527

528528
# Wildcard "*" matches any method; otherwise case-insensitive exact match.
529+
# RFC 9110 §9.3.2: HEAD is semantically identical to GET except no response body.
529530
method_matches(_, "*") if true
530531

531532
method_matches(actual, expected) if {
532533
expected != "*"
533534
upper(actual) == upper(expected)
534535
}
535536

537+
method_matches(actual, expected) if {
538+
upper(actual) == "HEAD"
539+
upper(expected) == "GET"
540+
}
541+
536542
# Path matching: "**" matches everything; otherwise glob.match with "/" delimiter.
537543
#
538544
# INVARIANT: `input.request.path` is canonicalized by the sandbox before

crates/openshell-sandbox/src/opa.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4805,4 +4805,29 @@ network_policies:
48054805
decision.reason
48064806
);
48074807
}
4808+
4809+
#[test]
4810+
fn l7_head_allowed_where_get_is_allowed() {
4811+
let engine = l7_engine();
4812+
let input = l7_input("api.example.com", 8080, "HEAD", "/repos/myorg/foo");
4813+
assert!(eval_l7(&engine, &input));
4814+
}
4815+
4816+
#[test]
4817+
fn l7_head_denied_when_only_post_allowed() {
4818+
let engine = OpaEngine::from_strings(
4819+
TEST_POLICY,
4820+
"network_policies:\n p:\n name: p\n endpoints:\n - host: h.test\n port: 80\n protocol: rest\n enforcement: enforce\n rules:\n - allow: {method: POST, path: \"/\"}\n binaries:\n - {path: /bin/sh}\n",
4821+
)
4822+
.unwrap();
4823+
let input = l7_input("h.test", 80, "HEAD", "/");
4824+
assert!(!eval_l7(&engine, &input));
4825+
}
4826+
4827+
#[test]
4828+
fn l7_options_not_implicitly_allowed_by_get() {
4829+
let engine = l7_engine();
4830+
let input = l7_input("api.example.com", 8080, "OPTIONS", "/repos/myorg/foo");
4831+
assert!(!eval_l7(&engine, &input));
4832+
}
48084833
}

0 commit comments

Comments
 (0)