coretrace-python-analyzer 0.16.0__tar.gz → 0.17.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.16.0 → coretrace_python_analyzer-0.17.0}/CHANGELOG.md +6 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/PKG-INFO +1 -1
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/docs/plugins.md +1 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/docs/usage.md +3 -3
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/pyproject.toml +1 -1
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/__init__.py +1 -1
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/engine.py +7 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/interprocedural/__init__.py +4 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/interprocedural/callgraph.py +52 -7
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/interprocedural/summaries.py +6 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/taint/__init__.py +2 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/taint/engine.py +34 -7
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/taint/models.py +43 -1
- coretrace_python_analyzer-0.17.0/tests/test_base_patterns.py +326 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_release.py +1 -1
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/.github/workflows/ci.yml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/.github/workflows/release.yml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/.gitignore +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/LICENSE +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/NOTICE +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/README.md +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/docs/architecture.md +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/examples/add.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/examples/canonical_symbols.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/__main__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/abstract/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/abstract/constants.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/abstract/heap.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/abstract/ranges.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/abstract/strings.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/abstract/values.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/analysis/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/analysis/manager.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/analysis/provider.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/dependency/dependency_policy/dependency_policy.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/dependency/dependency_policy/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/dependency/reachable_vulnerability/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/dependency/reachable_vulnerability/reachable_vulnerability.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/dependency/sample_advisories/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/dependency/sample_advisories/sample_advisories.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/dependency/vulnerable_dependency/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/dependency/vulnerable_dependency/vulnerable_dependency.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/aiohttp/aiohttp_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/aiohttp/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/bottle/bottle_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/bottle/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/cli/cli_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/cli/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/credentials/credential_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/credentials/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/db_drivers/db_driver_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/db_drivers/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/django/django_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/django/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/fastapi/fastapi_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/fastapi/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/flask/flask_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/flask/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/http_clients/http_client_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/http_clients/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/python_stdlib/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/python_stdlib/python_stdlib.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/sqlalchemy/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/sqlalchemy/sqlalchemy_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/tornado/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/models/tornado/tornado_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/secrets/config_secrets/config_secrets.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/secrets/config_secrets/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/secrets/hardcoded_secrets/hardcoded_secrets.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/secrets/hardcoded_secrets/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/code_injection/code_injection.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/code_injection/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/command_injection/command_injection.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/command_injection/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/insecure_deserialization/insecure_deserialization.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/insecure_deserialization/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/nosql_injection/nosql_injection.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/nosql_injection/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/open_redirect/open_redirect.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/open_redirect/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/path_traversal/path_traversal.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/path_traversal/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/plaintext_credentials/plaintext_credentials.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/plaintext_credentials/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/sql_injection/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/sql_injection/sql_injection.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/ssrf/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/ssrf/ssrf.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/xss/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/security/xss/xss.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/dangerous_eval/dangerous_eval.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/dangerous_eval/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/flask_debug/flask_debug.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/flask_debug/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/insecure_tempfile/insecure_tempfile.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/insecure_tempfile/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/insecure_tls/insecure_tls.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/insecure_tls/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/missing_timeout/missing_timeout.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/missing_timeout/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/unsafe_archive/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/unsafe_archive/unsafe_archive.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/unsafe_xml/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/unsafe_xml/unsafe_xml.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/weak_crypto/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/weak_crypto/weak_crypto.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/weak_random/plugin.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/bundled/syntax/weak_random/weak_random.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/cache.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/cfg/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/cfg/builder.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/cfg/dominance.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/cfg/model.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/cli.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/dataflow/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/dataflow/lattice.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/dataflow/solver.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/dependency/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/dependency/advisories.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/dependency/correlation.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/dependency/graph.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/dependency/policy.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/dependency/sbom.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/dependency/vex.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/findings/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/findings/baseline.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/findings/coverage.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/findings/model.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/findings/provenance.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/findings/refutation.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/findings/suppressions.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/frontend/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/frontend/ast_adapter.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/frontend/parser.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/hir/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/hir/nodes.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/hir/visitors.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/interprocedural/modulegraph.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/ir/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/ir/defuse.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/ir/lowering.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/ir/model.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/ir/printer.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/ir/ssa.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/plugins/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/plugins/api.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/plugins/detectors.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/plugins/loader.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/plugins/manifest.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/plugins/registry.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/plugins/secrets.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/reporters/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/reporters/json_format.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/reporters/report.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/reporters/sarif.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/reporters/text.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/semantic/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/semantic/identity.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/semantic/imports.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/semantic/scopes.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/semantic/symbols.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/source/__init__.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/source/manager.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/source/model.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/taint/routes.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/taint/templates.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/taint/urls.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/Chatbot.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/DjangoGoat.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/Flask-Image-Editing-Website.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/InsecureGram.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/MiniBookApiServer.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/NPL-IA.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/Spam-Detection-Project.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/Vulnerable_fastapi.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/dvpwa.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/full-stack-fastapi-template.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/healthchecks.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/httpie.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/luigi.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/my_gdb.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/network-topologer.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/pygoat.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/uploadbox-cloud-storage-solution.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/vulnerable-flask.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/expected/yt-fts.json +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/fixtures/vulnerable-flask/README.md +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/fixtures/vulnerable-flask/app.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/fixtures/vulnerable-flask/requirements.txt +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/fixtures/vulnerable-flask/vulnerable_services.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/regression/repositories.toml +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_advisory_evidence.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_advisory_feeds.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_advisory_url_host.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_aiohttp_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_analysis_manager.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_architecture.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_argument_conditions.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_attacker_arguments.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_audit_detectors.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_baseline.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_cache.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_cfg.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_class_keywords_with_targets.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_cli.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_closures.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_code_injection.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_config_secrets_coverage.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_constants.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_correlation.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_credential_context.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_dataflow.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_dependencies.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_detectors.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_discovery.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_django_http_clients.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_django_routes.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_django_safe_values.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_docs.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_dominance.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_emit_ir.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_exceptions.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_factories_match_loop_else.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_fail_on.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_fastapi_cli_precision.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_frameworks.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_frontend_gaps.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_heap.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_hex_digests.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_hir_builder.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_imports.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_interprocedural.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_interprocedural_taint.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_ir.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_match_patterns.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_members.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_module_level.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_nonlocal_writeback.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_nosql_injection.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_open_redirect_destinations.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_operator_sources.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_packaging.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_parallel.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_parser.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_plaintext_credentials.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_plugins.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_project.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_project_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_project_validators.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_provenance.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_pyir_imports.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_read_entry_points.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_real_code_precision.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_redirect_targets.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_refutation.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_refutation_evidence.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_regression.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_relative_paths.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_remaining_limits.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_reporters.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_safe_arguments.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_scale.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_scopes.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_secrets_sbom.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_self_state.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_source_manager.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_ssa.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_ssrf_destinations.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_ssrf_targets.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_summary_sanitizers.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_suppressions.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_symbol_resolution.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_symbols.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_syntactic_rules.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_syntax_control_flow.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_syntax_coverage.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_syntax_expressions.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_taint.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_template_context_flows.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_template_escaping.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_template_filter_calls.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_template_request_processor.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_tornado_bottle_models.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_url_proof.py +0 -0
- {coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/tests/test_vex.py +0 -0
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.17.0 (2026-09-28)
|
|
4
|
+
|
|
5
|
+
### Plugins
|
|
6
|
+
|
|
7
|
+
- `BasePattern(pattern, label, parameters, kinds)` makes the methods of a class whose base's canonical symbol matches a regular expression entry points, for bases generated per project such as a gRPC servicer's, whatever the module's prefix and however the base is imported. Each parameter after `self` is, by position, either input of the model's kinds or an object of a class the model names, which the sources on that class taint without the object being input: a `Source` on `ServicerContext.invocation_metadata` gives the client's metadata, and `peer()` gives nothing. When the project holds the base, only the methods the base defines are entry points, so a servicer's utility methods are not; otherwise every method with the listed number of parameters is. `async` methods and the messages of an iterated parameter are covered (#176).
|
|
8
|
+
|
|
3
9
|
## 0.16.0 (2026-09-27)
|
|
4
10
|
|
|
5
11
|
### Advisories
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: coretrace-python-analyzer
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.17.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
|
|
@@ -154,6 +154,7 @@ class BottleModels(ModelPlugin):
|
|
|
154
154
|
| `EntryPoint(symbol, label, kinds=ALL)` | A decorator or a class base whose functions receive their parameters as `label` input, such as `flask.Flask.route`. |
|
|
155
155
|
| `TypedParameter(symbol, label, kinds=ALL)` | A class whose annotated parameters carry `label` input, such as Django's `HttpRequest`. |
|
|
156
156
|
| `NamedParameter(pattern, label, kinds)` | A regular expression on parameter names; matching parameters carry `kinds`, as `password` carries `CREDENTIAL`. |
|
|
157
|
+
| `BasePattern(pattern, label, parameters=(None,), kinds=ALL)` | A regular expression on the canonical symbol of a class's base, for bases generated per project such as a gRPC servicer's (`(?:^|\.)\w+_pb2_grpc\.\w+Servicer$`), whatever the module's prefix and however the base is imported. The methods taking the parameters listed, by position after `self`, are entry points: a position left `None` is `label` input carrying `kinds`; one holding a class symbol denotes an object of that class, which the sources on the class taint, as `invocation_metadata()` on a `ServicerContext`, without the object itself being input. When the project holds the base, only the methods the base defines count; otherwise every method with that number of parameters. Inheritance identifies a potential service, not its registration on a server. |
|
|
157
158
|
| `RouteRegistrar(symbol, argument, label, kinds=ALL, keyword=None)` | A call registering a view at argument `argument` (or `keyword`), such as Django's `path`; the view receives `label` input. |
|
|
158
159
|
| `SuffixSink(suffix, kinds, positions=())` | A sink matched by the end of the symbol, for methods of any class such as `objects.raw`. |
|
|
159
160
|
| `SafeArgument(symbol, argument, values, position=None, kinds=ALL)` | A call to the sink `symbol` whose `argument` (by keyword, or at `position`) denotes one of `values` is not a sink for `kinds`, such as `yaml.load` with `Loader=yaml.SafeLoader`. Values are written as the analyzer records arguments: a symbol by its canonical name, a constant as Python writes it (`True`). Only a value given explicitly makes the call safe. |
|
|
@@ -241,7 +241,7 @@ the directory of the checked file; a path outside it is printed as it is.
|
|
|
241
241
|
```json
|
|
242
242
|
{
|
|
243
243
|
"schema_version": 1,
|
|
244
|
-
"tool": {"name": "coretrace-python-analyzer", "version": "0.
|
|
244
|
+
"tool": {"name": "coretrace-python-analyzer", "version": "0.17.0"},
|
|
245
245
|
"root": "/home/me/project",
|
|
246
246
|
"findings": [
|
|
247
247
|
{
|
|
@@ -273,7 +273,7 @@ bytes. A single-file check lists no components.
|
|
|
273
273
|
|
|
274
274
|
```json
|
|
275
275
|
"tool": {
|
|
276
|
-
"name": "coretrace-python-analyzer", "version": "0.
|
|
276
|
+
"name": "coretrace-python-analyzer", "version": "0.17.0",
|
|
277
277
|
"components": [
|
|
278
278
|
{"kind": "plugin", "name": "curated-advisories", "version": "2026.09.25", "digest": "sha256:…"},
|
|
279
279
|
{"kind": "advisories", "name": "advisories.json", "digest": "sha256:…"}
|
|
@@ -513,7 +513,7 @@ project's behalf would go unseen. Without a lock file, a package is never
|
|
|
513
513
|
`not_affected`. The document's `@id` derives from its statements, so two runs with the
|
|
514
514
|
same result share it; its `author` is `Unknown Author`, as OpenVEX tools write when they
|
|
515
515
|
cannot know it. Its `tooling` names the analyzer and each component with its digest
|
|
516
|
-
(`coretrace-python-analyzer 0.
|
|
516
|
+
(`coretrace-python-analyzer 0.17.0; curated-advisories 2026.09.25 (sha256:…)`), so the
|
|
517
517
|
`@id` changes with the advisory data a statement was decided with.
|
|
518
518
|
|
|
519
519
|
## Large projects
|
{coretrace_python_analyzer-0.16.0 → coretrace_python_analyzer-0.17.0}/src/coretrace_python/engine.py
RENAMED
|
@@ -80,6 +80,7 @@ from coretrace_python.interprocedural import (
|
|
|
80
80
|
ModuleFunction,
|
|
81
81
|
ModuleGraph,
|
|
82
82
|
ProjectSummaries,
|
|
83
|
+
SignaturesAnalysis,
|
|
83
84
|
SummaryAnalysis,
|
|
84
85
|
SummaryIndex,
|
|
85
86
|
SymbolRead,
|
|
@@ -164,6 +165,7 @@ ALL_ANALYSES: tuple[AnyAnalysis, ...] = (
|
|
|
164
165
|
EscapedTemplates,
|
|
165
166
|
ClearingAnalysis,
|
|
166
167
|
TemplateCallsAnalysis,
|
|
168
|
+
SignaturesAnalysis,
|
|
167
169
|
)
|
|
168
170
|
|
|
169
171
|
|
|
@@ -205,6 +207,7 @@ class ResultsEvicted(TransformationPass):
|
|
|
205
207
|
EscapedTemplates,
|
|
206
208
|
ClearingAnalysis,
|
|
207
209
|
TemplateCallsAnalysis,
|
|
210
|
+
SignaturesAnalysis,
|
|
208
211
|
}
|
|
209
212
|
)
|
|
210
213
|
|
|
@@ -268,6 +271,7 @@ def build_manager(
|
|
|
268
271
|
table = (models or SecurityModelRegistry()).freeze()
|
|
269
272
|
manager.provide(SecurityModelAnalysis, table)
|
|
270
273
|
manager.provide(MembersAnalysis, table.members_by_class())
|
|
274
|
+
manager.provide(SignaturesAnalysis, table.signatures())
|
|
271
275
|
manager.provide(ClearingAnalysis, table.clearing())
|
|
272
276
|
manager.provide(ProjectSummaries, SummaryIndex())
|
|
273
277
|
manager.provide(RegisteredRoutes, _routes_of(manager))
|
|
@@ -323,6 +327,7 @@ def analyze_file(source: SourceFile, plugin_roots: Sequence[Path]) -> FileAnalys
|
|
|
323
327
|
table = plugin_models(loaded.plugin for loaded in registry)
|
|
324
328
|
manager.provide(SecurityModelAnalysis, table)
|
|
325
329
|
manager.provide(MembersAnalysis, table.members_by_class())
|
|
330
|
+
manager.provide(SignaturesAnalysis, table.signatures())
|
|
326
331
|
manager.provide(ClearingAnalysis, table.clearing())
|
|
327
332
|
manager.provide(ProjectSummaries, SummaryIndex())
|
|
328
333
|
manager.provide(RegisteredRoutes, _routes_of(manager))
|
|
@@ -418,6 +423,7 @@ def analyze_project(
|
|
|
418
423
|
for manager in managers.values():
|
|
419
424
|
manager.provide(SecurityModelAnalysis, models)
|
|
420
425
|
manager.provide(MembersAnalysis, members)
|
|
426
|
+
manager.provide(SignaturesAnalysis, models.signatures())
|
|
421
427
|
manager.provide(DependencyAnalysis, dependencies)
|
|
422
428
|
|
|
423
429
|
imports: dict[str, ImportTable] = {}
|
|
@@ -730,6 +736,7 @@ def _analyse_batch(batch: _Batch) -> dict[str, dict[str, Any]]:
|
|
|
730
736
|
for manager in managers.values():
|
|
731
737
|
manager.provide(SecurityModelAnalysis, models)
|
|
732
738
|
manager.provide(MembersAnalysis, members)
|
|
739
|
+
manager.provide(SignaturesAnalysis, models.signatures())
|
|
733
740
|
manager.provide(DependencyAnalysis, dependencies)
|
|
734
741
|
manager.provide(RegisteredRoutes, routes)
|
|
735
742
|
manager.provide(EscapedTemplates, escaped)
|
|
@@ -8,6 +8,8 @@ from coretrace_python.interprocedural.callgraph import (
|
|
|
8
8
|
ExternalSymbol,
|
|
9
9
|
KnownFunction,
|
|
10
10
|
ModuleFunction,
|
|
11
|
+
Signature,
|
|
12
|
+
SignaturesAnalysis,
|
|
11
13
|
SymbolRead,
|
|
12
14
|
Target,
|
|
13
15
|
UnknownTarget,
|
|
@@ -56,6 +58,8 @@ __all__ = [
|
|
|
56
58
|
"Mutation",
|
|
57
59
|
"NonlocalWrite",
|
|
58
60
|
"ProjectSummaries",
|
|
61
|
+
"Signature",
|
|
62
|
+
"SignaturesAnalysis",
|
|
59
63
|
"SummaryAnalysis",
|
|
60
64
|
"SummaryIndex",
|
|
61
65
|
"SummaryTable",
|
|
@@ -9,6 +9,7 @@ reads, called or not: reading ``request.form`` runs its getter.
|
|
|
9
9
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
|
+
import re
|
|
12
13
|
from collections.abc import Mapping
|
|
13
14
|
from dataclasses import dataclass, field
|
|
14
15
|
from types import MappingProxyType
|
|
@@ -104,6 +105,30 @@ class SymbolRead:
|
|
|
104
105
|
symbol: SymbolId
|
|
105
106
|
|
|
106
107
|
|
|
108
|
+
@dataclass(frozen=True)
|
|
109
|
+
class Signature:
|
|
110
|
+
"""What the parameters of the methods of a class denote when the canonical symbol
|
|
111
|
+
of its base matches ``pattern``, by position after ``self``: a class symbol, or None
|
|
112
|
+
for a parameter denoting none. A method taking another number of parameters has
|
|
113
|
+
none. The engine derives signatures from the security models (§16)."""
|
|
114
|
+
|
|
115
|
+
pattern: str
|
|
116
|
+
parameters: tuple[SymbolId | None, ...]
|
|
117
|
+
|
|
118
|
+
def matches(self, base: SymbolId) -> bool:
|
|
119
|
+
return re.search(self.pattern, base.canonical_name) is not None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class SignaturesAnalysis(Analysis[tuple[Signature, ...]]):
|
|
123
|
+
"""The signatures the models declare, provided by the engine; none on its own."""
|
|
124
|
+
|
|
125
|
+
name: ClassVar[str] = "interprocedural.signatures"
|
|
126
|
+
|
|
127
|
+
@classmethod
|
|
128
|
+
def compute(cls, ctx: AnalysisContext) -> tuple[Signature, ...]:
|
|
129
|
+
return ()
|
|
130
|
+
|
|
131
|
+
|
|
107
132
|
@dataclass(frozen=True)
|
|
108
133
|
class ModuleFunction:
|
|
109
134
|
"""One function of a module as a project plugin sees it: the name the call graph
|
|
@@ -357,6 +382,20 @@ def _annotated(
|
|
|
357
382
|
return found
|
|
358
383
|
|
|
359
384
|
|
|
385
|
+
def _declared(
|
|
386
|
+
function: nodes.Function, ssa: FunctionIR, bases: tuple[SymbolId, ...], signatures: tuple[Signature, ...]
|
|
387
|
+
) -> dict[Value, SymbolId]:
|
|
388
|
+
"""Parameters a signature types by their position, for a method of a class one of
|
|
389
|
+
whose ``bases`` matches the signature and which takes the parameters it lists."""
|
|
390
|
+
|
|
391
|
+
given = function.parameters[1:]
|
|
392
|
+
for signature in signatures:
|
|
393
|
+
if any(signature.matches(base) for base in bases) and len(given) == len(signature.parameters):
|
|
394
|
+
typed = zip(ssa.parameters[1:], signature.parameters, strict=False)
|
|
395
|
+
return {value: symbol for value, symbol in typed if symbol is not None}
|
|
396
|
+
return {}
|
|
397
|
+
|
|
398
|
+
|
|
360
399
|
def _typed_with_module_classes(
|
|
361
400
|
function: nodes.Function, ssa: FunctionIR, classes: Mapping[str, frozenset[str]]
|
|
362
401
|
) -> dict[Value, str]:
|
|
@@ -372,12 +411,15 @@ def _typed_with_module_classes(
|
|
|
372
411
|
|
|
373
412
|
class CallGraphAnalysis(Analysis[CallGraph]):
|
|
374
413
|
name: ClassVar[str] = "interprocedural.callgraph"
|
|
375
|
-
requires: ClassVar[frozenset[AnyAnalysis]] = frozenset(
|
|
414
|
+
requires: ClassVar[frozenset[AnyAnalysis]] = frozenset(
|
|
415
|
+
{SSAAnalysis, ScopeAnalysis, SymbolAnalysis, SignaturesAnalysis}
|
|
416
|
+
)
|
|
376
417
|
|
|
377
418
|
@classmethod
|
|
378
419
|
def compute(cls, ctx: AnalysisContext) -> CallGraph:
|
|
379
420
|
scopes = ctx.get(ScopeAnalysis)
|
|
380
421
|
table = ctx.get(SymbolAnalysis)
|
|
422
|
+
signatures = ctx.get(SignaturesAnalysis)
|
|
381
423
|
definitions: dict[str, nodes.Function] = {}
|
|
382
424
|
for function in analyzable_functions(ctx.module):
|
|
383
425
|
# A property and its setter, or a redefinition, share a qualified name; each
|
|
@@ -396,14 +438,15 @@ class CallGraphAnalysis(Analysis[CallGraph]):
|
|
|
396
438
|
for statement in ctx.module.body
|
|
397
439
|
if isinstance(statement, nodes.Class)
|
|
398
440
|
}
|
|
441
|
+
# Inheritance follows the first base that resolves; a signature may match any.
|
|
399
442
|
bases: dict[str, SymbolId] = {}
|
|
443
|
+
ancestry: dict[str, tuple[SymbolId, ...]] = {}
|
|
400
444
|
for statement in ctx.module.body:
|
|
401
445
|
if isinstance(statement, nodes.Class):
|
|
402
|
-
for
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
break
|
|
446
|
+
resolved = [table.resolve_expression(scopes.module_scope.id, base) for base in statement.bases]
|
|
447
|
+
ancestry[statement.name] = tuple(symbol for symbol in resolved if symbol is not None)
|
|
448
|
+
if ancestry[statement.name]:
|
|
449
|
+
bases[statement.name] = ancestry[statement.name][0]
|
|
407
450
|
sites: dict[str, tuple[CallSite, ...]] = {}
|
|
408
451
|
symbols: dict[str, Mapping[Value, SymbolId]] = {}
|
|
409
452
|
reads: dict[str, tuple[SymbolRead, ...]] = {}
|
|
@@ -418,11 +461,13 @@ class CallGraphAnalysis(Analysis[CallGraph]):
|
|
|
418
461
|
owner = name.rsplit(".", 1)[0] if "." in name and name.rsplit(".", 1)[0] in classes else None
|
|
419
462
|
if owner is not None and _is_staticmethod(function):
|
|
420
463
|
owner = None # a static method has no receiver
|
|
464
|
+
# A signature types parameters by their position; an annotation says more.
|
|
465
|
+
declared = _declared(function, ssa, ancestry.get(owner, ()) if owner is not None else (), signatures)
|
|
421
466
|
targets, symbols[name] = resolve_targets(
|
|
422
467
|
ssa,
|
|
423
468
|
scopes,
|
|
424
469
|
known,
|
|
425
|
-
_annotated(function, ssa, scopes, table),
|
|
470
|
+
{**declared, **_annotated(function, ssa, scopes, table)},
|
|
426
471
|
frozenset(definitions),
|
|
427
472
|
classes,
|
|
428
473
|
owner,
|
|
@@ -363,6 +363,12 @@ class SummaryIndex:
|
|
|
363
363
|
def summary(self, symbol: SymbolId) -> FunctionSummary | None:
|
|
364
364
|
return self.summaries.get(symbol)
|
|
365
365
|
|
|
366
|
+
def defines(self, owner: SymbolId) -> bool:
|
|
367
|
+
"""Whether the project defines a function of ``owner``, a class or a module."""
|
|
368
|
+
|
|
369
|
+
prefix = owner.canonical_name + "."
|
|
370
|
+
return any(s.canonical_name.startswith(prefix) for s in self.symbols)
|
|
371
|
+
|
|
366
372
|
def __eq__(self, other: object) -> bool:
|
|
367
373
|
return isinstance(other, SummaryIndex) and dict(self.summaries) == dict(other.summaries)
|
|
368
374
|
|
|
@@ -12,6 +12,7 @@ from coretrace_python.taint.engine import (
|
|
|
12
12
|
from coretrace_python.taint.models import (
|
|
13
13
|
TEXT_KINDS,
|
|
14
14
|
AuthorizationGuard,
|
|
15
|
+
BasePattern,
|
|
15
16
|
EntryPoint,
|
|
16
17
|
Model,
|
|
17
18
|
ModelError,
|
|
@@ -47,6 +48,7 @@ __all__ = [
|
|
|
47
48
|
"FILTER_FUNCTIONS",
|
|
48
49
|
"TEXT_KINDS",
|
|
49
50
|
"AuthorizationGuard",
|
|
51
|
+
"BasePattern",
|
|
50
52
|
"EntryPoint",
|
|
51
53
|
"EntryPointAnalysis",
|
|
52
54
|
"EscapedTemplates",
|
|
@@ -80,6 +80,7 @@ from coretrace_python.semantic.symbols import SymbolAnalysis, SymbolId, SymbolTa
|
|
|
80
80
|
from coretrace_python.source import SourceSpan
|
|
81
81
|
from coretrace_python.taint.models import (
|
|
82
82
|
TEXT_KINDS,
|
|
83
|
+
BasePattern,
|
|
83
84
|
EntryPoint,
|
|
84
85
|
ModelTable,
|
|
85
86
|
SecurityModelAnalysis,
|
|
@@ -780,9 +781,11 @@ def entry_point_of(
|
|
|
780
781
|
symbols: SymbolTable,
|
|
781
782
|
owner: nodes.Class | None = None,
|
|
782
783
|
instances: Instances | None = None,
|
|
784
|
+
project: SummaryIndex | None = None,
|
|
783
785
|
) -> EntryPoint | None:
|
|
784
786
|
"""The entry-point model matching one of the function's decorators or, for a
|
|
785
|
-
method, one of the bases of ``owner``, if any
|
|
787
|
+
method, one of the bases of ``owner``, if any: by symbol, or by a base pattern when
|
|
788
|
+
the method is one the pattern covers (``project`` says what the base defines)."""
|
|
786
789
|
|
|
787
790
|
scope = scopes.scope_for(function)
|
|
788
791
|
enclosing = scope.parent if scope.parent is not None else scope.id
|
|
@@ -803,9 +806,24 @@ def entry_point_of(
|
|
|
803
806
|
entry = models.entry_point(candidate)
|
|
804
807
|
if entry is not None:
|
|
805
808
|
return entry
|
|
809
|
+
pattern = models.base_pattern(candidate) if id(expression) in enclosing_of else None
|
|
810
|
+
if pattern is not None and _covered(function, candidate, pattern, project):
|
|
811
|
+
return EntryPoint(candidate, pattern.label, pattern.kinds)
|
|
806
812
|
return None
|
|
807
813
|
|
|
808
814
|
|
|
815
|
+
def _covered(function: nodes.Function, base: SymbolId, pattern: BasePattern, project: SummaryIndex | None) -> bool:
|
|
816
|
+
"""Whether a method of a class deriving from ``base`` is one ``pattern`` covers: it
|
|
817
|
+
takes the parameters the pattern lists and, when the project holds the base, the
|
|
818
|
+
base defines it; a utility method of the class is no entry point."""
|
|
819
|
+
|
|
820
|
+
if len(function.parameters) - 1 != len(pattern.parameters):
|
|
821
|
+
return False
|
|
822
|
+
if project is None or not project.defines(base):
|
|
823
|
+
return True
|
|
824
|
+
return project.summary(base.attribute(function.name)) is not None
|
|
825
|
+
|
|
826
|
+
|
|
809
827
|
def function_entry_point(
|
|
810
828
|
function: nodes.Function,
|
|
811
829
|
module: nodes.Module,
|
|
@@ -814,6 +832,7 @@ def function_entry_point(
|
|
|
814
832
|
symbols: SymbolTable,
|
|
815
833
|
instances: Instances | None = None,
|
|
816
834
|
routes: Routes | None = None,
|
|
835
|
+
project: SummaryIndex | None = None,
|
|
817
836
|
) -> EntryPoint | None:
|
|
818
837
|
"""The entry point ``function`` is: one of its decorators or, for a method, one of its
|
|
819
838
|
class's bases matching an entry-point model, or a registration elsewhere (``routes``)."""
|
|
@@ -823,7 +842,7 @@ def function_entry_point(
|
|
|
823
842
|
if enclosing_function is not None:
|
|
824
843
|
# ``app = Flask(__name__)`` inside ``create_app``: routes defined there resolve.
|
|
825
844
|
instances = {**(instances or {}), **local_instances(enclosing_function, scopes, symbols)}
|
|
826
|
-
entry = entry_point_of(function, models, scopes, symbols, owner, instances)
|
|
845
|
+
entry = entry_point_of(function, models, scopes, symbols, owner, instances, project)
|
|
827
846
|
if entry is None and routes:
|
|
828
847
|
qualified = function.name if owner is None else f"{owner.name}.{function.name}"
|
|
829
848
|
entry = routes.get(project_symbol(module.name, qualified))
|
|
@@ -849,23 +868,29 @@ def parameter_sources(
|
|
|
849
868
|
symbols: SymbolTable,
|
|
850
869
|
instances: Instances | None = None,
|
|
851
870
|
routes: Routes | None = None,
|
|
871
|
+
project: SummaryIndex | None = None,
|
|
852
872
|
) -> Mapping[int, Source]:
|
|
853
873
|
"""The attacker-controlled parameters of ``function``, by index: every parameter of an
|
|
854
874
|
entry point (``self`` excepted for a method), including one registered elsewhere
|
|
855
875
|
(``routes``), and every parameter annotated with a typed-parameter symbol. An entry
|
|
856
876
|
point's parameter annotated with scalars is text: FastAPI validates it before the
|
|
857
877
|
handler runs, and a scalar cannot hold a query operator. So are the URL parameters
|
|
858
|
-
a view receives after a request object.
|
|
878
|
+
a view receives after a request object. A parameter a base pattern types with a
|
|
879
|
+
class is not input: the sources on that class say what it gives."""
|
|
859
880
|
|
|
860
881
|
owner = _owner(module, function)
|
|
861
882
|
sources: dict[int, Source] = {}
|
|
862
883
|
scope = scopes.scope_for(function)
|
|
863
884
|
enclosing = scope.parent if scope.parent is not None else scope.id
|
|
864
|
-
entry = function_entry_point(function, module, models, scopes, symbols, instances, routes)
|
|
885
|
+
entry = function_entry_point(function, module, models, scopes, symbols, instances, routes, project)
|
|
865
886
|
if entry is not None:
|
|
866
887
|
first = 1 if owner is not None else 0
|
|
867
888
|
request = models.request_object(entry.symbol)
|
|
889
|
+
pattern = models.base_pattern(entry.symbol) if models.entry_point(entry.symbol) is None else None
|
|
890
|
+
roles = pattern.parameters if pattern is not None else ()
|
|
868
891
|
for index in range(first, len(function.parameters)):
|
|
892
|
+
if index - first < len(roles) and roles[index - first] is not None:
|
|
893
|
+
continue
|
|
869
894
|
annotation = function.parameters[index].annotation
|
|
870
895
|
text = (request is not None and index > first) or (
|
|
871
896
|
annotation is not None and _scalar(annotation, symbols, enclosing)
|
|
@@ -1010,11 +1035,12 @@ class TaintAnalysis(FunctionAnalysis[TaintFacts]):
|
|
|
1010
1035
|
graph = ctx.get(CallGraphAnalysis)
|
|
1011
1036
|
models = ctx.get(SecurityModelAnalysis)
|
|
1012
1037
|
scopes, symbols = ctx.get(ScopeAnalysis), ctx.get(SymbolAnalysis)
|
|
1013
|
-
|
|
1038
|
+
project = ctx.get(ProjectSummaries)
|
|
1039
|
+
instances = factory_instances(ctx.module, scopes, symbols, ctx.get(SummaryAnalysis), project)
|
|
1014
1040
|
routes = ctx.get(RegisteredRoutes)
|
|
1015
1041
|
|
|
1016
1042
|
def sources_of(member: nodes.Function) -> Mapping[int, Source]:
|
|
1017
|
-
return parameter_sources(member, ctx.module, models, scopes, symbols, instances, routes)
|
|
1043
|
+
return parameter_sources(member, ctx.module, models, scopes, symbols, instances, routes, project)
|
|
1018
1044
|
|
|
1019
1045
|
ssa = ctx.get(SSAAnalysis, function)
|
|
1020
1046
|
heap = ctx.get(HeapAnalysis, function)
|
|
@@ -1068,9 +1094,10 @@ class EntryPointAnalysis(Analysis[tuple[ModuleFunction, ...]]):
|
|
|
1068
1094
|
scopes, symbols = ctx.get(ScopeAnalysis), ctx.get(SymbolAnalysis)
|
|
1069
1095
|
instances = factory_instances(ctx.module, scopes, symbols, ctx.get(SummaryAnalysis), ctx.get(ProjectSummaries))
|
|
1070
1096
|
routes = ctx.get(RegisteredRoutes)
|
|
1097
|
+
project = ctx.get(ProjectSummaries)
|
|
1071
1098
|
functions: list[ModuleFunction] = []
|
|
1072
1099
|
for name, function in graph.definitions.items():
|
|
1073
|
-
entry = function_entry_point(function, ctx.module, models, scopes, symbols, instances, routes)
|
|
1100
|
+
entry = function_entry_point(function, ctx.module, models, scopes, symbols, instances, routes, project)
|
|
1074
1101
|
functions.append(ModuleFunction(name, function.span, entry.label if entry is not None else None))
|
|
1075
1102
|
return tuple(functions)
|
|
1076
1103
|
|
|
@@ -17,7 +17,7 @@ from types import MappingProxyType
|
|
|
17
17
|
from typing import ClassVar
|
|
18
18
|
|
|
19
19
|
from coretrace_python.analysis import Analysis, AnalysisContext, MissingInputError
|
|
20
|
-
from coretrace_python.interprocedural import Clearing, TemplateCalls, TemplateFilter
|
|
20
|
+
from coretrace_python.interprocedural import Clearing, Signature, TemplateCalls, TemplateFilter
|
|
21
21
|
from coretrace_python.semantic.symbols import Members, SymbolId
|
|
22
22
|
|
|
23
23
|
|
|
@@ -145,6 +145,32 @@ class NamedParameter:
|
|
|
145
145
|
return re.search(self.pattern, name) is not None
|
|
146
146
|
|
|
147
147
|
|
|
148
|
+
@dataclass(frozen=True)
|
|
149
|
+
class BasePattern:
|
|
150
|
+
"""Methods of a class whose base's canonical symbol matches ``pattern`` are entry
|
|
151
|
+
points labelled ``label``, when they take the parameters the model lists, by
|
|
152
|
+
position after ``self``: a position left None is attacker input carrying ``kinds``;
|
|
153
|
+
one holding a class symbol denotes an object of that class, which the sources on
|
|
154
|
+
the class taint. A gRPC servicer's RPCs take the request, or the iterator of the
|
|
155
|
+
client's messages, and a ``ServicerContext``. When the project holds the base,
|
|
156
|
+
only the methods it defines are entry points; otherwise every method with that
|
|
157
|
+
number of parameters. Inheritance identifies a potential service, not its
|
|
158
|
+
registration on a server."""
|
|
159
|
+
|
|
160
|
+
pattern: str
|
|
161
|
+
label: str
|
|
162
|
+
parameters: tuple[SymbolId | None, ...] = (None,)
|
|
163
|
+
kinds: TaintKind = TaintKind.ALL
|
|
164
|
+
|
|
165
|
+
@property
|
|
166
|
+
def symbol(self) -> SymbolId:
|
|
167
|
+
digest = hashlib.sha1(self.pattern.encode("utf-8")).hexdigest()[:12]
|
|
168
|
+
return SymbolId(f"python.base.p{digest}")
|
|
169
|
+
|
|
170
|
+
def matches(self, base: SymbolId) -> bool:
|
|
171
|
+
return re.search(self.pattern, base.canonical_name) is not None
|
|
172
|
+
|
|
173
|
+
|
|
148
174
|
@dataclass(frozen=True)
|
|
149
175
|
class RouteRegistrar:
|
|
150
176
|
"""A call registering a handler elsewhere (``path('login/', views.log_in)``): the
|
|
@@ -251,6 +277,7 @@ Model = (
|
|
|
251
277
|
| TemplateRender
|
|
252
278
|
| Members
|
|
253
279
|
| RequestObject
|
|
280
|
+
| BasePattern
|
|
254
281
|
)
|
|
255
282
|
|
|
256
283
|
|
|
@@ -270,6 +297,7 @@ class ModelTable:
|
|
|
270
297
|
template_renders: tuple[TemplateRender, ...] = ()
|
|
271
298
|
members: tuple[Members, ...] = ()
|
|
272
299
|
request_objects: tuple[RequestObject, ...] = ()
|
|
300
|
+
base_patterns: tuple[BasePattern, ...] = ()
|
|
273
301
|
_by_symbol: dict[type[Model], dict[SymbolId, Model]] = field(
|
|
274
302
|
init=False, repr=False, compare=False
|
|
275
303
|
)
|
|
@@ -287,6 +315,7 @@ class ModelTable:
|
|
|
287
315
|
SafeArgument: {m.symbol: m for m in self.safe_arguments},
|
|
288
316
|
TemplateRender: {m.symbol: m for m in self.template_renders},
|
|
289
317
|
RequestObject: {m.symbol: m for m in self.request_objects},
|
|
318
|
+
BasePattern: {m.symbol: m for m in self.base_patterns},
|
|
290
319
|
}
|
|
291
320
|
object.__setattr__(self, "_by_symbol", MappingProxyType(index))
|
|
292
321
|
|
|
@@ -356,8 +385,20 @@ class ModelTable:
|
|
|
356
385
|
self.template_renders,
|
|
357
386
|
self.members,
|
|
358
387
|
self.request_objects,
|
|
388
|
+
self.base_patterns,
|
|
359
389
|
)
|
|
360
390
|
|
|
391
|
+
def base_pattern(self, base: SymbolId) -> BasePattern | None:
|
|
392
|
+
"""The pattern model the canonical symbol of a class's ``base`` matches, if any."""
|
|
393
|
+
|
|
394
|
+
return next((m for m in self.base_patterns if m.matches(base)), None)
|
|
395
|
+
|
|
396
|
+
def signatures(self) -> tuple[Signature, ...]:
|
|
397
|
+
"""What the methods of the classes the base patterns match receive, by position,
|
|
398
|
+
for the call graph to type them."""
|
|
399
|
+
|
|
400
|
+
return tuple(Signature(m.pattern, m.parameters) for m in self.base_patterns)
|
|
401
|
+
|
|
361
402
|
def sanitizer(self, symbol: SymbolId) -> Sanitizer | None:
|
|
362
403
|
found = self._by_symbol[Sanitizer].get(symbol)
|
|
363
404
|
return found if isinstance(found, Sanitizer) else None
|
|
@@ -451,6 +492,7 @@ class SecurityModelRegistry:
|
|
|
451
492
|
template_renders=tuple(m for m in models if isinstance(m, TemplateRender)),
|
|
452
493
|
members=tuple(m for m in models if isinstance(m, Members)),
|
|
453
494
|
request_objects=tuple(m for m in models if isinstance(m, RequestObject)),
|
|
495
|
+
base_patterns=tuple(m for m in models if isinstance(m, BasePattern)),
|
|
454
496
|
)
|
|
455
497
|
|
|
456
498
|
|