Spaces:
Running
Running
| import os | |
| import tempfile | |
| import pytest | |
| from app.tools.ast_parser import ( | |
| detect_security_issues, | |
| parse_python_file, | |
| parse_repository, | |
| scan_repository_security, | |
| ) | |
| def _write(tmpdir: str, filename: str, content: str) -> str: | |
| path = os.path.join(tmpdir, filename) | |
| with open(path, "w") as f: | |
| f.write(content) | |
| return path | |
| # ββ parse_python_file ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def test_parse_python_file_extracts_functions() -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| p = _write(d, "f.py", "def hello(x, y):\n pass\n") | |
| result = parse_python_file(p) | |
| assert any(fn["name"] == "hello" for fn in result["functions"]) | |
| assert result["errors"] == [] | |
| def test_parse_python_file_extracts_classes() -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| p = _write(d, "c.py", "class Foo:\n pass\n") | |
| result = parse_python_file(p) | |
| assert any(cls["name"] == "Foo" for cls in result["classes"]) | |
| def test_parse_python_file_extracts_imports() -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| p = _write(d, "i.py", "import os\nfrom pathlib import Path\n") | |
| result = parse_python_file(p) | |
| assert "os" in result["imports"] | |
| assert "pathlib" in result["imports"] | |
| def test_parse_python_file_handles_syntax_error() -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| p = _write(d, "bad.py", "def broken(\n") | |
| result = parse_python_file(p) | |
| assert any("SyntaxError" in e for e in result["errors"]) | |
| def test_parse_repository_skips_non_python() -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| _write(d, "readme.md", "# hi") | |
| _write(d, "main.py", "x = 1\n") | |
| results = parse_repository(d) | |
| assert len(results) == 1 | |
| assert results[0]["file"].endswith("main.py") | |
| # ββ detect_security_issues βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def test_detects_eval() -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| p = _write(d, "e.py", "result = eval(user_input)\n") | |
| findings = detect_security_issues(p) | |
| rules = [f["rule"] for f in findings] | |
| assert "dangerous-eval" in rules | |
| def test_detects_exec() -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| p = _write(d, "e.py", "exec(user_code)\n") | |
| findings = detect_security_issues(p) | |
| rules = [f["rule"] for f in findings] | |
| assert "dangerous-exec" in rules | |
| def test_detects_shell_true() -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| p = _write(d, "s.py", "import subprocess\nsubprocess.run(cmd, shell=True)\n") | |
| findings = detect_security_issues(p) | |
| rules = [f["rule"] for f in findings] | |
| assert "shell-injection" in rules | |
| def test_detects_hardcoded_secret() -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| p = _write(d, "k.py", 'api_key = "supersecretvalue"\n') | |
| findings = detect_security_issues(p) | |
| rules = [f["rule"] for f in findings] | |
| assert "hardcoded-secret" in rules | |
| def test_no_false_positive_on_clean_file() -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| p = _write(d, "clean.py", "def add(a, b):\n return a + b\n") | |
| findings = detect_security_issues(p) | |
| assert findings == [] | |
| def test_handles_syntax_error_gracefully() -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| p = _write(d, "bad.py", "def broken(\n") | |
| findings = detect_security_issues(p) | |
| assert findings == [] # returns empty, doesn't raise | |
| def test_scan_repository_security_aggregates() -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| _write(d, "a.py", "eval(x)\n") | |
| _write(d, "b.py", "def safe():\n return 1\n") | |
| findings = scan_repository_security(d) | |
| assert any(f["rule"] == "dangerous-eval" for f in findings) | |
| def test_parametrized_detection(rule: str, code: str) -> None: | |
| with tempfile.TemporaryDirectory() as d: | |
| p = _write(d, "t.py", code) | |
| findings = detect_security_issues(p) | |
| assert any(f["rule"] == rule for f in findings) |