coretrace-python-analyzer 0.20.0__tar.gz → 0.22.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- coretrace_python_analyzer-0.22.0/AUTHORS.md +7 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/CHANGELOG.md +59 -0
- coretrace_python_analyzer-0.22.0/CODE_OF_CONDUCT.md +130 -0
- coretrace_python_analyzer-0.22.0/CONTRIBUTING.md +17 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/PKG-INFO +10 -1
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/README.md +9 -0
- coretrace_python_analyzer-0.22.0/SECURITY.md +15 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/docs/plugins.md +29 -4
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/docs/usage.md +151 -10
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/pyproject.toml +1 -1
- coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/analysis.stderr +0 -0
- coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/findings.json +5470 -0
- coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/rapport.md +260 -0
- coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/sbom.json +1486 -0
- coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/triage.csv +88 -0
- coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/verification.txt +13 -0
- coretrace_python_analyzer-0.22.0/reports/mitmproxy-2026-10-02/vex.json +33 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/__init__.py +1 -1
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/reachable_vulnerability/reachable_vulnerability.py +19 -13
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/vulnerable_dependency/vulnerable_dependency.py +33 -9
- coretrace_python_analyzer-0.22.0/src/coretrace_python/bundled/security/command_injection/command_injection.py +1042 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/command_injection/plugin.toml +1 -1
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/cache.py +38 -4
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/cli.py +51 -9
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/advisories.py +36 -1
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/correlation.py +151 -13
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/graph.py +71 -34
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/vex.py +5 -2
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/engine.py +38 -7
- coretrace_python_analyzer-0.22.0/src/coretrace_python/findings/baseline.py +333 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/findings/model.py +3 -2
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/findings/suppressions.py +11 -3
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/frontend/ast_adapter.py +27 -1
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/frontend/parser.py +3 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/interprocedural/__init__.py +2 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/interprocedural/callgraph.py +131 -5
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/ir/lowering.py +4 -1
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/ir/model.py +8 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/__init__.py +2 -1
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/detectors.py +30 -4
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/secrets.py +231 -36
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/reporters/json_format.py +14 -7
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/reporters/report.py +7 -2
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/reporters/sarif.py +19 -12
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/reporters/text.py +5 -4
- coretrace_python_analyzer-0.22.0/src/coretrace_python/source/__init__.py +17 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/source/manager.py +16 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/source/model.py +20 -0
- coretrace_python_analyzer-0.22.0/src/coretrace_python/source/positions.py +420 -0
- coretrace_python_analyzer-0.22.0/src/coretrace_python/taint/commands.py +45 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/taint/models.py +10 -7
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/full-stack-fastapi-template.json +0 -6
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/healthchecks.json +0 -18
- coretrace_python_analyzer-0.22.0/tests/test_argument_present_conditions.py +205 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_baseline.py +4 -3
- coretrace_python_analyzer-0.22.0/tests/test_baseline_digests.py +155 -0
- coretrace_python_analyzer-0.22.0/tests/test_baseline_key.py +412 -0
- coretrace_python_analyzer-0.22.0/tests/test_baseline_schema_1.py +100 -0
- coretrace_python_analyzer-0.22.0/tests/test_command_arguments.py +278 -0
- coretrace_python_analyzer-0.22.0/tests/test_command_decided_cases.py +48 -0
- coretrace_python_analyzer-0.22.0/tests/test_command_injection_nature.py +92 -0
- coretrace_python_analyzer-0.22.0/tests/test_config_value_spans.py +67 -0
- coretrace_python_analyzer-0.22.0/tests/test_deep_nesting.py +92 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_detectors.py +9 -1
- coretrace_python_analyzer-0.22.0/tests/test_entry_point_suffixes.py +259 -0
- coretrace_python_analyzer-0.22.0/tests/test_file_locations.py +213 -0
- coretrace_python_analyzer-0.22.0/tests/test_folded_secret_literals.py +124 -0
- coretrace_python_analyzer-0.22.0/tests/test_line_numbering.py +136 -0
- coretrace_python_analyzer-0.22.0/tests/test_lock_dependency_maps.py +86 -0
- coretrace_python_analyzer-0.22.0/tests/test_lock_positions.py +108 -0
- coretrace_python_analyzer-0.22.0/tests/test_password_hashes.py +73 -0
- coretrace_python_analyzer-0.22.0/tests/test_powershell_file_operand.py +47 -0
- coretrace_python_analyzer-0.22.0/tests/test_relative_root.py +111 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_release.py +1 -1
- coretrace_python_analyzer-0.22.0/tests/test_sarif_injection.py +58 -0
- coretrace_python_analyzer-0.22.0/tests/test_sequence_conditions.py +461 -0
- coretrace_python_analyzer-0.22.0/tests/test_structured_positions.py +196 -0
- coretrace_python_analyzer-0.22.0/tests/test_tar_implementations.py +69 -0
- coretrace_python_analyzer-0.22.0/tests/test_url_secret_placeholders.py +66 -0
- coretrace_python_analyzer-0.20.0/src/coretrace_python/bundled/security/command_injection/command_injection.py +0 -17
- coretrace_python_analyzer-0.20.0/src/coretrace_python/findings/baseline.py +0 -99
- coretrace_python_analyzer-0.20.0/src/coretrace_python/source/__init__.py +0 -13
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/.github/workflows/ci.yml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/.github/workflows/release.yml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/.gitignore +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/LICENSE +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/NOTICE +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/docs/architecture.md +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/examples/add.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/examples/canonical_symbols.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/__main__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/abstract/__init__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/abstract/constants.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/abstract/heap.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/abstract/ranges.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/abstract/strings.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/abstract/values.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/analysis/__init__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/analysis/manager.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/analysis/provider.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/dependency_policy/dependency_policy.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/dependency_policy/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/reachable_vulnerability/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/sample_advisories/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/sample_advisories/sample_advisories.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/dependency/vulnerable_dependency/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/aiohttp/aiohttp_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/aiohttp/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/bottle/bottle_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/bottle/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/cli/cli_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/cli/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/credentials/credential_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/credentials/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/db_drivers/db_driver_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/db_drivers/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/django/django_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/django/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/fastapi/fastapi_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/fastapi/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/flask/flask_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/flask/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/http_clients/http_client_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/http_clients/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/python_stdlib/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/python_stdlib/python_stdlib.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/sqlalchemy/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/sqlalchemy/sqlalchemy_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/tornado/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/models/tornado/tornado_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/secrets/config_secrets/config_secrets.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/secrets/config_secrets/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/secrets/hardcoded_secrets/hardcoded_secrets.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/secrets/hardcoded_secrets/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/code_injection/code_injection.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/code_injection/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/insecure_deserialization/insecure_deserialization.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/insecure_deserialization/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/nosql_injection/nosql_injection.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/nosql_injection/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/open_redirect/open_redirect.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/open_redirect/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/path_traversal/path_traversal.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/path_traversal/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/plaintext_credentials/plaintext_credentials.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/plaintext_credentials/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/sql_injection/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/sql_injection/sql_injection.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/ssrf/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/ssrf/ssrf.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/xss/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/security/xss/xss.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/dangerous_eval/dangerous_eval.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/dangerous_eval/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/flask_debug/flask_debug.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/flask_debug/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/insecure_tempfile/insecure_tempfile.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/insecure_tempfile/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/insecure_tls/insecure_tls.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/insecure_tls/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/missing_timeout/missing_timeout.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/missing_timeout/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/unsafe_archive/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/unsafe_archive/unsafe_archive.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/unsafe_xml/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/unsafe_xml/unsafe_xml.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/weak_crypto/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/weak_crypto/weak_crypto.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/weak_random/plugin.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/bundled/syntax/weak_random/weak_random.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/cfg/__init__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/cfg/builder.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/cfg/dominance.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/cfg/model.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dataflow/__init__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dataflow/lattice.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dataflow/solver.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/__init__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/policy.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/dependency/sbom.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/findings/__init__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/findings/coverage.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/findings/provenance.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/findings/refutation.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/frontend/__init__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/hir/__init__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/hir/nodes.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/hir/visitors.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/interprocedural/modulegraph.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/interprocedural/summaries.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/ir/__init__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/ir/defuse.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/ir/printer.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/ir/ssa.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/api.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/loader.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/manifest.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/plugins/registry.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/reporters/__init__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/semantic/__init__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/semantic/identity.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/semantic/imports.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/semantic/scopes.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/semantic/symbols.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/taint/__init__.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/taint/engine.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/taint/routes.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/taint/templates.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/src/coretrace_python/taint/urls.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/Chatbot.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/DjangoGoat.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/Flask-Image-Editing-Website.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/InsecureGram.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/MiniBookApiServer.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/NPL-IA.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/Spam-Detection-Project.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/Vulnerable_fastapi.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/dvpwa.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/httpie.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/luigi.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/my_gdb.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/network-topologer.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/pygoat.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/uploadbox-cloud-storage-solution.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/vulnerable-flask.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/expected/yt-fts.json +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/fixtures/vulnerable-flask/README.md +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/fixtures/vulnerable-flask/app.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/fixtures/vulnerable-flask/requirements.txt +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/fixtures/vulnerable-flask/vulnerable_services.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/regression/repositories.toml +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_advisory_evidence.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_advisory_feeds.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_advisory_url_host.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_aiohttp_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_analysis_manager.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_architecture.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_argument_conditions.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_attacker_arguments.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_audit_detectors.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_base_patterns.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_block_super.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_cache.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_cfg.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_class_keywords_with_targets.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_cli.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_closures.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_code_injection.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_config_secrets_coverage.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_constants.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_correlation.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_credential_context.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_dataflow.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_declared_entry_points.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_dependencies.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_discovery.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_django_http_clients.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_django_routes.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_django_safe_values.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_docs.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_dominance.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_emit_ir.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_entry_point_aliases.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_exceptions.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_factories_match_loop_else.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_fail_on.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_fastapi_cli_precision.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_frameworks.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_frontend_gaps.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_function_aliases_api.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_heap.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_hex_digests.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_hir_builder.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_imports.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_interprocedural.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_interprocedural_taint.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_ir.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_key_taint.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_keyword_name_conditions.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_match_patterns.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_members.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_module_identity.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_module_level.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_nonlocal_writeback.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_nosql_injection.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_open_redirect_destinations.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_operator_sources.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_packaging.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_parallel.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_parser.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_plaintext_credentials.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_plugins.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_project.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_project_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_project_validators.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_provenance.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_pyir_imports.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_read_entry_points.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_real_code_precision.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_redirect_targets.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_refutation.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_refutation_evidence.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_regression.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_relative_paths.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_remaining_limits.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_reporters.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_safe_arguments.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_scale.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_scopes.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_secrets_sbom.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_self_state.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_settings_scope.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_source_manager.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_ssa.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_ssrf_destinations.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_ssrf_targets.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_summary_sanitizers.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_suppressions.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_symbol_resolution.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_symbols.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_syntactic_rules.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_syntax_control_flow.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_syntax_coverage.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_syntax_expressions.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_taint.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_template_context_flows.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_template_escaping.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_template_filter_calls.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_template_filter_overrides.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_template_request_processor.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_tornado_bottle_models.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_unreadable_templates.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_url_proof.py +0 -0
- {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.22.0}/tests/test_vex.py +0 -0
|
@@ -1,5 +1,64 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.22.0 (2026-10-08)
|
|
4
|
+
|
|
5
|
+
### Compatibility and migration
|
|
6
|
+
|
|
7
|
+
- Baselines change format twice in this release, and no baseline is ever converted or rewritten on its own. Without a key, baselines are recorded in schema 3, whose entries hold digests of the text a finding covers instead of that text (#226); with a key, in schema 4, keyed with HMAC-SHA-256 (#235). Schema 1 and 2 files are still read without a key, with exact matching only: an entry identifies a finding on a single line as before, a finding over several lines is reported new, and every run warns on standard error that the file may contain secrets in plain text. While a key is given, only a schema 4 baseline is read: an unkeyed one (schema 1, 2 or 3) stops the check with exit status 2. To migrate, review the findings, then record the baseline explicitly with `--record-baseline` (schema 3, or schema 4 with a key); the old file's secrets remain in the history of a repository that committed it.
|
|
8
|
+
- A keyed baseline needs its key: from the file `--baseline-key-file` names, which must lie outside the analysed directory and be another file than the baseline, or else from `CORETRACE_BASELINE_KEY`; the file comes first. The key is at least 16 bytes, trailing line breaks are not part of it, and an empty variable is an error. Without the key, or with another one, the check stops with exit status 2 and records nothing; recording over a schema 4 baseline without its key is refused too. Rotating the key is an explicit `--record-baseline` under the new key. Generate the key at random (`python -c "import secrets; print(secrets.token_hex(32))"`) and keep it out of the repository: a key a person chooses can be guessed from the baseline (#225).
|
|
9
|
+
- Findings may move or reappear once: dependency and configuration findings of a check given a relative root are now located relative to that root (`uv.lock`, not `proj/uv.lock`) (#212); findings in JSON, TOML and lock files are located at their own line or by a JSON pointer (#222); a vulnerable package pinned in a lock file is located at its own `[[package]]` entry. Baselines recorded before should be recorded again after review.
|
|
10
|
+
- A finding whose line cannot be established has a file location: in the JSON report its `line`, `column`, `end_line` and `end_column` are `null` and a `pointer` field names the value (RFC 6901); its SARIF location has no `region`, the pointer under the location's `properties`; the text report shows `path:` without a line. Inline suppressions apply only to findings at a verified line (#222).
|
|
11
|
+
- `command-injection` severities change: an element of an argument list run without a shell is reported by what the input controls there, `medium` by default, `high` when an option of the program runs it, refuted when a constant prefix keeps it from being an option or an option keeps it as data (#217). The rule id is unchanged; the message of an option injection is titled `Option injection` (#232). Existing suppressions and baselines of the rule keep matching by rule id; baselined findings whose severity changed are still baselined.
|
|
12
|
+
- A file whose syntax is nested more than 200 levels deep (a long chain of `+` or chained calls, which only generated code writes) is reported as a `syntax-error` and not analysed, instead of aborting the whole scan (#234).
|
|
13
|
+
- The cache format changes (14): caches built by an earlier version miss once.
|
|
14
|
+
- Plugin API: `Finding.span` is a `Location`, a `SourceSpan` or a `FileLocation` (#222); `Assessment` gains optional `title` and `metadata` fields (#232). Plugins that read `finding.span.start_line` should check for a `SourceSpan` first.
|
|
15
|
+
|
|
16
|
+
### Baseline
|
|
17
|
+
|
|
18
|
+
- `--record-baseline` records the current findings as the baseline even when the file exists; the file (the target of a symbolic link) is replaced atomically, keeping its permissions, only once the analysis succeeded and the report is rendered, so the previous baseline stays in place when the check fails (#235).
|
|
19
|
+
- `--baseline-key-file FILE` gives the key of a schema 4 baseline; `CORETRACE_BASELINE_KEY` gives it otherwise. The key never appears in a report, message or file; a `key_check` value in the baseline tells the key apart without revealing it (#235).
|
|
20
|
+
- An entry is recognised by a digest of the text of every line its finding covers: a secret written over several lines, whose first line does not hold it, is new once its body changes (#223, #226). A finding at a file location is recognised by digests of its value and of its pointer, whose keys may themselves be secrets (#222, #226).
|
|
21
|
+
- Line numbers follow one rule everywhere, as Python counts lines (`\n`, `\r\n` or a lone `\r`, never U+2028 or a form feed), so a fingerprint or a suppression never refers to another line (#222).
|
|
22
|
+
|
|
23
|
+
### Secrets
|
|
24
|
+
|
|
25
|
+
- A string expression whose parts are all constant (`+` of strings, `sep.join` of a list or tuple of strings, an f-string whose parts are all constant) is judged as one value, reported once at the whole expression with the strongest finding of the value and its pieces; `PASSWORD = "Zx81kQpL" + "w0RtY7vB" + …` and `TOKEN = "ghp_" + "…"` are now reported. When the whole value is no secret, its pieces are judged on their own, as before (#231).
|
|
26
|
+
- A `.env`, YAML, INI or properties value that continues past its key's line (an open quote, a trailing backslash, deeper indentation) is located over every line it continues on (#226).
|
|
27
|
+
- Password hashes are no longer reported as hardcoded credentials: modular crypt and PHC strings, bcrypt, Werkzeug's `scrypt:`/`pbkdf2:` and Django's encodings; an identifier followed by text of another shape is still a plaintext password (#214).
|
|
28
|
+
- The `url` pattern no longer reports placeholders (`?token=...`, `<token>`) nor an IP address or `localhost` and a port before `@` (proxy specifications); a password runs to the last `@` before the host. A `SecretPattern` may name a `secret` group, which the placeholder check then judges (#215).
|
|
29
|
+
- In `package-lock.json` and `npm-shrinkwrap.json`, the keys of dependency, `requires` and `bin` maps are package or command names, not credential names (#216).
|
|
30
|
+
|
|
31
|
+
### Command injection
|
|
32
|
+
|
|
33
|
+
- The command a process starter runs (`subprocess.run`, `call`, `check_call`, `check_output`, `Popen`) is read element by element, with a documented option model for git, ssh, tar, rsync, find, rm, cmd, PowerShell, the shells and the interpreters, wrappers such as sudo, env, xargs and timeout read again with their program's model; the evidence says what the input controls (#217).
|
|
34
|
+
- The finding's `injection` metadata says what the input is when the rule establishes it: `command` (it runs or chooses what runs) or `option` (an option, or the value of an option not established to run it), in the JSON report and as the only `properties` of the SARIF result; it is absent when the kind cannot be established (#232, #236).
|
|
35
|
+
- The script after `pwsh -File` is a file name, however it is spelled (#229). `gtar` is read as GNU tar, `bsdtar` as libarchive's (`-I` names a file of patterns), and a bare `tar`'s `-I`, `--to-command` and `--checkpoint-action` are `high` and kept for review (#230).
|
|
36
|
+
|
|
37
|
+
### Dependencies
|
|
38
|
+
|
|
39
|
+
- A vulnerable package pinned in `uv.lock` or `poetry.lock` is located at its own entry, and the message states the evidence: `werkzeug 3.1.5, pinned in uv.lock, is in <3.1.6 (required by flask)` (#222). Requirements of `pyproject.toml` are located at their own element or key, or given a file location.
|
|
40
|
+
- `--advisories` and `--policy` paths, and the root itself, are resolved once, so their findings and notes are located relative to the root whatever the working directory (#212).
|
|
41
|
+
|
|
42
|
+
### Frontend
|
|
43
|
+
|
|
44
|
+
- Syntax nested deeper than the analysis follows is rejected before PyHIR is built, and Python 3.11's parser recursion is a parse error of the file, so the rest of the project is still analysed (#234).
|
|
45
|
+
|
|
46
|
+
### Documentation
|
|
47
|
+
|
|
48
|
+
- `docs/usage.md` documents keyed baselines, `--record-baseline`, `--baseline-key-file`, file locations and the `injection` metadata; `docs/plugins.md` documents `FileLocation`, `Assessment.title` and `metadata`, and the `secret` group of a `SecretPattern`. Repository governance files (contributing, conduct, authors, security) are added (#204).
|
|
49
|
+
|
|
50
|
+
## 0.21.0 (2026-09-30)
|
|
51
|
+
|
|
52
|
+
### Advisories
|
|
53
|
+
|
|
54
|
+
- An `argument` condition may carry `present: true`: the argument being passed at all, whatever its value, is the condition, as a `\r` in `web.Response(reason=…)` needs `reason` given, constant or not. It names the argument by keyword or position as today and excludes `values` and `default`. A call giving the argument — positionally, by keyword, or through a `**` literal with constant keys, folded into the keywords — meets it even when the value is unknown, so attacker input there makes the call exploitable; a call surely not giving it is ruled out (`app:5 python.aiohttp.web.Response(reason absent)`) and a project passing only such calls stays `not_affected`; a call unpacking `*args` or a `**mapping` whose keys are not written leaves it pending review (#195).
|
|
55
|
+
- A curated entry point may declare `suffixes`, for receivers the engine cannot type: `Item.objects.annotate(...)` derives the project's own `python.app.models.Item.objects.annotate`, which the canonical `python.django.db.models.QuerySet.annotate` entry point never matches. A suffix matches any symbol of the project's own modules ending with a dot plus the suffix, on dot boundaries as a `SuffixSink` matches, never another package's symbol; a queryset chain is declared explicitly (`objects.filter.annotate`), and a suffix is at least two dot-separated names. The finding keeps the advisory's symbol as `entry_point` and the derived one as `symbol`; conditions, `attacker_arguments` and the ruled-out evidence of contradicted calls apply through a suffix as through the exact symbol. An exact advisory sink whose symbol a bundled suffix sink also matches (`objects.extra`) now composes its kinds with the suffix sink's instead of shadowing them (#197).
|
|
56
|
+
- An advisory condition of kind `sequence` says the flaw spans two calls on one receiver: the first call leaves state on the object the entry point — the second call — reuses. It names the `method` the first call must be, by canonical name or `.`-suffix, and, optionally, the argument that call must carry (`{"kind": "sequence", "method": "Session.get", "argument": "verify", "values": ["False"], ...}`), so `s = requests.Session(); s.get(url, verify=False); s.get(other)` marks the second `get` reachable with the prior call as evidence (requests CVE-2024-35195). A receiver followed whole — bound once to the result of a call or a `with` and used only to call its methods — with no matching call on every path to the entry call rules it out (`app.fetch:6 python.requests.Session.get(no prior Session.get on the receiver)`), and a project with only such calls stays `not_affected`. A receiver the engine cannot follow (a parameter, a module-level instance, one passed to another function or mutated through an attribute), a matching call only in a branch or textually later, an unpacking that leaves the first call's arguments undecided, or an entry call that itself carries the named argument — its own prior across the iterations of a loop — leaves the condition pending review (#194).
|
|
57
|
+
|
|
58
|
+
### Plugins
|
|
59
|
+
|
|
60
|
+
- `CallSite.prior_calls` records, for a receiver the engine follows whole, the other external calls on the same receiver (`PriorCall`: symbol, location, arguments, and whether it surely executes before this one), in source order; `CallGraph.prior_calls_at` reads it by location, and `check_conditions` takes it to decide `sequence` conditions. The cache format changes.
|
|
61
|
+
|
|
3
62
|
## 0.20.0 (2026-09-30)
|
|
4
63
|
|
|
5
64
|
### Advisories
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
This policy applies to the CoreTrace Python Analyzer repository and its community spaces.
|
|
4
|
+
|
|
5
|
+
## Our Pledge
|
|
6
|
+
|
|
7
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
8
|
+
community a harassment-free experience for everyone, regardless of age, body
|
|
9
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
10
|
+
identity and expression, level of experience, education, socio-economic status,
|
|
11
|
+
nationality, personal appearance, race, religion, or sexual identity
|
|
12
|
+
and orientation.
|
|
13
|
+
|
|
14
|
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
15
|
+
diverse, inclusive, and healthy community.
|
|
16
|
+
|
|
17
|
+
## Our Standards
|
|
18
|
+
|
|
19
|
+
Examples of behavior that contributes to a positive environment for our
|
|
20
|
+
community include:
|
|
21
|
+
|
|
22
|
+
* Demonstrating empathy and kindness toward other people
|
|
23
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
|
24
|
+
* Giving and gracefully accepting constructive feedback
|
|
25
|
+
* Accepting responsibility and apologizing to those affected by our mistakes,
|
|
26
|
+
and learning from the experience
|
|
27
|
+
* Focusing on what is best not just for us as individuals, but for the
|
|
28
|
+
overall community
|
|
29
|
+
|
|
30
|
+
Examples of unacceptable behavior include:
|
|
31
|
+
|
|
32
|
+
* The use of sexualized language or imagery, and sexual attention or
|
|
33
|
+
advances of any kind
|
|
34
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
35
|
+
* Public or private harassment
|
|
36
|
+
* Publishing others' private information, such as a physical or email
|
|
37
|
+
address, without their explicit permission
|
|
38
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
|
39
|
+
professional setting
|
|
40
|
+
|
|
41
|
+
## Enforcement Responsibilities
|
|
42
|
+
|
|
43
|
+
Community leaders are responsible for clarifying and enforcing our standards of
|
|
44
|
+
acceptable behavior and will take appropriate and fair corrective action in
|
|
45
|
+
response to any behavior that they deem inappropriate, threatening, offensive,
|
|
46
|
+
or harmful.
|
|
47
|
+
|
|
48
|
+
Community leaders have the right and responsibility to remove, edit, or reject
|
|
49
|
+
comments, commits, code, wiki edits, issues, and other contributions that are
|
|
50
|
+
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
|
51
|
+
decisions when appropriate.
|
|
52
|
+
|
|
53
|
+
## Scope
|
|
54
|
+
|
|
55
|
+
This Code of Conduct applies within all community spaces, and also applies when
|
|
56
|
+
an individual is officially representing the community in public spaces.
|
|
57
|
+
Examples of representing our community include using an official e-mail address,
|
|
58
|
+
posting via an official social media account, or acting as an appointed
|
|
59
|
+
representative at an online or offline event.
|
|
60
|
+
|
|
61
|
+
## Enforcement
|
|
62
|
+
|
|
63
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
64
|
+
reported to the community leaders responsible for enforcement at
|
|
65
|
+
hugo.payet@epitech.eu.
|
|
66
|
+
All complaints will be reviewed and investigated promptly and fairly.
|
|
67
|
+
|
|
68
|
+
All community leaders are obligated to respect the privacy and security of the
|
|
69
|
+
reporter of any incident.
|
|
70
|
+
|
|
71
|
+
## Enforcement Guidelines
|
|
72
|
+
|
|
73
|
+
Community leaders will follow these Community Impact Guidelines in determining
|
|
74
|
+
the consequences for any action they deem in violation of this Code of Conduct:
|
|
75
|
+
|
|
76
|
+
### 1. Correction
|
|
77
|
+
|
|
78
|
+
**Community Impact**: Use of inappropriate language or other behavior deemed
|
|
79
|
+
unprofessional or unwelcome in the community.
|
|
80
|
+
|
|
81
|
+
**Consequence**: A private, written warning from community leaders, providing
|
|
82
|
+
clarity around the nature of the violation and an explanation of why the
|
|
83
|
+
behavior was inappropriate. A public apology may be requested.
|
|
84
|
+
|
|
85
|
+
### 2. Warning
|
|
86
|
+
|
|
87
|
+
**Community Impact**: A violation through a single incident or series
|
|
88
|
+
of actions.
|
|
89
|
+
|
|
90
|
+
**Consequence**: A warning with consequences for continued behavior. No
|
|
91
|
+
interaction with the people involved, including unsolicited interaction with
|
|
92
|
+
those enforcing the Code of Conduct, for a specified period of time. This
|
|
93
|
+
includes avoiding interactions in community spaces as well as external channels
|
|
94
|
+
like social media. Violating these terms may lead to a temporary or
|
|
95
|
+
permanent ban.
|
|
96
|
+
|
|
97
|
+
### 3. Temporary Ban
|
|
98
|
+
|
|
99
|
+
**Community Impact**: A serious violation of community standards, including
|
|
100
|
+
sustained inappropriate behavior.
|
|
101
|
+
|
|
102
|
+
**Consequence**: A temporary ban from any sort of interaction or public
|
|
103
|
+
communication with the community for a specified period of time. No public or
|
|
104
|
+
private interaction with the people involved, including unsolicited interaction
|
|
105
|
+
with those enforcing the Code of Conduct, is allowed during this period.
|
|
106
|
+
Violating these terms may lead to a permanent ban.
|
|
107
|
+
|
|
108
|
+
### 4. Permanent Ban
|
|
109
|
+
|
|
110
|
+
**Community Impact**: Demonstrating a pattern of violation of community
|
|
111
|
+
standards, including sustained inappropriate behavior, harassment of an
|
|
112
|
+
individual, or aggression toward or disparagement of classes of individuals.
|
|
113
|
+
|
|
114
|
+
**Consequence**: A permanent ban from any sort of public interaction within
|
|
115
|
+
the community.
|
|
116
|
+
|
|
117
|
+
## Attribution
|
|
118
|
+
|
|
119
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
120
|
+
version 2.0, available at
|
|
121
|
+
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
|
122
|
+
|
|
123
|
+
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
|
124
|
+
enforcement ladder](https://github.com/mozilla/diversity).
|
|
125
|
+
|
|
126
|
+
[homepage]: https://www.contributor-covenant.org
|
|
127
|
+
|
|
128
|
+
For answers to common questions about this code of conduct, see the FAQ at
|
|
129
|
+
https://www.contributor-covenant.org/faq. Translations are available at
|
|
130
|
+
https://www.contributor-covenant.org/translations.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Contributing to CoreTrace Python Analyzer
|
|
2
|
+
|
|
3
|
+
## Local setup
|
|
4
|
+
|
|
5
|
+
Python 3.11 or newer is required. Create a virtual environment and install the development dependencies:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
python3 -m venv .venv
|
|
9
|
+
.venv/bin/python -m pip install -e '.[dev]'
|
|
10
|
+
.venv/bin/python -m mypy
|
|
11
|
+
.venv/bin/python -m pytest
|
|
12
|
+
.venv/bin/python -m ruff check .
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The [README](README.md#development) explains the separate network-dependent regression corpus. Update documentation when changing rules, reports or plugin contracts, and describe the checks you ran in your pull request. Keep changes focused and use an English Conventional Commit subject.
|
|
16
|
+
|
|
17
|
+
Report suspected vulnerabilities through [SECURITY.md](SECURITY.md) rather than a public issue.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: coretrace-python-analyzer
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.22.0
|
|
4
4
|
Summary: Static security analysis infrastructure for Python code
|
|
5
5
|
Project-URL: Homepage, https://github.com/CoreTrace/coretrace-python-analyzer
|
|
6
6
|
Project-URL: Repository, https://github.com/CoreTrace/coretrace-python-analyzer
|
|
@@ -53,6 +53,15 @@ semantic resolution of imports and scopes, lowering to a small intermediate
|
|
|
53
53
|
representation (PyIR), control-flow graphs, SSA, data-flow and abstract interpretation,
|
|
54
54
|
interprocedural summaries, taint and refutation, then plugins and reporters.
|
|
55
55
|
|
|
56
|
+
## Repository documents
|
|
57
|
+
|
|
58
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
59
|
+
- [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
|
|
60
|
+
- [AUTHORS.md](AUTHORS.md)
|
|
61
|
+
- [CHANGELOG.md](CHANGELOG.md)
|
|
62
|
+
- [LICENSE](LICENSE)
|
|
63
|
+
- [SECURITY.md](SECURITY.md)
|
|
64
|
+
|
|
56
65
|
## Development
|
|
57
66
|
|
|
58
67
|
```bash
|
|
@@ -23,6 +23,15 @@ semantic resolution of imports and scopes, lowering to a small intermediate
|
|
|
23
23
|
representation (PyIR), control-flow graphs, SSA, data-flow and abstract interpretation,
|
|
24
24
|
interprocedural summaries, taint and refutation, then plugins and reporters.
|
|
25
25
|
|
|
26
|
+
## Repository documents
|
|
27
|
+
|
|
28
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
29
|
+
- [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
|
|
30
|
+
- [AUTHORS.md](AUTHORS.md)
|
|
31
|
+
- [CHANGELOG.md](CHANGELOG.md)
|
|
32
|
+
- [LICENSE](LICENSE)
|
|
33
|
+
- [SECURITY.md](SECURITY.md)
|
|
34
|
+
|
|
26
35
|
## Development
|
|
27
36
|
|
|
28
37
|
```bash
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
Security fixes target `main` and the latest tagged release, when one exists. Older tags are not maintained. Include the exact tag or commit in a report.
|
|
6
|
+
|
|
7
|
+
## Reporting a vulnerability
|
|
8
|
+
|
|
9
|
+
Report privately through [GitHub private vulnerability reporting](https://github.com/CoreTrace/coretrace-python-analyzer/security/advisories/new). Do not publish a suspected vulnerability in an issue or pull request.
|
|
10
|
+
|
|
11
|
+
Include reproduction steps, expected and observed behavior, the affected platform and version, and the possible impact. Remove credentials and other sensitive data from examples.
|
|
12
|
+
|
|
13
|
+
## Scope
|
|
14
|
+
|
|
15
|
+
CoreTrace Python Analyzer parses and analyzes source trees and dependency metadata. Reports about crafted input, unsafe file access or report generation should include a sanitized sample and the command used.
|
|
@@ -127,6 +127,19 @@ judges by its own criteria. The refutation's
|
|
|
127
127
|
verdict, which other consumers of the flow such as the advisory correlation read, does
|
|
128
128
|
not change; a rule reading more analyses declares them in its `requires`.
|
|
129
129
|
|
|
130
|
+
A rule that tells cases of its sinks apart by severity too overrides `assess(ctx,
|
|
131
|
+
function, flow, verdict)`, which returns an `Assessment` of the verdict and the
|
|
132
|
+
severity; by default it pairs `judge`'s verdict with the rule's `severity`. A `hotspot`
|
|
133
|
+
verdict lowers the confidence of the finding, never its severity. An `Assessment` may
|
|
134
|
+
also carry a `title` for the finding's message instead of the rule's, and `metadata`
|
|
135
|
+
the finding carries besides the flow's; the rule id never changes, so suppressions and
|
|
136
|
+
baselines keep matching. `command-injection`
|
|
137
|
+
reads there the command a flow reaches (`coretrace_python.taint.commands`): a shell
|
|
138
|
+
string or the program is `high`; an element of an argument list run without a shell is
|
|
139
|
+
an option, `medium` unless a documented option of the program runs a command it chooses.
|
|
140
|
+
It sets the `injection` metadata (`command` or `option`, the latter titled `Option
|
|
141
|
+
injection`) only when it establishes what the input is.
|
|
142
|
+
|
|
130
143
|
### Security models: `ModelPlugin`
|
|
131
144
|
|
|
132
145
|
Declares sources, sinks and sanitizers for a library or a framework. A model plugin
|
|
@@ -195,8 +208,12 @@ A model plugin may also carry `advisories`, a tuple of `Advisory` values
|
|
|
195
208
|
symbols, as the shipped `sample-advisories` plugin does. Requirements matching them are
|
|
196
209
|
reported, calls to the affected symbols become reachable vulnerabilities and tainted
|
|
197
210
|
calls become exploitable ones. An advisory's entry points carry `conditions`, of kind
|
|
198
|
-
`argument
|
|
199
|
-
|
|
211
|
+
`argument` (on the value, or with `present` on the argument being passed at all),
|
|
212
|
+
`host`, `semantic`, `keyword_name` or `sequence`, and `attacker_arguments`, decided as
|
|
213
|
+
the [usage guide](usage.md) describes. An entry point may also declare `suffixes`,
|
|
214
|
+
matched against the tail of a derived symbol of the project's own modules on dot
|
|
215
|
+
boundaries, as a `SuffixSink` matches, for receivers the engine cannot type (see the
|
|
216
|
+
usage guide).
|
|
200
217
|
|
|
201
218
|
### Reclassifying findings: `ProjectPlugin.refine`
|
|
202
219
|
|
|
@@ -251,6 +268,10 @@ class InternalSecrets(SecretDetector):
|
|
|
251
268
|
credential_names: ClassVar[tuple[str, ...]] = (*DEFAULT_CREDENTIAL_NAMES, "acme_key")
|
|
252
269
|
```
|
|
253
270
|
|
|
271
|
+
A pattern whose regex names a `secret` group (`(?P<secret>...)`) is judged on that group:
|
|
272
|
+
a match whose secret is a placeholder (`...`, `<token>`, `${VAR}`, fewer than four
|
|
273
|
+
characters) is not reported, as with credential names.
|
|
274
|
+
|
|
254
275
|
`entropy_threshold`, `hex_entropy_threshold` and `minimum_length` tune the high-entropy
|
|
255
276
|
rule. Findings carry a redacted preview only.
|
|
256
277
|
|
|
@@ -304,8 +325,12 @@ any analysis result: `SSAAnalysis` (`coretrace_python.ir.ssa`) for the code,
|
|
|
304
325
|
## Findings
|
|
305
326
|
|
|
306
327
|
A `Finding` (`coretrace_python.findings`) has a `rule_id`, a `message`, a `Severity`, a
|
|
307
|
-
`Confidence`, a `
|
|
308
|
-
|
|
328
|
+
`Confidence`, a location, the enclosing `function` and string `metadata`. Rule ids are
|
|
329
|
+
lower-case words joined by dashes. The location (`span`) is a `SourceSpan` (file, start
|
|
330
|
+
and end line and column) when the line is established, or a `FileLocation` (file and the
|
|
331
|
+
JSON pointer of a value) for a value of a structured file whose line cannot be: a plugin
|
|
332
|
+
that reads a finding's line checks which it has, and never invents a line for a
|
|
333
|
+
`FileLocation` (`coretrace_python.source.positions` places JSON and TOML values).
|
|
309
334
|
|
|
310
335
|
## Testing a plugin
|
|
311
336
|
|
|
@@ -56,6 +56,8 @@ coretrace-python-analyzer [--check | --emit-ir [--ssa]] [options] [path]
|
|
|
56
56
|
| `--import-advisories SRC OUT` | Convert an OSV dump into the local advisory file `OUT`, then exit. |
|
|
57
57
|
| `--fail-on SEVERITY` | Exit with status 1 only when a finding of this severity or above was reported: `info`, `low`, `medium`, `high` or `critical`. Default: any finding. |
|
|
58
58
|
| `--baseline PATH` | The accepted findings: written on the first run, then only findings not recorded there fail the check. |
|
|
59
|
+
| `--baseline-key-file FILE` | With `--baseline`, the file holding the key of a keyed baseline (schema 4), kept out of the analysed directory; read before `CORETRACE_BASELINE_KEY`. |
|
|
60
|
+
| `--record-baseline` | With `--baseline`, record the current findings as the baseline, replacing the file only once the check succeeded. |
|
|
59
61
|
| `--emit-ir` | Print the intermediate representation of `path` instead of checking it. |
|
|
60
62
|
| `--ssa` | With `--emit-ir`, print the static single assignment form. |
|
|
61
63
|
| `--help` | Show the options and exit. |
|
|
@@ -84,7 +86,10 @@ get_asgi_application()` in `asgi.py` or `email = forms.EmailField()` in a form c
|
|
|
84
86
|
calls the analyzer sees, and a module-level `os.system(input())` is a finding in `<module>`.
|
|
85
87
|
A function using syntax outside the supported subset is reported as an
|
|
86
88
|
`unsupported-syntax` note and the other functions are still analysed; a file Python
|
|
87
|
-
itself cannot parse is reported as a `syntax-error
|
|
89
|
+
itself cannot parse is reported as a `syntax-error`, and so is a file whose syntax is
|
|
90
|
+
nested more than 200 levels deep (a chain of hundreds of `+` or chained calls, which only
|
|
91
|
+
generated code writes), which the analyzer does not follow; the other files are still
|
|
92
|
+
analysed. The coverage line and the JSON
|
|
88
93
|
report's per-file detail tell "no findings" from "nothing analysed".
|
|
89
94
|
|
|
90
95
|
Taint follows values between functions and across files through function summaries,
|
|
@@ -115,7 +120,7 @@ variable is not treated that way yet.
|
|
|
115
120
|
|
|
116
121
|
| Rule | Reached sink |
|
|
117
122
|
|---|---|
|
|
118
|
-
| `command-injection` | Shell or process execution (`os.system`, `subprocess` with a string, …). |
|
|
123
|
+
| `command-injection` | Shell or process execution (`os.system`, `subprocess` with a string, …), judged on what the input controls in the command. A string a shell runs, a string naming the program, the program itself, or an operand the program runs as a command (after the host for `ssh`, the program of `sudo`, `env`, `xargs`, `timeout`…, any argument of a batch file) is `high`. The script an interpreter runs (`bash run.sh`, `python tool.py`, its first operand when no option such as `-c` gives the code), or the module of `python -m`, is `high` and kept for review: execution is possible, and its exploitability depends on the file the input chooses. The arguments after a script or code are the script's own: options of unknown meaning, reported `medium` (a hotspot after an option of the script), refuted behind a constant prefix. Otherwise an element of an argument list run without a shell can only be read as an option: `medium`, or `high` when a documented option of the program runs a command it chooses (`git push --receive-pack=…`, `ssh -o ProxyCommand=…`). A value a documented option takes is judged by what the option does with it, whatever its prefix: run it (`sh -c`, `cmd /c`, `python -c`: `high`), keep it as data (`git commit -m`: refuted). After an option the rule does not know, the finding stays a hotspot to review. A constant prefix that keeps a standalone input from being an option (`f"v{version}"`), or an operand after `--` for a program that honours it, is refuted. Every case keeps the rule id `command-injection`, so suppressions and baselines match whatever the case. When the rule reads the command element by element and establishes what the input is there, the finding's `injection` metadata (in the JSON report, and as the only property of its SARIF result) says so: `command` when the input runs or chooses what runs (a shell string, the program, an operand run as a command, the value of an option that runs it); `option` when it can only reach the program as an option or as the value of an option not established to run it, and the message is then titled `Option injection`. When that cannot be established (an option whose effect is to review, an unknown program or element before the input, a command that is not a list or tuple display, a sink such as `os.system` the rule does not read element by element), the metadata is absent and the title stays `Command injection`. |
|
|
119
124
|
| `code-injection` | The code `eval` or `exec` runs; the globals and locals passed with it are data. `dangerous-eval` reports every such call, this rule the ones attacker input reaches. |
|
|
120
125
|
| `sql-injection` | A database statement (`cursor.execute`, SQLAlchemy `text`, Django `raw`, …). Parameters of a parameterised query are not statements. |
|
|
121
126
|
| `nosql-injection` | A NoSQL query, such as a MongoDB filter, given attacker input that may hold a structure: a JSON body giving `{"$ne": null}` matches any value. The input that may hold a structure is JSON, the raw bodies a `json.loads` decodes, files, WebSocket messages and standard input. Text cannot hold an operator: form fields, query parameters, headers, cookies, URL parameters, the command line, the environment, and an entry-point parameter annotated with scalars (`str`, `int`, `Optional[str]`, `Annotated[str, Query()]`, `list[str]`, …), which FastAPI validates. A Django, REST framework, aiohttp or tornado view reads a request object: its text attributes (`GET`, `POST`, `headers`, `query_params`, `query`, `match_info`, `arguments`, …) and the URL parameters after it are text, its body, files and `data` are not. Limits: a helper function the request is passed to reads it as a whole; the keys of a dict are not followed, so a string concatenated into `$where` is not reported. The analyzer ships no NoSQL sink: model plugins declare them. |
|
|
@@ -215,7 +220,8 @@ The comment also works in requirements files, where a line
|
|
|
215
220
|
`pyyaml==5.3.1 # coretrace: ignore[vulnerable-dependency]` silences that requirement's
|
|
216
221
|
finding. Suppressed findings are kept apart: the text report counts them, the JSON report
|
|
217
222
|
lists them under `suppressed`, the SARIF log marks them as suppressed in source, and
|
|
218
|
-
they never affect the exit status.
|
|
223
|
+
they never affect the exit status. A comment only suppresses a finding located at a
|
|
224
|
+
verified line; a finding with a file location (see Reports) is never suppressed this way.
|
|
219
225
|
|
|
220
226
|
## Adopting the analyzer on an existing code base
|
|
221
227
|
|
|
@@ -227,12 +233,62 @@ coretrace-python-analyzer --check src/ --baseline coretrace-baseline.json
|
|
|
227
233
|
|
|
228
234
|
The first run writes the file with every current finding and passes. Later runs set the
|
|
229
235
|
recorded findings apart and fail only on new ones. A finding is recognised by its file,
|
|
230
|
-
its rule, its function and the text of
|
|
231
|
-
above it does not make it new; a change to
|
|
232
|
-
|
|
236
|
+
its rule, its function and the text of every line it covers, not by its line number, so
|
|
237
|
+
code inserted above it does not make it new; a change to its text does, on any of its
|
|
238
|
+
lines, such as the body of a key written over several lines. Commit the file and shrink
|
|
239
|
+
it as findings are fixed: an entry without a matching finding is simply unused.
|
|
233
240
|
Baselined findings are counted in the text report, listed under `baselined` in the JSON
|
|
234
241
|
report and marked `baselineState: unchanged` in the SARIF log, where new results are
|
|
235
|
-
marked `new`.
|
|
242
|
+
marked `new`. A finding with a file location is recognised by the JSON pointer of its
|
|
243
|
+
value and its value instead of the text of a line, so a new value at the same place is a
|
|
244
|
+
new finding. Entries hold a digest of that text, value and pointer, never the text
|
|
245
|
+
itself, so no accepted secret is stored in plain text. That does not make the file
|
|
246
|
+
confidential: a digest does not hide a weak secret from whoever guesses it, since a
|
|
247
|
+
guessed password, hashed with its line, can be checked against the file. Treat the
|
|
248
|
+
baseline as a possibly sensitive file, or key it.
|
|
249
|
+
|
|
250
|
+
A keyed baseline does not let candidate values be tested without its key. The key comes
|
|
251
|
+
from the file `--baseline-key-file` names, or else from the `CORETRACE_BASELINE_KEY`
|
|
252
|
+
environment variable, as a CI secret; the file comes first when both are given. The check
|
|
253
|
+
refuses a key file inside the analysed directory, however its path is spelled, or the
|
|
254
|
+
baseline itself; keep it out of the whole repository too, which the check cannot tell
|
|
255
|
+
(a hard link escapes it as well). Generate the key at random, for instance with
|
|
256
|
+
`python -c "import secrets; print(secrets.token_hex(32))"`, and share it as a secret
|
|
257
|
+
(a CI secret, a password manager): a key a person chooses can be guessed from the
|
|
258
|
+
baseline. It is at least 16 bytes long, and trailing line breaks are not part of it, from
|
|
259
|
+
the file or the variable alike; an empty variable is an error, as a CI job whose secret
|
|
260
|
+
is missing passes one. Every process of the check, plugins and `--jobs` workers included,
|
|
261
|
+
can read the variable. With a key, the
|
|
262
|
+
baseline is recorded in schema 4: every digest is an HMAC-SHA-256 under the key, and a
|
|
263
|
+
check value, never the key, tells which key recorded it. The key appears in no report,
|
|
264
|
+
message or file the check writes. A schema 4 baseline needs its key: without it, or
|
|
265
|
+
with another, the check stops with an explicit error, exit status 2, and records
|
|
266
|
+
nothing. Recording over a schema 4 baseline without its key is refused too, rather than
|
|
267
|
+
turning it back into an unkeyed one: delete the file to do that explicitly. Without a
|
|
268
|
+
key, baselines are recorded in schema 3, with the guarantee above.
|
|
269
|
+
|
|
270
|
+
`--record-baseline` records the current findings as the baseline even when the file
|
|
271
|
+
exists, under the key given, if any; the file (the target of a symbolic link) is
|
|
272
|
+
replaced at once, keeping its permissions, only once the analysis succeeded and its
|
|
273
|
+
report is rendered, so the previous baseline stays in place when the check fails. Review the findings
|
|
274
|
+
before recording: they all become accepted. Rotating the key is such a record under the
|
|
275
|
+
new key, once the findings are reviewed; the old key then no longer reads the baseline.
|
|
276
|
+
|
|
277
|
+
Baselines are written in schema 3, or in schema 4 with a key. A file written by an
|
|
278
|
+
earlier version, in schema 1 or 2, is still read and never rewritten, and the check warns
|
|
279
|
+
on standard error, once per run, that it may contain secrets in plain text: its entries
|
|
280
|
+
hold the text of each
|
|
281
|
+
finding's first line. They match exactly as they did a finding on a single line; a
|
|
282
|
+
finding over several lines, whose other lines they do not hold, is reported as new, and
|
|
283
|
+
so is a finding in a JSON, TOML or lock file that a schema 1 entry, recorded with the
|
|
284
|
+
text of its key's first line, cannot identify with certainty. The exit status depends
|
|
285
|
+
on the findings only. Review such a baseline and its new findings, then migrate it
|
|
286
|
+
explicitly with `--record-baseline`, to schema 3, or to schema 4 with a key. While a key
|
|
287
|
+
is given, only a schema 4 baseline is read: an unkeyed one (schema 1, 2 or 3) stops the
|
|
288
|
+
check with an error, so that it cannot stand in for the keyed one; review it, then record
|
|
289
|
+
it in schema 4 with `--record-baseline`. No baseline is ever converted or rewritten
|
|
290
|
+
without `--record-baseline`. The
|
|
291
|
+
old file's secrets remain in the history of a repository that committed it.
|
|
236
292
|
|
|
237
293
|
## Reports
|
|
238
294
|
|
|
@@ -247,7 +303,7 @@ the directory of the checked file; a path outside it is printed as it is.
|
|
|
247
303
|
```json
|
|
248
304
|
{
|
|
249
305
|
"schema_version": 1,
|
|
250
|
-
"tool": {"name": "coretrace-python-analyzer", "version": "0.
|
|
306
|
+
"tool": {"name": "coretrace-python-analyzer", "version": "0.22.0"},
|
|
251
307
|
"root": "/home/me/project",
|
|
252
308
|
"findings": [
|
|
253
309
|
{
|
|
@@ -267,6 +323,17 @@ the directory of the checked file; a path outside it is printed as it is.
|
|
|
267
323
|
}
|
|
268
324
|
```
|
|
269
325
|
|
|
326
|
+
Lines are counted as Python counts them, by `\n`, `\r\n` or a lone `\r` (never U+2028
|
|
327
|
+
or a form feed), in every report, suppression and baseline. A value of a JSON or TOML
|
|
328
|
+
file, a package of a lock file, or a requirement of `pyproject.toml`, is located at its own line,
|
|
329
|
+
which a separate component establishes from the value's structural path and checks
|
|
330
|
+
against the value. When it cannot (a dotted TOML key, an inline table, a multi-line
|
|
331
|
+
value), the finding gets a file location instead of a guessed line: `line`, `column`,
|
|
332
|
+
`end_line` and `end_column` are `null`, and `pointer` gives the JSON pointer of the value
|
|
333
|
+
in the file (`"/tool/app/api_token"`). The SARIF log gives such a result no `region`,
|
|
334
|
+
with the pointer under the location's `properties`, and the text report shows the file
|
|
335
|
+
alone (`settings.toml: high hardcoded-credential: …`).
|
|
336
|
+
|
|
270
337
|
`root` is the directory the paths are relative to. A file's `status` is `analysed`,
|
|
271
338
|
`ambiguous` (analysed, but another file has its module name, see above), `syntax-error`
|
|
272
339
|
or `unreadable`; only `analysed` files count in `files_analysed`.
|
|
@@ -281,7 +348,7 @@ bytes. A single-file check lists no components.
|
|
|
281
348
|
|
|
282
349
|
```json
|
|
283
350
|
"tool": {
|
|
284
|
-
"name": "coretrace-python-analyzer", "version": "0.
|
|
351
|
+
"name": "coretrace-python-analyzer", "version": "0.22.0",
|
|
285
352
|
"components": [
|
|
286
353
|
{"kind": "plugin", "name": "curated-advisories", "version": "2026.09.25", "digest": "sha256:…"},
|
|
287
354
|
{"kind": "advisories", "name": "advisories.json", "digest": "sha256:…"}
|
|
@@ -370,6 +437,29 @@ it is reachable, called or not — `request.form['name']`, `for key in request.f
|
|
|
370
437
|
`request.form.get('name')` all read it. A function reading it several times is reported
|
|
371
438
|
once, where it first reads it.
|
|
372
439
|
|
|
440
|
+
An entry point may declare `suffixes`, for receivers the engine cannot type. A project
|
|
441
|
+
reaches `python.django.db.models.QuerySet.annotate` through a manager on its own model,
|
|
442
|
+
`Item.objects.annotate(...)`, whose call derives the project's own symbol
|
|
443
|
+
`python.app.models.Item.objects.annotate` — `Item` is a project class, `objects` an
|
|
444
|
+
attribute the engine does not type — so the canonical entry point never matches. A
|
|
445
|
+
suffix matches any symbol of the project's own modules ending with a dot plus the
|
|
446
|
+
suffix:
|
|
447
|
+
|
|
448
|
+
```json
|
|
449
|
+
{"symbol": "python.django.db.models.QuerySet.annotate", "justification": "…",
|
|
450
|
+
"suffixes": ["objects.annotate", "objects.filter.annotate"]}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
A queryset chain is declared explicitly: `Item.objects.filter(...).annotate(...)`
|
|
454
|
+
derives `…objects.filter.annotate`, which only the second suffix matches. A suffix is
|
|
455
|
+
at least two dot-separated names, so a bare method name, matching every project method
|
|
456
|
+
of that name, cannot be declared; another package's symbol, such as
|
|
457
|
+
`other_lib.objects.annotate`, never matches. The finding names the advisory's symbol as
|
|
458
|
+
`entry_point` and the derived one as `symbol`, and the entry point's conditions and
|
|
459
|
+
`attacker_arguments` apply through a suffix as through the exact symbol. A project
|
|
460
|
+
attribute chain genuinely ending with a declared suffix matches too — the vulnerable
|
|
461
|
+
version range and the conditions still gate what is reported.
|
|
462
|
+
|
|
373
463
|
A filter of Django's own libraries that a project template applies is a call to the
|
|
374
464
|
function behind it, placed at the template's line: `{{ bio|striptags }}` calls
|
|
375
465
|
`python.django.template.defaultfilters.striptags`, and so do filters in tag arguments
|
|
@@ -471,6 +561,16 @@ a call passing a variable, or unpacking `*args` or `**kwargs`, leaves the condit
|
|
|
471
561
|
pending review. A `semantic` condition — the document's tags, the platform, the
|
|
472
562
|
template's origin — cannot be decided and is always pending review, never dropped.
|
|
473
563
|
|
|
564
|
+
An `argument` condition with `"present": true` says the argument being passed at all,
|
|
565
|
+
whatever its value, is the condition, as a `\r` in `web.Response(reason=…)` needs
|
|
566
|
+
`reason` given, constant or not: `{"kind": "argument", "text": "…", "argument":
|
|
567
|
+
"reason", "position": 1, "present": true}`, exclusive with `values` and `default`. A
|
|
568
|
+
call giving the argument — positionally, by keyword, or through a `**` literal with
|
|
569
|
+
constant keys, which is folded into the keywords — meets it even when the value is
|
|
570
|
+
unknown; a call surely not giving it does not reach the vulnerability and is ruled out
|
|
571
|
+
(`(reason absent)`); a call unpacking `*args` or a `**mapping` whose keys the engine
|
|
572
|
+
cannot read leaves it pending review.
|
|
573
|
+
|
|
474
574
|
A `host` condition says the attacker must choose the host of the URL passed as
|
|
475
575
|
`argument` (or at `position`), as credentials leaking to the host of a crafted URL
|
|
476
576
|
need: `{"kind": "host", "text": "…", "argument": "url", "position": 0}`. It is
|
|
@@ -514,6 +614,47 @@ Keys passed through a project wrapper stay pending, and `mapping.update(other)`,
|
|
|
514
614
|
taint. A literal the function fills after building it (`m = {}; m[alias] = expr`)
|
|
515
615
|
has keys the literal does not write, so the call is not ruled out.
|
|
516
616
|
|
|
617
|
+
A `sequence` condition says the flaw spans two calls on one receiver: a first call
|
|
618
|
+
leaves state on the object, and the entry point — the second call — reuses it, as
|
|
619
|
+
`Session.get(url, verify=False)` disables certificate verification for the pooled
|
|
620
|
+
connection a later `Session.get(other)` on the same session reuses (requests
|
|
621
|
+
CVE-2024-35195). It names the `method` the first call must be, by canonical name or
|
|
622
|
+
`.`-suffix, and, optionally, the argument that call must carry, read as an argument
|
|
623
|
+
condition reads it:
|
|
624
|
+
|
|
625
|
+
```json
|
|
626
|
+
{
|
|
627
|
+
"kind": "sequence",
|
|
628
|
+
"text": "a prior call on the same session disabled certificate verification",
|
|
629
|
+
"method": "Session.get",
|
|
630
|
+
"argument": "verify",
|
|
631
|
+
"values": ["False"]
|
|
632
|
+
}
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
The engine follows a receiver bound once in the analysed function to the result of a
|
|
636
|
+
call or a `with` and used only to call its methods. The outcome has three cases:
|
|
637
|
+
|
|
638
|
+
- A prior call on the same receiver, on every path to the entry call, matches the
|
|
639
|
+
method and carries a value in `values` (`default` for an absent argument): the
|
|
640
|
+
condition is met, and the evidence names that call's line.
|
|
641
|
+
- The receiver's whole lifetime is visible and no such prior call can precede — one
|
|
642
|
+
call alone on the receiver, or the two calls on different receivers: the condition
|
|
643
|
+
is contradicted, the call is ruled out
|
|
644
|
+
(`app.fetch:6 python.requests.Session.get(no prior Session.get on the receiver)`)
|
|
645
|
+
and a project with only such calls stays `not_affected`.
|
|
646
|
+
- Otherwise the condition stays pending review: a receiver the engine cannot follow —
|
|
647
|
+
a parameter, a module-level instance, one passed to another function or mutated
|
|
648
|
+
through an attribute such as `s.verify = False` — a prior call whose arguments a
|
|
649
|
+
`*`/`**` unpacking leaves undecided, or a flow reaching the entry point inside a
|
|
650
|
+
callee.
|
|
651
|
+
|
|
652
|
+
Only a prior call on every path to the entry call counts as before it: a matching
|
|
653
|
+
call in a branch that may not run, or a textually later one, leaves the condition
|
|
654
|
+
pending, since a loop may bring it before the entry call. A call that itself carries
|
|
655
|
+
what the condition requires of the first call is never ruled out either: across the
|
|
656
|
+
iterations of a loop it is its own prior.
|
|
657
|
+
|
|
517
658
|
Every dependency finding records the highest level of evidence established in its
|
|
518
659
|
`level` metadata: `declared` (the requirement allows a vulnerable version), `imported`
|
|
519
660
|
(a module of the package is imported somewhere), `reachable` (an entry point or affected
|
|
@@ -577,7 +718,7 @@ project's behalf would go unseen. Without a lock file, a package is never
|
|
|
577
718
|
`not_affected`. The document's `@id` derives from its statements, so two runs with the
|
|
578
719
|
same result share it; its `author` is `Unknown Author`, as OpenVEX tools write when they
|
|
579
720
|
cannot know it. Its `tooling` names the analyzer and each component with its digest
|
|
580
|
-
(`coretrace-python-analyzer 0.
|
|
721
|
+
(`coretrace-python-analyzer 0.22.0; curated-advisories 2026.09.25 (sha256:…)`), so the
|
|
581
722
|
`@id` changes with the advisory data a statement was decided with.
|
|
582
723
|
|
|
583
724
|
## Large projects
|
|
File without changes
|