sourcecode 4.9.0__tar.gz → 4.10.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.
- {sourcecode-4.9.0 → sourcecode-4.10.0}/CHANGELOG.md +40 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/PKG-INFO +23 -10
- {sourcecode-4.9.0 → sourcecode-4.10.0}/README.md +22 -9
- {sourcecode-4.9.0 → sourcecode-4.10.0}/pyproject.toml +1 -1
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/audit_report.py +21 -2
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/cache_model.py +6 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/canonical_ir.py +19 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/cli.py +148 -10
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/migrate_check.py +307 -1
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/progress.py +21 -6
- sourcecode-4.10.0/src/sourcecode/provenance.py +202 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/release_info.py +1 -1
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/risk.py +11 -0
- sourcecode-4.10.0/src/sourcecode/runs.py +136 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/sarif.py +12 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/security_config_scan.py +55 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/.gitignore +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/.ruff.toml +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/CLAUDE.md +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/CONTRIBUTING.md +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/LICENSE +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/SECURITY.md +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/raw +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/scripts/perf_harness.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/archetype.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/baseline_autocapture.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/cache.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/caller_reach.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/chain_rules.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/classifier.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/client_calls.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/compare.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/context_cache.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/contract_init.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/data_exposure.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/data_labels.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/defect_identity.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/degradation.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/deployment_prefix.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/envelope.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/environment_resolution.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/explain.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/facts/__init__.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/facts/registry.json +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/filter_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/git_checkout.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/identity_fallback.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/integration_coordinates.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/license.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/non_coverage.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/openrewrite_recipe.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/parse_cache.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/path_admission.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/perf.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/pipe_contract.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/posture.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/reference_facts.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/remedies.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/repository_ir.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/result.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps_graph.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps_impact.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps_intf.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps_struct.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps_txsec.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/ris.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/rule_catalog.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/schema.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/security_config.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/security_posture.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/semantic_integration_engine.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/serializer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/servlet_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/source_text.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_profiles.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_properties.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/target_admission.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/test_gap_ranking.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/test_sources.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/token_estimate.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/validation_inference.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/verify_repo.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/version_check.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/functions/README.md +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -2,6 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [4.10.0] — 2026-08-05
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Canonical endpoint projection rejects parser-corrupt Java handler names.**
|
|
10
|
+
Reserved Java keywords such as `if` can no longer reach CIR/risk as synthetic
|
|
11
|
+
handler symbols.
|
|
12
|
+
- **`DEAD-001` reports commented Java security annotations.** Java comments that
|
|
13
|
+
contain Spring/Jakarta/custom security annotations are now treated as disabled
|
|
14
|
+
controls, while active annotations stay out of dead-code findings.
|
|
15
|
+
- **`SEC-007` reports JavaMelody descriptor credentials.** `authorized-users`
|
|
16
|
+
values in deployment descriptors are detected and redacted even when they are
|
|
17
|
+
not written as `{SHA-*}` digest literals.
|
|
18
|
+
- **`audit-report` can reuse existing risk evidence.** `--from-risk risk.json`
|
|
19
|
+
packages a previous `ask risk` payload instead of recomputing repo-wide risk.
|
|
20
|
+
- **Long analysis observability improved.** `ASK_PROGRESS=1` enables non-TTY
|
|
21
|
+
heartbeat lines, long commands write durable `.ask/runs` records, and file
|
|
22
|
+
outputs are written atomically.
|
|
23
|
+
- **Large-repo CI budgets are explicit.** `ASK_MAX_ANALYSIS_SECONDS` can fail a
|
|
24
|
+
repo-wide/deep command before work starts when the configured budget is below
|
|
25
|
+
the command's safe floor.
|
|
26
|
+
|
|
27
|
+
### Documentation
|
|
28
|
+
|
|
29
|
+
- README, user guide and root `ask --help` now distinguish per-symbol,
|
|
30
|
+
inventory and repo-wide/deep command costs instead of treating cache
|
|
31
|
+
benchmarks as universal runtime promises.
|
|
32
|
+
|
|
33
|
+
## [4.9.1] — 2026-08-04
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- **Java LTS/licensing inventory in `migrate-check`.** Reports Java 8/11/17/21/25
|
|
38
|
+
evidence from Maven/Gradle, local runtime hints and container files, target-LTS
|
|
39
|
+
blockers via `--target-jdk`, and explicit Oracle JDK licensing-review signals
|
|
40
|
+
without changing migration readiness scoring.
|
|
41
|
+
- **Claim provenance ledger.** `risk`, `enrich`, `migrate-check`, `audit-report`
|
|
42
|
+
and `prepare-context` now emit `evidence_manifest` with stable claim IDs,
|
|
43
|
+
source paths/lines, command inputs, ASK version, git HEAD and freshness metadata.
|
|
44
|
+
|
|
5
45
|
## [4.9.0] — 2026-08-04
|
|
6
46
|
|
|
7
47
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.10.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
|
-

|
|
46
46
|

