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.
Files changed (287) hide show
  1. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/CHANGELOG.md +10 -0
  2. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/PKG-INFO +1 -1
  3. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/docs/plugins.md +1 -1
  4. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/docs/usage.md +6 -6
  5. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/pyproject.toml +1 -1
  6. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/__init__.py +1 -1
  7. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/taint/engine.py +15 -4
  8. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/taint/models.py +7 -2
  9. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/taint/templates.py +11 -2
  10. coretrace_python_analyzer-0.18.0/tests/test_declared_entry_points.py +155 -0
  11. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_release.py +1 -1
  12. coretrace_python_analyzer-0.18.0/tests/test_unreadable_templates.py +70 -0
  13. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/.github/workflows/ci.yml +0 -0
  14. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/.github/workflows/release.yml +0 -0
  15. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/.gitignore +0 -0
  16. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/LICENSE +0 -0
  17. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/NOTICE +0 -0
  18. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/README.md +0 -0
  19. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/docs/architecture.md +0 -0
  20. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/examples/add.py +0 -0
  21. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/examples/canonical_symbols.py +0 -0
  22. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/__main__.py +0 -0
  23. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/abstract/__init__.py +0 -0
  24. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/abstract/constants.py +0 -0
  25. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/abstract/heap.py +0 -0
  26. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/abstract/ranges.py +0 -0
  27. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/abstract/strings.py +0 -0
  28. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/abstract/values.py +0 -0
  29. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/analysis/__init__.py +0 -0
  30. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/analysis/manager.py +0 -0
  31. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/analysis/provider.py +0 -0
  32. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/dependency_policy/dependency_policy.py +0 -0
  33. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/dependency_policy/plugin.toml +0 -0
  34. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/reachable_vulnerability/plugin.toml +0 -0
  35. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/reachable_vulnerability/reachable_vulnerability.py +0 -0
  36. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/sample_advisories/plugin.toml +0 -0
  37. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/sample_advisories/sample_advisories.py +0 -0
  38. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/vulnerable_dependency/plugin.toml +0 -0
  39. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/dependency/vulnerable_dependency/vulnerable_dependency.py +0 -0
  40. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/aiohttp/aiohttp_models.py +0 -0
  41. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/aiohttp/plugin.toml +0 -0
  42. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/bottle/bottle_models.py +0 -0
  43. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/bottle/plugin.toml +0 -0
  44. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/cli/cli_models.py +0 -0
  45. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/cli/plugin.toml +0 -0
  46. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/credentials/credential_models.py +0 -0
  47. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/credentials/plugin.toml +0 -0
  48. {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
  49. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/db_drivers/plugin.toml +0 -0
  50. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/django/django_models.py +0 -0
  51. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/django/plugin.toml +0 -0
  52. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/fastapi/fastapi_models.py +0 -0
  53. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/fastapi/plugin.toml +0 -0
  54. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/flask/flask_models.py +0 -0
  55. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/flask/plugin.toml +0 -0
  56. {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
  57. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/http_clients/plugin.toml +0 -0
  58. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/python_stdlib/plugin.toml +0 -0
  59. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/python_stdlib/python_stdlib.py +0 -0
  60. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/sqlalchemy/plugin.toml +0 -0
  61. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/sqlalchemy/sqlalchemy_models.py +0 -0
  62. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/tornado/plugin.toml +0 -0
  63. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/models/tornado/tornado_models.py +0 -0
  64. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/secrets/config_secrets/config_secrets.py +0 -0
  65. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/secrets/config_secrets/plugin.toml +0 -0
  66. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/secrets/hardcoded_secrets/hardcoded_secrets.py +0 -0
  67. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/secrets/hardcoded_secrets/plugin.toml +0 -0
  68. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/code_injection/code_injection.py +0 -0
  69. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/code_injection/plugin.toml +0 -0
  70. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/command_injection/command_injection.py +0 -0
  71. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/command_injection/plugin.toml +0 -0
  72. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/insecure_deserialization/insecure_deserialization.py +0 -0
  73. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/insecure_deserialization/plugin.toml +0 -0
  74. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/nosql_injection/nosql_injection.py +0 -0
  75. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/nosql_injection/plugin.toml +0 -0
  76. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/open_redirect/open_redirect.py +0 -0
  77. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/open_redirect/plugin.toml +0 -0
  78. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/path_traversal/path_traversal.py +0 -0
  79. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/path_traversal/plugin.toml +0 -0
  80. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/plaintext_credentials/plaintext_credentials.py +0 -0
  81. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/plaintext_credentials/plugin.toml +0 -0
  82. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/sql_injection/plugin.toml +0 -0
  83. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/sql_injection/sql_injection.py +0 -0
  84. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/ssrf/plugin.toml +0 -0
  85. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/ssrf/ssrf.py +0 -0
  86. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/xss/plugin.toml +0 -0
  87. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/security/xss/xss.py +0 -0
  88. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/dangerous_eval/dangerous_eval.py +0 -0
  89. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/dangerous_eval/plugin.toml +0 -0
  90. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/flask_debug/flask_debug.py +0 -0
  91. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/flask_debug/plugin.toml +0 -0
  92. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/insecure_tempfile/insecure_tempfile.py +0 -0
  93. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/insecure_tempfile/plugin.toml +0 -0
  94. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/insecure_tls/insecure_tls.py +0 -0
  95. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/insecure_tls/plugin.toml +0 -0
  96. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/missing_timeout/missing_timeout.py +0 -0
  97. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/missing_timeout/plugin.toml +0 -0
  98. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/unsafe_archive/plugin.toml +0 -0
  99. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/unsafe_archive/unsafe_archive.py +0 -0
  100. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/unsafe_xml/plugin.toml +0 -0
  101. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/unsafe_xml/unsafe_xml.py +0 -0
  102. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/weak_crypto/plugin.toml +0 -0
  103. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/weak_crypto/weak_crypto.py +0 -0
  104. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/weak_random/plugin.toml +0 -0
  105. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/bundled/syntax/weak_random/weak_random.py +0 -0
  106. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/cache.py +0 -0
  107. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/cfg/__init__.py +0 -0
  108. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/cfg/builder.py +0 -0
  109. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/cfg/dominance.py +0 -0
  110. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/cfg/model.py +0 -0
  111. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/cli.py +0 -0
  112. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dataflow/__init__.py +0 -0
  113. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dataflow/lattice.py +0 -0
  114. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dataflow/solver.py +0 -0
  115. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/__init__.py +0 -0
  116. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/advisories.py +0 -0
  117. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/correlation.py +0 -0
  118. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/graph.py +0 -0
  119. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/policy.py +0 -0
  120. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/sbom.py +0 -0
  121. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/dependency/vex.py +0 -0
  122. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/engine.py +0 -0
  123. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/__init__.py +0 -0
  124. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/baseline.py +0 -0
  125. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/coverage.py +0 -0
  126. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/model.py +0 -0
  127. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/provenance.py +0 -0
  128. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/refutation.py +0 -0
  129. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/findings/suppressions.py +0 -0
  130. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/frontend/__init__.py +0 -0
  131. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/frontend/ast_adapter.py +0 -0
  132. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/frontend/parser.py +0 -0
  133. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/hir/__init__.py +0 -0
  134. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/hir/nodes.py +0 -0
  135. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/hir/visitors.py +0 -0
  136. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/interprocedural/__init__.py +0 -0
  137. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/interprocedural/callgraph.py +0 -0
  138. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/interprocedural/modulegraph.py +0 -0
  139. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/interprocedural/summaries.py +0 -0
  140. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/ir/__init__.py +0 -0
  141. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/ir/defuse.py +0 -0
  142. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/ir/lowering.py +0 -0
  143. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/ir/model.py +0 -0
  144. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/ir/printer.py +0 -0
  145. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/ir/ssa.py +0 -0
  146. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/__init__.py +0 -0
  147. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/api.py +0 -0
  148. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/detectors.py +0 -0
  149. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/loader.py +0 -0
  150. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/manifest.py +0 -0
  151. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/registry.py +0 -0
  152. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/plugins/secrets.py +0 -0
  153. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/reporters/__init__.py +0 -0
  154. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/reporters/json_format.py +0 -0
  155. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/reporters/report.py +0 -0
  156. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/reporters/sarif.py +0 -0
  157. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/reporters/text.py +0 -0
  158. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/semantic/__init__.py +0 -0
  159. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/semantic/identity.py +0 -0
  160. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/semantic/imports.py +0 -0
  161. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/semantic/scopes.py +0 -0
  162. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/semantic/symbols.py +0 -0
  163. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/source/__init__.py +0 -0
  164. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/source/manager.py +0 -0
  165. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/source/model.py +0 -0
  166. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/taint/__init__.py +0 -0
  167. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/taint/routes.py +0 -0
  168. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/src/coretrace_python/taint/urls.py +0 -0
  169. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/Chatbot.json +0 -0
  170. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/DjangoGoat.json +0 -0
  171. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/Flask-Image-Editing-Website.json +0 -0
  172. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/InsecureGram.json +0 -0
  173. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/MiniBookApiServer.json +0 -0
  174. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/NPL-IA.json +0 -0
  175. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/Spam-Detection-Project.json +0 -0
  176. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/Vulnerable_fastapi.json +0 -0
  177. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/dvpwa.json +0 -0
  178. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/full-stack-fastapi-template.json +0 -0
  179. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/healthchecks.json +0 -0
  180. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/httpie.json +0 -0
  181. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/luigi.json +0 -0
  182. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/my_gdb.json +0 -0
  183. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/network-topologer.json +0 -0
  184. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/pygoat.json +0 -0
  185. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/uploadbox-cloud-storage-solution.json +0 -0
  186. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/vulnerable-flask.json +0 -0
  187. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/expected/yt-fts.json +0 -0
  188. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/fixtures/vulnerable-flask/README.md +0 -0
  189. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/fixtures/vulnerable-flask/app.py +0 -0
  190. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/fixtures/vulnerable-flask/requirements.txt +0 -0
  191. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/fixtures/vulnerable-flask/vulnerable_services.py +0 -0
  192. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/regression/repositories.toml +0 -0
  193. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_advisory_evidence.py +0 -0
  194. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_advisory_feeds.py +0 -0
  195. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_advisory_url_host.py +0 -0
  196. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_aiohttp_models.py +0 -0
  197. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_analysis_manager.py +0 -0
  198. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_architecture.py +0 -0
  199. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_argument_conditions.py +0 -0
  200. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_attacker_arguments.py +0 -0
  201. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_audit_detectors.py +0 -0
  202. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_base_patterns.py +0 -0
  203. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_baseline.py +0 -0
  204. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_cache.py +0 -0
  205. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_cfg.py +0 -0
  206. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_class_keywords_with_targets.py +0 -0
  207. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_cli.py +0 -0
  208. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_closures.py +0 -0
  209. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_code_injection.py +0 -0
  210. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_config_secrets_coverage.py +0 -0
  211. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_constants.py +0 -0
  212. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_correlation.py +0 -0
  213. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_credential_context.py +0 -0
  214. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_dataflow.py +0 -0
  215. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_dependencies.py +0 -0
  216. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_detectors.py +0 -0
  217. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_discovery.py +0 -0
  218. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_django_http_clients.py +0 -0
  219. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_django_routes.py +0 -0
  220. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_django_safe_values.py +0 -0
  221. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_docs.py +0 -0
  222. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_dominance.py +0 -0
  223. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_emit_ir.py +0 -0
  224. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_exceptions.py +0 -0
  225. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_factories_match_loop_else.py +0 -0
  226. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_fail_on.py +0 -0
  227. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_fastapi_cli_precision.py +0 -0
  228. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_frameworks.py +0 -0
  229. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_frontend_gaps.py +0 -0
  230. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_heap.py +0 -0
  231. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_hex_digests.py +0 -0
  232. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_hir_builder.py +0 -0
  233. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_imports.py +0 -0
  234. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_interprocedural.py +0 -0
  235. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_interprocedural_taint.py +0 -0
  236. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_ir.py +0 -0
  237. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_match_patterns.py +0 -0
  238. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_members.py +0 -0
  239. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_module_level.py +0 -0
  240. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_nonlocal_writeback.py +0 -0
  241. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_nosql_injection.py +0 -0
  242. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_open_redirect_destinations.py +0 -0
  243. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_operator_sources.py +0 -0
  244. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_packaging.py +0 -0
  245. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_parallel.py +0 -0
  246. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_parser.py +0 -0
  247. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_plaintext_credentials.py +0 -0
  248. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_plugins.py +0 -0
  249. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_project.py +0 -0
  250. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_project_models.py +0 -0
  251. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_project_validators.py +0 -0
  252. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_provenance.py +0 -0
  253. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_pyir_imports.py +0 -0
  254. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_read_entry_points.py +0 -0
  255. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_real_code_precision.py +0 -0
  256. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_redirect_targets.py +0 -0
  257. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_refutation.py +0 -0
  258. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_refutation_evidence.py +0 -0
  259. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_regression.py +0 -0
  260. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_relative_paths.py +0 -0
  261. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_remaining_limits.py +0 -0
  262. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_reporters.py +0 -0
  263. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_safe_arguments.py +0 -0
  264. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_scale.py +0 -0
  265. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_scopes.py +0 -0
  266. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_secrets_sbom.py +0 -0
  267. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_self_state.py +0 -0
  268. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_source_manager.py +0 -0
  269. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_ssa.py +0 -0
  270. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_ssrf_destinations.py +0 -0
  271. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_ssrf_targets.py +0 -0
  272. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_summary_sanitizers.py +0 -0
  273. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_suppressions.py +0 -0
  274. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_symbol_resolution.py +0 -0
  275. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_symbols.py +0 -0
  276. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_syntactic_rules.py +0 -0
  277. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_syntax_control_flow.py +0 -0
  278. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_syntax_coverage.py +0 -0
  279. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_syntax_expressions.py +0 -0
  280. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_taint.py +0 -0
  281. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_template_context_flows.py +0 -0
  282. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_template_escaping.py +0 -0
  283. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_template_filter_calls.py +0 -0
  284. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_template_request_processor.py +0 -0
  285. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_tornado_bottle_models.py +0 -0
  286. {coretrace_python_analyzer-0.17.0 → coretrace_python_analyzer-0.18.0}/tests/test_url_proof.py +0 -0
  287. {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.17.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 named by an expression, a template found through a `DIRS` entry not named
160
- `templates`, one shipped by an installed package, one rendered through `get_template`,
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.17.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.17.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.17.0; curated-advisories 2026.09.25 (sha256:…)`), so the
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "coretrace-python-analyzer"
7
- version = "0.17.0"
7
+ version = "0.18.0"
8
8
  description = "Static security analysis infrastructure for Python code"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,4 +1,4 @@
1
1
  """CoreTrace's Python static analysis frontend."""
2
2
 
3
- __version__ = "0.17.0"
3
+ __version__ = "0.18.0"
4
4
 
@@ -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, or a registration elsewhere (``routes``)."""
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 and routes:
847
+ if entry is None:
847
848
  qualified = function.name if owner is None else f"{owner.name}.{function.name}"
848
- entry = routes.get(project_symbol(module.name, qualified))
849
+ entry = _declared(project_symbol(module.name, qualified), models, routes)
849
850
  if entry is None and owner is not None:
850
- entry = routes.get(project_symbol(module.name, owner.name))
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``, and methods of classes deriving from it,
114
- receive attacker-controlled parameters."""
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 escape.
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 = [_inspect(_read(path)) for path in paths]
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.17.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()