sourcecode 4.0.0__tar.gz → 4.1.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.0.0 → sourcecode-4.1.0}/CHANGELOG.md +105 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/PKG-INFO +64 -6
- {sourcecode-4.0.0 → sourcecode-4.1.0}/README.md +63 -5
- {sourcecode-4.0.0 → sourcecode-4.1.0}/pyproject.toml +1 -1
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/cli.py +63 -14
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/envelope.py +10 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/non_coverage.py +8 -5
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/posture.py +90 -0
- sourcecode-4.1.0/src/sourcecode/release_info.py +123 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/remedies.py +17 -0
- sourcecode-4.1.0/src/sourcecode/rule_catalog.py +108 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/schemas/envelope-v1.schema.json +8 -1
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/security_config_scan.py +132 -1
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/spring_security_audit.py +19 -2
- {sourcecode-4.0.0 → sourcecode-4.1.0}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/.gitignore +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/.ruff.toml +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/CONTRIBUTING.md +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/LICENSE +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/SECURITY.md +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/raw +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/scripts/perf_harness.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/archetype.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/cache.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/cache_model.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/caller_reach.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/chain_rules.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/classifier.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/compare.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/context_cache.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/contract_init.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/defect_identity.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/degradation.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/deployment_prefix.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/environment_resolution.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/explain.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/facts/__init__.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/facts/registry.json +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/filter_surface.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/git_checkout.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/identity_fallback.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/integration_coordinates.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/license.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/migrate_check.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/parse_cache.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/path_admission.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/perf.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/pipe_contract.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/progress.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/reference_facts.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/repository_ir.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/result.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/steps.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/steps_graph.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/steps_impact.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/steps_intf.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/steps_struct.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/retrieval/steps_txsec.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/ris.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/risk.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/schema.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/security_config.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/security_posture.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/semantic_integration_engine.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/serializer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/spring_profiles.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/spring_properties.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/target_admission.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/test_gap_ranking.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/test_sources.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/token_estimate.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/validation_inference.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/verify_repo.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/version_check.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/supabase/functions/README.md +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-4.0.0 → sourcecode-4.1.0}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -2,6 +2,111 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [4.1.0] — 2026-08-03
|
|
6
|
+
|
|
7
|
+
Minor, not a patch, and the criterion is this project's own: a new rule can trip
|
|
8
|
+
a gate that was green yesterday. `spring-audit --ci` and `verify --fail-on any`
|
|
9
|
+
will fail on a repository that stores a credential in a deployment descriptor —
|
|
10
|
+
correctly, and for the first time. Nothing is removed, no default moves, and no
|
|
11
|
+
exit code changes meaning.
|
|
12
|
+
|
|
13
|
+
Field audit #8 (deep read-only audit of the eval #6/#7 repository, by a new
|
|
14
|
+
evaluator, 100 % catalogue coverage) ran a build self-reporting **3.5.0** while
|
|
15
|
+
4.0.1 was shipping, and re-derived twelve of its fourteen product complaints from
|
|
16
|
+
rows already closed — one of them the answer to its own critical finding. The
|
|
17
|
+
first entry below is that defect; the rest are the three findings that survived
|
|
18
|
+
verification against 4.0.1.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **SEC-007 — a credential stored in a deployment descriptor** (CL-10). The audit
|
|
23
|
+
found `monitor:{SHA-256}dc20b820…` in
|
|
24
|
+
`src/main/options/{DPA,M3,M3DEV}/WEB-INF/web.xml`: unsalted, the same hash in all
|
|
25
|
+
three per-environment overlays, and found by hand because *"los overlays
|
|
26
|
+
`src/main/options/**` son punto ciego"*. The gap was admission surface, not
|
|
27
|
+
detection — those descriptors are files `environment_resolution`,
|
|
28
|
+
`filter_surface` and `path_filters` already open, and SEC-004 already names a
|
|
29
|
+
fast unsalted digest. The rule fires on the **shape of the value**
|
|
30
|
+
(`{ALGO}<hex>`), never on the parameter's name (VAI), with `${placeholder}` as
|
|
31
|
+
the negative control; the digest is truncated in the finding, because a report
|
|
32
|
+
about a credential must not be a place to read one from; and identical digests
|
|
33
|
+
across descriptors are composed into the statement the audit actually made —
|
|
34
|
+
three environments share one credential, so the least protected decides the
|
|
35
|
+
strength of all three. NC-002 is **narrowed, not deleted**: Helm values, CI
|
|
36
|
+
variable files and shell scripts stay declared out of scope. Zero findings across
|
|
37
|
+
six field repositories.
|
|
38
|
+
- **`ask version` says how old the build is** (C4-12). Age in days alone would not
|
|
39
|
+
have caught the audit's case — that build was three days old. On this project's
|
|
40
|
+
cadence three days is six releases (eight, in fact). So the block publishes the
|
|
41
|
+
release date, the measured release rate (2.07/day over the last 30 releases), an
|
|
42
|
+
**estimate** of releases since with its basis, and an advisory naming the upgrade
|
|
43
|
+
command and the defect ledger. It never claims a newer release exists: offline,
|
|
44
|
+
that would be the confident-wrong answer the ledger exists to prevent. `_meta`
|
|
45
|
+
carries `tool_release_date` only — the date is a constant of the build, the age
|
|
46
|
+
changes daily, and the envelope is byte-identical by contract.
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- **`posture` now says when the container would not contradict its own resolution**
|
|
51
|
+
(CL-11). `allow-bean-definition-overriding: true` and
|
|
52
|
+
`allow-circular-references: true`, in the repository whose entire security verdict
|
|
53
|
+
turns on which `SecurityConfig` bean wins: with overriding enabled a second
|
|
54
|
+
definition replaces the first silently, so the startup failure that would have
|
|
55
|
+
caught a filter-chain override never happens. The block only ever **lowers**
|
|
56
|
+
confidence, so it sits beside the verdict and is repeated inside
|
|
57
|
+
`security.resolution_is_a_default` — the C1-20 lesson runs the other way here, and
|
|
58
|
+
a caveat a reader has to go and find does not reach the conclusion it was written
|
|
59
|
+
for. An undecidable setting is not read as off.
|
|
60
|
+
- **The platform claim matches what the battery can check** (C3-38). Third field
|
|
61
|
+
report of console mojibake on Windows/PowerShell; C3-3 and C3-12 are both recorded
|
|
62
|
+
*does not reproduce*, both scoped macOS-only. Patching a codec that was never
|
|
63
|
+
reproduced is what C3-27's rule forbids, so the README states instead that
|
|
64
|
+
Windows is a target the battery cannot verify, names what the CLI does do for it,
|
|
65
|
+
and cites the three rows. A documented limit is not a fix: C3-38 stays open until
|
|
66
|
+
a Windows runner exists.
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## [4.0.1] — 2026-08-02
|
|
70
|
+
|
|
71
|
+
Patch, and the criterion is the one this project has used since 3.2.0: nothing here
|
|
72
|
+
moves a published field, an exit code or a default. Three surfaces stopped
|
|
73
|
+
misdescribing an engine that did not change — the release advertised half its own
|
|
74
|
+
security ruleset, the front page led to neither capability the field asked for by
|
|
75
|
+
name, and the document both of them call the full command reference covered fewer
|
|
76
|
+
than half the commands. All three were found in-house.
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
|
|
80
|
+
- **`spring-audit --help` advertised three security rules and the build ships six**
|
|
81
|
+
(C4-9). The one-liner the root panel prints, and the command's own screen, said
|
|
82
|
+
`security surface (SEC-001..003)` two releases after CL-9 shipped SEC-004, SEC-005
|
|
83
|
+
and SEC-006; `docs/PRODUCT_TIERS.md` said `TX-001..005 + SEC-001..003` and
|
|
84
|
+
`docs/USER_GUIDE.md` said `TX-001..TX-005`. The engine was right in every case —
|
|
85
|
+
the product advertised half its ruleset, in the release that answered the field's
|
|
86
|
+
complaint about security recall. `sourcecode/rule_catalog.py` now holds one summary
|
|
87
|
+
line per rule and the help renders from it, while the id *set* is derived from the
|
|
88
|
+
shipped pattern registries by `tests/test_rule_catalog.py`: a seventh rule fails the
|
|
89
|
+
build until it is documented, and no surface may name a rule the build cannot emit.
|
|
90
|
+
The non-coverage block in the same help is rendered from `non_coverage` too, which
|
|
91
|
+
had a renderer with no consumer beside four rows restated by hand.
|
|
92
|
+
- **The front page did not lead to either remedy that C4-8 closed** (C4-10). The
|
|
93
|
+
pointer lived in the payload that states the limitation, which reaches an agent and
|
|
94
|
+
not a reader who has not run the command yet — the same reader who wrote
|
|
95
|
+
`ask posture --provenance` and `ask contracts init` by hand after a full session.
|
|
96
|
+
`ask --help` now renders a *Questions the repository alone does not answer* block
|
|
97
|
+
from `remedies.REMEDIES`, and lists `risk .` in Start here; the README carries
|
|
98
|
+
`--resolve-environments`, `verify --init` and `ask risk` in the Quickstart,
|
|
99
|
+
`--resolve-environments` in §5b beside the `--diff` it qualifies, and a §5c for
|
|
100
|
+
composed risk. `tests/test_remedies.py` fails when a remedy is absent from either
|
|
101
|
+
surface.
|
|
102
|
+
- **The "full command reference" documented 14 of 32 commands** (C4-11). `verify`,
|
|
103
|
+
`verify-edit` and `pr-impact` — the three gate commands — appeared only as names in
|
|
104
|
+
the tier table, and eight more had no occurrence in the file at all. Sections added
|
|
105
|
+
for the gate family (with the exit-code contract they share), for `plan`, `compare`,
|
|
106
|
+
`delta` and `contract-diff`, and a table for the rest.
|
|
107
|
+
`tests/test_user_guide_coverage.py` takes the command population from the CLI and
|
|
108
|
+
parses every invocation the guide prints against it.
|
|
109
|
+
|
|
5
110
|
## [4.0.0] — 2026-08-02
|
|
6
111
|
|
|
7
112
|
Major because two published `gate_coverage` fields are removed, not because the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.1.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
|
|
@@ -97,13 +97,25 @@ 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
|
|
100
|
+
ask version # ask 4.1.0 — and, on a build that has aged,
|
|
101
|
+
# how many releases have probably shipped since
|
|
101
102
|
```
|
|
102
103
|
|
|
103
104
|
> **Package vs. command.** The install package is named `sourcecode` this release
|
|
104
105
|
> (renaming the distribution is a separate, breaking change). Installing it gives you the
|
|
105
106
|
> canonical **`ask`** command plus the deprecated **`sourcecode`** alias.
|
|
106
107
|
|
|
108
|
+
> **Platforms.** Developed and tested on macOS and Linux; every release runs its full
|
|
109
|
+
> battery there. **Windows/PowerShell is a target we cannot verify:** the CLI is written
|
|
110
|
+
> for it — UTF-8 streams are forced at both console entry points, a successful run writes
|
|
111
|
+
> nothing to stderr (PowerShell 5.1 raises `NativeCommandError` on any stderr write), and
|
|
112
|
+
> the MCP server strips the BOM PowerShell puts on stdin — but no Windows runner exists in
|
|
113
|
+
> the battery. Three separate field reports of console mojibake (`—` rendering as `â€"`)
|
|
114
|
+
> have never reproduced under measurement, and the only variable those reports share is the
|
|
115
|
+
> platform we cannot exercise (C3-3, C3-12, C3-38 in the
|
|
116
|
+
> [defect ledger](docs/DEFECT-LEDGER.md)). On Windows, prefer `--output <file>` over shell
|
|
117
|
+
> redirection, and report a rendering problem rather than assuming it is known.
|
|
118
|
+
|
|
107
119
|
---
|
|
108
120
|
|
|
109
121
|
## Quickstart
|
|
@@ -129,6 +141,26 @@ ask spring-audit /path/to/repo
|
|
|
129
141
|
ask migrate-check /path/to/repo --compact
|
|
130
142
|
```
|
|
131
143
|
|
|
144
|
+
**Then the three that finish the sentence the four above start.** A profile-set answer stays
|
|
145
|
+
conditional until you know which set the deployment starts with, a gate nobody can populate is
|
|
146
|
+
a gate nobody runs, and a defect ranked without its reach is a linter note:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Which profile set ACTUALLY runs? Reads every artefact that can set it — build,
|
|
150
|
+
# descriptors, Dockerfile, Compose, Kubernetes, launch scripts — with file:line, and
|
|
151
|
+
# says NOT DECIDED IN THIS REPOSITORY when nothing in the tree decides it. Then ranks
|
|
152
|
+
# every admissible set by what it leaves reachable without authentication.
|
|
153
|
+
ask posture /path/to/repo --resolve-environments
|
|
154
|
+
|
|
155
|
+
# Derive the contracts this repository already satisfies, execute each one before
|
|
156
|
+
# writing it, and populate .ask/contracts.yml from the measurement instead of by hand.
|
|
157
|
+
ask verify /path/to/repo --init
|
|
158
|
+
|
|
159
|
+
# What each defect actually costs once reach, access and write effect are in it:
|
|
160
|
+
# severity × reachability × auth_verdict × write_effect, ordered, every factor traceable.
|
|
161
|
+
ask risk /path/to/repo
|
|
162
|
+
```
|
|
163
|
+
|
|
132
164
|
Then the everyday loop:
|
|
133
165
|
|
|
134
166
|
```bash
|
|
@@ -145,13 +177,17 @@ ask onboard /path/to/repo
|
|
|
145
177
|
ask review-pr /path/to/repo --since main
|
|
146
178
|
|
|
147
179
|
# CI gate on NEW violations only, instead of on pre-existing debt
|
|
180
|
+
ask verify /path/to/repo --init # derive the contracts, don't hand-write them
|
|
148
181
|
ask verify /path/to/repo --capture-baseline # accept today's debt, once
|
|
149
182
|
ask verify /path/to/repo # then: only new violations block
|
|
150
183
|
```
|
|
151
184
|
|
|
152
|
-
> **Adopting a gate on a real codebase.**
|
|
153
|
-
>
|
|
154
|
-
>
|
|
185
|
+
> **Adopting a gate on a real codebase.** Nobody hand-writes contracts for a 3 000-file
|
|
186
|
+
> monolith, so `ask verify --init` derives the ones the repository satisfies **today** and
|
|
187
|
+
> executes each before writing it — init followed by verify passes by construction.
|
|
188
|
+
> A repository that starts declaring contracts already violates them somewhere; `ask verify`
|
|
189
|
+
> is **baseline-relative by default** (`--fail-on new`) so the gate survives contact with
|
|
190
|
+
> reality instead of being switched off on day one.
|
|
155
191
|
> `ask baseline capture|diff|trend` is a different thing: versioned architectural metrics over
|
|
156
192
|
> time, for trend reporting rather than blocking.
|
|
157
193
|
|
|
@@ -194,10 +230,32 @@ What a profile set **actually wires**: which conditional beans register, which d
|
|
|
194
230
|
`ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
|
|
195
231
|
→ [posture.md](docs/posture.md)
|
|
196
232
|
|
|
233
|
+
**`--resolve-environments` carries it past the edge of the repository.** Every answer above
|
|
234
|
+
is conditional on a profile set, and which set runs is decided by the deployment. This flag
|
|
235
|
+
reads every artefact in the tree that can set `spring.profiles.active` — Maven/Gradle,
|
|
236
|
+
`web.xml`, `Dockerfile`, Compose, Kubernetes, launch scripts — with `file:line`, and returns
|
|
237
|
+
`decided_in_repository`, `artefacts_disagree` (two deployments, never resolved by picking
|
|
238
|
+
one) or **`NOT DECIDED IN THIS REPOSITORY`**. Then it resolves every admissible set over one
|
|
239
|
+
parse and publishes the worst. A field audit closed those five hops by hand with grep before
|
|
240
|
+
the flag existed.
|
|
241
|
+
`ask posture . --resolve-environments`
|
|
242
|
+
|
|
197
243
|
Unresolved is a first-class outcome: a condition the resolver cannot decide is reported as a
|
|
198
244
|
hole with the condition named, never folded into active or inactive. **A posture answer that
|
|
199
245
|
guesses is a confident security falsehood — the worst failure mode this tool has.**
|
|
200
246
|
|
|
247
|
+
### 5c · Composed Risk *(experimental)*
|
|
248
|
+
Every command above answers one axis, and a reader composes them by hand. `ask risk` does the
|
|
249
|
+
join over the endpoint and symbol ids these commands already share with each other:
|
|
250
|
+
`severity_effective = defect_severity × reachability × auth_verdict × write_effect`. The
|
|
251
|
+
product of the published factors **is** the published score — decomposable to the four
|
|
252
|
+
figures and the authority behind each — and an axis this build cannot measure is `unknown`,
|
|
253
|
+
weighted 1.0 and named in `blind_axes` rather than silently treated as safe. Measured on a
|
|
254
|
+
field case: a defect both `spring-audit` and `impact-chain` called *medium* composes to
|
|
255
|
+
**high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
|
|
256
|
+
`ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
|
|
257
|
+
→ [reference](docs/USER_GUIDE.md)
|
|
258
|
+
|
|
201
259
|
### 6 · Developer Workflows
|
|
202
260
|
The everyday loop: diff-based PR review, symptom-driven bug triage, and delta context for continuous agent runs.
|
|
203
261
|
`ask review-pr` · `ask fix-bug` · `ask prepare-context`
|
|
@@ -285,7 +343,7 @@ reading JSON sees the same boundary a buyer reads here.
|
|
|
285
343
|
| Not covered | Why | What answers it |
|
|
286
344
|
|---|---|---|
|
|
287
345
|
| **Whether request input reaches a sink — no dataflow or taint analysis.** | This engine resolves structure and wiring without compiling. Taint needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL). What this product adds on top is reachability: which of that tool's findings sit behind an endpoint that is reachable unauthenticated. |
|
|
288
|
-
| **Secrets outside Java
|
|
346
|
+
| **Secrets outside Java, Spring configuration and the deployment descriptors — a Helm value, a CI variable file, a shell script.** | The file population this analyzer reads is the Java source, the Spring configuration convention and the descriptors it already parses to resolve an environment. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. Narrowed by CL-10: a credential stored in `web.xml` or a Spring XML context IS reported (SEC-007), because those files were already being read. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
|
|
289
347
|
| **Filter-chain order and per-filter URL patterns — the presence of a custom filter is structural only.** | Which filter runs first is decided by bean ordering this analyzer does not resolve. Where two active configurations both match a request, the answer published is `undecided` rather than a guess. | `ask posture --profile <set>` states per endpoint what the readable rules decide and what they leave undecided. |
|
|
290
348
|
| **Known vulnerabilities in dependencies — no CVE database, no version advisory matching.** | Enriching a vulnerability feed is a different product with a different update cadence; a stale embedded database is worse than no database, because it reads as a clean bill of health. | A dependency scanner (Trivy, OWASP Dependency-Check). `impact-chain` then answers which of its findings anything actually reaches. |
|
|
291
349
|
|
|
@@ -59,13 +59,25 @@ 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
|
|
62
|
+
ask version # ask 4.1.0 — and, on a build that has aged,
|
|
63
|
+
# how many releases have probably shipped since
|
|
63
64
|
```
|
|
64
65
|
|
|
65
66
|
> **Package vs. command.** The install package is named `sourcecode` this release
|
|
66
67
|
> (renaming the distribution is a separate, breaking change). Installing it gives you the
|
|
67
68
|
> canonical **`ask`** command plus the deprecated **`sourcecode`** alias.
|
|
68
69
|
|
|
70
|
+
> **Platforms.** Developed and tested on macOS and Linux; every release runs its full
|
|
71
|
+
> battery there. **Windows/PowerShell is a target we cannot verify:** the CLI is written
|
|
72
|
+
> for it — UTF-8 streams are forced at both console entry points, a successful run writes
|
|
73
|
+
> nothing to stderr (PowerShell 5.1 raises `NativeCommandError` on any stderr write), and
|
|
74
|
+
> the MCP server strips the BOM PowerShell puts on stdin — but no Windows runner exists in
|
|
75
|
+
> the battery. Three separate field reports of console mojibake (`—` rendering as `â€"`)
|
|
76
|
+
> have never reproduced under measurement, and the only variable those reports share is the
|
|
77
|
+
> platform we cannot exercise (C3-3, C3-12, C3-38 in the
|
|
78
|
+
> [defect ledger](docs/DEFECT-LEDGER.md)). On Windows, prefer `--output <file>` over shell
|
|
79
|
+
> redirection, and report a rendering problem rather than assuming it is known.
|
|
80
|
+
|
|
69
81
|
---
|
|
70
82
|
|
|
71
83
|
## Quickstart
|
|
@@ -91,6 +103,26 @@ ask spring-audit /path/to/repo
|
|
|
91
103
|
ask migrate-check /path/to/repo --compact
|
|
92
104
|
```
|
|
93
105
|
|
|
106
|
+
**Then the three that finish the sentence the four above start.** A profile-set answer stays
|
|
107
|
+
conditional until you know which set the deployment starts with, a gate nobody can populate is
|
|
108
|
+
a gate nobody runs, and a defect ranked without its reach is a linter note:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Which profile set ACTUALLY runs? Reads every artefact that can set it — build,
|
|
112
|
+
# descriptors, Dockerfile, Compose, Kubernetes, launch scripts — with file:line, and
|
|
113
|
+
# says NOT DECIDED IN THIS REPOSITORY when nothing in the tree decides it. Then ranks
|
|
114
|
+
# every admissible set by what it leaves reachable without authentication.
|
|
115
|
+
ask posture /path/to/repo --resolve-environments
|
|
116
|
+
|
|
117
|
+
# Derive the contracts this repository already satisfies, execute each one before
|
|
118
|
+
# writing it, and populate .ask/contracts.yml from the measurement instead of by hand.
|
|
119
|
+
ask verify /path/to/repo --init
|
|
120
|
+
|
|
121
|
+
# What each defect actually costs once reach, access and write effect are in it:
|
|
122
|
+
# severity × reachability × auth_verdict × write_effect, ordered, every factor traceable.
|
|
123
|
+
ask risk /path/to/repo
|
|
124
|
+
```
|
|
125
|
+
|
|
94
126
|
Then the everyday loop:
|
|
95
127
|
|
|
96
128
|
```bash
|
|
@@ -107,13 +139,17 @@ ask onboard /path/to/repo
|
|
|
107
139
|
ask review-pr /path/to/repo --since main
|
|
108
140
|
|
|
109
141
|
# CI gate on NEW violations only, instead of on pre-existing debt
|
|
142
|
+
ask verify /path/to/repo --init # derive the contracts, don't hand-write them
|
|
110
143
|
ask verify /path/to/repo --capture-baseline # accept today's debt, once
|
|
111
144
|
ask verify /path/to/repo # then: only new violations block
|
|
112
145
|
```
|
|
113
146
|
|
|
114
|
-
> **Adopting a gate on a real codebase.**
|
|
115
|
-
>
|
|
116
|
-
>
|
|
147
|
+
> **Adopting a gate on a real codebase.** Nobody hand-writes contracts for a 3 000-file
|
|
148
|
+
> monolith, so `ask verify --init` derives the ones the repository satisfies **today** and
|
|
149
|
+
> executes each before writing it — init followed by verify passes by construction.
|
|
150
|
+
> A repository that starts declaring contracts already violates them somewhere; `ask verify`
|
|
151
|
+
> is **baseline-relative by default** (`--fail-on new`) so the gate survives contact with
|
|
152
|
+
> reality instead of being switched off on day one.
|
|
117
153
|
> `ask baseline capture|diff|trend` is a different thing: versioned architectural metrics over
|
|
118
154
|
> time, for trend reporting rather than blocking.
|
|
119
155
|
|
|
@@ -156,10 +192,32 @@ What a profile set **actually wires**: which conditional beans register, which d
|
|
|
156
192
|
`ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
|
|
157
193
|
→ [posture.md](docs/posture.md)
|
|
158
194
|
|
|
195
|
+
**`--resolve-environments` carries it past the edge of the repository.** Every answer above
|
|
196
|
+
is conditional on a profile set, and which set runs is decided by the deployment. This flag
|
|
197
|
+
reads every artefact in the tree that can set `spring.profiles.active` — Maven/Gradle,
|
|
198
|
+
`web.xml`, `Dockerfile`, Compose, Kubernetes, launch scripts — with `file:line`, and returns
|
|
199
|
+
`decided_in_repository`, `artefacts_disagree` (two deployments, never resolved by picking
|
|
200
|
+
one) or **`NOT DECIDED IN THIS REPOSITORY`**. Then it resolves every admissible set over one
|
|
201
|
+
parse and publishes the worst. A field audit closed those five hops by hand with grep before
|
|
202
|
+
the flag existed.
|
|
203
|
+
`ask posture . --resolve-environments`
|
|
204
|
+
|
|
159
205
|
Unresolved is a first-class outcome: a condition the resolver cannot decide is reported as a
|
|
160
206
|
hole with the condition named, never folded into active or inactive. **A posture answer that
|
|
161
207
|
guesses is a confident security falsehood — the worst failure mode this tool has.**
|
|
162
208
|
|
|
209
|
+
### 5c · Composed Risk *(experimental)*
|
|
210
|
+
Every command above answers one axis, and a reader composes them by hand. `ask risk` does the
|
|
211
|
+
join over the endpoint and symbol ids these commands already share with each other:
|
|
212
|
+
`severity_effective = defect_severity × reachability × auth_verdict × write_effect`. The
|
|
213
|
+
product of the published factors **is** the published score — decomposable to the four
|
|
214
|
+
figures and the authority behind each — and an axis this build cannot measure is `unknown`,
|
|
215
|
+
weighted 1.0 and named in `blind_axes` rather than silently treated as safe. Measured on a
|
|
216
|
+
field case: a defect both `spring-audit` and `impact-chain` called *medium* composes to
|
|
217
|
+
**high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
|
|
218
|
+
`ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
|
|
219
|
+
→ [reference](docs/USER_GUIDE.md)
|
|
220
|
+
|
|
163
221
|
### 6 · Developer Workflows
|
|
164
222
|
The everyday loop: diff-based PR review, symptom-driven bug triage, and delta context for continuous agent runs.
|
|
165
223
|
`ask review-pr` · `ask fix-bug` · `ask prepare-context`
|
|
@@ -247,7 +305,7 @@ reading JSON sees the same boundary a buyer reads here.
|
|
|
247
305
|
| Not covered | Why | What answers it |
|
|
248
306
|
|---|---|---|
|
|
249
307
|
| **Whether request input reaches a sink — no dataflow or taint analysis.** | This engine resolves structure and wiring without compiling. Taint needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL). What this product adds on top is reachability: which of that tool's findings sit behind an endpoint that is reachable unauthenticated. |
|
|
250
|
-
| **Secrets outside Java
|
|
308
|
+
| **Secrets outside Java, Spring configuration and the deployment descriptors — a Helm value, a CI variable file, a shell script.** | The file population this analyzer reads is the Java source, the Spring configuration convention and the descriptors it already parses to resolve an environment. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. Narrowed by CL-10: a credential stored in `web.xml` or a Spring XML context IS reported (SEC-007), because those files were already being read. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
|
|
251
309
|
| **Filter-chain order and per-filter URL patterns — the presence of a custom filter is structural only.** | Which filter runs first is decided by bean ordering this analyzer does not resolve. Where two active configurations both match a request, the answer published is `undecided` rather than a guess. | `ask posture --profile <set>` states per endpoint what the readable rules decide and what they leave undecided. |
|
|
252
310
|
| **Known vulnerabilities in dependencies — no CVE database, no version advisory matching.** | Enriching a vulnerability feed is a different product with a different update cadence; a stale embedded database is worse than no database, because it reads as a clean bill of health. | A dependency scanner (Trivy, OWASP Dependency-Check). `impact-chain` then answers which of its findings anything actually reaches. |
|
|
253
311
|
|
|
@@ -297,6 +297,27 @@ def _group_help_block() -> str:
|
|
|
297
297
|
return "\n".join(lines)
|
|
298
298
|
|
|
299
299
|
|
|
300
|
+
def _remedy_help_block() -> str:
|
|
301
|
+
"""The front page names the answers the field asked for as missing features.
|
|
302
|
+
|
|
303
|
+
C4-8 was closed in the payload: a limitation now carries the invocation that
|
|
304
|
+
resolves it. But the evaluator who wrote `ask posture --provenance` and `ask
|
|
305
|
+
contracts init` by hand was reading `--help` first, and neither shipped flag
|
|
306
|
+
was on it. The block is rendered from `remedies.REMEDIES`, so the pointer and
|
|
307
|
+
the capability cannot drift — `tests/test_remedies.py` already refuses a
|
|
308
|
+
remedy whose option the CLI does not accept.
|
|
309
|
+
"""
|
|
310
|
+
from sourcecode.remedies import headlines
|
|
311
|
+
|
|
312
|
+
lines = ["[bold]Questions the repository alone does not answer:[/bold]"]
|
|
313
|
+
for invocation, headline in headlines():
|
|
314
|
+
# Bare invocation, like every other block on this page: the header panels
|
|
315
|
+
# print without the `ask ` prefix (C3-16).
|
|
316
|
+
bare = invocation.removeprefix("ask ")
|
|
317
|
+
lines.append(f" {bare:<33}[dim]# {headline}[/dim]")
|
|
318
|
+
return "\n".join(lines)
|
|
319
|
+
|
|
320
|
+
|
|
300
321
|
def _build_help_text() -> str:
|
|
301
322
|
"""Build --help text dynamically based on current license state."""
|
|
302
323
|
try:
|
|
@@ -323,6 +344,9 @@ of files) in minutes. Semantic analysis itself is sub-second; repo indexing domi
|
|
|
323
344
|
endpoints . [dim]# endpoints + effective path + policy[/dim]
|
|
324
345
|
spring-audit . [dim]# TX anomalies + security surface[/dim]
|
|
325
346
|
migrate-check . --compact [dim]# Boot 2→3: located blockers + effort[/dim]
|
|
347
|
+
risk . [dim]# defects ranked by reach × access (exp.)[/dim]
|
|
348
|
+
|
|
349
|
+
{_remedy_help_block()}
|
|
326
350
|
|
|
327
351
|
[bold]Agent context:[/bold]
|
|
328
352
|
ask --compact [dim]# high-signal summary (~2,500–4,000 tokens)[/dim]
|
|
@@ -6438,19 +6462,11 @@ def spring_audit_cmd(
|
|
|
6438
6462
|
help=_NO_CACHE_SUBCOMMAND_HELP,
|
|
6439
6463
|
),
|
|
6440
6464
|
) -> None:
|
|
6441
|
-
"""Spring semantic audit:
|
|
6465
|
+
"""Spring semantic audit: {{RULE_SUMMARY}}.
|
|
6442
6466
|
|
|
6443
6467
|
\b
|
|
6444
6468
|
Detects:
|
|
6445
|
-
|
|
6446
|
-
TX-002 REQUIRES_NEW nested in REQUIRED call chain
|
|
6447
|
-
TX-003 readOnly=true boundary propagating to write operation
|
|
6448
|
-
TX-004 NOT_SUPPORTED/NEVER within active TX chain
|
|
6449
|
-
TX-005 Exception swallowing inside @Transactional
|
|
6450
|
-
TX-006 Self-invocation of @Transactional sibling (proxy bypass)
|
|
6451
|
-
SEC-001 Unsecured endpoint in annotation_based security model
|
|
6452
|
-
SEC-002 CVE-2025-41248: @PreAuthorize on inherited method from generic supertype
|
|
6453
|
-
SEC-003 @Transactional on @Controller/@RestController (TX in wrong layer)
|
|
6469
|
+
{{RULE_LIST}}
|
|
6454
6470
|
|
|
6455
6471
|
\b
|
|
6456
6472
|
Findings and defects are two counts, both published. A rule fires per
|
|
@@ -6482,10 +6498,7 @@ def spring_audit_cmd(
|
|
|
6482
6498
|
\b
|
|
6483
6499
|
What it does not look at (the whole list is in the payload's `non_coverage`,
|
|
6484
6500
|
and in the README):
|
|
6485
|
-
|
|
6486
|
-
NC-002 secrets outside Java and Spring configuration
|
|
6487
|
-
NC-003 filter-chain ORDER — a custom filter's presence is structural only
|
|
6488
|
-
NC-004 known vulnerabilities in dependencies — no CVE matching
|
|
6501
|
+
{{NON_COVERAGE}}
|
|
6489
6502
|
Silence about those is not evidence that there is nothing to find.
|
|
6490
6503
|
"""
|
|
6491
6504
|
import json as _json
|
|
@@ -6587,6 +6600,30 @@ def spring_audit_cmd(
|
|
|
6587
6600
|
raise typer.Exit(code=1)
|
|
6588
6601
|
|
|
6589
6602
|
|
|
6603
|
+
def _render_audit_help(doc: str) -> str:
|
|
6604
|
+
"""Fill the rule and non-coverage blocks from the tables that own them.
|
|
6605
|
+
|
|
6606
|
+
The rules this command detects were written out by hand in its own help, and
|
|
6607
|
+
stayed at `SEC-001..003` for two releases after CL-9 shipped three more — the
|
|
6608
|
+
C4-1 shape, where a curated list beside a generated one drifts and the
|
|
6609
|
+
curated one is what the reader gets. Both blocks are rendered now, so adding
|
|
6610
|
+
a rule updates the help by construction.
|
|
6611
|
+
"""
|
|
6612
|
+
from sourcecode import non_coverage, rule_catalog
|
|
6613
|
+
|
|
6614
|
+
nc_lines = [
|
|
6615
|
+
f" {line}" for line in non_coverage.render_help_lines("security_surface", width=68)
|
|
6616
|
+
]
|
|
6617
|
+
return (
|
|
6618
|
+
doc.replace("{{RULE_SUMMARY}}", rule_catalog.summary_line())
|
|
6619
|
+
.replace("{{RULE_LIST}}", rule_catalog.render_help_block())
|
|
6620
|
+
.replace("{{NON_COVERAGE}}", "\n".join(nc_lines))
|
|
6621
|
+
)
|
|
6622
|
+
|
|
6623
|
+
|
|
6624
|
+
spring_audit_cmd.__doc__ = _render_audit_help(spring_audit_cmd.__doc__ or "")
|
|
6625
|
+
|
|
6626
|
+
|
|
6590
6627
|
# ── verify-edit: in-loop semantic diff gate ───────────────────────────────────
|
|
6591
6628
|
|
|
6592
6629
|
|
|
@@ -8897,8 +8934,16 @@ def version_cmd() -> None:
|
|
|
8897
8934
|
{"cli_version": "1.33.11", "mcp_schema_version": "1.33.11",
|
|
8898
8935
|
"compatibility_schema_version": "1.0"}
|
|
8899
8936
|
"""
|
|
8937
|
+
from sourcecode.release_info import advisory_line, build_status
|
|
8938
|
+
|
|
8900
8939
|
if getattr(sys.stdout, "isatty", lambda: False)():
|
|
8901
8940
|
typer.echo(f"ask {__version__}")
|
|
8941
|
+
# C4-12: the field audits builds that are days old and many releases
|
|
8942
|
+
# behind, and nothing said so. Printed only when it applies — an advisory
|
|
8943
|
+
# on every run is one nobody reads.
|
|
8944
|
+
_advisory = advisory_line()
|
|
8945
|
+
if _advisory:
|
|
8946
|
+
typer.echo(_advisory)
|
|
8902
8947
|
else:
|
|
8903
8948
|
import json as _json_ver
|
|
8904
8949
|
from sourcecode.envelope import ENVELOPE_VERSION, available_schemas
|
|
@@ -8906,6 +8951,10 @@ def version_cmd() -> None:
|
|
|
8906
8951
|
"cli_version": __version__,
|
|
8907
8952
|
"mcp_schema_version": __version__,
|
|
8908
8953
|
"compatibility_schema_version": "1.0",
|
|
8954
|
+
# Which release this is, when it shipped, and how far behind it
|
|
8955
|
+
# probably is. The estimate carries its basis and never claims a
|
|
8956
|
+
# newer release exists (C4-12).
|
|
8957
|
+
"build": build_status(),
|
|
8909
8958
|
# What a consumer should actually pin against: the release string
|
|
8910
8959
|
# changes every release, the envelope version only when the output
|
|
8911
8960
|
# contract does.
|
|
@@ -123,6 +123,16 @@ def build_meta(
|
|
|
123
123
|
"tool_version": __version__,
|
|
124
124
|
"command": command,
|
|
125
125
|
}
|
|
126
|
+
# C4-12: a consumer holding a payload could not tell how old the build that
|
|
127
|
+
# produced it was. The DATE is a constant of the build, so it goes here; the
|
|
128
|
+
# AGE changes daily and would break the byte-identical property above, so it
|
|
129
|
+
# is derived where it is asked for (`ask version`), never in the envelope.
|
|
130
|
+
try:
|
|
131
|
+
from sourcecode.release_info import RELEASE_DATE
|
|
132
|
+
|
|
133
|
+
meta["tool_release_date"] = RELEASE_DATE
|
|
134
|
+
except Exception:
|
|
135
|
+
pass
|
|
126
136
|
if schema_version:
|
|
127
137
|
meta["schema_version"] = schema_version
|
|
128
138
|
|
|
@@ -74,13 +74,16 @@ NON_COVERAGE: tuple[NonCoverage, ...] = (
|
|
|
74
74
|
id="NC-002",
|
|
75
75
|
surface="security_surface",
|
|
76
76
|
not_covered=(
|
|
77
|
-
"Secrets outside Java
|
|
78
|
-
"
|
|
77
|
+
"Secrets outside Java, Spring configuration and the deployment "
|
|
78
|
+
"descriptors — a Helm value, a CI variable file, a shell script."
|
|
79
79
|
),
|
|
80
80
|
why=(
|
|
81
|
-
"The file population this analyzer reads is the Java source
|
|
82
|
-
"
|
|
83
|
-
"
|
|
81
|
+
"The file population this analyzer reads is the Java source, the Spring "
|
|
82
|
+
"configuration convention and the descriptors it already parses to "
|
|
83
|
+
"resolve an environment. A secret elsewhere is not missed by a weak "
|
|
84
|
+
"rule; it is outside the set of files anything here opens. Narrowed by "
|
|
85
|
+
"CL-10: a credential stored in `web.xml` or a Spring XML context IS "
|
|
86
|
+
"reported (SEC-007), because those files were already being read."
|
|
84
87
|
),
|
|
85
88
|
instead="A dedicated secret scanner over the whole tree (gitleaks, trufflehog).",
|
|
86
89
|
),
|