coretrace-python-analyzer 0.20.0__tar.gz → 0.21.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 (298) hide show
  1. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/CHANGELOG.md +12 -0
  2. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/PKG-INFO +1 -1
  3. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/docs/plugins.md +6 -2
  4. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/docs/usage.md +77 -3
  5. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/pyproject.toml +1 -1
  6. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/__init__.py +1 -1
  7. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/dependency/reachable_vulnerability/reachable_vulnerability.py +19 -13
  8. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/dependency/vulnerable_dependency/vulnerable_dependency.py +10 -3
  9. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/cache.py +17 -1
  10. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/dependency/advisories.py +36 -1
  11. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/dependency/correlation.py +151 -13
  12. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/dependency/graph.py +20 -4
  13. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/engine.py +32 -7
  14. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/interprocedural/__init__.py +2 -0
  15. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/interprocedural/callgraph.py +131 -5
  16. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/taint/models.py +10 -7
  17. coretrace_python_analyzer-0.21.0/tests/test_argument_present_conditions.py +205 -0
  18. coretrace_python_analyzer-0.21.0/tests/test_entry_point_suffixes.py +259 -0
  19. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_release.py +1 -1
  20. coretrace_python_analyzer-0.21.0/tests/test_sequence_conditions.py +461 -0
  21. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/.github/workflows/ci.yml +0 -0
  22. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/.github/workflows/release.yml +0 -0
  23. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/.gitignore +0 -0
  24. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/LICENSE +0 -0
  25. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/NOTICE +0 -0
  26. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/README.md +0 -0
  27. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/docs/architecture.md +0 -0
  28. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/examples/add.py +0 -0
  29. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/examples/canonical_symbols.py +0 -0
  30. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/__main__.py +0 -0
  31. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/abstract/__init__.py +0 -0
  32. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/abstract/constants.py +0 -0
  33. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/abstract/heap.py +0 -0
  34. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/abstract/ranges.py +0 -0
  35. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/abstract/strings.py +0 -0
  36. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/abstract/values.py +0 -0
  37. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/analysis/__init__.py +0 -0
  38. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/analysis/manager.py +0 -0
  39. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/analysis/provider.py +0 -0
  40. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/dependency/dependency_policy/dependency_policy.py +0 -0
  41. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/dependency/dependency_policy/plugin.toml +0 -0
  42. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/dependency/reachable_vulnerability/plugin.toml +0 -0
  43. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/dependency/sample_advisories/plugin.toml +0 -0
  44. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/dependency/sample_advisories/sample_advisories.py +0 -0
  45. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/dependency/vulnerable_dependency/plugin.toml +0 -0
  46. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/aiohttp/aiohttp_models.py +0 -0
  47. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/aiohttp/plugin.toml +0 -0
  48. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/bottle/bottle_models.py +0 -0
  49. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/bottle/plugin.toml +0 -0
  50. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/cli/cli_models.py +0 -0
  51. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/cli/plugin.toml +0 -0
  52. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/credentials/credential_models.py +0 -0
  53. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/credentials/plugin.toml +0 -0
  54. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/db_drivers/db_driver_models.py +0 -0
  55. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/db_drivers/plugin.toml +0 -0
  56. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/django/django_models.py +0 -0
  57. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/django/plugin.toml +0 -0
  58. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/fastapi/fastapi_models.py +0 -0
  59. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/fastapi/plugin.toml +0 -0
  60. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/flask/flask_models.py +0 -0
  61. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/flask/plugin.toml +0 -0
  62. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/http_clients/http_client_models.py +0 -0
  63. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/http_clients/plugin.toml +0 -0
  64. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/python_stdlib/plugin.toml +0 -0
  65. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/python_stdlib/python_stdlib.py +0 -0
  66. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/sqlalchemy/plugin.toml +0 -0
  67. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/sqlalchemy/sqlalchemy_models.py +0 -0
  68. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/tornado/plugin.toml +0 -0
  69. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/models/tornado/tornado_models.py +0 -0
  70. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/secrets/config_secrets/config_secrets.py +0 -0
  71. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/secrets/config_secrets/plugin.toml +0 -0
  72. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/secrets/hardcoded_secrets/hardcoded_secrets.py +0 -0
  73. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/secrets/hardcoded_secrets/plugin.toml +0 -0
  74. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/code_injection/code_injection.py +0 -0
  75. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/code_injection/plugin.toml +0 -0
  76. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/command_injection/command_injection.py +0 -0
  77. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/command_injection/plugin.toml +0 -0
  78. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/insecure_deserialization/insecure_deserialization.py +0 -0
  79. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/insecure_deserialization/plugin.toml +0 -0
  80. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/nosql_injection/nosql_injection.py +0 -0
  81. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/nosql_injection/plugin.toml +0 -0
  82. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/open_redirect/open_redirect.py +0 -0
  83. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/open_redirect/plugin.toml +0 -0
  84. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/path_traversal/path_traversal.py +0 -0
  85. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/path_traversal/plugin.toml +0 -0
  86. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/plaintext_credentials/plaintext_credentials.py +0 -0
  87. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/plaintext_credentials/plugin.toml +0 -0
  88. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/sql_injection/plugin.toml +0 -0
  89. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/sql_injection/sql_injection.py +0 -0
  90. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/ssrf/plugin.toml +0 -0
  91. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/ssrf/ssrf.py +0 -0
  92. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/xss/plugin.toml +0 -0
  93. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/security/xss/xss.py +0 -0
  94. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/dangerous_eval/dangerous_eval.py +0 -0
  95. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/dangerous_eval/plugin.toml +0 -0
  96. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/flask_debug/flask_debug.py +0 -0
  97. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/flask_debug/plugin.toml +0 -0
  98. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/insecure_tempfile/insecure_tempfile.py +0 -0
  99. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/insecure_tempfile/plugin.toml +0 -0
  100. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/insecure_tls/insecure_tls.py +0 -0
  101. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/insecure_tls/plugin.toml +0 -0
  102. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/missing_timeout/missing_timeout.py +0 -0
  103. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/missing_timeout/plugin.toml +0 -0
  104. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/unsafe_archive/plugin.toml +0 -0
  105. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/unsafe_archive/unsafe_archive.py +0 -0
  106. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/unsafe_xml/plugin.toml +0 -0
  107. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/unsafe_xml/unsafe_xml.py +0 -0
  108. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/weak_crypto/plugin.toml +0 -0
  109. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/weak_crypto/weak_crypto.py +0 -0
  110. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/weak_random/plugin.toml +0 -0
  111. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/bundled/syntax/weak_random/weak_random.py +0 -0
  112. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/cfg/__init__.py +0 -0
  113. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/cfg/builder.py +0 -0
  114. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/cfg/dominance.py +0 -0
  115. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/cfg/model.py +0 -0
  116. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/cli.py +0 -0
  117. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/dataflow/__init__.py +0 -0
  118. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/dataflow/lattice.py +0 -0
  119. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/dataflow/solver.py +0 -0
  120. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/dependency/__init__.py +0 -0
  121. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/dependency/policy.py +0 -0
  122. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/dependency/sbom.py +0 -0
  123. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/dependency/vex.py +0 -0
  124. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/findings/__init__.py +0 -0
  125. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/findings/baseline.py +0 -0
  126. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/findings/coverage.py +0 -0
  127. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/findings/model.py +0 -0
  128. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/findings/provenance.py +0 -0
  129. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/findings/refutation.py +0 -0
  130. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/findings/suppressions.py +0 -0
  131. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/frontend/__init__.py +0 -0
  132. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/frontend/ast_adapter.py +0 -0
  133. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/frontend/parser.py +0 -0
  134. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/hir/__init__.py +0 -0
  135. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/hir/nodes.py +0 -0
  136. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/hir/visitors.py +0 -0
  137. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/interprocedural/modulegraph.py +0 -0
  138. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/interprocedural/summaries.py +0 -0
  139. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/ir/__init__.py +0 -0
  140. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/ir/defuse.py +0 -0
  141. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/ir/lowering.py +0 -0
  142. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/ir/model.py +0 -0
  143. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/ir/printer.py +0 -0
  144. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/ir/ssa.py +0 -0
  145. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/plugins/__init__.py +0 -0
  146. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/plugins/api.py +0 -0
  147. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/plugins/detectors.py +0 -0
  148. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/plugins/loader.py +0 -0
  149. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/plugins/manifest.py +0 -0
  150. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/plugins/registry.py +0 -0
  151. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/plugins/secrets.py +0 -0
  152. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/reporters/__init__.py +0 -0
  153. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/reporters/json_format.py +0 -0
  154. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/reporters/report.py +0 -0
  155. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/reporters/sarif.py +0 -0
  156. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/reporters/text.py +0 -0
  157. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/semantic/__init__.py +0 -0
  158. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/semantic/identity.py +0 -0
  159. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/semantic/imports.py +0 -0
  160. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/semantic/scopes.py +0 -0
  161. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/semantic/symbols.py +0 -0
  162. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/source/__init__.py +0 -0
  163. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/source/manager.py +0 -0
  164. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/source/model.py +0 -0
  165. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/taint/__init__.py +0 -0
  166. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/taint/engine.py +0 -0
  167. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/taint/routes.py +0 -0
  168. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/taint/templates.py +0 -0
  169. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/src/coretrace_python/taint/urls.py +0 -0
  170. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/Chatbot.json +0 -0
  171. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/DjangoGoat.json +0 -0
  172. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/Flask-Image-Editing-Website.json +0 -0
  173. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/InsecureGram.json +0 -0
  174. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/MiniBookApiServer.json +0 -0
  175. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/NPL-IA.json +0 -0
  176. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/Spam-Detection-Project.json +0 -0
  177. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/Vulnerable_fastapi.json +0 -0
  178. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/dvpwa.json +0 -0
  179. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/full-stack-fastapi-template.json +0 -0
  180. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/healthchecks.json +0 -0
  181. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/httpie.json +0 -0
  182. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/luigi.json +0 -0
  183. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/my_gdb.json +0 -0
  184. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/network-topologer.json +0 -0
  185. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/pygoat.json +0 -0
  186. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/uploadbox-cloud-storage-solution.json +0 -0
  187. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/vulnerable-flask.json +0 -0
  188. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/expected/yt-fts.json +0 -0
  189. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/fixtures/vulnerable-flask/README.md +0 -0
  190. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/fixtures/vulnerable-flask/app.py +0 -0
  191. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/fixtures/vulnerable-flask/requirements.txt +0 -0
  192. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/fixtures/vulnerable-flask/vulnerable_services.py +0 -0
  193. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/regression/repositories.toml +0 -0
  194. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_advisory_evidence.py +0 -0
  195. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_advisory_feeds.py +0 -0
  196. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_advisory_url_host.py +0 -0
  197. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_aiohttp_models.py +0 -0
  198. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_analysis_manager.py +0 -0
  199. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_architecture.py +0 -0
  200. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_argument_conditions.py +0 -0
  201. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_attacker_arguments.py +0 -0
  202. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_audit_detectors.py +0 -0
  203. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_base_patterns.py +0 -0
  204. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_baseline.py +0 -0
  205. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_block_super.py +0 -0
  206. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_cache.py +0 -0
  207. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_cfg.py +0 -0
  208. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_class_keywords_with_targets.py +0 -0
  209. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_cli.py +0 -0
  210. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_closures.py +0 -0
  211. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_code_injection.py +0 -0
  212. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_config_secrets_coverage.py +0 -0
  213. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_constants.py +0 -0
  214. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_correlation.py +0 -0
  215. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_credential_context.py +0 -0
  216. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_dataflow.py +0 -0
  217. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_declared_entry_points.py +0 -0
  218. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_dependencies.py +0 -0
  219. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_detectors.py +0 -0
  220. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_discovery.py +0 -0
  221. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_django_http_clients.py +0 -0
  222. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_django_routes.py +0 -0
  223. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_django_safe_values.py +0 -0
  224. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_docs.py +0 -0
  225. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_dominance.py +0 -0
  226. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_emit_ir.py +0 -0
  227. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_entry_point_aliases.py +0 -0
  228. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_exceptions.py +0 -0
  229. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_factories_match_loop_else.py +0 -0
  230. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_fail_on.py +0 -0
  231. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_fastapi_cli_precision.py +0 -0
  232. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_frameworks.py +0 -0
  233. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_frontend_gaps.py +0 -0
  234. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_function_aliases_api.py +0 -0
  235. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_heap.py +0 -0
  236. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_hex_digests.py +0 -0
  237. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_hir_builder.py +0 -0
  238. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_imports.py +0 -0
  239. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_interprocedural.py +0 -0
  240. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_interprocedural_taint.py +0 -0
  241. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_ir.py +0 -0
  242. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_key_taint.py +0 -0
  243. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_keyword_name_conditions.py +0 -0
  244. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_match_patterns.py +0 -0
  245. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_members.py +0 -0
  246. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_module_identity.py +0 -0
  247. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_module_level.py +0 -0
  248. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_nonlocal_writeback.py +0 -0
  249. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_nosql_injection.py +0 -0
  250. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_open_redirect_destinations.py +0 -0
  251. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_operator_sources.py +0 -0
  252. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_packaging.py +0 -0
  253. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_parallel.py +0 -0
  254. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_parser.py +0 -0
  255. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_plaintext_credentials.py +0 -0
  256. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_plugins.py +0 -0
  257. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_project.py +0 -0
  258. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_project_models.py +0 -0
  259. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_project_validators.py +0 -0
  260. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_provenance.py +0 -0
  261. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_pyir_imports.py +0 -0
  262. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_read_entry_points.py +0 -0
  263. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_real_code_precision.py +0 -0
  264. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_redirect_targets.py +0 -0
  265. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_refutation.py +0 -0
  266. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_refutation_evidence.py +0 -0
  267. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_regression.py +0 -0
  268. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_relative_paths.py +0 -0
  269. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_remaining_limits.py +0 -0
  270. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_reporters.py +0 -0
  271. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_safe_arguments.py +0 -0
  272. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_scale.py +0 -0
  273. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_scopes.py +0 -0
  274. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_secrets_sbom.py +0 -0
  275. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_self_state.py +0 -0
  276. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_settings_scope.py +0 -0
  277. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_source_manager.py +0 -0
  278. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_ssa.py +0 -0
  279. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_ssrf_destinations.py +0 -0
  280. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_ssrf_targets.py +0 -0
  281. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_summary_sanitizers.py +0 -0
  282. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_suppressions.py +0 -0
  283. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_symbol_resolution.py +0 -0
  284. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_symbols.py +0 -0
  285. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_syntactic_rules.py +0 -0
  286. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_syntax_control_flow.py +0 -0
  287. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_syntax_coverage.py +0 -0
  288. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_syntax_expressions.py +0 -0
  289. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_taint.py +0 -0
  290. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_template_context_flows.py +0 -0
  291. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_template_escaping.py +0 -0
  292. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_template_filter_calls.py +0 -0
  293. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_template_filter_overrides.py +0 -0
  294. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_template_request_processor.py +0 -0
  295. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_tornado_bottle_models.py +0 -0
  296. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_unreadable_templates.py +0 -0
  297. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_url_proof.py +0 -0
  298. {coretrace_python_analyzer-0.20.0 → coretrace_python_analyzer-0.21.0}/tests/test_vex.py +0 -0
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.21.0 (2026-09-30)
4
+
5
+ ### Advisories
6
+
7
+ - An `argument` condition may carry `present: true`: the argument being passed at all, whatever its value, is the condition, as a `\r` in `web.Response(reason=…)` needs `reason` given, constant or not. It names the argument by keyword or position as today and excludes `values` and `default`. A call giving the argument — positionally, by keyword, or through a `**` literal with constant keys, folded into the keywords — meets it even when the value is unknown, so attacker input there makes the call exploitable; a call surely not giving it is ruled out (`app:5 python.aiohttp.web.Response(reason absent)`) and a project passing only such calls stays `not_affected`; a call unpacking `*args` or a `**mapping` whose keys are not written leaves it pending review (#195).
8
+ - A curated entry point may declare `suffixes`, for receivers the engine cannot type: `Item.objects.annotate(...)` derives the project's own `python.app.models.Item.objects.annotate`, which the canonical `python.django.db.models.QuerySet.annotate` entry point never matches. A suffix matches any symbol of the project's own modules ending with a dot plus the suffix, on dot boundaries as a `SuffixSink` matches, never another package's symbol; a queryset chain is declared explicitly (`objects.filter.annotate`), and a suffix is at least two dot-separated names. The finding keeps the advisory's symbol as `entry_point` and the derived one as `symbol`; conditions, `attacker_arguments` and the ruled-out evidence of contradicted calls apply through a suffix as through the exact symbol. An exact advisory sink whose symbol a bundled suffix sink also matches (`objects.extra`) now composes its kinds with the suffix sink's instead of shadowing them (#197).
9
+ - An advisory condition of kind `sequence` says the flaw spans two calls on one receiver: the first call leaves state on the object the entry point — the second call — reuses. It names the `method` the first call must be, by canonical name or `.`-suffix, and, optionally, the argument that call must carry (`{"kind": "sequence", "method": "Session.get", "argument": "verify", "values": ["False"], ...}`), so `s = requests.Session(); s.get(url, verify=False); s.get(other)` marks the second `get` reachable with the prior call as evidence (requests CVE-2024-35195). A receiver followed whole — bound once to the result of a call or a `with` and used only to call its methods — with no matching call on every path to the entry call rules it out (`app.fetch:6 python.requests.Session.get(no prior Session.get on the receiver)`), and a project with only such calls stays `not_affected`. A receiver the engine cannot follow (a parameter, a module-level instance, one passed to another function or mutated through an attribute), a matching call only in a branch or textually later, an unpacking that leaves the first call's arguments undecided, or an entry call that itself carries the named argument — its own prior across the iterations of a loop — leaves the condition pending review (#194).
10
+
11
+ ### Plugins
12
+
13
+ - `CallSite.prior_calls` records, for a receiver the engine follows whole, the other external calls on the same receiver (`PriorCall`: symbol, location, arguments, and whether it surely executes before this one), in source order; `CallGraph.prior_calls_at` reads it by location, and `check_conditions` takes it to decide `sequence` conditions. The cache format changes.
14
+
3
15
  ## 0.20.0 (2026-09-30)
4
16
 
5
17
  ### Advisories
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: coretrace-python-analyzer
3
- Version: 0.20.0
3
+ Version: 0.21.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
@@ -195,8 +195,12 @@ A model plugin may also carry `advisories`, a tuple of `Advisory` values
195
195
  symbols, as the shipped `sample-advisories` plugin does. Requirements matching them are
196
196
  reported, calls to the affected symbols become reachable vulnerabilities and tainted
197
197
  calls become exploitable ones. An advisory's entry points carry `conditions`, of kind
198
- `argument`, `host`, `semantic` or `keyword_name`, and `attacker_arguments`, decided as
199
- the [usage guide](usage.md) describes.
198
+ `argument` (on the value, or with `present` on the argument being passed at all),
199
+ `host`, `semantic`, `keyword_name` or `sequence`, and `attacker_arguments`, decided as
200
+ the [usage guide](usage.md) describes. An entry point may also declare `suffixes`,
201
+ matched against the tail of a derived symbol of the project's own modules on dot
202
+ boundaries, as a `SuffixSink` matches, for receivers the engine cannot type (see the
203
+ usage guide).
200
204
 
201
205
  ### Reclassifying findings: `ProjectPlugin.refine`
202
206
 
@@ -247,7 +247,7 @@ the directory of the checked file; a path outside it is printed as it is.
247
247
  ```json
248
248
  {
249
249
  "schema_version": 1,
250
- "tool": {"name": "coretrace-python-analyzer", "version": "0.20.0"},
250
+ "tool": {"name": "coretrace-python-analyzer", "version": "0.21.0"},
251
251
  "root": "/home/me/project",
252
252
  "findings": [
253
253
  {
@@ -281,7 +281,7 @@ bytes. A single-file check lists no components.
281
281
 
282
282
  ```json
283
283
  "tool": {
284
- "name": "coretrace-python-analyzer", "version": "0.20.0",
284
+ "name": "coretrace-python-analyzer", "version": "0.21.0",
285
285
  "components": [
286
286
  {"kind": "plugin", "name": "curated-advisories", "version": "2026.09.25", "digest": "sha256:…"},
287
287
  {"kind": "advisories", "name": "advisories.json", "digest": "sha256:…"}
@@ -370,6 +370,29 @@ it is reachable, called or not — `request.form['name']`, `for key in request.f
370
370
  `request.form.get('name')` all read it. A function reading it several times is reported
371
371
  once, where it first reads it.
372
372
 
373
+ An entry point may declare `suffixes`, for receivers the engine cannot type. A project
374
+ reaches `python.django.db.models.QuerySet.annotate` through a manager on its own model,
375
+ `Item.objects.annotate(...)`, whose call derives the project's own symbol
376
+ `python.app.models.Item.objects.annotate` — `Item` is a project class, `objects` an
377
+ attribute the engine does not type — so the canonical entry point never matches. A
378
+ suffix matches any symbol of the project's own modules ending with a dot plus the
379
+ suffix:
380
+
381
+ ```json
382
+ {"symbol": "python.django.db.models.QuerySet.annotate", "justification": "…",
383
+ "suffixes": ["objects.annotate", "objects.filter.annotate"]}
384
+ ```
385
+
386
+ A queryset chain is declared explicitly: `Item.objects.filter(...).annotate(...)`
387
+ derives `…objects.filter.annotate`, which only the second suffix matches. A suffix is
388
+ at least two dot-separated names, so a bare method name, matching every project method
389
+ of that name, cannot be declared; another package's symbol, such as
390
+ `other_lib.objects.annotate`, never matches. The finding names the advisory's symbol as
391
+ `entry_point` and the derived one as `symbol`, and the entry point's conditions and
392
+ `attacker_arguments` apply through a suffix as through the exact symbol. A project
393
+ attribute chain genuinely ending with a declared suffix matches too — the vulnerable
394
+ version range and the conditions still gate what is reported.
395
+
373
396
  A filter of Django's own libraries that a project template applies is a call to the
374
397
  function behind it, placed at the template's line: `{{ bio|striptags }}` calls
375
398
  `python.django.template.defaultfilters.striptags`, and so do filters in tag arguments
@@ -471,6 +494,16 @@ a call passing a variable, or unpacking `*args` or `**kwargs`, leaves the condit
471
494
  pending review. A `semantic` condition — the document's tags, the platform, the
472
495
  template's origin — cannot be decided and is always pending review, never dropped.
473
496
 
497
+ An `argument` condition with `"present": true` says the argument being passed at all,
498
+ whatever its value, is the condition, as a `\r` in `web.Response(reason=…)` needs
499
+ `reason` given, constant or not: `{"kind": "argument", "text": "…", "argument":
500
+ "reason", "position": 1, "present": true}`, exclusive with `values` and `default`. A
501
+ call giving the argument — positionally, by keyword, or through a `**` literal with
502
+ constant keys, which is folded into the keywords — meets it even when the value is
503
+ unknown; a call surely not giving it does not reach the vulnerability and is ruled out
504
+ (`(reason absent)`); a call unpacking `*args` or a `**mapping` whose keys the engine
505
+ cannot read leaves it pending review.
506
+
474
507
  A `host` condition says the attacker must choose the host of the URL passed as
475
508
  `argument` (or at `position`), as credentials leaking to the host of a crafted URL
476
509
  need: `{"kind": "host", "text": "…", "argument": "url", "position": 0}`. It is
@@ -514,6 +547,47 @@ Keys passed through a project wrapper stay pending, and `mapping.update(other)`,
514
547
  taint. A literal the function fills after building it (`m = {}; m[alias] = expr`)
515
548
  has keys the literal does not write, so the call is not ruled out.
516
549
 
550
+ A `sequence` condition says the flaw spans two calls on one receiver: a first call
551
+ leaves state on the object, and the entry point — the second call — reuses it, as
552
+ `Session.get(url, verify=False)` disables certificate verification for the pooled
553
+ connection a later `Session.get(other)` on the same session reuses (requests
554
+ CVE-2024-35195). It names the `method` the first call must be, by canonical name or
555
+ `.`-suffix, and, optionally, the argument that call must carry, read as an argument
556
+ condition reads it:
557
+
558
+ ```json
559
+ {
560
+ "kind": "sequence",
561
+ "text": "a prior call on the same session disabled certificate verification",
562
+ "method": "Session.get",
563
+ "argument": "verify",
564
+ "values": ["False"]
565
+ }
566
+ ```
567
+
568
+ The engine follows a receiver bound once in the analysed function to the result of a
569
+ call or a `with` and used only to call its methods. The outcome has three cases:
570
+
571
+ - A prior call on the same receiver, on every path to the entry call, matches the
572
+ method and carries a value in `values` (`default` for an absent argument): the
573
+ condition is met, and the evidence names that call's line.
574
+ - The receiver's whole lifetime is visible and no such prior call can precede — one
575
+ call alone on the receiver, or the two calls on different receivers: the condition
576
+ is contradicted, the call is ruled out
577
+ (`app.fetch:6 python.requests.Session.get(no prior Session.get on the receiver)`)
578
+ and a project with only such calls stays `not_affected`.
579
+ - Otherwise the condition stays pending review: a receiver the engine cannot follow —
580
+ a parameter, a module-level instance, one passed to another function or mutated
581
+ through an attribute such as `s.verify = False` — a prior call whose arguments a
582
+ `*`/`**` unpacking leaves undecided, or a flow reaching the entry point inside a
583
+ callee.
584
+
585
+ Only a prior call on every path to the entry call counts as before it: a matching
586
+ call in a branch that may not run, or a textually later one, leaves the condition
587
+ pending, since a loop may bring it before the entry call. A call that itself carries
588
+ what the condition requires of the first call is never ruled out either: across the
589
+ iterations of a loop it is its own prior.
590
+
517
591
  Every dependency finding records the highest level of evidence established in its
518
592
  `level` metadata: `declared` (the requirement allows a vulnerable version), `imported`
519
593
  (a module of the package is imported somewhere), `reachable` (an entry point or affected
@@ -577,7 +651,7 @@ project's behalf would go unseen. Without a lock file, a package is never
577
651
  `not_affected`. The document's `@id` derives from its statements, so two runs with the
578
652
  same result share it; its `author` is `Unknown Author`, as OpenVEX tools write when they
579
653
  cannot know it. Its `tooling` names the analyzer and each component with its digest
580
- (`coretrace-python-analyzer 0.20.0; curated-advisories 2026.09.25 (sha256:…)`), so the
654
+ (`coretrace-python-analyzer 0.21.0; curated-advisories 2026.09.25 (sha256:…)`), so the
581
655
  `@id` changes with the advisory data a statement was decided with.
582
656
 
583
657
  ## Large projects
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "coretrace-python-analyzer"
7
- version = "0.20.0"
7
+ version = "0.21.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.20.0"
3
+ __version__ = "0.21.0"
4
4
 
@@ -8,12 +8,14 @@ from collections.abc import Iterator, Sequence
8
8
  from typing import ClassVar
9
9
 
10
10
  from coretrace_python.analysis import AnyAnalysis
11
- from coretrace_python.dependency import Advisory, DependencyAnalysis
11
+ from coretrace_python.dependency import Advisory, AdvisoryEntryPoint, DependencyAnalysis
12
12
  from coretrace_python.dependency.correlation import (
13
13
  ConditionCheck,
14
+ affected_entries,
14
15
  affected_symbols,
15
16
  check_conditions,
16
17
  evidence,
18
+ suffix_index,
17
19
  )
18
20
  from coretrace_python.findings import Confidence, Finding
19
21
  from coretrace_python.interprocedural import CallGraphAnalysis, ExternalSymbol
@@ -30,6 +32,7 @@ class ReachableVulnerabilityPlugin(ProjectPlugin):
30
32
  affected = affected_symbols(ctx.dependencies, ctx.advisories)
31
33
  if not affected:
32
34
  return ()
35
+ suffixes = suffix_index(affected, ctx.modules)
33
36
  findings: list[Finding] = []
34
37
  for module in ctx.modules:
35
38
  graph = ctx.call_graph(module)
@@ -37,30 +40,28 @@ class ReachableVulnerabilityPlugin(ProjectPlugin):
37
40
  for site in graph.sites(function):
38
41
  if not isinstance(site.target, ExternalSymbol):
39
42
  continue
40
- for advisory in affected.get(site.target.symbol, ()):
41
- entry = advisory.entry_point(site.target.symbol)
43
+ for advisory, entry in affected_entries(site.target.symbol, affected, suffixes):
42
44
  if entry is not None and entry.read:
43
45
  continue # a call reads its callee first: reported with the reads
44
- check = check_conditions(entry, site.arguments)
46
+ check = check_conditions(entry, site.arguments, prior_calls=site.prior_calls)
45
47
  if check.contradicted is not None:
46
48
  continue
47
- findings.append(_reached(advisory, site.target.symbol, site.location, function, check))
49
+ findings.append(_reached(advisory, site.target.symbol, site.location, function, check, entry))
48
50
  # Reading ``request.form.get`` reads ``request.form``: one finding per entry
49
51
  # point and function, where the function first reads it.
50
52
  reported: set[tuple[Advisory, SymbolId]] = set()
51
53
  for read in graph.reads(function):
52
54
  for symbol in _read_through(read.symbol):
53
- for advisory in affected.get(symbol, ()):
54
- entry = advisory.entry_point(symbol)
55
+ for advisory, entry in affected_entries(symbol, affected, suffixes):
55
56
  if entry is None or not entry.read or (advisory, symbol) in reported:
56
57
  continue
57
58
  reported.add((advisory, symbol))
58
59
  check = check_conditions(entry, None)
59
- findings.append(_reached(advisory, symbol, read.location, function, check))
60
+ findings.append(_reached(advisory, symbol, read.location, function, check, entry))
60
61
  for call in ctx.templates.calls:
61
- for advisory in affected.get(call.symbol, ()):
62
- check = check_conditions(advisory.entry_point(call.symbol), None)
63
- findings.append(_reached(advisory, call.symbol, call.span, None, check))
62
+ for advisory, entry in affected_entries(call.symbol, affected, suffixes):
63
+ check = check_conditions(entry, None)
64
+ findings.append(_reached(advisory, call.symbol, call.span, None, check, entry))
64
65
  return findings
65
66
 
66
67
 
@@ -73,7 +74,12 @@ def _read_through(symbol: SymbolId) -> Iterator[SymbolId]:
73
74
 
74
75
 
75
76
  def _reached(
76
- advisory: Advisory, symbol: SymbolId, span: SourceSpan, function: str | None, check: ConditionCheck
77
+ advisory: Advisory,
78
+ symbol: SymbolId,
79
+ span: SourceSpan,
80
+ function: str | None,
81
+ check: ConditionCheck,
82
+ entry: AdvisoryEntryPoint | None,
77
83
  ) -> Finding:
78
84
  return Finding(
79
85
  rule_id="reachable-vulnerability",
@@ -85,5 +91,5 @@ def _reached(
85
91
  confidence=Confidence.HIGH,
86
92
  span=span,
87
93
  function=function,
88
- metadata=evidence(advisory, symbol, "reachable", check),
94
+ metadata=evidence(advisory, symbol, "reachable", check, entry),
89
95
  )
@@ -7,7 +7,13 @@ from typing import ClassVar
7
7
 
8
8
  from coretrace_python.analysis import AnyAnalysis
9
9
  from coretrace_python.dependency import DependencyAnalysis
10
- from coretrace_python.dependency.correlation import affected_symbols, check_conditions, ruled_out
10
+ from coretrace_python.dependency.correlation import (
11
+ affected_entries,
12
+ affected_symbols,
13
+ check_conditions,
14
+ ruled_out,
15
+ suffix_index,
16
+ )
11
17
  from coretrace_python.findings import Confidence, Finding
12
18
  from coretrace_python.interprocedural import CallGraphAnalysis, ExternalSymbol
13
19
  from coretrace_python.plugins import ProjectContext, ProjectPlugin
@@ -57,6 +63,7 @@ def _ruled_out(ctx: ProjectContext) -> dict[str, list[str]]:
57
63
  conditions: the evidence that the requirement, imported, is not reached there."""
58
64
 
59
65
  affected = affected_symbols(ctx.dependencies, ctx.advisories)
66
+ suffixes = suffix_index(affected, ctx.modules)
60
67
  excluded: dict[str, list[str]] = {}
61
68
  for module in sorted(ctx.modules):
62
69
  graph = ctx.call_graph(module)
@@ -64,8 +71,8 @@ def _ruled_out(ctx: ProjectContext) -> dict[str, list[str]]:
64
71
  for site in graph.sites(function):
65
72
  if not isinstance(site.target, ExternalSymbol):
66
73
  continue
67
- for advisory in affected.get(site.target.symbol, ()):
68
- check = check_conditions(advisory.entry_point(site.target.symbol), site.arguments)
74
+ for advisory, entry in affected_entries(site.target.symbol, affected, suffixes):
75
+ check = check_conditions(entry, site.arguments, prior_calls=site.prior_calls)
69
76
  if check.contradicted is not None:
70
77
  excluded.setdefault(advisory.id, []).append(ruled_out(module, site, check))
71
78
  return excluded
@@ -34,6 +34,7 @@ from coretrace_python.interprocedural import (
34
34
  ModuleGraph,
35
35
  Mutation,
36
36
  NonlocalWrite,
37
+ PriorCall,
37
38
  SummaryIndex,
38
39
  SymbolRead,
39
40
  Target,
@@ -42,7 +43,7 @@ from coretrace_python.interprocedural import (
42
43
  from coretrace_python.semantic.symbols import SymbolId
43
44
  from coretrace_python.source import SourceId, SourceSpan
44
45
 
45
- CACHE_FORMAT = 12
46
+ CACHE_FORMAT = 13
46
47
 
47
48
 
48
49
  @dataclass(frozen=True)
@@ -351,18 +352,33 @@ def _encode_site(site: CallSite) -> dict[str, Any]:
351
352
  "location": _encode_span(site.location),
352
353
  "target": _encode_target(site.target),
353
354
  "arguments": _encode_arguments(site.arguments),
355
+ "prior": None
356
+ if site.prior_calls is None
357
+ else [
358
+ [str(p.symbol), _encode_span(p.location), _encode_arguments(p.arguments), p.dominates]
359
+ for p in site.prior_calls
360
+ ],
354
361
  }
355
362
 
356
363
 
357
364
  def _decode_site(data: Mapping[str, Any]) -> CallSite:
365
+ prior = data["prior"]
358
366
  return CallSite(
359
367
  _string(data["caller"]),
360
368
  _decode_span(data["location"]),
361
369
  _decode_target(data["target"]),
362
370
  _decode_arguments(data["arguments"]),
371
+ None if prior is None else tuple(_decode_prior(entry) for entry in prior),
363
372
  )
364
373
 
365
374
 
375
+ def _decode_prior(data: Any) -> PriorCall:
376
+ symbol, span, arguments, dominates = data
377
+ if not isinstance(dominates, bool):
378
+ raise TypeError(f"expected a boolean, got {dominates!r}")
379
+ return PriorCall(SymbolId(_string(symbol)), _decode_span(span), _decode_arguments(arguments), dominates)
380
+
381
+
366
382
  def _encode_arguments(arguments: Arguments) -> dict[str, Any]:
367
383
  return {
368
384
  "positional": list(arguments.positional),
@@ -6,7 +6,7 @@ events into a version specifier; ``dump_advisories`` writes them as a small JSON
6
6
  that a project keeps at its root as ``advisories.json`` or passes with ``--advisories``.
7
7
  OSV records name no affected APIs, so imported advisories feed the requirement checks
8
8
  and the SBOM; a file completed by hand with ``affected_symbols``, ``entry_points`` and
9
- their ``conditions`` also feeds the reachability and correlation checks.
9
+ their ``conditions`` and ``suffixes`` also feeds the reachability and correlation checks.
10
10
  """
11
11
 
12
12
  from __future__ import annotations
@@ -161,6 +161,8 @@ def _entry_point_entry(entry_point: AdvisoryEntryPoint) -> dict[str, Any]:
161
161
  }
162
162
  if entry_point.read:
163
163
  entry["read"] = True
164
+ if entry_point.suffixes:
165
+ entry["suffixes"] = list(entry_point.suffixes)
164
166
  if entry_point.attacker_arguments:
165
167
  entry["attacker_arguments"] = [_attacker_argument_entry(a) for a in entry_point.attacker_arguments]
166
168
  return entry
@@ -187,6 +189,10 @@ def _condition_entry(condition: Condition) -> dict[str, Any]:
187
189
  entry["position"] = condition.position
188
190
  if condition.default:
189
191
  entry["default"] = True
192
+ if condition.present:
193
+ entry["present"] = True
194
+ if condition.method is not None:
195
+ entry["method"] = condition.method
190
196
  return entry
191
197
 
192
198
 
@@ -226,9 +232,20 @@ def _entry_point(entry: Mapping[str, Any]) -> AdvisoryEntryPoint:
226
232
  tuple(_condition(c) for c in entry.get("conditions") or []),
227
233
  read,
228
234
  tuple(_attacker_argument(a) for a in entry.get("attacker_arguments") or []),
235
+ tuple(_suffix(s) for s in entry.get("suffixes") or []),
229
236
  )
230
237
 
231
238
 
239
+ def _suffix(value: Any) -> str:
240
+ if not isinstance(value, str):
241
+ raise TypeError(f"an entry point suffix must be a string, got {value!r}")
242
+ parts = value.split(".")
243
+ # A single name (``annotate``) would match every project method of that name.
244
+ if len(parts) < 2 or not all(p.isidentifier() for p in parts):
245
+ raise ValueError(f"an entry point suffix is at least two dot-separated names, got {value!r}")
246
+ return value
247
+
248
+
232
249
  def _attacker_argument(entry: Mapping[str, Any]) -> AttackerArgument:
233
250
  argument, position, variadic = entry.get("argument"), entry.get("position"), entry.get("variadic", False)
234
251
  if argument is not None and not isinstance(argument, str):
@@ -251,6 +268,9 @@ def _condition(entry: Mapping[str, Any]) -> Condition:
251
268
  default = entry.get("default", False)
252
269
  if not isinstance(default, bool):
253
270
  raise TypeError(f"condition default must be true or false, got {default!r}")
271
+ present = entry.get("present", False)
272
+ if not isinstance(present, bool):
273
+ raise TypeError(f"condition present must be true or false, got {present!r}")
254
274
  condition = Condition(
255
275
  str(entry["kind"]),
256
276
  str(entry["text"]),
@@ -258,7 +278,22 @@ def _condition(entry: Mapping[str, Any]) -> Condition:
258
278
  tuple(str(v) for v in entry.get("values") or []),
259
279
  position,
260
280
  default,
281
+ present,
282
+ None if entry.get("method") is None else str(entry["method"]),
261
283
  )
284
+ if condition.present and (
285
+ condition.kind != "argument"
286
+ or (condition.argument is None and condition.position is None)
287
+ or condition.values
288
+ or condition.default
289
+ ):
290
+ raise ValueError("a present condition names the argument that must be passed, by keyword or position, and nothing else")
291
+ if condition.kind == "sequence" and not condition.method:
292
+ raise ValueError("a sequence condition names the method of the prior call")
293
+ if condition.kind == "sequence" and condition.values and condition.argument is None:
294
+ raise ValueError("the values of a sequence condition need the argument they constrain")
295
+ if condition.kind != "sequence" and condition.method is not None:
296
+ raise ValueError(f"only a sequence condition names a method, not {condition.kind!r}")
262
297
  if condition.kind == "host" and (
263
298
  (condition.argument is None and condition.position is None) or condition.values or condition.default
264
299
  ):