| 419 | # ============================================================ |
| 420 | |
| 421 | class TestCLIvsHTTPTaint: |
| 422 | def test_http_path_fires_PATH813(self): |
| 423 | # @app.route path param → HttpRequest → PATH813 |
| 424 | code = """ |
| 425 | path = request.GET.get('path') |
| 426 | from pathlib import Path |
| 427 | Path(path).mkdir(parents=True, exist_ok=True) |
| 428 | """ |
| 429 | assert fires(code, "PATH813"), "HTTP path traversal must fire PATH813" |
| 430 | |
| 431 | def test_cli_path_no_PATH813(self): |
| 432 | # @app.command path param → OperatorConfig → no PATH813 |
| 433 | code = """ |
| 434 | @app.command() |
| 435 | def run(output): |
| 436 | from pathlib import Path |
| 437 | Path(output).mkdir(parents=True, exist_ok=True) |
| 438 | """ |
| 439 | assert not_fires(code, "PATH813"), \ |
| 440 | "CLI operator path must NOT fire PATH813 — operator chose the path" |
| 441 | |
| 442 | def test_json_load_supply_chain_fires(self): |
| 443 | # json.load is a FILE_DESERIALIZER: always produces HttpRequest taint |
| 444 | # regardless of how the file path was obtained. Supply-chain detection |
| 445 | # is preserved even when the operator chose the file path. |
| 446 | code = """ |
| 447 | import json |
| 448 | config_path = request.POST.get("config") |
| 449 | data = json.load(open(config_path)) |
| 450 | f = open(data, "w") |
| 451 | """ |
| 452 | assert fires(code, "OPEN1149"), \ |
| 453 | "json.load FILE_DESERIALIZER must propagate HttpRequest to open() sink" |
nothing calls this directly
no outgoing calls
no test coverage detected