sourcecode 4.9.0__tar.gz → 4.9.1__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.9.1}/CHANGELOG.md +12 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/PKG-INFO +17 -6
- {sourcecode-4.9.0 → sourcecode-4.9.1}/README.md +16 -5
- {sourcecode-4.9.0 → sourcecode-4.9.1}/pyproject.toml +1 -1
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/__init__.py +1 -1
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/audit_report.py +11 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/cli.py +34 -6
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/migrate_check.py +307 -1
- sourcecode-4.9.1/src/sourcecode/provenance.py +202 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/risk.py +11 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/sarif.py +12 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/.gitignore +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/.ruff.toml +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/CLAUDE.md +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/CONTRIBUTING.md +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/LICENSE +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/SECURITY.md +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/raw +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/scripts/perf_harness.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/archetype.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/baseline_autocapture.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/cache.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/cache_model.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/caller_reach.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/chain_rules.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/classifier.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/client_calls.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/compare.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/context_cache.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/contract_init.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/data_exposure.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/data_labels.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/defect_identity.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/degradation.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/deployment_prefix.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/envelope.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/environment_resolution.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/explain.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/facts/__init__.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/facts/registry.json +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/filter_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/git_checkout.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/identity_fallback.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/integration_coordinates.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/license.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/non_coverage.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/openrewrite_recipe.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/parse_cache.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/path_admission.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/perf.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/pipe_contract.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/posture.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/progress.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/redactor.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/reference_facts.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/release_info.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/remedies.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/repository_ir.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/result.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/steps.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/steps_graph.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/steps_impact.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/steps_intf.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/steps_struct.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/retrieval/steps_txsec.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/ris.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/rule_catalog.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/scanner.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/schema.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/security_config.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/security_config_scan.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/security_posture.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/semantic_integration_engine.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/serializer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/servlet_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/source_text.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/spring_profiles.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/spring_properties.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/target_admission.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/test_gap_ranking.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/test_sources.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/token_estimate.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/validation_inference.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/verify_repo.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/version_check.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/src/sourcecode/workspace.py +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/supabase/functions/README.md +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-4.9.0 → sourcecode-4.9.1}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [4.9.1] — 2026-08-04
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Java LTS/licensing inventory in `migrate-check`.** Reports Java 8/11/17/21/25
|
|
10
|
+
evidence from Maven/Gradle, local runtime hints and container files, target-LTS
|
|
11
|
+
blockers via `--target-jdk`, and explicit Oracle JDK licensing-review signals
|
|
12
|
+
without changing migration readiness scoring.
|
|
13
|
+
- **Claim provenance ledger.** `risk`, `enrich`, `migrate-check`, `audit-report`
|
|
14
|
+
and `prepare-context` now emit `evidence_manifest` with stable claim IDs,
|
|
15
|
+
source paths/lines, command inputs, ASK version, git HEAD and freshness metadata.
|
|
16
|
+
|
|
5
17
|
## [4.9.0] — 2026-08-04
|
|
6
18
|
|
|
7
19
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 4.9.
|
|
3
|
+
Version: 4.9.1
|
|
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`**
|
|
@@ -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.9.
|
|
100
|
+
ask version # ask 4.9.1 — and, on a build that has aged,
|
|
101
101
|
# how many releases have probably shipped since
|
|
102
102
|
```
|
|
103
103
|
|
|
@@ -137,8 +137,9 @@ ask endpoints /path/to/repo
|
|
|
137
137
|
# CGLIB no-op), security surface, request-body validation.
|
|
138
138
|
ask spring-audit /path/to/repo
|
|
139
139
|
|
|
140
|
-
# Spring Boot 2→3 readiness
|
|
140
|
+
# Spring Boot 2→3 readiness plus Java LTS/licensing inventory.
|
|
141
141
|
ask migrate-check /path/to/repo --compact
|
|
142
|
+
# Add --target-jdk 25 to make the LTS route explicit.
|
|
142
143
|
```
|
|
143
144
|
|
|
144
145
|
**Then the three that finish the sentence the four above start.** A profile-set answer stays
|
|
@@ -308,12 +309,12 @@ from it.
|
|
|
308
309
|
| `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
|
|
309
310
|
| `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
311
|
| `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 |
|
|
312
|
+
| `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
313
|
| `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
314
|
| `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
315
|
| `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
316
|
| `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 |
|
|
317
|
+
| `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
318
|
| `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
|
|
318
319
|
| `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
|
|
319
320
|
| `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
|
|
@@ -401,6 +402,16 @@ and that gap is the honest description, not a defect to argue with. `migrate-che
|
|
|
401
402
|
the OpenRewrite recipe each finding carries so the executor that does apply changes has its
|
|
402
403
|
input.
|
|
403
404
|
|
|
405
|
+
**Java LTS/licensing inventory.** `migrate-check` emits `java_lts_inventory` beside the migration
|
|
406
|
+
scores. It reads Maven/Gradle, local runtime hints and container files for Java 8/11/17/21/25
|
|
407
|
+
evidence, reports target-LTS blockers with `--target-jdk`, and marks explicit Oracle JDK evidence
|
|
408
|
+
as `licensing_review_needed`. This is inventory evidence, not legal advice.
|
|
409
|
+
|
|
410
|
+
**Claim provenance ledger.** JSON outputs from `risk`, `enrich`, `migrate-check`,
|
|
411
|
+
`audit-report` and `prepare-context` include `evidence_manifest`: stable claim IDs mapped to
|
|
412
|
+
source paths/lines, command inputs, ASK version, git HEAD and freshness metadata. The manifest
|
|
413
|
+
indexes claims already in the payload; it does not add analysis or certify compliance.
|
|
414
|
+
|
|
404
415
|
|
|
405
416
|
---
|
|
406
417
|
|
|
@@ -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`**
|
|
@@ -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.9.
|
|
62
|
+
ask version # ask 4.9.1 — and, on a build that has aged,
|
|
63
63
|
# how many releases have probably shipped since
|
|
64
64
|
```
|
|
65
65
|
|
|
@@ -99,8 +99,9 @@ ask endpoints /path/to/repo
|
|
|
99
99
|
# CGLIB no-op), security surface, request-body validation.
|
|
100
100
|
ask spring-audit /path/to/repo
|
|
101
101
|
|
|
102
|
-
# Spring Boot 2→3 readiness
|
|
102
|
+
# Spring Boot 2→3 readiness plus Java LTS/licensing inventory.
|
|
103
103
|
ask migrate-check /path/to/repo --compact
|
|
104
|
+
# Add --target-jdk 25 to make the LTS route explicit.
|
|
104
105
|
```
|
|
105
106
|
|
|
106
107
|
**Then the three that finish the sentence the four above start.** A profile-set answer stays
|
|
@@ -270,12 +271,12 @@ from it.
|
|
|
270
271
|
| `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
|
|
271
272
|
| `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
273
|
| `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 |
|
|
274
|
+
| `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
275
|
| `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
276
|
| `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
277
|
| `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
278
|
| `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 |
|
|
279
|
+
| `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
280
|
| `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
|
|
280
281
|
| `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
|
|
281
282
|
| `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
|
|
@@ -363,6 +364,16 @@ and that gap is the honest description, not a defect to argue with. `migrate-che
|
|
|
363
364
|
the OpenRewrite recipe each finding carries so the executor that does apply changes has its
|
|
364
365
|
input.
|
|
365
366
|
|
|
367
|
+
**Java LTS/licensing inventory.** `migrate-check` emits `java_lts_inventory` beside the migration
|
|
368
|
+
scores. It reads Maven/Gradle, local runtime hints and container files for Java 8/11/17/21/25
|
|
369
|
+
evidence, reports target-LTS blockers with `--target-jdk`, and marks explicit Oracle JDK evidence
|
|
370
|
+
as `licensing_review_needed`. This is inventory evidence, not legal advice.
|
|
371
|
+
|
|
372
|
+
**Claim provenance ledger.** JSON outputs from `risk`, `enrich`, `migrate-check`,
|
|
373
|
+
`audit-report` and `prepare-context` include `evidence_manifest`: stable claim IDs mapped to
|
|
374
|
+
source paths/lines, command inputs, ASK version, git HEAD and freshness metadata. The manifest
|
|
375
|
+
indexes claims already in the payload; it does not add analysis or certify compliance.
|
|
376
|
+
|
|
366
377
|
|
|
367
378
|
---
|
|
368
379
|
|
|
@@ -78,6 +78,17 @@ def build_audit_report(
|
|
|
78
78
|
"non_coverage": (risk.get("non_coverage") or {}).get("items", []),
|
|
79
79
|
},
|
|
80
80
|
}
|
|
81
|
+
from sourcecode.provenance import build_evidence_manifest
|
|
82
|
+
unsigned["evidence_manifest"] = build_evidence_manifest(
|
|
83
|
+
unsigned,
|
|
84
|
+
command="audit-report",
|
|
85
|
+
root=root,
|
|
86
|
+
inputs={
|
|
87
|
+
"profiles": sorted(profiles) if profiles else None,
|
|
88
|
+
"risk_limit": risk_limit,
|
|
89
|
+
"signed": bool(sign_key),
|
|
90
|
+
},
|
|
91
|
+
)
|
|
81
92
|
# Sign and publish the same JSON-normalized material. Some embedded evidence
|
|
82
93
|
# may contain tuples or other JSON-coercible values; normalizing before signing
|
|
83
94
|
# avoids a signature over an in-memory shape the user never receives.
|
|
@@ -345,7 +345,7 @@ of files) in minutes. Semantic analysis itself is sub-second; repo indexing domi
|
|
|
345
345
|
posture . --diff dev:prod [dim]# effective access, two profile sets (exp.)[/dim]
|
|
346
346
|
endpoints . [dim]# endpoints + effective path + policy[/dim]
|
|
347
347
|
spring-audit . [dim]# TX anomalies + security surface[/dim]
|
|
348
|
-
migrate-check . --compact [dim]# Boot 2→3
|
|
348
|
+
migrate-check . --compact [dim]# Boot 2→3 + Java LTS/licensing inventory[/dim]
|
|
349
349
|
risk . [dim]# defects ranked by reach × access (exp.)[/dim]
|
|
350
350
|
|
|
351
351
|
{_remedy_help_block()}
|
|
@@ -3875,6 +3875,11 @@ def prepare_context_cmd(
|
|
|
3875
3875
|
ask prepare-context review-pr . --since main --output review.json
|
|
3876
3876
|
ask prepare-context onboard --llm-prompt
|
|
3877
3877
|
ask prepare-context --task-help
|
|
3878
|
+
|
|
3879
|
+
\b
|
|
3880
|
+
Provenance:
|
|
3881
|
+
JSON output includes evidence_manifest: claim IDs for context files and
|
|
3882
|
+
source-backed rows, plus command inputs, ASK version, git HEAD and freshness.
|
|
3878
3883
|
"""
|
|
3879
3884
|
from sourcecode.prepare_context import TASKS, TaskContextBuilder
|
|
3880
3885
|
|
|
@@ -4419,6 +4424,20 @@ def prepare_context_cmd(
|
|
|
4419
4424
|
_skipped.append("test_gap_discovery")
|
|
4420
4425
|
out["skipped_analyzers"] = _skipped
|
|
4421
4426
|
|
|
4427
|
+
from sourcecode.provenance import build_evidence_manifest as _build_evidence_manifest
|
|
4428
|
+
out["evidence_manifest"] = _build_evidence_manifest(
|
|
4429
|
+
out,
|
|
4430
|
+
command="prepare-context",
|
|
4431
|
+
root=target,
|
|
4432
|
+
inputs={
|
|
4433
|
+
"task": task,
|
|
4434
|
+
"since": since,
|
|
4435
|
+
"format": format or "json",
|
|
4436
|
+
"fast": fast,
|
|
4437
|
+
"llm_prompt": llm_prompt,
|
|
4438
|
+
},
|
|
4439
|
+
)
|
|
4440
|
+
|
|
4422
4441
|
# P0-1: Apply output budget per task — safety net for large repos.
|
|
4423
4442
|
_pc_budget = _prepare_context_budget(task)
|
|
4424
4443
|
|
|
@@ -8015,7 +8034,8 @@ def audit_report_cmd(
|
|
|
8015
8034
|
This packages the same evidence `risk` and `posture` already publish into a
|
|
8016
8035
|
report a buyer can read: top risks, effective runtime posture, source-linked
|
|
8017
8036
|
evidence and non-coverage. It does not certify compliance, choose fixes or
|
|
8018
|
-
assign ROI.
|
|
8037
|
+
assign ROI. JSON includes evidence_manifest: claim IDs mapped to source spans,
|
|
8038
|
+
command inputs, ASK version and freshness.
|
|
8019
8039
|
|
|
8020
8040
|
\b
|
|
8021
8041
|
`--sign-key` adds an HMAC-SHA256 signature over the canonical JSON payload.
|
|
@@ -8724,9 +8744,9 @@ def migrate_check_cmd(
|
|
|
8724
8744
|
None,
|
|
8725
8745
|
"--target-jdk",
|
|
8726
8746
|
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
|
-
"
|
|
8747
|
+
"The JDK you are actually moving to (e.g. 11, 17, 21, 25). Rules "
|
|
8748
|
+
"for a later JDK are not your blockers and are not reported. Also "
|
|
8749
|
+
"sets java_lts_inventory.target_lts."
|
|
8730
8750
|
),
|
|
8731
8751
|
),
|
|
8732
8752
|
keep_boot: bool = typer.Option(
|
|
@@ -8786,7 +8806,7 @@ def migrate_check_cmd(
|
|
|
8786
8806
|
help="Caller BFS depth for --blast-radius (1-8, default: 4).",
|
|
8787
8807
|
),
|
|
8788
8808
|
) -> None:
|
|
8789
|
-
"""Spring Boot 2→3 migration readiness
|
|
8809
|
+
"""Spring Boot 2→3 migration readiness + Java LTS/licensing inventory.
|
|
8790
8810
|
|
|
8791
8811
|
\b
|
|
8792
8812
|
Detects:
|
|
@@ -8815,6 +8835,7 @@ def migrate_check_cmd(
|
|
|
8815
8835
|
ask migrate-check . --compact bounded decision summary
|
|
8816
8836
|
ask migrate-check /path/to/repo --format text
|
|
8817
8837
|
ask migrate-check . --min-severity high
|
|
8838
|
+
ask migrate-check . --target-jdk 25 Java LTS target inventory
|
|
8818
8839
|
ask migrate-check . --table --rule MIG-001 --band critical --top-n 20
|
|
8819
8840
|
ask migrate-check . --output migration.json
|
|
8820
8841
|
ask migrate-check . --snapshot --ref sprint-12 persist a readiness point
|
|
@@ -8837,6 +8858,13 @@ def migrate_check_cmd(
|
|
|
8837
8858
|
<repo>/.ask/readiness-history). --trend reads that series and reports
|
|
8838
8859
|
first→last movement — no improving/degrading label, and readiness_score is
|
|
8839
8860
|
flagged not-comparable when the applicable dimension set changed.
|
|
8861
|
+
|
|
8862
|
+
\b
|
|
8863
|
+
Java LTS/licensing inventory:
|
|
8864
|
+
The JSON report includes java_lts_inventory: Java 8/11/17/21/25 evidence
|
|
8865
|
+
from Maven/Gradle, local runtime hints and container files; target-LTS
|
|
8866
|
+
blockers; and explicit Oracle JDK/licensing-review signals. This is
|
|
8867
|
+
inventory evidence, not legal advice, and it never changes readiness_score.
|
|
8840
8868
|
"""
|
|
8841
8869
|
from sourcecode.repository_ir import find_java_files
|
|
8842
8870
|
from sourcecode.migrate_check import run_migrate_check
|
|
@@ -860,6 +860,282 @@ def _parse_major(version: "Optional[str]") -> "Optional[int]":
|
|
|
860
860
|
return None
|
|
861
861
|
m = re.match(r"\s*(\d+)", version)
|
|
862
862
|
return int(m.group(1)) if m else None
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
_MAVEN_JAVA_VERSION_RE: re.Pattern = re.compile(
|
|
866
|
+
r"<(java\.version|maven\.compiler\.(?:source|target|release))>\s*([^<${}]+)\s*</\1>",
|
|
867
|
+
re.IGNORECASE,
|
|
868
|
+
)
|
|
869
|
+
_MAVEN_COMPILER_TAG_RE: re.Pattern = re.compile(
|
|
870
|
+
r"<(?:source|target|release)>\s*([^<${}]+)\s*</(?:source|target|release)>",
|
|
871
|
+
re.IGNORECASE,
|
|
872
|
+
)
|
|
873
|
+
_GRADLE_JAVA_ENUM_RE: re.Pattern = re.compile(
|
|
874
|
+
r"JavaVersion\.VERSION_(?:1_)?(\d+)", re.IGNORECASE
|
|
875
|
+
)
|
|
876
|
+
_GRADLE_JAVA_ASSIGN_RE: re.Pattern = re.compile(
|
|
877
|
+
r"(?:sourceCompatibility|targetCompatibility|javaVersion|languageVersion)\s*=?\s*['\"]?(\d+(?:\.\d+)?)",
|
|
878
|
+
re.IGNORECASE,
|
|
879
|
+
)
|
|
880
|
+
_GRADLE_TOOLCHAIN_RE: re.Pattern = re.compile(
|
|
881
|
+
r"JavaLanguageVersion\.of\s*\(\s*(\d+)\s*\)", re.IGNORECASE
|
|
882
|
+
)
|
|
883
|
+
_JAVA_VERSION_LINE_RE: re.Pattern = re.compile(
|
|
884
|
+
r"(?:JAVA_VERSION|JDK_VERSION|java\.version)\s*[=:]\s*['\"]?(\d+(?:\.\d+)?)",
|
|
885
|
+
re.IGNORECASE,
|
|
886
|
+
)
|
|
887
|
+
_DOCKER_FROM_RE: re.Pattern = re.compile(
|
|
888
|
+
r"^\s*FROM\s+(?:--platform=\S+\s+)?(\S+)", re.IGNORECASE | re.MULTILINE
|
|
889
|
+
)
|
|
890
|
+
_DOCKER_JAVA_TAG_RE: re.Pattern = re.compile(
|
|
891
|
+
r"(?:^|[:\-_])(?:jdk|jre|java)?(?:-)?(1\.8|8|11|17|21|25)(?:[.\-_a-z0-9]*|$)",
|
|
892
|
+
re.IGNORECASE,
|
|
893
|
+
)
|
|
894
|
+
_JAVA_LTS_RELEASES: frozenset[int] = frozenset({8, 11, 17, 21, 25})
|
|
895
|
+
_JAVA_LTS_SUPPORT_FILE_NAMES: frozenset[str] = frozenset({
|
|
896
|
+
"gradle.properties", ".java-version", ".sdkmanrc", "Dockerfile",
|
|
897
|
+
"dockerfile", "compose.yaml", "compose.yml", "docker-compose.yaml",
|
|
898
|
+
"docker-compose.yml", "jvm.config",
|
|
899
|
+
})
|
|
900
|
+
|
|
901
|
+
|
|
902
|
+
def _normalize_java_major(value: str) -> Optional[int]:
|
|
903
|
+
"""Normalize Java version spellings (`1.8`, `VERSION_17`, `21.0.2`) to major."""
|
|
904
|
+
value = value.strip().strip("'\"")
|
|
905
|
+
if value.startswith("1."):
|
|
906
|
+
parts = value.split(".")
|
|
907
|
+
if len(parts) > 1 and parts[1].isdigit():
|
|
908
|
+
return int(parts[1])
|
|
909
|
+
m = re.match(r"(\d+)", value)
|
|
910
|
+
if not m:
|
|
911
|
+
return None
|
|
912
|
+
return int(m.group(1))
|
|
913
|
+
|
|
914
|
+
|
|
915
|
+
def _java_lts_name(major: Optional[int]) -> str:
|
|
916
|
+
if major is None:
|
|
917
|
+
return "unknown"
|
|
918
|
+
return f"Java {major}" + (" LTS" if major in _JAVA_LTS_RELEASES else "")
|
|
919
|
+
|
|
920
|
+
|
|
921
|
+
def _java_distribution_from_text(text: str) -> Optional[str]:
|
|
922
|
+
low = text.lower()
|
|
923
|
+
for marker, name in (
|
|
924
|
+
("eclipse-temurin", "Eclipse Temurin"),
|
|
925
|
+
("adoptium", "Eclipse Temurin"),
|
|
926
|
+
("amazoncorretto", "Amazon Corretto"),
|
|
927
|
+
("corretto", "Amazon Corretto"),
|
|
928
|
+
("liberica", "BellSoft Liberica"),
|
|
929
|
+
("azul", "Azul Zulu"),
|
|
930
|
+
("zulu", "Azul Zulu"),
|
|
931
|
+
("graalvm", "GraalVM"),
|
|
932
|
+
("oracle", "Oracle JDK"),
|
|
933
|
+
("openjdk", "OpenJDK"),
|
|
934
|
+
):
|
|
935
|
+
if marker in low:
|
|
936
|
+
return name
|
|
937
|
+
return None
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
def _java_evidence(
|
|
941
|
+
*,
|
|
942
|
+
source: str,
|
|
943
|
+
path: str,
|
|
944
|
+
value: str,
|
|
945
|
+
version: Optional[int],
|
|
946
|
+
distribution: Optional[str] = None,
|
|
947
|
+
) -> dict:
|
|
948
|
+
out = {
|
|
949
|
+
"source": source,
|
|
950
|
+
"path": path,
|
|
951
|
+
"value": value,
|
|
952
|
+
"version": version,
|
|
953
|
+
"version_label": _java_lts_name(version),
|
|
954
|
+
}
|
|
955
|
+
if distribution:
|
|
956
|
+
out["distribution"] = distribution
|
|
957
|
+
return out
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
def _find_java_lts_support_files(root: Path) -> list[tuple[Path, str]]:
|
|
961
|
+
"""Files that may declare build/runtime Java without executing the project."""
|
|
962
|
+
found: list[tuple[Path, str]] = []
|
|
963
|
+
for dirpath, dirnames, filenames in os.walk(root):
|
|
964
|
+
dirnames[:] = [d for d in dirnames if d not in _SKIP_DIRS or d == ".mvn"]
|
|
965
|
+
dp = Path(dirpath)
|
|
966
|
+
try:
|
|
967
|
+
rel_dir = dp.relative_to(root)
|
|
968
|
+
except ValueError:
|
|
969
|
+
continue
|
|
970
|
+
for fname in filenames:
|
|
971
|
+
if fname not in _JAVA_LTS_SUPPORT_FILE_NAMES:
|
|
972
|
+
continue
|
|
973
|
+
abs_path = dp / fname
|
|
974
|
+
rel = str(rel_dir / fname) if str(rel_dir) != "." else fname
|
|
975
|
+
found.append((abs_path, rel))
|
|
976
|
+
return found
|
|
977
|
+
|
|
978
|
+
|
|
979
|
+
def _java_lts_inventory(
|
|
980
|
+
root: Path,
|
|
981
|
+
build_texts: "Iterable[tuple[str, str]]",
|
|
982
|
+
*,
|
|
983
|
+
spring_boot_version: Optional[str],
|
|
984
|
+
target_jdk: Optional[int],
|
|
985
|
+
) -> dict:
|
|
986
|
+
"""Java LTS/licensing inventory for migration planning.
|
|
987
|
+
|
|
988
|
+
Bounded evidence only: build descriptors and local deployment hints. No build
|
|
989
|
+
execution, no legal verdict, and no inference from absent runtime metadata.
|
|
990
|
+
"""
|
|
991
|
+
target_lts = target_jdk or 25
|
|
992
|
+
evidence: list[dict] = []
|
|
993
|
+
limitations: list[str] = []
|
|
994
|
+
|
|
995
|
+
for rel_path, raw_text in build_texts:
|
|
996
|
+
text = _resolve_maven_properties(raw_text) if rel_path.endswith("pom.xml") else raw_text
|
|
997
|
+
if rel_path.endswith("pom.xml"):
|
|
998
|
+
for m in _MAVEN_JAVA_VERSION_RE.finditer(text):
|
|
999
|
+
major = _normalize_java_major(m.group(2))
|
|
1000
|
+
evidence.append(_java_evidence(
|
|
1001
|
+
source=f"maven_property:{m.group(1)}",
|
|
1002
|
+
path=rel_path,
|
|
1003
|
+
value=m.group(2).strip(),
|
|
1004
|
+
version=major,
|
|
1005
|
+
))
|
|
1006
|
+
for m in _MAVEN_COMPILER_TAG_RE.finditer(text):
|
|
1007
|
+
major = _normalize_java_major(m.group(1))
|
|
1008
|
+
evidence.append(_java_evidence(
|
|
1009
|
+
source="maven_compiler_plugin",
|
|
1010
|
+
path=rel_path,
|
|
1011
|
+
value=m.group(1).strip(),
|
|
1012
|
+
version=major,
|
|
1013
|
+
))
|
|
1014
|
+
elif rel_path.endswith((".gradle", ".gradle.kts", "gradle.properties")):
|
|
1015
|
+
for pat, source in (
|
|
1016
|
+
(_GRADLE_JAVA_ENUM_RE, "gradle_java_version_enum"),
|
|
1017
|
+
(_GRADLE_JAVA_ASSIGN_RE, "gradle_java_assignment"),
|
|
1018
|
+
(_GRADLE_TOOLCHAIN_RE, "gradle_toolchain"),
|
|
1019
|
+
(_JAVA_VERSION_LINE_RE, "gradle_property"),
|
|
1020
|
+
):
|
|
1021
|
+
for m in pat.finditer(text):
|
|
1022
|
+
major = _normalize_java_major(m.group(1))
|
|
1023
|
+
evidence.append(_java_evidence(
|
|
1024
|
+
source=source,
|
|
1025
|
+
path=rel_path,
|
|
1026
|
+
value=m.group(1).strip(),
|
|
1027
|
+
version=major,
|
|
1028
|
+
))
|
|
1029
|
+
|
|
1030
|
+
for abs_path, rel_path in _find_java_lts_support_files(root):
|
|
1031
|
+
if rel_path.endswith(("pom.xml", "build.gradle", "build.gradle.kts")):
|
|
1032
|
+
continue
|
|
1033
|
+
try:
|
|
1034
|
+
text = abs_path.read_text(encoding="utf-8", errors="replace")
|
|
1035
|
+
except OSError:
|
|
1036
|
+
limitations.append(f"{rel_path}: could not be read")
|
|
1037
|
+
continue
|
|
1038
|
+
if rel_path.endswith((".java-version", ".sdkmanrc", "jvm.config", "gradle.properties")):
|
|
1039
|
+
for m in _JAVA_VERSION_LINE_RE.finditer(text):
|
|
1040
|
+
major = _normalize_java_major(m.group(1))
|
|
1041
|
+
evidence.append(_java_evidence(
|
|
1042
|
+
source="java_version_file",
|
|
1043
|
+
path=rel_path,
|
|
1044
|
+
value=m.group(1).strip(),
|
|
1045
|
+
version=major,
|
|
1046
|
+
))
|
|
1047
|
+
if rel_path.endswith(".java-version"):
|
|
1048
|
+
major = _normalize_java_major(text.strip())
|
|
1049
|
+
evidence.append(_java_evidence(
|
|
1050
|
+
source="java_version_file",
|
|
1051
|
+
path=rel_path,
|
|
1052
|
+
value=text.strip(),
|
|
1053
|
+
version=major,
|
|
1054
|
+
))
|
|
1055
|
+
if "docker" in rel_path.lower() or rel_path.lower().endswith(("compose.yml", "compose.yaml")):
|
|
1056
|
+
for m in _DOCKER_FROM_RE.finditer(text):
|
|
1057
|
+
image = m.group(1).strip()
|
|
1058
|
+
tag_major: Optional[int] = None
|
|
1059
|
+
tag_match = _DOCKER_JAVA_TAG_RE.search(image)
|
|
1060
|
+
if tag_match:
|
|
1061
|
+
tag_major = _normalize_java_major(tag_match.group(1))
|
|
1062
|
+
evidence.append(_java_evidence(
|
|
1063
|
+
source="container_base_image",
|
|
1064
|
+
path=rel_path,
|
|
1065
|
+
value=image,
|
|
1066
|
+
version=tag_major,
|
|
1067
|
+
distribution=_java_distribution_from_text(image),
|
|
1068
|
+
))
|
|
1069
|
+
for m in _JAVA_VERSION_LINE_RE.finditer(text):
|
|
1070
|
+
major = _normalize_java_major(m.group(1))
|
|
1071
|
+
evidence.append(_java_evidence(
|
|
1072
|
+
source="container_java_env",
|
|
1073
|
+
path=rel_path,
|
|
1074
|
+
value=m.group(1).strip(),
|
|
1075
|
+
version=major,
|
|
1076
|
+
distribution=_java_distribution_from_text(text),
|
|
1077
|
+
))
|
|
1078
|
+
|
|
1079
|
+
versions = sorted({e["version"] for e in evidence if isinstance(e.get("version"), int)})
|
|
1080
|
+
distributions = sorted({e["distribution"] for e in evidence if e.get("distribution")})
|
|
1081
|
+
target_blockers: list[dict] = []
|
|
1082
|
+
for version in versions:
|
|
1083
|
+
if version < target_lts:
|
|
1084
|
+
target_blockers.append({
|
|
1085
|
+
"kind": "version_below_target_lts",
|
|
1086
|
+
"version": version,
|
|
1087
|
+
"target_lts": target_lts,
|
|
1088
|
+
"reason": f"{_java_lts_name(version)} evidence is below target {_java_lts_name(target_lts)}",
|
|
1089
|
+
})
|
|
1090
|
+
if not versions:
|
|
1091
|
+
target_blockers.append({
|
|
1092
|
+
"kind": "java_version_unknown",
|
|
1093
|
+
"version": None,
|
|
1094
|
+
"target_lts": target_lts,
|
|
1095
|
+
"reason": "No Java source/target/runtime version evidence found in build or deployment hints.",
|
|
1096
|
+
})
|
|
1097
|
+
|
|
1098
|
+
licensing_reasons: list[str] = []
|
|
1099
|
+
oracle_evidence = [
|
|
1100
|
+
e for e in evidence
|
|
1101
|
+
if str(e.get("distribution", "")).lower() == "oracle jdk"
|
|
1102
|
+
or ("oracle" in str(e.get("value", "")).lower() and "jdk" in str(e.get("value", "")).lower())
|
|
1103
|
+
]
|
|
1104
|
+
for e in oracle_evidence:
|
|
1105
|
+
licensing_reasons.append(
|
|
1106
|
+
f"{e['path']} declares {e.get('distribution', 'Oracle JDK')} "
|
|
1107
|
+
f"{e.get('version_label', 'unknown version')} ({e['source']}); review support/licensing terms."
|
|
1108
|
+
)
|
|
1109
|
+
|
|
1110
|
+
return {
|
|
1111
|
+
"schema_version": "java-lts-inventory-v1",
|
|
1112
|
+
"target_lts": target_lts,
|
|
1113
|
+
"target_lts_basis": (
|
|
1114
|
+
"--target-jdk supplied by caller" if target_jdk else
|
|
1115
|
+
"default planning target for the 2026 Java LTS/licensing inventory"
|
|
1116
|
+
),
|
|
1117
|
+
"versions": {
|
|
1118
|
+
"detected": versions,
|
|
1119
|
+
"lowest": versions[0] if versions else None,
|
|
1120
|
+
"highest": versions[-1] if versions else None,
|
|
1121
|
+
"labels": [_java_lts_name(v) for v in versions],
|
|
1122
|
+
},
|
|
1123
|
+
"distributions": distributions,
|
|
1124
|
+
"evidence": evidence,
|
|
1125
|
+
"spring_boot_version_detected": spring_boot_version,
|
|
1126
|
+
"target_lts_blockers": target_blockers,
|
|
1127
|
+
"licensing_review_needed": bool(licensing_reasons),
|
|
1128
|
+
"licensing_review_reasons": licensing_reasons,
|
|
1129
|
+
"legal_disclaimer": (
|
|
1130
|
+
"Inventory signal only, not legal advice. ASK marks explicit Oracle JDK "
|
|
1131
|
+
"or unknown-version evidence for review; license entitlement must be "
|
|
1132
|
+
"confirmed from contracts and deployed binaries."
|
|
1133
|
+
),
|
|
1134
|
+
"limitations": limitations + [
|
|
1135
|
+
"No build was executed; Maven/Gradle toolchains and transitive runtime images may be incomplete.",
|
|
1136
|
+
"Distribution detection is based on local build/container text only.",
|
|
1137
|
+
],
|
|
1138
|
+
}
|
|
863
1139
|
# Cap on total readiness deduction from JDK-modernization findings (medium/low),
|
|
864
1140
|
# so reflection/date cleanups cannot collapse a jakarta-ready repo's headline.
|
|
865
1141
|
_JDK_ADVISORY_DEDUCTION_CAP: int = 15
|
|
@@ -1527,6 +1803,10 @@ class MigrationReport:
|
|
|
1527
1803
|
# Opt-in — attached by the CLI under --blast-radius; None when not computed,
|
|
1528
1804
|
# and then absent from the payload so the default report stays byte-identical.
|
|
1529
1805
|
blast_radius: Optional[dict] = None
|
|
1806
|
+
# F-P: Java LTS/licensing inventory, derived from build/runtime hints. Additive
|
|
1807
|
+
# field: it informs migration planning but does not participate in readiness_score.
|
|
1808
|
+
java_lts_inventory: dict = field(default_factory=dict)
|
|
1809
|
+
evidence_manifest: dict = field(default_factory=dict)
|
|
1530
1810
|
|
|
1531
1811
|
def finalize(self) -> "MigrationReport":
|
|
1532
1812
|
if not self.generated_at:
|
|
@@ -2052,6 +2332,8 @@ class MigrationReport:
|
|
|
2052
2332
|
"spring_test_only": self.spring_test_only,
|
|
2053
2333
|
"spring_boot_2_detected": self.spring_boot_2_detected,
|
|
2054
2334
|
"spring_boot_version_detected": self.spring_boot_version_detected,
|
|
2335
|
+
"java_lts_inventory": self.java_lts_inventory,
|
|
2336
|
+
**({"evidence_manifest": self.evidence_manifest} if self.evidence_manifest else {}),
|
|
2055
2337
|
"summary": self.summary,
|
|
2056
2338
|
"findings": [f.to_dict() for f in _listed],
|
|
2057
2339
|
"hibernate": self.hibernate.to_dict() if self.hibernate is not None else None,
|
|
@@ -2155,6 +2437,9 @@ class MigrationReport:
|
|
|
2155
2437
|
f"(readiness_score reflects jakarta/Boot3 only — Hibernate is a separate rewrite axis)"]
|
|
2156
2438
|
if self.headline_blocker else []),
|
|
2157
2439
|
f"Spring present: {self.spring_present} Spring Boot 2 detected: {_boot}",
|
|
2440
|
+
f"Java LTS inventory: target {self.java_lts_inventory.get('target_lts', 'unknown')} "
|
|
2441
|
+
f"detected {self.java_lts_inventory.get('versions', {}).get('labels', [])} "
|
|
2442
|
+
f"licensing_review_needed={self.java_lts_inventory.get('licensing_review_needed', False)}",
|
|
2158
2443
|
f"Migration blockers (readiness dimensions): {self.migration_blocking_count}",
|
|
2159
2444
|
f"Blocking issues (product code): {self.blocking_count} "
|
|
2160
2445
|
f"(critical: {main_crit}, high: {main_high})"
|
|
@@ -2534,6 +2819,7 @@ def run_migrate_check(
|
|
|
2534
2819
|
dep_read_errors = 0
|
|
2535
2820
|
raw_dep_findings: list[MigrationFinding] = []
|
|
2536
2821
|
_build_texts: list[str] = []
|
|
2822
|
+
_build_sources: list[tuple[str, str]] = []
|
|
2537
2823
|
for abs_path, rel_path in build_files:
|
|
2538
2824
|
try:
|
|
2539
2825
|
text = abs_path.read_text(encoding="utf-8", errors="replace")
|
|
@@ -2541,6 +2827,7 @@ def run_migrate_check(
|
|
|
2541
2827
|
dep_read_errors += 1
|
|
2542
2828
|
continue
|
|
2543
2829
|
_build_texts.append(text)
|
|
2830
|
+
_build_sources.append((rel_path, text))
|
|
2544
2831
|
dep_findings = _scan_dep_file(text, rel_path)
|
|
2545
2832
|
filtered = [f for f in dep_findings if SEVERITY_ORDER.get(f.severity, 3) <= min_order]
|
|
2546
2833
|
raw_dep_findings.extend(filtered)
|
|
@@ -2595,6 +2882,12 @@ def run_migrate_check(
|
|
|
2595
2882
|
root, spring_runtime_import_seen, spring_test_import_seen
|
|
2596
2883
|
)
|
|
2597
2884
|
spring_boot_present = _detect_spring_boot_present(root)
|
|
2885
|
+
java_lts_inventory = _java_lts_inventory(
|
|
2886
|
+
root,
|
|
2887
|
+
_build_sources,
|
|
2888
|
+
spring_boot_version=spring_boot_version,
|
|
2889
|
+
target_jdk=target_jdk,
|
|
2890
|
+
)
|
|
2598
2891
|
|
|
2599
2892
|
# BUG #8: classify each finding's code context (main / test / generated) so the
|
|
2600
2893
|
# report can keep test fixtures and autogenerated sources out of blocking_count.
|
|
@@ -2645,6 +2938,7 @@ def run_migrate_check(
|
|
|
2645
2938
|
jakarta_namespace_adopted=jakarta_import_count > 0,
|
|
2646
2939
|
findings=all_findings,
|
|
2647
2940
|
hibernate=hibernate_strat,
|
|
2941
|
+
java_lts_inventory=java_lts_inventory,
|
|
2648
2942
|
limitations=limitations,
|
|
2649
2943
|
metadata={
|
|
2650
2944
|
"java_files_scanned": len(file_paths),
|
|
@@ -2703,7 +2997,19 @@ def run_migrate_check(
|
|
|
2703
2997
|
except Exception:
|
|
2704
2998
|
pass
|
|
2705
2999
|
|
|
2706
|
-
|
|
3000
|
+
report = report.finalize()
|
|
3001
|
+
from sourcecode.provenance import build_evidence_manifest
|
|
3002
|
+
report.evidence_manifest = build_evidence_manifest(
|
|
3003
|
+
report.to_dict(),
|
|
3004
|
+
command="migrate-check",
|
|
3005
|
+
root=root,
|
|
3006
|
+
inputs={
|
|
3007
|
+
"min_severity": min_severity,
|
|
3008
|
+
"target_jdk": target_jdk,
|
|
3009
|
+
"keep_boot": keep_boot,
|
|
3010
|
+
},
|
|
3011
|
+
)
|
|
3012
|
+
return report
|
|
2707
3013
|
|
|
2708
3014
|
|
|
2709
3015
|
# Remaining static limitations — things that truly require runtime analysis
|