|
|
47
47
|
|
|
48
48
|
> **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
|
|
@@ -54,9 +54,9 @@ Description-Content-Type: text/markdown
|
|
|
54
54
|
|
|
55
55
|
## The problem
|
|
56
56
|
|
|
57
|
-
Every time an AI coding agent starts a new session, it has to re-parse the repository from scratch.
|
|
57
|
+
Every time an AI coding agent starts a new session, it has to re-parse the repository from scratch. On small and mid-sized repos that cost is seconds; on large Java/Spring monoliths, repo-wide semantic composition can be minutes. Multiply that by dozens of agent turns per hour, and repo context acquisition becomes a real bottleneck — not just latency, but tokens, compute, and iteration velocity.
|
|
58
58
|
|
|
59
|
-
ASK Engine solves this with a persistent structural cache keyed on file content hashes. After the first scan,
|
|
59
|
+
ASK Engine solves this with a persistent structural cache keyed on file content hashes. After the first scan, later invocations reuse pre-built context whenever their command can consume the warmed layers. The repo doesn't change? The cache doesn't expire.
|
|
60
60
|
|
|
61
61
|
**The cache is not a performance optimization. It is what makes ASK Engine usable as infrastructure rather than a one-off tool.**
|
|
62
62
|
|
|
@@ -69,9 +69,11 @@ ASK Engine solves this with a persistent structural cache keyed on file content
|
|
|
69
69
|
| Keycloak | 7,885 Java files | 10.5s | 0.6s | **~17x** |
|
|
70
70
|
| BroadleafCommerce | 2,985 Java files | 2.7s | 0.3s | **~9x** |
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
These numbers are cache-layer benchmarks, not a promise for every command. Per-symbol queries and compact context benefit most. Inventory commands scale with file count. Repo-wide/deep compositions such as `risk`, `audit-report` and large `spring-audit` runs can take minutes on multi-thousand-endpoint repositories and belong in a supervised or nightly job unless CI sets an explicit budget.
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
With the right command class, ASK Engine becomes **constant infrastructure** inside agent loops — call the fast/context surfaces before edits and reserve deep compositions for the points where their evidence is worth the runtime.
|
|
75
|
+
|
|
76
|
+
**Large-repo controls.** Set `ASK_PROGRESS=1` to get line heartbeats in non-TTY supervised runs. Set `ASK_MAX_ANALYSIS_SECONDS=<seconds>` to fail before starting a repo-wide/deep command whose configured budget is below its safe floor. Use `ask audit-report --from-risk risk.json` to package an existing risk run instead of recomputing it.
|
|
75
77
|
|
|
76
78
|
**What a warm actually covers.** `ask cache warm` runs the compact analysis: it rebuilds the
|
|
77
79
|
shared structural layers (L1/L2 + the Repository Intelligence Snapshot + the shared Canonical
|
|
@@ -97,7 +99,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
|
|
|
97
99
|
# pip / pipx
|
|
98
100
|
pipx install sourcecode # or: pip install sourcecode
|
|
99
101
|
|
|
100
|
-
ask version # ask 4.
|
|
102
|
+
ask version # ask 4.10.0 — and, on a build that has aged,
|
|
101
103
|
# how many releases have probably shipped since
|
|
102
104
|
```
|
|
103
105
|
|
|
@@ -137,8 +139,9 @@ ask endpoints /path/to/repo
|
|
|
137
139
|
# CGLIB no-op), security surface, request-body validation.
|
|
138
140
|
ask spring-audit /path/to/repo
|
|
139
141
|
|
|
140
|
-
# Spring Boot 2→3 readiness
|
|
142
|
+
# Spring Boot 2→3 readiness plus Java LTS/licensing inventory.
|
|
141
143
|
ask migrate-check /path/to/repo --compact
|
|
144
|
+
# Add --target-jdk 25 to make the LTS route explicit.
|
|
142
145
|
```
|
|
143
146
|
|
|
144
147
|
**Then the three that finish the sentence the four above start.** A profile-set answer stays
|
|
@@ -308,12 +311,12 @@ from it.
|
|
|
308
311
|
| `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
|
|
309
312
|
| `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
313
|
| `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 |
|
|
314
|
+
| `audit-report` | experimental | human audit bundle over existing `risk` + `posture` evidence, optionally signed | includes `evidence_manifest` claim provenance; `--format markdown`; `--sign-key <file>` signs canonical JSON with HMAC-SHA256 |
|
|
312
315
|
| `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 |
|
|
313
316
|
| `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 |
|
|
314
317
|
| `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 |
|
|
315
318
|
| `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 |
|
|
319
|
+
| `migrate-check` | core | Boot 2→3 readiness + Java LTS/licensing inventory: located blockers, per-dimension score, effort, detected Java 8/11/17/21/25 evidence and explicit licensing-review signals | `--target-jdk 25` sets the target LTS route; `--blast-radius` orders the re-test plan; `--table --rule MIG-001 --band critical --top-n 20` for blocker triage |
|
|
317
320
|
| `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
|
|
318
321
|
| `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
|
|
319
322
|
| `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
|
|
@@ -401,6 +404,16 @@ and that gap is the honest description, not a defect to argue with. `migrate-che
|
|
|
401
404
|
the OpenRewrite recipe each finding carries so the executor that does apply changes has its
|
|
402
405
|
input.
|
|
403
406
|
|
|
407
|
+
**Java LTS/licensing inventory.** `migrate-check` emits `java_lts_inventory` beside the migration
|
|
408
|
+
scores. It reads Maven/Gradle, local runtime hints and container files for Java 8/11/17/21/25
|
|
409
|
+
evidence, reports target-LTS blockers with `--target-jdk`, and marks explicit Oracle JDK evidence
|
|
410
|
+
as `licensing_review_needed`. This is inventory evidence, not legal advice.
|
|
411
|
+
|
|
412
|
+
**Claim provenance ledger.** JSON outputs from `risk`, `enrich`, `migrate-check`,
|
|
413
|
+
`audit-report` and `prepare-context` include `evidence_manifest`: stable claim IDs mapped to
|
|
414
|
+
source paths/lines, command inputs, ASK version, git HEAD and freshness metadata. The manifest
|
|
415
|
+
indexes claims already in the payload; it does not add analysis or certify compliance.
|
|
416
|
+
|
|
404
417
|
|
|
405
418
|
---
|
|
406
419
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
**Context · Impact · Migration · Architecture · Review — everything from one structural model.**
|
|
6
6
|
|
|
7
|
-

|
|
8
8
|

|
|
9
9
|
|
|
10
10
|
> **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
|
|
17
17
|
## The problem
|
|
18
18
|
|
|
19
|
-
Every time an AI coding agent starts a new session, it has to re-parse the repository from scratch.
|
|
19
|
+
Every time an AI coding agent starts a new session, it has to re-parse the repository from scratch. On small and mid-sized repos that cost is seconds; on large Java/Spring monoliths, repo-wide semantic composition can be minutes. Multiply that by dozens of agent turns per hour, and repo context acquisition becomes a real bottleneck — not just latency, but tokens, compute, and iteration velocity.
|
|
20
20
|
|
|
21
|
-
ASK Engine solves this with a persistent structural cache keyed on file content hashes. After the first scan,
|
|
21
|
+
ASK Engine solves this with a persistent structural cache keyed on file content hashes. After the first scan, later invocations reuse pre-built context whenever their command can consume the warmed layers. The repo doesn't change? The cache doesn't expire.
|
|
22
22
|
|
|
23
23
|
**The cache is not a performance optimization. It is what makes ASK Engine usable as infrastructure rather than a one-off tool.**
|
|
24
24
|
|
|
@@ -31,9 +31,11 @@ ASK Engine solves this with a persistent structural cache keyed on file content
|
|
|
31
31
|
| Keycloak | 7,885 Java files | 10.5s | 0.6s | **~17x** |
|
|
32
32
|
| BroadleafCommerce | 2,985 Java files | 2.7s | 0.3s | **~9x** |
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
These numbers are cache-layer benchmarks, not a promise for every command. Per-symbol queries and compact context benefit most. Inventory commands scale with file count. Repo-wide/deep compositions such as `risk`, `audit-report` and large `spring-audit` runs can take minutes on multi-thousand-endpoint repositories and belong in a supervised or nightly job unless CI sets an explicit budget.
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
With the right command class, ASK Engine becomes **constant infrastructure** inside agent loops — call the fast/context surfaces before edits and reserve deep compositions for the points where their evidence is worth the runtime.
|
|
37
|
+
|
|
38
|
+
**Large-repo controls.** Set `ASK_PROGRESS=1` to get line heartbeats in non-TTY supervised runs. Set `ASK_MAX_ANALYSIS_SECONDS=<seconds>` to fail before starting a repo-wide/deep command whose configured budget is below its safe floor. Use `ask audit-report --from-risk risk.json` to package an existing risk run instead of recomputing it.
|
|
37
39
|
|
|
38
40
|
**What a warm actually covers.** `ask cache warm` runs the compact analysis: it rebuilds the
|
|
39
41
|
shared structural layers (L1/L2 + the Repository Intelligence Snapshot + the shared Canonical
|
|
@@ -59,7 +61,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
|
|
|
59
61
|
# pip / pipx
|
|
60
62
|
pipx install sourcecode # or: pip install sourcecode
|
|
61
63
|
|
|
62
|
-
ask version # ask 4.
|
|
64
|
+
ask version # ask 4.10.0 — and, on a build that has aged,
|
|
63
65
|
# how many releases have probably shipped since
|
|
64
66
|
```
|
|
65
67
|
|
|
@@ -99,8 +101,9 @@ ask endpoints /path/to/repo
|
|
|
99
101
|
# CGLIB no-op), security surface, request-body validation.
|
|
100
102
|
ask spring-audit /path/to/repo
|
|
101
103
|
|
|
102
|
-
# Spring Boot 2→3 readiness
|
|
104
|
+
# Spring Boot 2→3 readiness plus Java LTS/licensing inventory.
|
|
103
105
|
ask migrate-check /path/to/repo --compact
|
|
106
|
+
# Add --target-jdk 25 to make the LTS route explicit.
|
|
104
107
|
```
|
|
105
108
|
|
|
106
109
|
**Then the three that finish the sentence the four above start.** A profile-set answer stays
|
|
@@ -270,12 +273,12 @@ from it.
|
|
|
270
273
|
| `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
|
|
271
274
|
| `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
275
|
| `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 |
|
|
276
|
+
| `audit-report` | experimental | human audit bundle over existing `risk` + `posture` evidence, optionally signed | includes `evidence_manifest` claim provenance; `--format markdown`; `--sign-key <file>` signs canonical JSON with HMAC-SHA256 |
|
|
274
277
|
| `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 |
|
|
275
278
|
| `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 |
|
|
276
279
|
| `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 |
|
|
277
280
|
| `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 |
|
|
281
|
+
| `migrate-check` | core | Boot 2→3 readiness + Java LTS/licensing inventory: located blockers, per-dimension score, effort, detected Java 8/11/17/21/25 evidence and explicit licensing-review signals | `--target-jdk 25` sets the target LTS route; `--blast-radius` orders the re-test plan; `--table --rule MIG-001 --band critical --top-n 20` for blocker triage |
|
|
279
282
|
| `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
|
|
280
283
|
| `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
|
|
281
284
|
| `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
|
|
@@ -363,6 +366,16 @@ and that gap is the honest description, not a defect to argue with. `migrate-che
|
|
|
363
366
|
the OpenRewrite recipe each finding carries so the executor that does apply changes has its
|
|
364
367
|
input.
|
|
365
368
|
|
|
369
|
+
**Java LTS/licensing inventory.** `migrate-check` emits `java_lts_inventory` beside the migration
|
|
370
|
+
scores. It reads Maven/Gradle, local runtime hints and container files for Java 8/11/17/21/25
|
|
371
|
+
evidence, reports target-LTS blockers with `--target-jdk`, and marks explicit Oracle JDK evidence
|
|
372
|
+
as `licensing_review_needed`. This is inventory evidence, not legal advice.
|
|
373
|
+
|
|
374
|
+
**Claim provenance ledger.** JSON outputs from `risk`, `enrich`, `migrate-check`,
|
|
375
|
+
`audit-report` and `prepare-context` include `evidence_manifest`: stable claim IDs mapped to
|
|
376
|
+
source paths/lines, command inputs, ASK version, git HEAD and freshness metadata. The manifest
|
|
377
|
+
indexes claims already in the payload; it does not add analysis or certify compliance.
|
|
378
|
+
|
|
366
379
|
|
|
367
380
|
---
|
|
368
381
|
|
|
@@ -39,13 +39,19 @@ def build_audit_report(
|
|
|
39
39
|
profiles: Optional[set[str]] = None,
|
|
40
40
|
sign_key: Optional[bytes] = None,
|
|
41
41
|
risk_limit: int = 10,
|
|
42
|
+
risk_payload: Optional[dict[str, Any]] = None,
|
|
42
43
|
) -> dict[str, Any]:
|
|
43
44
|
"""Build the buyer-readable audit bundle from existing command payloads."""
|
|
44
45
|
from sourcecode.posture import build_posture
|
|
45
|
-
from sourcecode.risk import build_risk
|
|
46
46
|
|
|
47
47
|
root = Path(root).resolve()
|
|
48
|
-
|
|
48
|
+
if risk_payload is None:
|
|
49
|
+
from sourcecode.risk import build_risk
|
|
50
|
+
risk = build_risk(root, limit=risk_limit, min_band="low", profiles=profiles)
|
|
51
|
+
risk_source = "computed"
|
|
52
|
+
else:
|
|
53
|
+
risk = risk_payload
|
|
54
|
+
risk_source = "from-risk"
|
|
49
55
|
posture = build_posture(root, profiles or set())
|
|
50
56
|
top_risks = risk.get("risks", [])[:risk_limit]
|
|
51
57
|
access = ((posture.get("endpoints") or {}).get("effective_access") or {})
|
|
@@ -58,6 +64,7 @@ def build_audit_report(
|
|
|
58
64
|
**({"profile_set": sorted(profiles)} if profiles else {}),
|
|
59
65
|
"summary": {
|
|
60
66
|
"risk_model": risk.get("model"),
|
|
67
|
+
"risk_source": risk_source,
|
|
61
68
|
"total_defects": risk.get("total_defects"),
|
|
62
69
|
"total_findings": risk.get("total_findings"),
|
|
63
70
|
"risk_bands": risk.get("by_band", {}),
|
|
@@ -78,6 +85,18 @@ def build_audit_report(
|
|
|
78
85
|
"non_coverage": (risk.get("non_coverage") or {}).get("items", []),
|
|
79
86
|
},
|
|
80
87
|
}
|
|
88
|
+
from sourcecode.provenance import build_evidence_manifest
|
|
89
|
+
unsigned["evidence_manifest"] = build_evidence_manifest(
|
|
90
|
+
unsigned,
|
|
91
|
+
command="audit-report",
|
|
92
|
+
root=root,
|
|
93
|
+
inputs={
|
|
94
|
+
"profiles": sorted(profiles) if profiles else None,
|
|
95
|
+
"risk_limit": risk_limit,
|
|
96
|
+
"risk_source": risk_source,
|
|
97
|
+
"signed": bool(sign_key),
|
|
98
|
+
},
|
|
99
|
+
)
|
|
81
100
|
# Sign and publish the same JSON-normalized material. Some embedded evidence
|
|
82
101
|
# may contain tuples or other JSON-coercible values; normalizing before signing
|
|
83
102
|
# avoids a signature over an in-memory shape the user never receives.
|
|
@@ -144,6 +144,12 @@ COMMANDS: tuple[CommandCache, ...] = (
|
|
|
144
144
|
"repository side, so what it buys is what it buys `risk`.",
|
|
145
145
|
"not measured on the battery yet — bounded by the `risk` composition, plus "
|
|
146
146
|
"reading one JSON file"),
|
|
147
|
+
CommandCache("audit-report", ("cir", "parse"), "shared", False,
|
|
148
|
+
"Packages `risk` and `posture` evidence. A warm helps the repository side; "
|
|
149
|
+
"`--from-risk risk.json` skips risk recomputation entirely and only builds "
|
|
150
|
+
"the posture/report projection.",
|
|
151
|
+
"not measured on the battery yet — bounded by `risk` + `posture`, or by "
|
|
152
|
+
"`posture` when `--from-risk` is supplied"),
|
|
147
153
|
CommandCache("migrate-recipe", ("parse",), "shared", False,
|
|
148
154
|
"Runs the same scan as `migrate-check` and projects its findings into an "
|
|
149
155
|
"OpenRewrite recipe, so it buys exactly what a warm buys `migrate-check`: "
|
|
@@ -43,6 +43,23 @@ _REVERSE_EXCLUDE: frozenset[str] = frozenset({"annotated_with", "mapped_to"})
|
|
|
43
43
|
# the CIR endpoint count reconciles with the `endpoints` command). See BUG #7.
|
|
44
44
|
_FQN_PATH_RE: re.Pattern = re.compile(r"/(org|com|net|io|edu)\.[a-z][a-z0-9]*\.[a-zA-Z]")
|
|
45
45
|
|
|
46
|
+
_JAVA_RESERVED_HANDLER_NAMES: frozenset[str] = frozenset({
|
|
47
|
+
"if", "else", "for", "while", "do", "switch", "case", "break", "continue",
|
|
48
|
+
"return", "new", "throw", "try", "catch", "finally", "instanceof",
|
|
49
|
+
"this", "super", "void", "class", "interface", "enum", "extends", "implements",
|
|
50
|
+
"import", "package", "static", "final", "abstract", "synchronized", "native",
|
|
51
|
+
"true", "false", "null",
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _route_has_reserved_handler(route: dict) -> bool:
|
|
56
|
+
"""Reject parser-corrupt endpoint symbols such as ``pkg.Controller#if``."""
|
|
57
|
+
symbol = str(route.get("symbol") or "")
|
|
58
|
+
if "#" not in symbol:
|
|
59
|
+
return False
|
|
60
|
+
handler = symbol.rsplit("#", 1)[1].split("(", 1)[0].strip()
|
|
61
|
+
return handler in _JAVA_RESERVED_HANDLER_NAMES
|
|
62
|
+
|
|
46
63
|
|
|
47
64
|
# ---------------------------------------------------------------------------
|
|
48
65
|
# CanonicalSecurity
|
|
@@ -438,6 +455,8 @@ def ir_dict_to_canonical(
|
|
|
438
455
|
for r in route_surface:
|
|
439
456
|
if r.get("scope") == "test_util":
|
|
440
457
|
continue
|
|
458
|
+
if _route_has_reserved_handler(r):
|
|
459
|
+
continue
|
|
441
460
|
if _FQN_PATH_RE.search(r.get("path", "") or ""):
|
|
442
461
|
continue
|
|
443
462
|
ep = _route_to_canonical_endpoint(r)
|
|
@@ -338,14 +338,16 @@ def _build_help_text() -> str:
|
|
|
338
338
|
Deterministic Java/Spring semantics and reusable structural context for AI coding agents.
|
|
339
339
|
|
|
340
340
|
Cache warms on first scan; later calls reuse pre-built context instead of rescanning.
|
|
341
|
-
|
|
342
|
-
|
|
341
|
+
Performance depends on command class and repo size: per-symbol queries are the fast path,
|
|
342
|
+
inventory commands scale with files, and repo-wide/deep compositions can take
|
|
343
|
+
minutes on multi-thousand-endpoint repositories. Use deep jobs nightly or with
|
|
344
|
+
ASK_MAX_ANALYSIS_SECONDS/ASK_PROGRESS when CI needs an explicit budget.
|
|
343
345
|
|
|
344
346
|
[bold]Start here — Java/Spring analysis:[/bold]
|
|
345
347
|
posture . --diff dev:prod [dim]# effective access, two profile sets (exp.)[/dim]
|
|
346
348
|
endpoints . [dim]# endpoints + effective path + policy[/dim]
|
|
347
349
|
spring-audit . [dim]# TX anomalies + security surface[/dim]
|
|
348
|
-
migrate-check . --compact [dim]# Boot 2→3
|
|
350
|
+
migrate-check . --compact [dim]# Boot 2→3 + Java LTS/licensing inventory[/dim]
|
|
349
351
|
risk . [dim]# defects ranked by reach × access (exp.)[/dim]
|
|
350
352
|
|
|
351
353
|
{_remedy_help_block()}
|
|
@@ -881,9 +883,24 @@ def _enforce_format(command: str, fmt: str) -> None:
|
|
|
881
883
|
|
|
882
884
|
|
|
883
885
|
def _safe_write_file(path: "Path", content: str) -> None:
|
|
884
|
-
"""
|
|
886
|
+
"""Atomically write content to path, emitting a clean JSON error on I/O failure."""
|
|
885
887
|
try:
|
|
886
|
-
path
|
|
888
|
+
path = Path(path)
|
|
889
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
890
|
+
tmp = path.with_name(f".{path.name}.tmp-{os.getpid()}-{time.time_ns()}")
|
|
891
|
+
tmp.write_text(content, encoding="utf-8")
|
|
892
|
+
tmp.replace(path)
|
|
893
|
+
try:
|
|
894
|
+
from sourcecode.runs import active_run
|
|
895
|
+
run = active_run()
|
|
896
|
+
if run is not None:
|
|
897
|
+
run.write(
|
|
898
|
+
status="running",
|
|
899
|
+
output_path=path,
|
|
900
|
+
output_size=path.stat().st_size,
|
|
901
|
+
)
|
|
902
|
+
except Exception:
|
|
903
|
+
pass
|
|
887
904
|
except OSError as _exc:
|
|
888
905
|
_emit_error_json(
|
|
889
906
|
INVALID_INPUT_CODE,
|
|
@@ -968,6 +985,50 @@ def _active_command_context() -> "tuple[str, Optional[Path]]":
|
|
|
968
985
|
|
|
969
986
|
|
|
970
987
|
_EXPENSIVE_ANALYSIS_TTL_SECONDS = 6 * 60 * 60
|
|
988
|
+
_ANALYSIS_CLASSES: dict[str, tuple[str, int, str]] = {
|
|
989
|
+
"spring-audit": ("repo-wide", 600, "use nightly/deep tier on large repositories"),
|
|
990
|
+
"risk": ("deep", 1200, "run `ask spring-audit` or a saved `risk.json` first"),
|
|
991
|
+
"audit-report": ("deep", 1200, "reuse `--from-risk risk.json` or schedule nightly"),
|
|
992
|
+
"verify --init": ("repo-wide", 600, "derive contracts outside pre-commit"),
|
|
993
|
+
"verify": ("core", 60, "run with a larger CI budget or narrow the contract set"),
|
|
994
|
+
"migrate-check": ("repo-wide", 600, "run inventory in CI and deep migration checks nightly"),
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
|
|
998
|
+
def _analysis_budget(command: str) -> dict[str, Any]:
|
|
999
|
+
cls, recommended, fallback = _ANALYSIS_CLASSES.get(
|
|
1000
|
+
command, ("repo-wide", 600, "run this command in a supervised or nightly job")
|
|
1001
|
+
)
|
|
1002
|
+
configured: Optional[float] = None
|
|
1003
|
+
raw = os.environ.get("ASK_MAX_ANALYSIS_SECONDS")
|
|
1004
|
+
if raw:
|
|
1005
|
+
try:
|
|
1006
|
+
configured = float(raw)
|
|
1007
|
+
except ValueError:
|
|
1008
|
+
configured = None
|
|
1009
|
+
return {
|
|
1010
|
+
"class": cls,
|
|
1011
|
+
"recommended_min_seconds": recommended,
|
|
1012
|
+
"configured_max_seconds": configured,
|
|
1013
|
+
"fallback": fallback,
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
|
|
1017
|
+
def _enforce_analysis_budget(command: str, budget: dict[str, Any]) -> None:
|
|
1018
|
+
configured = budget.get("configured_max_seconds")
|
|
1019
|
+
recommended = float(budget.get("recommended_min_seconds") or 0)
|
|
1020
|
+
if configured is None or float(configured) >= recommended:
|
|
1021
|
+
return
|
|
1022
|
+
_emit_error_json(
|
|
1023
|
+
INVALID_INPUT_CODE,
|
|
1024
|
+
(
|
|
1025
|
+
f"{command} is a {budget.get('class')} analysis and the configured "
|
|
1026
|
+
f"budget ({configured:g}s) is below its safe floor ({recommended:g}s)."
|
|
1027
|
+
),
|
|
1028
|
+
hint=str(budget.get("fallback") or "raise ASK_MAX_ANALYSIS_SECONDS"),
|
|
1029
|
+
expected=f"ASK_MAX_ANALYSIS_SECONDS >= {recommended:g}",
|
|
1030
|
+
)
|
|
1031
|
+
raise typer.Exit(code=2)
|
|
971
1032
|
|
|
972
1033
|
|
|
973
1034
|
def _analysis_lock_path(path: Path) -> Path:
|
|
@@ -1051,8 +1112,14 @@ def _emit_analysis_contention_warning(command: str, path: Path, phase: str) -> N
|
|
|
1051
1112
|
@contextlib.contextmanager
|
|
1052
1113
|
def _expensive_analysis_scope(command: str, path: Path, phase: str):
|
|
1053
1114
|
"""Register a long repository-wide analysis and warn on concurrent runs."""
|
|
1115
|
+
from sourcecode.runs import RunRecord, reset_active_run, set_active_run
|
|
1116
|
+
|
|
1054
1117
|
lock_path = _analysis_lock_path(path)
|
|
1055
1118
|
_emit_analysis_contention_warning(command, path, phase)
|
|
1119
|
+
budget = _analysis_budget(command)
|
|
1120
|
+
_enforce_analysis_budget(command, budget)
|
|
1121
|
+
run_record = RunRecord.start(path, command, phase, budget=budget)
|
|
1122
|
+
run_token = set_active_run(run_record)
|
|
1056
1123
|
token = f"{os.getpid()}:{time.time_ns()}"
|
|
1057
1124
|
owns_lock = False
|
|
1058
1125
|
if _active_analysis_record(lock_path) is None:
|
|
@@ -1077,6 +1144,12 @@ def _expensive_analysis_scope(command: str, path: Path, phase: str):
|
|
|
1077
1144
|
owns_lock = False
|
|
1078
1145
|
try:
|
|
1079
1146
|
yield
|
|
1147
|
+
if run_record is not None:
|
|
1148
|
+
run_record.write(status="complete", exit_code=0)
|
|
1149
|
+
except BaseException as exc:
|
|
1150
|
+
if run_record is not None:
|
|
1151
|
+
run_record.write(status="failed", exit_code=1, error=str(exc))
|
|
1152
|
+
raise
|
|
1080
1153
|
finally:
|
|
1081
1154
|
if owns_lock:
|
|
1082
1155
|
try:
|
|
@@ -1088,6 +1161,7 @@ def _expensive_analysis_scope(command: str, path: Path, phase: str):
|
|
|
1088
1161
|
lock_path.unlink()
|
|
1089
1162
|
except OSError:
|
|
1090
1163
|
pass
|
|
1164
|
+
reset_active_run(run_token)
|
|
1091
1165
|
|
|
1092
1166
|
|
|
1093
1167
|
def _emit_command_output(
|
|
@@ -3875,6 +3949,11 @@ def prepare_context_cmd(
|
|
|
3875
3949
|
ask prepare-context review-pr . --since main --output review.json
|
|
3876
3950
|
ask prepare-context onboard --llm-prompt
|
|
3877
3951
|
ask prepare-context --task-help
|
|
3952
|
+
|
|
3953
|
+
\b
|
|
3954
|
+
Provenance:
|
|
3955
|
+
JSON output includes evidence_manifest: claim IDs for context files and
|
|
3956
|
+
source-backed rows, plus command inputs, ASK version, git HEAD and freshness.
|
|
3878
3957
|
"""
|
|
3879
3958
|
from sourcecode.prepare_context import TASKS, TaskContextBuilder
|
|
3880
3959
|
|
|
@@ -4419,6 +4498,20 @@ def prepare_context_cmd(
|
|
|
4419
4498
|
_skipped.append("test_gap_discovery")
|
|
4420
4499
|
out["skipped_analyzers"] = _skipped
|
|
4421
4500
|
|
|
4501
|
+
from sourcecode.provenance import build_evidence_manifest as _build_evidence_manifest
|
|
4502
|
+
out["evidence_manifest"] = _build_evidence_manifest(
|
|
4503
|
+
out,
|
|
4504
|
+
command="prepare-context",
|
|
4505
|
+
root=target,
|
|
4506
|
+
inputs={
|
|
4507
|
+
"task": task,
|
|
4508
|
+
"since": since,
|
|
4509
|
+
"format": format or "json",
|
|
4510
|
+
"fast": fast,
|
|
4511
|
+
"llm_prompt": llm_prompt,
|
|
4512
|
+
},
|
|
4513
|
+
)
|
|
4514
|
+
|
|
4422
4515
|
# P0-1: Apply output budget per task — safety net for large repos.
|
|
4423
4516
|
_pc_budget = _prepare_context_budget(task)
|
|
4424
4517
|
|
|
@@ -8007,6 +8100,11 @@ def audit_report_cmd(
|
|
|
8007
8100
|
format: str = typer.Option(
|
|
8008
8101
|
"json", "--format", "-f", help="Output format: json, yaml or markdown."
|
|
8009
8102
|
),
|
|
8103
|
+
from_risk: Optional[Path] = typer.Option(
|
|
8104
|
+
None,
|
|
8105
|
+
"--from-risk",
|
|
8106
|
+
help="Reuse an existing `ask risk -o risk.json` payload instead of recomputing risk.",
|
|
8107
|
+
),
|
|
8010
8108
|
copy: bool = _copy_option(),
|
|
8011
8109
|
) -> None:
|
|
8012
8110
|
"""[EXPERIMENTAL] Human audit bundle over existing ASK evidence, optionally signed.
|
|
@@ -8015,7 +8113,8 @@ def audit_report_cmd(
|
|
|
8015
8113
|
This packages the same evidence `risk` and `posture` already publish into a
|
|
8016
8114
|
report a buyer can read: top risks, effective runtime posture, source-linked
|
|
8017
8115
|
evidence and non-coverage. It does not certify compliance, choose fixes or
|
|
8018
|
-
assign ROI.
|
|
8116
|
+
assign ROI. JSON includes evidence_manifest: claim IDs mapped to source spans,
|
|
8117
|
+
command inputs, ASK version and freshness.
|
|
8019
8118
|
|
|
8020
8119
|
\b
|
|
8021
8120
|
`--sign-key` adds an HMAC-SHA256 signature over the canonical JSON payload.
|
|
@@ -8024,6 +8123,7 @@ def audit_report_cmd(
|
|
|
8024
8123
|
\b
|
|
8025
8124
|
Examples:
|
|
8026
8125
|
ask audit-report .
|
|
8126
|
+
ask risk . -o risk.json && ask audit-report . --from-risk risk.json
|
|
8027
8127
|
ask audit-report . --profile prod --format markdown
|
|
8028
8128
|
ask audit-report . --sign-key audit.key -o audit-report.json
|
|
8029
8129
|
"""
|
|
@@ -8059,12 +8159,42 @@ def audit_report_cmd(
|
|
|
8059
8159
|
expected="a non-empty key file",
|
|
8060
8160
|
)
|
|
8061
8161
|
raise typer.Exit(code=1)
|
|
8162
|
+
risk_payload = None
|
|
8163
|
+
if from_risk is not None:
|
|
8164
|
+
risk_path = Path(from_risk).expanduser()
|
|
8165
|
+
if not risk_path.is_file():
|
|
8166
|
+
_emit_error_json(
|
|
8167
|
+
INVALID_INPUT_CODE,
|
|
8168
|
+
f"--from-risk must name a readable risk JSON file (got {str(from_risk)!r}).",
|
|
8169
|
+
hint="Example: ask risk . -o risk.json && ask audit-report . --from-risk risk.json",
|
|
8170
|
+
expected="an existing JSON file produced by `ask risk`",
|
|
8171
|
+
)
|
|
8172
|
+
raise typer.Exit(code=1)
|
|
8173
|
+
try:
|
|
8174
|
+
risk_payload = json.loads(risk_path.read_text(encoding="utf-8"))
|
|
8175
|
+
except Exception as exc:
|
|
8176
|
+
_emit_error_json(
|
|
8177
|
+
INVALID_INPUT_CODE,
|
|
8178
|
+
f"--from-risk is not valid JSON: {exc}",
|
|
8179
|
+
hint="Regenerate it with: ask risk . -o risk.json",
|
|
8180
|
+
expected="a JSON object produced by `ask risk`",
|
|
8181
|
+
)
|
|
8182
|
+
raise typer.Exit(code=1)
|
|
8183
|
+
if not isinstance(risk_payload, dict) or "risks" not in risk_payload:
|
|
8184
|
+
_emit_error_json(
|
|
8185
|
+
INVALID_INPUT_CODE,
|
|
8186
|
+
"--from-risk does not look like an `ask risk` payload.",
|
|
8187
|
+
hint="Regenerate it with: ask risk . -o risk.json",
|
|
8188
|
+
expected="a JSON object with a `risks` array",
|
|
8189
|
+
)
|
|
8190
|
+
raise typer.Exit(code=1)
|
|
8062
8191
|
|
|
8063
8192
|
_prog = Progress()
|
|
8064
8193
|
_prog.start("packaging audit evidence")
|
|
8065
8194
|
try:
|
|
8066
8195
|
data = build_audit_report(
|
|
8067
8196
|
path, profiles=_profile_set(profile), sign_key=key_bytes,
|
|
8197
|
+
risk_payload=risk_payload,
|
|
8068
8198
|
)
|
|
8069
8199
|
finally:
|
|
8070
8200
|
_prog.stop()
|
|
@@ -8724,9 +8854,9 @@ def migrate_check_cmd(
|
|
|
8724
8854
|
None,
|
|
8725
8855
|
"--target-jdk",
|
|
8726
8856
|
help=(
|
|
8727
|
-
"The JDK you are actually moving to (e.g. 11, 17, 21). Rules
|
|
8728
|
-
"later JDK are not your blockers and are not reported.
|
|
8729
|
-
"
|
|
8857
|
+
"The JDK you are actually moving to (e.g. 11, 17, 21, 25). Rules "
|
|
8858
|
+
"for a later JDK are not your blockers and are not reported. Also "
|
|
8859
|
+
"sets java_lts_inventory.target_lts."
|
|
8730
8860
|
),
|
|
8731
8861
|
),
|
|
8732
8862
|
keep_boot: bool = typer.Option(
|
|
@@ -8786,7 +8916,7 @@ def migrate_check_cmd(
|
|
|
8786
8916
|
help="Caller BFS depth for --blast-radius (1-8, default: 4).",
|
|
8787
8917
|
),
|
|
8788
8918
|
) -> None:
|
|
8789
|
-
"""Spring Boot 2→3 migration readiness
|
|
8919
|
+
"""Spring Boot 2→3 migration readiness + Java LTS/licensing inventory.
|
|
8790
8920
|
|
|
8791
8921
|
\b
|
|
8792
8922
|
Detects:
|
|
@@ -8815,6 +8945,7 @@ def migrate_check_cmd(
|
|
|
8815
8945
|
ask migrate-check . --compact bounded decision summary
|
|
8816
8946
|
ask migrate-check /path/to/repo --format text
|
|
8817
8947
|
ask migrate-check . --min-severity high
|
|
8948
|
+
ask migrate-check . --target-jdk 25 Java LTS target inventory
|
|
8818
8949
|
ask migrate-check . --table --rule MIG-001 --band critical --top-n 20
|
|
8819
8950
|
ask migrate-check . --output migration.json
|
|
8820
8951
|
ask migrate-check . --snapshot --ref sprint-12 persist a readiness point
|
|
@@ -8837,6 +8968,13 @@ def migrate_check_cmd(
|
|
|
8837
8968
|
<repo>/.ask/readiness-history). --trend reads that series and reports
|
|
8838
8969
|
first→last movement — no improving/degrading label, and readiness_score is
|
|
8839
8970
|
flagged not-comparable when the applicable dimension set changed.
|
|
8971
|
+
|
|
8972
|
+
\b
|
|
8973
|
+
Java LTS/licensing inventory:
|
|
8974
|
+
The JSON report includes java_lts_inventory: Java 8/11/17/21/25 evidence
|
|
8975
|
+
from Maven/Gradle, local runtime hints and container files; target-LTS
|
|
8976
|
+
blockers; and explicit Oracle JDK/licensing-review signals. This is
|
|
8977
|
+
inventory evidence, not legal advice, and it never changes readiness_score.
|
|
8840
8978
|
"""
|
|
8841
8979
|
from sourcecode.repository_ir import find_java_files
|
|
8842
8980
|
from sourcecode.migrate_check import run_migrate_check
|