sourcecode 4.7.0__tar.gz → 4.9.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 (216) hide show
  1. {sourcecode-4.7.0 → sourcecode-4.9.0}/CHANGELOG.md +68 -0
  2. {sourcecode-4.7.0 → sourcecode-4.9.0}/PKG-INFO +15 -14
  3. {sourcecode-4.7.0 → sourcecode-4.9.0}/README.md +14 -13
  4. {sourcecode-4.7.0 → sourcecode-4.9.0}/pyproject.toml +1 -1
  5. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/__init__.py +1 -1
  6. sourcecode-4.9.0/src/sourcecode/audit_report.py +147 -0
  7. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/cli.py +783 -88
  8. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/context_cache.py +48 -1
  9. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/environment_resolution.py +88 -6
  10. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/hibernate_strat.py +28 -6
  11. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/migrate_check.py +20 -3
  12. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/non_coverage.py +12 -10
  13. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/posture.py +2 -1
  14. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/risk.py +382 -22
  15. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/rule_catalog.py +6 -1
  16. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/spring_impact.py +8 -2
  17. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/spring_security_audit.py +338 -0
  18. {sourcecode-4.7.0 → sourcecode-4.9.0}/.github/workflows/build-windows.yml +0 -0
  19. {sourcecode-4.7.0 → sourcecode-4.9.0}/.gitignore +0 -0
  20. {sourcecode-4.7.0 → sourcecode-4.9.0}/.ruff.toml +0 -0
  21. {sourcecode-4.7.0 → sourcecode-4.9.0}/CLAUDE.md +0 -0
  22. {sourcecode-4.7.0 → sourcecode-4.9.0}/CONTRIBUTING.md +0 -0
  23. {sourcecode-4.7.0 → sourcecode-4.9.0}/LICENSE +0 -0
  24. {sourcecode-4.7.0 → sourcecode-4.9.0}/SECURITY.md +0 -0
  25. {sourcecode-4.7.0 → sourcecode-4.9.0}/raw +0 -0
  26. {sourcecode-4.7.0 → sourcecode-4.9.0}/scripts/compare_integration_engines.py +0 -0
  27. {sourcecode-4.7.0 → sourcecode-4.9.0}/scripts/customer_smoke_test.sh +0 -0
  28. {sourcecode-4.7.0 → sourcecode-4.9.0}/scripts/generate_jdk_exports.py +0 -0
  29. {sourcecode-4.7.0 → sourcecode-4.9.0}/scripts/perf_harness.py +0 -0
  30. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/adaptive_scanner.py +0 -0
  31. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/archetype.py +0 -0
  32. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/architectural_baseline.py +0 -0
  33. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/architectural_delta.py +0 -0
  34. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/architecture_analyzer.py +0 -0
  35. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/architecture_summary.py +0 -0
  36. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/ast_extractor.py +0 -0
  37. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/baseline_autocapture.py +0 -0
  38. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/cache.py +0 -0
  39. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/cache_model.py +0 -0
  40. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/call_surface.py +0 -0
  41. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/caller_metrics.py +0 -0
  42. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/caller_reach.py +0 -0
  43. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/canonical_ir.py +0 -0
  44. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/chain_rules.py +0 -0
  45. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/change_plan.py +0 -0
  46. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/cir_graphs.py +0 -0
  47. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/classifier.py +0 -0
  48. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/client_calls.py +0 -0
  49. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  50. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/compare.py +0 -0
  51. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/confidence_analyzer.py +0 -0
  52. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/constraint_diff.py +0 -0
  53. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/context_graph.py +0 -0
  54. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/context_scorer.py +0 -0
  55. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/context_summarizer.py +0 -0
  56. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/contract_diff.py +0 -0
  57. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/contract_init.py +0 -0
  58. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/contract_model.py +0 -0
  59. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/contract_pipeline.py +0 -0
  60. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/coverage_parser.py +0 -0
  61. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/data_exposure.py +0 -0
  62. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/data_labels.py +0 -0
  63. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/defect_identity.py +0 -0
  64. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/degradation.py +0 -0
  65. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/dependency_analyzer.py +0 -0
  66. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/deployment_prefix.py +0 -0
  67. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/__init__.py +0 -0
  68. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/base.py +0 -0
  69. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  70. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/dart.py +0 -0
  71. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/dotnet.py +0 -0
  72. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/elixir.py +0 -0
  73. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/go.py +0 -0
  74. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/heuristic.py +0 -0
  75. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/hybrid.py +0 -0
  76. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/java.py +0 -0
  77. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  78. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/nodejs.py +0 -0
  79. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/parsers.py +0 -0
  80. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/php.py +0 -0
  81. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/project.py +0 -0
  82. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/python.py +0 -0
  83. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/ruby.py +0 -0
  84. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/rust.py +0 -0
  85. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/systems.py +0 -0
  86. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/terraform.py +0 -0
  87. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/detectors/tooling.py +0 -0
  88. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/doc_analyzer.py +0 -0
  89. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
  90. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/endpoint_literals.py +0 -0
  91. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/endpoint_metrics.py +0 -0
  92. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  93. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/env_analyzer.py +0 -0
  94. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/envelope.py +0 -0
  95. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/error_schema.py +0 -0
  96. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/evidence_provider.py +0 -0
  97. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/explain.py +0 -0
  98. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/facts/__init__.py +0 -0
  99. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/facts/registry.json +0 -0
  100. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/file_chunker.py +0 -0
  101. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/file_classifier.py +0 -0
  102. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/filter_surface.py +0 -0
  103. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/format_contract.py +0 -0
  104. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/fqn_utils.py +0 -0
  105. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/git_analyzer.py +0 -0
  106. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/git_checkout.py +0 -0
  107. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/graph_analyzer.py +0 -0
  108. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/graph_evidence.py +0 -0
  109. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/identity_fallback.py +0 -0
  110. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/integration_coordinates.py +0 -0
  111. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/jdk_exports.py +0 -0
  112. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/license.py +0 -0
  113. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/mcp/__init__.py +0 -0
  114. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  115. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  116. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  117. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  118. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  119. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/mcp/orchestrator.py +0 -0
  120. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/mcp/registry.py +0 -0
  121. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/mcp/runner.py +0 -0
  122. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/mcp/server.py +0 -0
  123. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/mcp_nudge.py +0 -0
  124. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/metrics_analyzer.py +0 -0
  125. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/migration_blast.py +0 -0
  126. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/openapi_surface.py +0 -0
  127. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/openrewrite_recipe.py +0 -0
  128. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/output_budget.py +0 -0
  129. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/parse_cache.py +0 -0
  130. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/path_admission.py +0 -0
  131. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/path_filters.py +0 -0
  132. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/perf.py +0 -0
  133. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/pipe_contract.py +0 -0
  134. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/pr_comment_renderer.py +0 -0
  135. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/pr_impact.py +0 -0
  136. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/prepare_context.py +0 -0
  137. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/progress.py +0 -0
  138. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/ranking_engine.py +0 -0
  139. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/readiness_timeline.py +0 -0
  140. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/reconciliation.py +0 -0
  141. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/redactor.py +0 -0
  142. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/reference_facts.py +0 -0
  143. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/release_info.py +0 -0
  144. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/relevance_scorer.py +0 -0
  145. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/remedies.py +0 -0
  146. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/rename_refactor.py +0 -0
  147. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/repo_classifier.py +0 -0
  148. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/repository_ir.py +0 -0
  149. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/__init__.py +0 -0
  150. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/context.py +0 -0
  151. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/errors.py +0 -0
  152. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/executor.py +0 -0
  153. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/planner.py +0 -0
  154. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/query.py +0 -0
  155. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/request.py +0 -0
  156. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/resolution.py +0 -0
  157. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/result.py +0 -0
  158. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/retriever.py +0 -0
  159. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/runtime.py +0 -0
  160. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/steps.py +0 -0
  161. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
  162. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/steps_graph.py +0 -0
  163. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/steps_impact.py +0 -0
  164. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/steps_intf.py +0 -0
  165. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/steps_struct.py +0 -0
  166. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/retrieval/steps_txsec.py +0 -0
  167. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/ris.py +0 -0
  168. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/runtime_classifier.py +0 -0
  169. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/sarif.py +0 -0
  170. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/scanner.py +0 -0
  171. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/schema.py +0 -0
  172. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
  173. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/security_config.py +0 -0
  174. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/security_config_scan.py +0 -0
  175. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/security_posture.py +0 -0
  176. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/semantic_analyzer.py +0 -0
  177. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/semantic_impact_engine.py +0 -0
  178. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/semantic_integration_engine.py +0 -0
  179. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/semantic_services.py +0 -0
  180. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/serializer.py +0 -0
  181. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/servlet_surface.py +0 -0
  182. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/source_text.py +0 -0
  183. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/spring_event_topology.py +0 -0
  184. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/spring_findings.py +0 -0
  185. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/spring_model.py +0 -0
  186. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/spring_profiles.py +0 -0
  187. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/spring_properties.py +0 -0
  188. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/spring_semantic.py +0 -0
  189. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
  190. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/summarizer.py +0 -0
  191. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/target_admission.py +0 -0
  192. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/telemetry/__init__.py +0 -0
  193. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/telemetry/config.py +0 -0
  194. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/telemetry/consent.py +0 -0
  195. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/telemetry/events.py +0 -0
  196. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/telemetry/filters.py +0 -0
  197. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/telemetry/transport.py +0 -0
  198. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/test_gap_ranking.py +0 -0
  199. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/test_sources.py +0 -0
  200. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/token_estimate.py +0 -0
  201. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/tree_utils.py +0 -0
  202. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/type_usage_surface.py +0 -0
  203. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/validation_inference.py +0 -0
  204. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/validation_surface.py +0 -0
  205. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/verify_edit.py +0 -0
  206. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/verify_repo.py +0 -0
  207. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/verify_rules.py +0 -0
  208. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/version_check.py +0 -0
  209. {sourcecode-4.7.0 → sourcecode-4.9.0}/src/sourcecode/workspace.py +0 -0
  210. {sourcecode-4.7.0 → sourcecode-4.9.0}/supabase/functions/README.md +0 -0
  211. {sourcecode-4.7.0 → sourcecode-4.9.0}/supabase/functions/get-license/index.ts +0 -0
  212. {sourcecode-4.7.0 → sourcecode-4.9.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
  213. {sourcecode-4.7.0 → sourcecode-4.9.0}/supabase/functions/telemetry/index.ts +0 -0
  214. {sourcecode-4.7.0 → sourcecode-4.9.0}/supabase/sql/license_event_ordering.sql +0 -0
  215. {sourcecode-4.7.0 → sourcecode-4.9.0}/supabase/sql/licensing_schema.sql +0 -0
  216. {sourcecode-4.7.0 → sourcecode-4.9.0}/supabase/sql/telemetry_events.sql +0 -0
@@ -2,6 +2,74 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [4.9.0] — 2026-08-04
6
+
7
+ ### Added
8
+
9
+ - **Custom AOP security gate audit.** `spring-audit` now emits `GATE-001` through
10
+ `GATE-004` for custom authorization gates detected by the security posture
11
+ authority: Spring AOP proxy bypass, fail-open advice, disabled/tautological
12
+ annotation attributes, and fragile positional/reflection binding.
13
+ - **Deployment evidence for runtime posture.** `posture --resolve-environments`
14
+ accepts `--env-file FILE` and binds explicit deployment profile evidence to
15
+ `decided_case` while keeping repository defaults as lower-priority evidence.
16
+ - **Bounded HTTP-input-to-sink flow in `risk`.** The `query_construction` factor
17
+ now distinguishes a proven bounded path from annotated HTTP input, through
18
+ positional calls in repository Java sources, into known concatenated query
19
+ sinks. General taint remains explicitly outside scope.
20
+ - **SARIF triage table for `enrich`.** `enrich --table` now provides
21
+ auditor-facing filtering by scanner rule, composed band and top-N while
22
+ leaving JSON as the contract.
23
+ - **Signed audit report bundle.** New experimental `audit-report` command packages
24
+ existing `risk` and `posture` evidence into JSON or Markdown, with optional
25
+ HMAC-SHA256 signing over the canonical JSON payload via `--sign-key`.
26
+
27
+ ### Documentation
28
+
29
+ - README, user guide and root `ask --help` now list `audit-report`, the 4.9.0
30
+ version, `posture --env-file`, `enrich --table`, bounded `risk` flow and the
31
+ `GATE-*` rule family.
32
+
33
+ ## [4.8.0] — 2026-08-04
34
+
35
+ ### Fixed
36
+
37
+ - **`risk` now gives MyBatis XML findings real reach.** `SEC-008` mapper XML
38
+ binds to the Java mapper interface named by the XML namespace, then walks that
39
+ interface's callers instead of publishing manufactured zero reach.
40
+ - **`risk` now maps deployment descriptor controls to endpoint reach.**
41
+ `DEAD-001` in `web.xml` reads descriptor URL patterns and reports the
42
+ endpoint population they cover, or an explicit unknown reach reason when the
43
+ descriptor scope cannot be parsed.
44
+ - **`migrate-check` no longer scores unresolved transitive Hibernate as ready.**
45
+ `spring-boot-starter-data-jpa` without a resolved Hibernate version now
46
+ degrades to unresolved transitive evidence instead of `hibernate_readiness:
47
+ 100`.
48
+ - **`impact-chain` names caller-count units.** List entries, distinct symbols and
49
+ distinct classes are published separately so truncation warnings and metadata
50
+ no longer reuse one ambiguous "direct callers" phrase.
51
+ - **Expensive semantic passes warn about repository contention.** `spring-audit`,
52
+ `risk`, `migrate-check` and `verify` register an advisory analysis scope and
53
+ warn interactive users when another expensive `ask` process is already running
54
+ against the same repository.
55
+ - **Cache context stats publish lookup distributions.** `cache context-stats`
56
+ now includes lookup/build p50/p95 and context-layer payload sizes so cache-hit
57
+ cost can be budgeted instead of inferred.
58
+ - **Cache command grammar is consistent.** `ask cache model [path]` accepts a
59
+ repository path like sibling cache commands.
60
+
61
+ ### Added
62
+
63
+ - **Human-scale table triage for large audits.** `spring-audit`, `risk` and
64
+ `migrate-check` now support table renderers with direct filtering:
65
+ `--table`, `--rule`/`--only`, `--band` where applicable, and `--top-n`.
66
+
67
+ ### Documentation
68
+
69
+ - README and user guide examples now report `4.8.0`.
70
+ - The development roadmap records the saint-server field-evaluation fixes and
71
+ future feature queue.
72
+
5
73
  ## [4.7.0] — 2026-08-04
6
74
 
7
75
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 4.7.0
3
+ Version: 4.9.0
4
4
  Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
5
5
  License-File: LICENSE
6
6
  Keywords: agents,ai,codebase,context,developer-tools,llm
@@ -42,7 +42,7 @@ Description-Content-Type: text/markdown
42
42
 
43
43
  **Context · Impact · Migration · Architecture · Review — everything from one structural model.**
44
44
 
45
- ![Version](https://img.shields.io/badge/version-4.7.0-blue)
45
+ ![Version](https://img.shields.io/badge/version-4.9.0-blue)
46
46
  ![Python](https://img.shields.io/badge/python-3.9%2B-green)
47
47
 
48
48
  > **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
@@ -97,7 +97,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
97
97
  # pip / pipx
98
98
  pipx install sourcecode # or: pip install sourcecode
99
99
 
100
- ask version # ask 4.7.0 — and, on a build that has aged,
100
+ ask version # ask 4.9.0 — and, on a build that has aged,
101
101
  # how many releases have probably shipped since
102
102
  ```
103
103
 
@@ -260,10 +260,10 @@ figures and the authority behind each — and an axis this build cannot measure
260
260
  weighted 1.0 and named in `blind_axes` rather than silently treated as safe. Measured on a
261
261
  field case: a defect both `spring-audit` and `impact-chain` called *medium* composes to
262
262
  **high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
263
- The last two factors describe the input path a query assembled by concatenation, a route
264
- accepting a body with no declared constraint. They are **adjacencies, not dataflow**: no
265
- value is followed from a request to a sink, which is `NC-001` and is published in the
266
- payload's own `non_coverage` block.
263
+ The last two factors describe the input path: a query assembled by concatenation, a bounded
264
+ HTTP-input-to-query-sink path when ASK can prove one, and a route accepting a body with no
265
+ declared constraint. General taint remains `NC-001` and is published in the payload's own
266
+ `non_coverage` block.
267
267
  `ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
268
268
  → [reference](docs/USER_GUIDE.md)
269
269
 
@@ -289,7 +289,7 @@ experimental: both are true, and they are two different facts.
289
289
  |---|---|---|
290
290
  | **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
291
291
  | **supported** | maintained; fields are added, never removed without a major | every command not named in another row |
292
- | **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `enrich` · `data-exposure` · `migrate-recipe` · `posture` · `archetype` |
292
+ | **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `enrich` · `audit-report` · `data-exposure` · `migrate-recipe` · `posture` · `archetype` |
293
293
  | **parked** | kept working, no longer developed | `retrieve` |
294
294
 
295
295
  The same table is printed by `ask --help`, and both are generated from one authority
@@ -306,13 +306,14 @@ from it.
306
306
  | Command | Tier | Answers | Note |
307
307
  |---|---|---|---|
308
308
  | `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
309
- | `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority |
310
- | `enrich` | experimental | another scanner's SARIF findings, ranked by what this repository does with them | `--sarif <log>`; the same composition as `risk`, with the scanner as the severity authority |
309
+ | `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority; `--table --rule SEC-008 --band high --top-n 20` gives audit triage without `jq` |
310
+ | `enrich` | experimental | another scanner's SARIF findings, ranked by what this repository does with them | `--sarif <log>`; same composition as `risk`, with `--table --rule <id> --band high --top-n 20` for triage |
311
+ | `audit-report` | experimental | human audit bundle over existing `risk` + `posture` evidence, optionally signed | `--format markdown`; `--sign-key <file>` signs canonical JSON with HMAC-SHA256 |
311
312
  | `migrate-recipe` | experimental | the migration report as the OpenRewrite recipe that applies it | only recipes a finding named; the manual remainder published beside them; writes nothing without `--write`, and never a runnable command for an empty recipe list |
312
313
  | `data-exposure` | experimental | which routes can carry the data you labelled, and who reaches them | labels declared in `sourcecode.config.json` — never inferred from a name; `signature` and `call_reach` evidence published apart, field-level flow out of scope (NC-008). With nothing declared, `ask data-exposure /path/to/repo` answers `answered: false` and hands back the file, the key and an example to declare — it never reports zero exposed routes |
313
314
  | `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators). `--compact` answers the exposure census without the rows; `--servlets` lists the servlet-mounted surface as its own population; `--client-usage` says which routes the TS/JS client in this repository actually calls |
314
- | `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
315
- | `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
315
+ | `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment`; `--table --rule SEC-008 --top-n 20` for human-scale review |
316
+ | `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan; `--table --rule MIG-001 --band critical --top-n 20` for blocker triage |
316
317
  | `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
317
318
  | `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
318
319
  | `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
@@ -328,7 +329,7 @@ from it.
328
329
  | `retrieve` | parked | typed knowledge queries over the model | |
329
330
  | `archetype` | experimental | evidence-based architectural archetype | |
330
331
  | `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
331
- | `cache status\|warm\|model\|clear` · `auth` · `telemetry` · `mcp` · `config` · `version` | supported | housekeeping | `activate` too |
332
+ | `cache status\|warm\|model\|clear` · `auth` · `telemetry` · `mcp` · `config` · `version` | supported | housekeeping | `cache model [path]` explains what a warm buys per command; `activate` too |
332
333
 
333
334
  ---
334
335
 
@@ -356,7 +357,7 @@ reading JSON sees the same boundary a buyer reads here.
356
357
 
357
358
  | Not covered | Why | What answers it |
358
359
  |---|---|---|
359
- | **Whether request input reaches a sink no dataflow or taint analysis.** | This engine resolves structure and wiring without compiling. Taint needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL). What this product adds on top is reachability: which of that tool's findings sit behind an endpoint that is reachable unauthenticated. |
360
+ | **General request-input-to-sink taint analysis.** | `ask risk` includes a bounded slice for annotated HTTP parameters, positional calls in repository Java sources and known query sinks. Anything broader needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL) for complete taint. What this product adds on top is reachability and, for the bounded slice, whether an annotated HTTP input reaches a known concatenated query sink. |
360
361
  | **Secrets outside Java, Spring configuration and the deployment descriptors — a Helm value, a CI variable file, a shell script.** | The file population this analyzer reads is the Java source, the Spring configuration convention and the descriptors it already parses to resolve an environment. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. Narrowed by CL-10: a credential stored in `web.xml` or a Spring XML context IS reported (SEC-007), because those files were already being read. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
361
362
  | **Filter-chain order and per-filter URL patterns — the presence of a custom filter is structural only.** | Which filter runs first is decided by bean ordering this analyzer does not resolve. Where two active configurations both match a request, the answer published is `undecided` rather than a guess. | `ask posture --profile <set>` states per endpoint what the readable rules decide and what they leave undecided. |
362
363
  | **Known vulnerabilities in dependencies — no CVE database, no version advisory matching.** | Enriching a vulnerability feed is a different product with a different update cadence; a stale embedded database is worse than no database, because it reads as a clean bill of health. | A dependency scanner (Trivy, OWASP Dependency-Check). `impact-chain` then answers which of its findings anything actually reaches. |
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Context · Impact · Migration · Architecture · Review — everything from one structural model.**
6
6
 
7
- ![Version](https://img.shields.io/badge/version-4.7.0-blue)
7
+ ![Version](https://img.shields.io/badge/version-4.9.0-blue)
8
8
  ![Python](https://img.shields.io/badge/python-3.9%2B-green)
9
9
 
10
10
  > **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
@@ -59,7 +59,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
59
59
  # pip / pipx
60
60
  pipx install sourcecode # or: pip install sourcecode
61
61
 
62
- ask version # ask 4.7.0 — and, on a build that has aged,
62
+ ask version # ask 4.9.0 — and, on a build that has aged,
63
63
  # how many releases have probably shipped since
64
64
  ```
65
65
 
@@ -222,10 +222,10 @@ figures and the authority behind each — and an axis this build cannot measure
222
222
  weighted 1.0 and named in `blind_axes` rather than silently treated as safe. Measured on a
223
223
  field case: a defect both `spring-audit` and `impact-chain` called *medium* composes to
224
224
  **high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
225
- The last two factors describe the input path a query assembled by concatenation, a route
226
- accepting a body with no declared constraint. They are **adjacencies, not dataflow**: no
227
- value is followed from a request to a sink, which is `NC-001` and is published in the
228
- payload's own `non_coverage` block.
225
+ The last two factors describe the input path: a query assembled by concatenation, a bounded
226
+ HTTP-input-to-query-sink path when ASK can prove one, and a route accepting a body with no
227
+ declared constraint. General taint remains `NC-001` and is published in the payload's own
228
+ `non_coverage` block.
229
229
  `ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
230
230
  → [reference](docs/USER_GUIDE.md)
231
231
 
@@ -251,7 +251,7 @@ experimental: both are true, and they are two different facts.
251
251
  |---|---|---|
252
252
  | **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
253
253
  | **supported** | maintained; fields are added, never removed without a major | every command not named in another row |
254
- | **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `enrich` · `data-exposure` · `migrate-recipe` · `posture` · `archetype` |
254
+ | **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `enrich` · `audit-report` · `data-exposure` · `migrate-recipe` · `posture` · `archetype` |
255
255
  | **parked** | kept working, no longer developed | `retrieve` |
256
256
 
257
257
  The same table is printed by `ask --help`, and both are generated from one authority
@@ -268,13 +268,14 @@ from it.
268
268
  | Command | Tier | Answers | Note |
269
269
  |---|---|---|---|
270
270
  | `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
271
- | `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority |
272
- | `enrich` | experimental | another scanner's SARIF findings, ranked by what this repository does with them | `--sarif <log>`; the same composition as `risk`, with the scanner as the severity authority |
271
+ | `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority; `--table --rule SEC-008 --band high --top-n 20` gives audit triage without `jq` |
272
+ | `enrich` | experimental | another scanner's SARIF findings, ranked by what this repository does with them | `--sarif <log>`; same composition as `risk`, with `--table --rule <id> --band high --top-n 20` for triage |
273
+ | `audit-report` | experimental | human audit bundle over existing `risk` + `posture` evidence, optionally signed | `--format markdown`; `--sign-key <file>` signs canonical JSON with HMAC-SHA256 |
273
274
  | `migrate-recipe` | experimental | the migration report as the OpenRewrite recipe that applies it | only recipes a finding named; the manual remainder published beside them; writes nothing without `--write`, and never a runnable command for an empty recipe list |
274
275
  | `data-exposure` | experimental | which routes can carry the data you labelled, and who reaches them | labels declared in `sourcecode.config.json` — never inferred from a name; `signature` and `call_reach` evidence published apart, field-level flow out of scope (NC-008). With nothing declared, `ask data-exposure /path/to/repo` answers `answered: false` and hands back the file, the key and an example to declare — it never reports zero exposed routes |
275
276
  | `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators). `--compact` answers the exposure census without the rows; `--servlets` lists the servlet-mounted surface as its own population; `--client-usage` says which routes the TS/JS client in this repository actually calls |
276
- | `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
277
- | `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
277
+ | `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment`; `--table --rule SEC-008 --top-n 20` for human-scale review |
278
+ | `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan; `--table --rule MIG-001 --band critical --top-n 20` for blocker triage |
278
279
  | `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
279
280
  | `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
280
281
  | `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
@@ -290,7 +291,7 @@ from it.
290
291
  | `retrieve` | parked | typed knowledge queries over the model | |
291
292
  | `archetype` | experimental | evidence-based architectural archetype | |
292
293
  | `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
293
- | `cache status\|warm\|model\|clear` · `auth` · `telemetry` · `mcp` · `config` · `version` | supported | housekeeping | `activate` too |
294
+ | `cache status\|warm\|model\|clear` · `auth` · `telemetry` · `mcp` · `config` · `version` | supported | housekeeping | `cache model [path]` explains what a warm buys per command; `activate` too |
294
295
 
295
296
  ---
296
297
 
@@ -318,7 +319,7 @@ reading JSON sees the same boundary a buyer reads here.
318
319
 
319
320
  | Not covered | Why | What answers it |
320
321
  |---|---|---|
321
- | **Whether request input reaches a sink no dataflow or taint analysis.** | This engine resolves structure and wiring without compiling. Taint needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL). What this product adds on top is reachability: which of that tool's findings sit behind an endpoint that is reachable unauthenticated. |
322
+ | **General request-input-to-sink taint analysis.** | `ask risk` includes a bounded slice for annotated HTTP parameters, positional calls in repository Java sources and known query sinks. Anything broader needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL) for complete taint. What this product adds on top is reachability and, for the bounded slice, whether an annotated HTTP input reaches a known concatenated query sink. |
322
323
  | **Secrets outside Java, Spring configuration and the deployment descriptors — a Helm value, a CI variable file, a shell script.** | The file population this analyzer reads is the Java source, the Spring configuration convention and the descriptors it already parses to resolve an environment. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. Narrowed by CL-10: a credential stored in `web.xml` or a Spring XML context IS reported (SEC-007), because those files were already being read. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
323
324
  | **Filter-chain order and per-filter URL patterns — the presence of a custom filter is structural only.** | Which filter runs first is decided by bean ordering this analyzer does not resolve. Where two active configurations both match a request, the answer published is `undecided` rather than a guess. | `ask posture --profile <set>` states per endpoint what the readable rules decide and what they leave undecided. |
324
325
  | **Known vulnerabilities in dependencies — no CVE database, no version advisory matching.** | Enriching a vulnerability feed is a different product with a different update cadence; a stale embedded database is worse than no database, because it reads as a clean bill of health. | A dependency scanner (Trivy, OWASP Dependency-Check). `impact-chain` then answers which of its findings anything actually reaches. |
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "4.7.0"
7
+ version = "4.9.0"
8
8
  description = "Persistent structural context and ultra-fast repeated analysis for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -4,4 +4,4 @@ ASK Engine is the product. ``ask`` is the canonical CLI command; ``sourcecode``
4
4
  the legacy compatibility alias and the Python/PyPI package name. See
5
5
  docs/PRODUCT_IDENTITY.md (normative)."""
6
6
 
7
- __version__ = "4.7.0"
7
+ __version__ = "4.9.0"
@@ -0,0 +1,147 @@
1
+ """Signed audit report over existing ASK evidence.
2
+
3
+ This module packages facts other commands already publish. It does not score ROI,
4
+ choose a fix, or introduce a second judgement layer: the report summary is a
5
+ reader-friendly index over the embedded evidence blocks.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import hashlib
11
+ import hmac
12
+ import json
13
+ from datetime import datetime, timezone
14
+ from pathlib import Path
15
+ from typing import Any, Optional
16
+
17
+ from sourcecode import __version__
18
+
19
+ AUDIT_REPORT_SCHEMA = "audit-report-v1"
20
+
21
+
22
+ def _canonical_json(data: dict[str, Any]) -> bytes:
23
+ return json.dumps(data, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
24
+
25
+
26
+ def _sign(payload: dict[str, Any], key: bytes) -> dict[str, str]:
27
+ canonical = _canonical_json(payload)
28
+ return {
29
+ "algorithm": "hmac-sha256",
30
+ "payload_sha256": hashlib.sha256(canonical).hexdigest(),
31
+ "key_id": hashlib.sha256(key).hexdigest()[:12],
32
+ "signature": hmac.new(key, canonical, hashlib.sha256).hexdigest(),
33
+ }
34
+
35
+
36
+ def build_audit_report(
37
+ root: Path,
38
+ *,
39
+ profiles: Optional[set[str]] = None,
40
+ sign_key: Optional[bytes] = None,
41
+ risk_limit: int = 10,
42
+ ) -> dict[str, Any]:
43
+ """Build the buyer-readable audit bundle from existing command payloads."""
44
+ from sourcecode.posture import build_posture
45
+ from sourcecode.risk import build_risk
46
+
47
+ root = Path(root).resolve()
48
+ risk = build_risk(root, limit=risk_limit, min_band="low", profiles=profiles)
49
+ posture = build_posture(root, profiles or set())
50
+ top_risks = risk.get("risks", [])[:risk_limit]
51
+ access = ((posture.get("endpoints") or {}).get("effective_access") or {})
52
+
53
+ unsigned: dict[str, Any] = {
54
+ "schema_version": AUDIT_REPORT_SCHEMA,
55
+ "tool": {"name": "ask", "version": __version__},
56
+ "generated_at": datetime.now(timezone.utc).isoformat(),
57
+ "repository": {"path": str(root)},
58
+ **({"profile_set": sorted(profiles)} if profiles else {}),
59
+ "summary": {
60
+ "risk_model": risk.get("model"),
61
+ "total_defects": risk.get("total_defects"),
62
+ "total_findings": risk.get("total_findings"),
63
+ "risk_bands": risk.get("by_band", {}),
64
+ "top_risks_shown": len(top_risks),
65
+ "endpoint_access": access.get("summary", {}),
66
+ "unresolved_beans": len(posture.get("unresolved") or []),
67
+ },
68
+ "top_risks": top_risks,
69
+ "evidence": {
70
+ "risk": risk,
71
+ "posture": posture,
72
+ },
73
+ "limits": {
74
+ "statement": (
75
+ "This report packages existing ASK evidence. It does not certify "
76
+ "compliance, choose fixes, assign ROI, or replace a human audit decision."
77
+ ),
78
+ "non_coverage": (risk.get("non_coverage") or {}).get("items", []),
79
+ },
80
+ }
81
+ # Sign and publish the same JSON-normalized material. Some embedded evidence
82
+ # may contain tuples or other JSON-coercible values; normalizing before signing
83
+ # avoids a signature over an in-memory shape the user never receives.
84
+ normalized = json.loads(_canonical_json(unsigned).decode("utf-8"))
85
+ if sign_key:
86
+ normalized["signature"] = _sign(normalized, sign_key)
87
+ return normalized
88
+
89
+
90
+ def render_markdown(report: dict[str, Any]) -> str:
91
+ """Human report renderer over the JSON contract."""
92
+ summary = report.get("summary") or {}
93
+ repo = (report.get("repository") or {}).get("path", "")
94
+ profile = ", ".join(report.get("profile_set") or []) or "default"
95
+ lines = [
96
+ "# ASK Audit Report",
97
+ "",
98
+ f"- Repository: `{repo}`",
99
+ f"- ASK version: `{(report.get('tool') or {}).get('version', '')}`",
100
+ f"- Profile set: `{profile}`",
101
+ f"- Total defects: `{summary.get('total_defects')}`",
102
+ f"- Risk bands: `{summary.get('risk_bands')}`",
103
+ f"- Endpoint access: `{summary.get('endpoint_access')}`",
104
+ "",
105
+ "## Top Risks",
106
+ "",
107
+ ]
108
+ risks = report.get("top_risks") or []
109
+ if not risks:
110
+ lines.append("No composed risks were reported.")
111
+ else:
112
+ lines.extend([
113
+ "| Band | Score | Rules | File | Line | Title |",
114
+ "|---|---:|---|---|---:|---|",
115
+ ])
116
+ for row in risks:
117
+ rules = ", ".join(str(r) for r in row.get("rule_ids", []))
118
+ lines.append(
119
+ "| "
120
+ + " | ".join([
121
+ str(row.get("band", "")),
122
+ str(row.get("severity_effective", "")),
123
+ rules,
124
+ str(row.get("source_file", "")),
125
+ str(row.get("first_line", "")),
126
+ str(row.get("title", "")).replace("|", "\\|"),
127
+ ])
128
+ + " |"
129
+ )
130
+ lines.extend([
131
+ "",
132
+ "## Limits",
133
+ "",
134
+ str((report.get("limits") or {}).get("statement", "")),
135
+ ])
136
+ signature = report.get("signature")
137
+ if isinstance(signature, dict):
138
+ lines.extend([
139
+ "",
140
+ "## Signature",
141
+ "",
142
+ f"- Algorithm: `{signature.get('algorithm')}`",
143
+ f"- Payload SHA-256: `{signature.get('payload_sha256')}`",
144
+ f"- Key ID: `{signature.get('key_id')}`",
145
+ f"- Signature: `{signature.get('signature')}`",
146
+ ])
147
+ return "\n".join(lines) + "\n"