coretrace-python-analyzer 0.17.0__tar.gz → 0.18.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.17.0 → coretrace_python_analyzer-0.18.0}/CHANGELOG.md +10 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/PKG-INFO +1 -1
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/docs/plugins.md +1 -1
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/docs/usage.md +6 -6
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/pyproject.toml +1 -1
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/__init__.py +1 -1
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/taint/engine.py +15 -4
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/taint/models.py +7 -2
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/taint/templates.py +11 -2
- coretrace_python_analyzer-0.18.0/tests/test_declared_entry_points.py +155 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_release.py +1 -1
- coretrace_python_analyzer-0.18.0/tests/test_unreadable_templates.py +70 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/.github/workflows/ci.yml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/.github/workflows/release.yml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/.gitignore +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/LICENSE +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/NOTICE +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/README.md +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/docs/architecture.md +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/examples/add.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/examples/canonical_symbols.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/__main__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/abstract/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/abstract/constants.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/abstract/heap.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/abstract/ranges.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/abstract/strings.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/abstract/values.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/analysis/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/analysis/manager.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/analysis/provider.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/dependency_policy/dependency_policy.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/dependency_policy/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/reachable_vulnerability/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/reachable_vulnerability/reachable_vulnerability.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/sample_advisories/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/sample_advisories/sample_advisories.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/vulnerable_dependency/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/vulnerable_dependency/vulnerable_dependency.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/aiohttp/aiohttp_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/aiohttp/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/bottle/bottle_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/bottle/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/cli/cli_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/cli/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/credentials/credential_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/credentials/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/db_drivers/db_driver_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/db_drivers/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/django/django_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/django/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/fastapi/fastapi_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/fastapi/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/flask/flask_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/flask/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/http_clients/http_client_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/http_clients/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/python_stdlib/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/python_stdlib/python_stdlib.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/sqlalchemy/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/sqlalchemy/sqlalchemy_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/tornado/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/tornado/tornado_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/secrets/config_secrets/config_secrets.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/secrets/config_secrets/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/secrets/hardcoded_secrets/hardcoded_secrets.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/secrets/hardcoded_secrets/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/code_injection/code_injection.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/code_injection/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/command_injection/command_injection.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/command_injection/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/insecure_deserialization/insecure_deserialization.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/insecure_deserialization/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/nosql_injection/nosql_injection.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/nosql_injection/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/open_redirect/open_redirect.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/open_redirect/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/path_traversal/path_traversal.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/path_traversal/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/plaintext_credentials/plaintext_credentials.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/plaintext_credentials/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/sql_injection/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/sql_injection/sql_injection.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/ssrf/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/ssrf/ssrf.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/xss/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/xss/xss.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/dangerous_eval/dangerous_eval.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/dangerous_eval/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/flask_debug/flask_debug.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/flask_debug/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/insecure_tempfile/insecure_tempfile.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/insecure_tempfile/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/insecure_tls/insecure_tls.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/insecure_tls/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/missing_timeout/missing_timeout.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/missing_timeout/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/unsafe_archive/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/unsafe_archive/unsafe_archive.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/unsafe_xml/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/unsafe_xml/unsafe_xml.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/weak_crypto/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/weak_crypto/weak_crypto.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/weak_random/plugin.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/weak_random/weak_random.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/cache.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/cfg/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/cfg/builder.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/cfg/dominance.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/cfg/model.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/cli.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dataflow/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dataflow/lattice.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dataflow/solver.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/advisories.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/correlation.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/graph.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/policy.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/sbom.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/vex.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/engine.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/baseline.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/coverage.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/model.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/provenance.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/refutation.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/suppressions.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/frontend/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/frontend/ast_adapter.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/frontend/parser.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/hir/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/hir/nodes.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/hir/visitors.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/interprocedural/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/interprocedural/callgraph.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/interprocedural/modulegraph.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/interprocedural/summaries.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/ir/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/ir/defuse.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/ir/lowering.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/ir/model.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/ir/printer.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/ir/ssa.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/api.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/detectors.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/loader.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/manifest.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/registry.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/secrets.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/reporters/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/reporters/json_format.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/reporters/report.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/reporters/sarif.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/reporters/text.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/semantic/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/semantic/identity.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/semantic/imports.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/semantic/scopes.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/semantic/symbols.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/source/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/source/manager.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/source/model.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/taint/__init__.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/taint/routes.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/taint/urls.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/Chatbot.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/DjangoGoat.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/Flask-Image-Editing-Website.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/InsecureGram.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/MiniBookApiServer.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/NPL-IA.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/Spam-Detection-Project.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/Vulnerable_fastapi.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/dvpwa.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/full-stack-fastapi-template.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/healthchecks.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/httpie.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/luigi.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/my_gdb.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/network-topologer.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/pygoat.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/uploadbox-cloud-storage-solution.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/vulnerable-flask.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/yt-fts.json +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/fixtures/vulnerable-flask/README.md +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/fixtures/vulnerable-flask/app.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/fixtures/vulnerable-flask/requirements.txt +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/fixtures/vulnerable-flask/vulnerable_services.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/repositories.toml +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_advisory_evidence.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_advisory_feeds.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_advisory_url_host.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_aiohttp_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_analysis_manager.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_architecture.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_argument_conditions.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_attacker_arguments.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_audit_detectors.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_base_patterns.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_baseline.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_cache.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_cfg.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_class_keywords_with_targets.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_cli.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_closures.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_code_injection.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_config_secrets_coverage.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_constants.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_correlation.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_credential_context.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_dataflow.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_dependencies.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_detectors.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_discovery.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_django_http_clients.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_django_routes.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_django_safe_values.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_docs.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_dominance.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_emit_ir.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_exceptions.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_factories_match_loop_else.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_fail_on.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_fastapi_cli_precision.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_frameworks.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_frontend_gaps.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_heap.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_hex_digests.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_hir_builder.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_imports.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_interprocedural.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_interprocedural_taint.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_ir.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_match_patterns.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_members.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_module_level.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_nonlocal_writeback.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_nosql_injection.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_open_redirect_destinations.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_operator_sources.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_packaging.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_parallel.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_parser.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_plaintext_credentials.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_plugins.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_project.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_project_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_project_validators.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_provenance.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_pyir_imports.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_read_entry_points.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_real_code_precision.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_redirect_targets.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_refutation.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_refutation_evidence.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_regression.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_relative_paths.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_remaining_limits.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_reporters.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_safe_arguments.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_scale.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_scopes.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_secrets_sbom.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_self_state.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_source_manager.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_ssa.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_ssrf_destinations.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_ssrf_targets.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_summary_sanitizers.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_suppressions.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_symbol_resolution.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_symbols.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_syntactic_rules.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_syntax_control_flow.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_syntax_coverage.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_syntax_expressions.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_taint.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_template_context_flows.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_template_escaping.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_template_filter_calls.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_template_request_processor.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_tornado_bottle_models.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_url_proof.py +0 -0
- {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_vex.py +0 -0
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.18.0 (2026-09-28)
|
|
4
|
+
|
|
5
|
+
### Precision
|
|
6
|
+
|
|
7
|
+
- A Django template file the analyzer cannot read, because of its permissions, no longer counts as escaping everything it renders: it read the file as empty text, and an empty template escapes. The flow through `render_to_string` stays `xss`, and a template extending or including the unreadable one is not established to escape either, as for a template the analyzer cannot find. An unreadable file was already listed among the templates the project names but the run could not read.
|
|
8
|
+
|
|
9
|
+
### Plugins
|
|
10
|
+
|
|
11
|
+
- An `EntryPoint` may name a project function or class by its own symbol, `python.app.handlers.main`, so an integration reading a deployment declaration, a SAM template or a `serverless.yml`, can make a bare Lambda handler an entry point; the engine itself infers nothing from a function's name. `EntryPoint.inputs` limits the parameters that are input to the given positions, after `self` for a method: the handler's event, not its context (#180).
|
|
12
|
+
|
|
3
13
|
## 0.17.0 (2026-09-28)
|
|
4
14
|
|
|
5
15
|
### Plugins
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: coretrace-python-analyzer
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.18.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
|
|
@@ -151,7 +151,7 @@ class BottleModels(ModelPlugin):
|
|
|
151
151
|
| `Source(symbol, label, kinds=ALL)` | A call or attribute whose value is attacker-controlled; `label` names it in messages (`http`, `stdin`, `argv`, `http-response`). `kinds` restricts what it can inject. Text input, such as a form field, a header or a URL parameter, carries `TEXT_KINDS`, every kind but `NOSQL`: a string cannot hold a query operator. |
|
|
152
152
|
| `Sink(symbol, kinds, positions=(), keywords=())` | A call dangerous for `kinds`. `positions` limits a kind to the given argument indexes, and `keywords` to the given keyword names; a restricted kind reaches only the arguments listed there. SQL sinks read the statement only, and the SSRF sinks of HTTP clients read the URL, by position or as `url=`. A starred argument or `**kwargs` reaches no restricted kind. |
|
|
153
153
|
| `Sanitizer(symbol, kinds)` | A call whose result is safe for `kinds`, including when the call is inside a project function the data goes through. |
|
|
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
|
|
154
|
+
| `EntryPoint(symbol, label, kinds=ALL, inputs=None)` | A decorator or a class base whose functions receive their parameters as `label` input, such as `flask.Flask.route`; or a project function or class named by its own symbol (`python.app.handlers.main`), as an integration reading a deployment declaration names a Lambda handler. `inputs` limits the parameters that are input to those positions, after `self` for a method: a handler's event, not its context. |
|
|
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
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. |
|
|
@@ -156,9 +156,9 @@ It establishes escaping only when all of the following hold:
|
|
|
156
156
|
- No Python file of the project sets `autoescape` to `False`.
|
|
157
157
|
|
|
158
158
|
The analyzer never assumes escaping where it cannot read the template. That covers a
|
|
159
|
-
template
|
|
160
|
-
`templates`, one shipped by an installed package, one
|
|
161
|
-
and Flask's Jinja2 templates. The flow is then reported as before. A single-file check
|
|
159
|
+
template file it cannot read, a template named by an expression, a template found
|
|
160
|
+
through a `DIRS` entry not named `templates`, one shipped by an installed package, one
|
|
161
|
+
rendered through `get_template`, and Flask's Jinja2 templates. The flow is then reported as before. A single-file check
|
|
162
162
|
reads no template.
|
|
163
163
|
|
|
164
164
|
### Dangerous API usage
|
|
@@ -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.18.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.18.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.18.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
|
|
@@ -835,7 +835,8 @@ def function_entry_point(
|
|
|
835
835
|
project: SummaryIndex | None = None,
|
|
836
836
|
) -> EntryPoint | None:
|
|
837
837
|
"""The entry point ``function`` is: one of its decorators or, for a method, one of its
|
|
838
|
-
class's bases matching an entry-point model,
|
|
838
|
+
class's bases matching an entry-point model, a registration elsewhere (``routes``), or
|
|
839
|
+
a model naming the function, or its class, by its own project symbol."""
|
|
839
840
|
|
|
840
841
|
owner = _owner(module, function)
|
|
841
842
|
enclosing_function = _enclosing(module, function)
|
|
@@ -843,14 +844,22 @@ def function_entry_point(
|
|
|
843
844
|
# ``app = Flask(__name__)`` inside ``create_app``: routes defined there resolve.
|
|
844
845
|
instances = {**(instances or {}), **local_instances(enclosing_function, scopes, symbols)}
|
|
845
846
|
entry = entry_point_of(function, models, scopes, symbols, owner, instances, project)
|
|
846
|
-
if entry is None
|
|
847
|
+
if entry is None:
|
|
847
848
|
qualified = function.name if owner is None else f"{owner.name}.{function.name}"
|
|
848
|
-
entry =
|
|
849
|
+
entry = _declared(project_symbol(module.name, qualified), models, routes)
|
|
849
850
|
if entry is None and owner is not None:
|
|
850
|
-
entry =
|
|
851
|
+
entry = _declared(project_symbol(module.name, owner.name), models, routes)
|
|
851
852
|
return entry
|
|
852
853
|
|
|
853
854
|
|
|
855
|
+
def _declared(symbol: SymbolId, models: ModelTable, routes: Routes | None) -> EntryPoint | None:
|
|
856
|
+
"""The entry point a project ``symbol`` is: registered as a handler, or named by a
|
|
857
|
+
model."""
|
|
858
|
+
|
|
859
|
+
registered = routes.get(symbol) if routes else None
|
|
860
|
+
return registered if registered is not None else models.entry_point(symbol)
|
|
861
|
+
|
|
862
|
+
|
|
854
863
|
def _owner(module: nodes.Module, function: nodes.Function) -> nodes.Class | None:
|
|
855
864
|
"""The top-level class ``function`` is a method of, if any."""
|
|
856
865
|
|
|
@@ -891,6 +900,8 @@ def parameter_sources(
|
|
|
891
900
|
for index in range(first, len(function.parameters)):
|
|
892
901
|
if index - first < len(roles) and roles[index - first] is not None:
|
|
893
902
|
continue
|
|
903
|
+
if entry.inputs is not None and index - first not in entry.inputs:
|
|
904
|
+
continue
|
|
894
905
|
annotation = function.parameters[index].annotation
|
|
895
906
|
text = (request is not None and index > first) or (
|
|
896
907
|
annotation is not None and _scalar(annotation, symbols, enclosing)
|
|
@@ -110,12 +110,17 @@ class Sanitizer:
|
|
|
110
110
|
|
|
111
111
|
@dataclass(frozen=True)
|
|
112
112
|
class EntryPoint:
|
|
113
|
-
"""Functions decorated by ``symbol``,
|
|
114
|
-
|
|
113
|
+
"""Functions decorated by ``symbol``, methods of classes deriving from it, and, when
|
|
114
|
+
``symbol`` names a project function or class, that function or the class's methods
|
|
115
|
+
receive attacker-controlled parameters: those at ``inputs``, by position after
|
|
116
|
+
``self`` for a method, or every parameter when ``inputs`` is None. A deployment
|
|
117
|
+
declaration an integration reads names a Lambda handler this way, whose event is
|
|
118
|
+
input and whose context is not."""
|
|
115
119
|
|
|
116
120
|
symbol: SymbolId
|
|
117
121
|
label: str
|
|
118
122
|
kinds: TaintKind = TaintKind.ALL
|
|
123
|
+
inputs: tuple[int, ...] | None = None
|
|
119
124
|
|
|
120
125
|
|
|
121
126
|
@dataclass(frozen=True)
|
|
@@ -15,7 +15,8 @@ it extends or includes, can output data unescaped:
|
|
|
15
15
|
|
|
16
16
|
Templates are found under the project's ``templates`` directories, by their path below
|
|
17
17
|
one. A template the engine cannot find — named by an expression, under a ``DIRS`` entry
|
|
18
|
-
of another name, shipped by an installed package — is never assumed to
|
|
18
|
+
of another name, shipped by an installed package — or cannot read is never assumed to
|
|
19
|
+
escape.
|
|
19
20
|
|
|
20
21
|
A template applying a filter of Django's own libraries calls the function behind it
|
|
21
22
|
whenever it is rendered, though no Python call names that function: ``{{ bio|striptags }}``
|
|
@@ -149,7 +150,7 @@ def escaped_templates(root: Path) -> frozenset[str]:
|
|
|
149
150
|
local: dict[str, bool] = {}
|
|
150
151
|
requires: dict[str, set[str]] = {}
|
|
151
152
|
for name, paths in found.items():
|
|
152
|
-
verdicts = [
|
|
153
|
+
verdicts = [_verdict(path) for path in paths]
|
|
153
154
|
local[name] = all(safe for safe, _ in verdicts)
|
|
154
155
|
requires[name] = {needed for _, needs in verdicts for needed in needs}
|
|
155
156
|
escaped = {name for name, safe in local.items() if safe}
|
|
@@ -171,6 +172,14 @@ def _read(path: Path) -> str:
|
|
|
171
172
|
return _text(path) or ""
|
|
172
173
|
|
|
173
174
|
|
|
175
|
+
def _verdict(path: Path) -> tuple[bool, set[str]]:
|
|
176
|
+
"""Whether one template file escapes all it prints, and what it needs: a file the
|
|
177
|
+
engine cannot read is not established to escape, like a template it cannot find."""
|
|
178
|
+
|
|
179
|
+
text = _text(path)
|
|
180
|
+
return (False, set()) if text is None else _inspect(text)
|
|
181
|
+
|
|
182
|
+
|
|
174
183
|
def _text(path: Path) -> str | None:
|
|
175
184
|
"""The text of ``path``, or None when it cannot be read."""
|
|
176
185
|
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Entry points declared by their own symbol, with the parameters that are input.
|
|
2
|
+
|
|
3
|
+
Nothing in a bare AWS Lambda handler, ``def main(event, context)``, marks it: no
|
|
4
|
+
decorator, no base class, no registration call. What marks it is a deployment
|
|
5
|
+
declaration, a SAM template or a ``serverless.yml``, which an integration reads and
|
|
6
|
+
turns into an ``EntryPoint`` naming the project function by its symbol,
|
|
7
|
+
``python.app.handlers.main``. The engine then treats the function as it treats a
|
|
8
|
+
decorated one, whatever its parameters are called. An ``EntryPoint`` may also say which
|
|
9
|
+
parameters are input, by position after ``self``: a handler's event is, its context is
|
|
10
|
+
not. A class named this way makes every method an entry point, as a registered class
|
|
11
|
+
does. A function named ``handler`` is nothing without a declaration.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
import pytest
|
|
19
|
+
|
|
20
|
+
from coretrace_python import engine
|
|
21
|
+
from coretrace_python.findings import Finding
|
|
22
|
+
from coretrace_python.plugins import ProjectContext, ProjectPlugin
|
|
23
|
+
from coretrace_python.source import SourceManager
|
|
24
|
+
|
|
25
|
+
MANIFEST = (
|
|
26
|
+
'name = "declared-handlers"\nversion = "1.0.0"\nplugin_api = ">=1,<2"\nrequires = []\n'
|
|
27
|
+
'provides = ["model.declared-handlers"]\n\n[entrypoint]\nmodule = "declared"\nclass = "Declared"\n'
|
|
28
|
+
)
|
|
29
|
+
PLUGIN = '''
|
|
30
|
+
from typing import ClassVar
|
|
31
|
+
|
|
32
|
+
from coretrace_python.plugins import ModelPlugin
|
|
33
|
+
from coretrace_python.semantic.symbols import SymbolId
|
|
34
|
+
from coretrace_python.taint import EntryPoint, Model
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Declared(ModelPlugin):
|
|
38
|
+
name: ClassVar[str] = "declared-handlers"
|
|
39
|
+
models: ClassVar[tuple[Model, ...]] = (
|
|
40
|
+
EntryPoint(SymbolId("python.app.handlers.main"), "event", inputs=(0,)),
|
|
41
|
+
EntryPoint(SymbolId("python.app.handlers.Jobs.run"), "event", inputs=(0,)),
|
|
42
|
+
EntryPoint(SymbolId("python.app.handlers.Worker"), "event"),
|
|
43
|
+
EntryPoint(SymbolId("python.handlers.main"), "event", inputs=(0,)),
|
|
44
|
+
EntryPoint(SymbolId("python.jobs.task"), "queue", inputs=(1,)),
|
|
45
|
+
)
|
|
46
|
+
'''
|
|
47
|
+
HANDLERS = (
|
|
48
|
+
"import os\n\n"
|
|
49
|
+
"def main(evt, ctx):\n"
|
|
50
|
+
" os.system(evt['cmd'])\n"
|
|
51
|
+
" os.system(ctx.function_name)\n\n"
|
|
52
|
+
"def handler(event, context):\n"
|
|
53
|
+
" os.system(event['cmd'])\n\n"
|
|
54
|
+
"class Jobs:\n"
|
|
55
|
+
" def run(self, event, context):\n"
|
|
56
|
+
" os.system(event['cmd'])\n"
|
|
57
|
+
" os.system(context.function_name)\n\n"
|
|
58
|
+
" def other(self, event, context):\n"
|
|
59
|
+
" os.system(event['cmd'])\n\n"
|
|
60
|
+
"class Worker:\n"
|
|
61
|
+
" def start(self, event, context):\n"
|
|
62
|
+
" os.system(event['cmd'])\n"
|
|
63
|
+
" os.system(context.function_name)\n"
|
|
64
|
+
)
|
|
65
|
+
EVENT_LINES = [4, 12, 20, 21]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def plugins(tmp_path: Path) -> Path:
|
|
69
|
+
plugin = tmp_path / "plugins" / "declared"
|
|
70
|
+
plugin.mkdir(parents=True, exist_ok=True)
|
|
71
|
+
(plugin / "plugin.toml").write_text(MANIFEST, encoding="utf-8")
|
|
72
|
+
(plugin / "declared.py").write_text(PLUGIN, encoding="utf-8")
|
|
73
|
+
return tmp_path / "plugins"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def project(tmp_path: Path, files: dict[str, str]) -> Path:
|
|
77
|
+
root = tmp_path / "project"
|
|
78
|
+
for relative, text in {"app/__init__.py": "", **files}.items():
|
|
79
|
+
(root / relative).parent.mkdir(parents=True, exist_ok=True)
|
|
80
|
+
(root / relative).write_text(text, encoding="utf-8")
|
|
81
|
+
return root
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def commands(findings: tuple[Finding, ...]) -> list[tuple[int, str]]:
|
|
85
|
+
return sorted((f.span.start_line, f.metadata["source_label"]) for f in findings if f.rule_id == "command-injection")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def analyze(tmp_path: Path, files: dict[str, str], **options: object) -> list[tuple[int, str]]:
|
|
89
|
+
root = project(tmp_path, files)
|
|
90
|
+
roots = [engine.BUNDLED_PLUGINS, plugins(tmp_path)]
|
|
91
|
+
return commands(engine.analyze_project(root, roots, **options).findings) # type: ignore[arg-type]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# --------------------------------------------------------------------------- declared
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@pytest.mark.parametrize("jobs", [1, 2])
|
|
98
|
+
def test_a_function_declared_by_its_symbol_receives_its_inputs_whatever_their_names(tmp_path: Path, jobs: int) -> None:
|
|
99
|
+
files = {"app/handlers.py": HANDLERS, "app/other.py": "X = 1\n"}
|
|
100
|
+
|
|
101
|
+
# ``main``'s event, ``Jobs.run``'s event, and everything ``Worker.start`` takes;
|
|
102
|
+
# not the contexts of ``main`` and ``Jobs.run``, not ``handler``, not ``Jobs.other``.
|
|
103
|
+
assert analyze(tmp_path, files, jobs=jobs) == [(line, "event") for line in EVENT_LINES]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_a_function_named_handler_is_nothing_without_a_declaration(tmp_path: Path) -> None:
|
|
107
|
+
module = "import os\n\ndef handler(event, context):\n os.system(event['cmd'])\n\ndef lambda_handler(event, context):\n os.system(event['cmd'])\n"
|
|
108
|
+
|
|
109
|
+
assert analyze(tmp_path, {"app/lambda_function.py": module}) == []
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_a_single_file_check_honours_a_declared_symbol(tmp_path: Path) -> None:
|
|
113
|
+
source = SourceManager().add_source("handlers.py", HANDLERS)
|
|
114
|
+
|
|
115
|
+
findings = engine.analyze_file(source, [engine.BUNDLED_PLUGINS, plugins(tmp_path)]).findings
|
|
116
|
+
|
|
117
|
+
assert commands(findings) == [(4, "event")]
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_the_inputs_of_a_decorated_entry_point_can_be_limited_too(tmp_path: Path) -> None:
|
|
121
|
+
module = (
|
|
122
|
+
"import os\n"
|
|
123
|
+
"from jobs import task\n\n"
|
|
124
|
+
"@task\n"
|
|
125
|
+
"def send(channel, payload):\n"
|
|
126
|
+
" os.system(channel)\n"
|
|
127
|
+
" os.system(payload)\n"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
assert analyze(tmp_path, {"app/tasks.py": module}) == [(7, "queue")]
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def test_a_project_plugin_sees_the_declared_functions_as_entry_points(tmp_path: Path) -> None:
|
|
134
|
+
seen: dict[str, str | None] = {}
|
|
135
|
+
|
|
136
|
+
class Peek(ProjectPlugin):
|
|
137
|
+
name = "peek"
|
|
138
|
+
|
|
139
|
+
def analyze_project(self, ctx: ProjectContext) -> tuple[Finding, ...]:
|
|
140
|
+
for module in ctx.modules:
|
|
141
|
+
for function in ctx.functions(module):
|
|
142
|
+
seen[function.name] = function.entry_point
|
|
143
|
+
return ()
|
|
144
|
+
|
|
145
|
+
root = project(tmp_path, {"app/handlers.py": HANDLERS})
|
|
146
|
+
|
|
147
|
+
engine.analyze_project(root, [engine.BUNDLED_PLUGINS, plugins(tmp_path)], plugins=[Peek()])
|
|
148
|
+
|
|
149
|
+
assert {name: seen[name] for name in ("main", "handler", "Jobs.run", "Jobs.other", "Worker.start")} == {
|
|
150
|
+
"main": "event",
|
|
151
|
+
"handler": None,
|
|
152
|
+
"Jobs.run": "event",
|
|
153
|
+
"Jobs.other": None,
|
|
154
|
+
"Worker.start": "event",
|
|
155
|
+
}
|
|
@@ -30,7 +30,7 @@ def require_changelog() -> None:
|
|
|
30
30
|
def test_the_version_is_declared_once_and_mirrored() -> None:
|
|
31
31
|
project = tomllib.loads((REPO / "pyproject.toml").read_text(encoding="utf-8"))["project"]
|
|
32
32
|
|
|
33
|
-
assert project["version"] == coretrace_python.__version__ == "0.
|
|
33
|
+
assert project["version"] == coretrace_python.__version__ == "0.18.0"
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def test_the_changelog_starts_with_the_current_version() -> None:
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""A template file the engine cannot read proves nothing about escaping.
|
|
2
|
+
|
|
3
|
+
The analyzer establishes that a Django template escapes everything it renders only from
|
|
4
|
+
its text. A template file it cannot read, because of its permissions, is not assumed to
|
|
5
|
+
escape, no more than a template it cannot find: the flow through ``render_to_string``
|
|
6
|
+
stays ``xss``, and a template extending or including the unreadable one is not
|
|
7
|
+
established either.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
import pytest
|
|
16
|
+
|
|
17
|
+
from coretrace_python import engine
|
|
18
|
+
from coretrace_python.taint.templates import escaped_templates
|
|
19
|
+
|
|
20
|
+
VIEW = (
|
|
21
|
+
"from django.http import HttpRequest, HttpResponse\n"
|
|
22
|
+
"from django.template.loader import render_to_string\n\n"
|
|
23
|
+
"def page(request: HttpRequest):\n"
|
|
24
|
+
" return HttpResponse(render_to_string('app/page.html', {'name': request.GET['name']}))\n"
|
|
25
|
+
)
|
|
26
|
+
ESCAPING = "<p>{{ name }}</p>\n"
|
|
27
|
+
|
|
28
|
+
pytestmark = pytest.mark.skipif(os.name != "posix" or os.geteuid() == 0, reason="needs a file its owner cannot read")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def write(root: Path, files: dict[str, str]) -> None:
|
|
32
|
+
for relative, text in files.items():
|
|
33
|
+
(root / relative).parent.mkdir(parents=True, exist_ok=True)
|
|
34
|
+
(root / relative).write_text(text, encoding="utf-8")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def unreadable(path: Path) -> None:
|
|
38
|
+
path.chmod(0)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest.fixture
|
|
42
|
+
def readable_again(tmp_path: Path): # type: ignore[no-untyped-def]
|
|
43
|
+
yield
|
|
44
|
+
for path in tmp_path.rglob("*"):
|
|
45
|
+
if path.is_file():
|
|
46
|
+
path.chmod(0o644)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_a_template_file_that_cannot_be_read_is_not_escaped(tmp_path: Path, readable_again: None) -> None:
|
|
50
|
+
write(tmp_path, {"app/templates/app/page.html": ESCAPING, "app/templates/app/other.html": ESCAPING})
|
|
51
|
+
unreadable(tmp_path / "app/templates/app/page.html")
|
|
52
|
+
|
|
53
|
+
assert escaped_templates(tmp_path) == frozenset({"app/other.html"})
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_rendering_a_template_that_cannot_be_read_stays_cross_site_scripting(tmp_path: Path, readable_again: None) -> None:
|
|
57
|
+
write(tmp_path, {"app/views.py": VIEW, "app/templates/app/page.html": ESCAPING})
|
|
58
|
+
unreadable(tmp_path / "app/templates/app/page.html")
|
|
59
|
+
|
|
60
|
+
findings = engine.analyze_project(tmp_path, [engine.BUNDLED_PLUGINS]).findings
|
|
61
|
+
|
|
62
|
+
assert [f.span.start_line for f in findings if f.rule_id == "xss"] == [5]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@pytest.mark.parametrize("tag", ["{% extends 'app/base.html' %}", "{% include 'app/base.html' %}"])
|
|
66
|
+
def test_a_template_needing_one_that_cannot_be_read_is_not_escaped(tmp_path: Path, readable_again: None, tag: str) -> None:
|
|
67
|
+
write(tmp_path, {"app/templates/app/page.html": tag + ESCAPING, "app/templates/app/base.html": ESCAPING})
|
|
68
|
+
unreadable(tmp_path / "app/templates/app/base.html")
|
|
69
|
+
|
|
70
|
+
assert escaped_templates(tmp_path) == frozenset()
|
{coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/.github/workflows/ci.yml
RENAMED
|
File without changes
|
{coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/.github/workflows/release.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/examples/canonical_symbols.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|