|
21 | 21 | _HTTP_POLICY_IDS = { |
22 | 22 | "http_route_not_present", |
23 | 23 | "http_span_name_format", |
| 24 | + "http_url_path_format", |
24 | 25 | "required_attribute_not_present", |
25 | 26 | } |
26 | 27 |
|
@@ -147,6 +148,37 @@ def policy_advice( |
147 | 148 | path=_QUERY_PATH, |
148 | 149 | query=_QUERY_STRING, |
149 | 150 | ), |
| 151 | + _server_span( |
| 152 | + "GET /users/{leaked_query}", |
| 153 | + route="/users/{leaked_query}", |
| 154 | + path=f"{_QUERY_PATH}?{_QUERY_STRING}", |
| 155 | + ), |
| 156 | + _server_span( |
| 157 | + "GET /users/{leaked_with_query}", |
| 158 | + route="/users/{leaked_with_query}", |
| 159 | + path=f"{_QUERY_PATH}?{_QUERY_STRING}", |
| 160 | + query=_QUERY_STRING, |
| 161 | + ), |
| 162 | + _server_span( |
| 163 | + "GET /users/{query_free}", |
| 164 | + route="/users/{query_free}", |
| 165 | + path="/users/123", |
| 166 | + ), |
| 167 | + _server_span( |
| 168 | + "GET /users/{prefix_match}", |
| 169 | + route="/users/{prefix_match}", |
| 170 | + path=f"{_QUERY_PATH}7", |
| 171 | + ), |
| 172 | + _server_span( |
| 173 | + "GET /users/{encoded_question_mark}", |
| 174 | + route="/users/{encoded_question_mark}", |
| 175 | + path=f"{_QUERY_PATH}%3Fname", |
| 176 | + ), |
| 177 | + _server_span( |
| 178 | + "GET /users/{other_query}", |
| 179 | + route="/users/{other_query}", |
| 180 | + path=f"/users/123?{_QUERY_STRING}", |
| 181 | + ), |
150 | 182 | ] |
151 | 183 | ), |
152 | 184 | encoding="utf-8", |
@@ -281,3 +313,43 @@ def test_contract_query_request_with_url_query_has_no_finding( |
281 | 313 | policy_advice: dict[tuple[str, str], dict[str, dict[str, Any]]], |
282 | 314 | ) -> None: |
283 | 315 | assert policy_advice[("server", "GET /users/{with_query}")] == {} |
| 316 | + |
| 317 | + |
| 318 | +@pytest.mark.parametrize( |
| 319 | + ("target", "expected"), |
| 320 | + [ |
| 321 | + ( |
| 322 | + "leaked_query", |
| 323 | + {"required_attribute_not_present", "http_url_path_format"}, |
| 324 | + ), |
| 325 | + ("leaked_with_query", {"http_url_path_format"}), |
| 326 | + ("other_query", {"http_url_path_format"}), |
| 327 | + ], |
| 328 | +) |
| 329 | +def test_query_string_in_url_path_reports_a_leak( |
| 330 | + policy_advice: dict[tuple[str, str], dict[str, dict[str, Any]]], |
| 331 | + target: str, |
| 332 | + expected: set[str], |
| 333 | +) -> None: |
| 334 | + advice = policy_advice[("server", f"GET /users/{{{target}}}")] |
| 335 | + |
| 336 | + assert set(advice) == expected |
| 337 | + assert advice["http_url_path_format"]["context"] == { |
| 338 | + "attribute_key": "url.path", |
| 339 | + "kind": "server", |
| 340 | + } |
| 341 | + if "required_attribute_not_present" in expected: |
| 342 | + assert advice["required_attribute_not_present"]["context"] == { |
| 343 | + "attribute_key": "url.query", |
| 344 | + "kind": "server", |
| 345 | + } |
| 346 | + |
| 347 | + |
| 348 | +@pytest.mark.parametrize( |
| 349 | + "target", ["query_free", "prefix_match", "encoded_question_mark"] |
| 350 | +) |
| 351 | +def test_other_paths_do_not_require_url_query( |
| 352 | + policy_advice: dict[tuple[str, str], dict[str, dict[str, Any]]], |
| 353 | + target: str, |
| 354 | +) -> None: |
| 355 | + assert policy_advice[("server", f"GET /users/{{{target}}}")] == {} |
0 commit comments