@clear-capabilities/agentic-security-scanner 0.148.5 → 0.149.1

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.
@@ -1 +1 @@
1
- 87b411bffafaae98fef870a4379829e07500f8e62d528ff2370c540eab2dcee4 agentic-security.mjs
1
+ 355c84ce589f5528668e3a998ac7d3881acd362a59e75de241cb84088b7c42e5 agentic-security.mjs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clear-capabilities/agentic-security-scanner",
3
- "version": "0.148.5",
3
+ "version": "0.149.1",
4
4
  "description": "Scanner engine for the agentic-security Claude Code plugin — SAST, SCA (function-level reachability + CISA KEV), secrets, IaC, prompt-injection, MCP/agent-tool audit, auth/authZ deep analysis, attack chains, PoC generation, business logic, toxic-combinations scoring, SBOM, pipeline integrity, compliance attestation, and more.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -65,7 +65,7 @@
65
65
  "test:glob": "node --test test/glob-compat.test.js",
66
66
  "test:sast": "node --test test/cpp-hardcoded-secret.test.js test/sibling-guard.test.js test/comment-blindness.test.js test/crypto-specialist.test.js test/llm.test.js test/llm-cost-advisor.test.js test/llm-owasp.test.js test/logic.test.js test/authz.test.js test/model-load.test.js test/prompt-template.test.js test/business-logic.test.js test/python-sinks.test.js test/phase1-detectors.test.js test/phase2-detectors.test.js test/phase3-v3.test.js test/phase7-extensions.test.js test/phase8-extensions.test.js test/new-cwe-detectors.test.js test/file-upload.test.js test/llmsecops-detectors.test.js test/db-taint.test.js test/dart-swift.test.js test/zip-slip-containment-guard.test.js test/redos-anchoring.test.js test/path-guard-validator-call.test.js test/redos-nfa.test.js test/weak-randomness.test.js test/csharp-pipeline.test.js test/post-quantum-crypto.test.js test/web3-advanced.test.js test/cloud-iam-k8s.test.js test/crypto-protocol.test.js test/ml-supply-chain.test.js test/mcp-audit-scan.test.js test/wrong-context-sanitizer.test.js test/sanitizer-context.test.js test/frontend-hygiene.test.js test/csv-injection.test.js test/stored-taint.test.js test/tree-sitter-sinks.test.js test/kotlin-structural.test.js test/ruby-php-structural.test.js test/java-csharp-structural.test.js test/guard-recognition.test.js test/guard-window-identifier-correlation.test.js test/js-python-framework-structural.test.js test/go-structural.test.js test/secret-concat.test.js test/secret-redaction.test.js test/xss-reflected-multilang.test.js test/code-injection-multilang.test.js test/xxe-multilang.test.js test/xpath-injection-multilang.test.js test/gapfill-batch13.test.js test/agent-untrusted-flow.test.js test/api-authz.test.js test/event-entrypoint.test.js test/iac-terraform.test.js test/cross-service.test.js test/rbac-consistency.test.js test/adversarial-robustness.test.js test/secret-entropy.test.js test/comment-strip.test.js test/juliet-path-filter-gate.test.js test/java-bench-shape-opt-in.test.js test/reachability-missing-callgraph-data.test.js test/rate-limit.test.js test/auth-signals.test.js test/convention-deviation.test.js test/resource-exhaustion.test.js test/resource-exhaustion-realworld.test.js test/redirect-toctou.test.js test/redirect-toctou-realworld.test.js test/codegen-sink.test.js test/ownership-authz.test.js test/ownership-authz-realworld.test.js test/t21-precision-audit.test.js test/secrets-coverage.test.js test/prompt-injection-payloads.test.js test/iac-cloud-templates.test.js test/ruby-path-join.test.js test/sast/manifest-line-tracking.test.js",
67
67
  "test:posture": "node --test test/threat-model.test.js test/git-hardening.test.js test/privacy-framework.test.js test/material-change.test.js test/drift.test.js test/scorecard.test.js test/accuracy-scorecard.test.js test/scorecard-gate.test.js test/predeploy-gate.test.js test/release-check.test.js test/pre-push-gate.test.js test/dependency-currency.test.js test/package-contents-check.test.js test/gate-verdict-cache.test.js test/run-unit-tests.test.js test/release-workflow.test.js test/independent-population.test.js test/why-missed.test.js test/independent-scoring.test.js test/evidence-bundle.test.js test/obligation-evidence-pack.test.js test/policy-bundle.test.js test/discovery-memory.test.js test/mttr.test.js test/license-policy.test.js test/aibom.test.js test/sbom.test.js test/api-inventory.test.js test/iam-policy.test.js test/container.test.js test/container-runtime.test.js test/image-packages.test.js test/kev.test.js test/dep-confusion.test.js test/sca-deprecated.test.js test/sca-batch.test.js test/composite-risk.test.js test/epss-enrich.test.js test/sca-coverage.test.js test/gradle-deps.test.js test/sca-route-reachable.test.js test/sca-policy.test.js test/sca-verdict.test.js test/install-script.test.js test/sca-linked-findings.test.js test/packs.test.js test/flow-narration.test.js test/regression-test-gen.test.js test/deterministic-fix.test.js test/falsification.test.js test/verification-separation.test.js test/logic-claims.test.js test/attestation.test.js test/verify-attestation-cli.test.js test/comparison.test.js test/determinism-cross-machine.test.js test/fix-honesty-gate.test.js test/model-routing.test.js test/root-cause-sweep.test.js test/entrypoint-inventory.test.js test/relevance.test.js test/untrusted.test.js test/agent-hardening.test.js test/rule-synthesis.test.js test/policy-gate.test.js test/agents-memory.test.js test/cve-lookup.test.js test/cve-alert-daemon.test.js test/fix-verify-loop.test.js test/fix-verify-tests.test.js test/fix-acceptance.test.js test/exploitability-probability.test.js test/history-scan.test.js test/viral-features.test.js test/viral-v074.test.js test/state-dir.test.js test/ignore-pragma.test.js test/license-graph.test.js test/secret-live-check.test.js test/attack-taxonomy.test.js test/triage-memory.test.js test/pr-augment.test.js test/chat-batch2.test.js test/chat-batch3.test.js test/chat-batch4.test.js test/chat-batch5.test.js test/chat-batch6.test.js test/risk-scenario-disclosure.test.js test/egress-policy.test.js test/egress-policy-completeness.test.js test/egress-policy-integration.test.js test/router.test.js test/legacy-alias-redirect.test.js test/cache-economics.test.js test/coverage-report.test.js test/corpus-status.test.js test/provenance.test.js test/secret-history.test.js test/execution-proof.test.js test/fix-metrics.test.js test/corpus-enroll.test.js test/prove-findings.test.js test/corpus-match.test.js test/corpus-provenance.test.js test/learning-quorum.test.js test/llm-cache-integrity.test.js test/proof-artifact.test.js test/providers.test.js test/fleet.test.js test/autopilot.test.js test/autopilot-cli.test.js test/verifier-independence.test.js test/integrity-legacy-key.test.js test/suppression-visibility.test.js test/cost-ceiling.test.js test/local-endpoint.test.js test/model-trust.test.js test/vuln-archaeology.test.js test/scan-checkpoint.test.js test/llm-redact.test.js test/world-class-batch2.test.js test/world-class-modules.test.js test/privacy-ir-adapter.test.js test/privacy-taxonomy.test.js test/privacy-sink-policy.test.js test/privacy-governance.test.js test/privacy-inventory.test.js test/integration-end-to-end.test.js test/streak-cli-wiring.test.js test/stack-playbook.test.js test/machine-output-flag.test.js test/stdout-flush.test.js test/format-determinism.test.js test/only-flag-channels.test.js test/confidence.test.js test/security-trend.test.js test/calibration-drift.test.js test/validator-metrics.test.js test/clustering-ir-taint-line.test.js test/concurrency-cwe.test.js test/compliance-mapping-liveness.test.js test/module-artifact-liveness.test.js test/supply-chain-provenance-completeness.test.js test/compliance-severity-threshold.test.js test/compliance-severity-policy.test.js test/compliance-evidence-binding.test.js test/compliance-evidence-signing.test.js test/compliance-file-contains.test.js test/label-isolation.test.js test/evidence-grade-wording.test.js test/llm-model-status.test.js test/egress-policy-constraints.test.js test/egress-redact.test.js test/egress-audit.test.js test/egress-approved-providers.test.js test/family-registry.test.js test/coverage-strength.test.js test/framework-provenance.test.js test/framework-provenance-controlrefs.test.js test/third-party-verification.test.js test/proof-coverage.test.js test/calibration-holdout.test.js test/independent-population-gate.test.js test/catalog-freshness.test.js test/incremental-parity.test.js test/surface-smoke.test.js test/fix-coverage.test.js test/raw-source-carveout.test.js test/mlbom-conformance.test.js test/deploy-gate-replay.test.js test/sbom-conformance.test.js test/unscored-claims.test.js test/mcp-rug-pull.test.js test/agent-boundary-taint.test.js test/confinement-adversarial.test.js test/comment-strip-cost.test.js test/reachability-claim.test.js test/entrypoint-breadth.test.js test/dep-file-admission.test.js test/custom-rules-freshness.test.js test/posture/provenance-schema.test.js test/posture/provenance-cache.test.js test/helpers/build-git-fixture.test.js test/posture/provenance-git-evidence.test.js test/posture/provenance-dag-walk.test.js test/posture/provenance-confidence.test.js test/posture/provenance-predicate-replay.test.js test/posture/provenance-origin-resolver.test.js test/posture/provenance-ai-authorship.test.js test/posture/provenance-branch-entry.test.js test/posture/provenance-evidence-attribution.test.js test/posture/provenance-lifecycle.test.js test/posture/provenance-missing-control-resolver.test.js test/posture/provenance-missing-control-wiring.test.js test/posture/provenance-coordinator.test.js test/posture/provenance-sca-origin.test.js test/posture/provenance-transitive-sca.test.js test/posture/provenance-coordinator-sca.test.js test/posture/provenance-providers.test.js test/posture/provenance-evidence-bundle.test.js test/posture/provenance-repo-lineage.test.js test/posture/provenance-secrets-logic.test.js test/cli/provenance-flags.test.js test/cli/attest-provenance.test.js test/cli/attest-obligations.test.js test/cli/compliance-walkthrough-lineage.test.js test/cli/dataflow-export-privacy.test.js test/cli/dataflow-export-briefing.test.js test/cli/lineage-snapshot-persist.test.js test/cli/dataflow-diff.test.js test/cli/dataflow-watch.test.js test/cli/dataflow-recipients.test.js test/cli/dataflow-coverage.test.js test/security/provenance-safety.test.js test/security/provenance-injection.test.js test/posture/remediation-ledger.test.js",
68
- "test:dataflow": "node --test test/privacy-catalog.test.js test/privacy-deep-walker.test.js test/privacy-deep-e2e.test.js test/container-taint.test.js test/stored-taint-families.test.js test/py-annotation-sources.test.js test/fn-reach.test.js test/deep-taint.test.js test/calibration.test.js test/holdout-eval.test.js test/cross-lang-meta.test.js test/cross-lang-queues.test.js test/phase5-xlang.test.js test/phase5-coverage.test.js test/phase6-taint.test.js test/llm-validator-consistency.test.js test/llm-validator-default-on.test.js test/llm-validator-preset.test.js test/parser-py-cst.test.js test/chrome-probe.test.js test/parser-cs-kt.test.js test/parser-cs-annotations.test.js test/parser-cs-control-flow.test.js test/parser-kt-control-flow.test.js test/parser-js-annotations.test.js test/parser-java-annotations.test.js test/parser-java-control-flow.test.js test/parser-java-calls.test.js test/parser-go.test.js test/parser-php-rb.test.js test/parser-php-control-flow.test.js test/interproc-k2.test.js test/proven-clean.test.js test/backward-default.test.js test/incremental-cache.test.js test/string-regex-lattice.test.js test/closure-capture.test.js test/points-to.test.js test/type-stubs.test.js test/soft-taint.test.js test/ifds.test.js test/symbolic-exec-proof.test.js test/ifds-summary-edges.test.js test/stub-aware-filter.test.js test/cross-repo.test.js test/proof-gate.test.js test/layer-recall.test.js test/java-taint-flow.test.js test/kt-taint-flow.test.js test/sanitizer-typed-flow.test.js test/sanitizer-gate-unit.test.js test/proof-safe.test.js test/collection-taint.test.js test/kcfa-context.test.js test/kcfa-callstring.test.js test/flow-parity.test.js test/callgraph-resolve.test.js test/import-reachability.test.js test/ir-stats.test.js test/parser-cpp.test.js test/parser-js-decorators.test.js test/parser-js-if-else-cfg.test.js test/cpp-integration.test.js test/engine-reconnect.test.js test/phase2-scoping.test.js test/engine-recall.test.js test/catalog-annotation-source.test.js test/catalog-cs-p1.test.js test/catalog-expanded.test.js test/builtin-summaries.test.js test/interproc-mutation-crash.test.js test/mutated-param-taint.test.js test/return-sink-check.test.js test/higher-order-inline-callback.test.js test/interproc-findings-discard.test.js test/runscan-deep-option.test.js test/summary-cache-convergence.test.js test/parser-rb-calls.test.js test/parser-rb-module-level.test.js test/balanced-call.test.js test/destructuring-taint.test.js test/computed-member-taint.test.js test/string-interpolation-taint.test.js test/dataflow-deadcode-severity.test.js test/catalog-dotted-callee-lookup.test.js test/builtin-summary-family-blind-kill.test.js test/deep-mode-annotator-pipeline.test.js test/receiver-type-and-nested-calls.test.js test/member-write-and-loop-taint.test.js test/parser-py-module-level.test.js test/parser-php-module-level.test.js test/r14b-module-level-e2e.test.js test/annotation-taint-engine.test.js test/interproc-nested-call-taint.test.js test/catalog-xpath-injection.test.js test/catalog-ldap-injection.test.js test/catalog-xxe.test.js test/catalog-response-splitting.test.js test/catalog-code-injection.test.js test/parser-rb-control-flow.test.js test/catalog-ruby-p1.test.js test/callee-receiver-taint.test.js test/catalog-command-injection-p4.test.js test/catalog-xss-p4.test.js test/catalog-path-ssrf-p3.test.js test/catalog-ai-model-provider-precision.test.js test/catalog-orm-write.test.js test/dataflow/provenance-pipeline-integration.test.js",
68
+ "test:dataflow": "node --test test/privacy-catalog.test.js test/privacy-deep-walker.test.js test/privacy-deep-e2e.test.js test/container-taint.test.js test/stored-taint-families.test.js test/py-annotation-sources.test.js test/fn-reach.test.js test/deep-taint.test.js test/calibration.test.js test/holdout-eval.test.js test/cross-lang-meta.test.js test/cross-lang-queues.test.js test/phase5-xlang.test.js test/phase5-coverage.test.js test/phase6-taint.test.js test/llm-validator-consistency.test.js test/llm-validator-default-on.test.js test/llm-validator-preset.test.js test/parser-py-cst.test.js test/chrome-probe.test.js test/parser-cs-kt.test.js test/parser-cs-annotations.test.js test/parser-cs-control-flow.test.js test/parser-kt-control-flow.test.js test/parser-js-annotations.test.js test/parser-java-annotations.test.js test/parser-java-control-flow.test.js test/parser-java-calls.test.js test/parser-go.test.js test/parser-php-rb.test.js test/parser-php-control-flow.test.js test/interproc-k2.test.js test/proven-clean.test.js test/backward-default.test.js test/incremental-cache.test.js test/string-regex-lattice.test.js test/closure-capture.test.js test/points-to.test.js test/type-stubs.test.js test/soft-taint.test.js test/ifds.test.js test/symbolic-exec-proof.test.js test/ifds-summary-edges.test.js test/stub-aware-filter.test.js test/cross-repo.test.js test/proof-gate.test.js test/layer-recall.test.js test/java-taint-flow.test.js test/kt-taint-flow.test.js test/sanitizer-typed-flow.test.js test/sanitizer-gate-unit.test.js test/proof-safe.test.js test/collection-taint.test.js test/kcfa-context.test.js test/kcfa-callstring.test.js test/flow-parity.test.js test/callgraph-resolve.test.js test/import-reachability.test.js test/ir-stats.test.js test/parser-cpp.test.js test/parser-js-decorators.test.js test/parser-js-if-else-cfg.test.js test/cpp-integration.test.js test/engine-reconnect.test.js test/phase2-scoping.test.js test/engine-recall.test.js test/catalog-annotation-source.test.js test/catalog-cs-p1.test.js test/catalog-expanded.test.js test/builtin-summaries.test.js test/interproc-mutation-crash.test.js test/mutated-param-taint.test.js test/return-sink-check.test.js test/higher-order-inline-callback.test.js test/interproc-findings-discard.test.js test/runscan-deep-option.test.js test/summary-cache-convergence.test.js test/parser-rb-calls.test.js test/parser-rb-module-level.test.js test/balanced-call.test.js test/destructuring-taint.test.js test/computed-member-taint.test.js test/string-interpolation-taint.test.js test/dataflow-deadcode-severity.test.js test/catalog-dotted-callee-lookup.test.js test/builtin-summary-family-blind-kill.test.js test/deep-mode-annotator-pipeline.test.js test/receiver-type-and-nested-calls.test.js test/member-write-and-loop-taint.test.js test/parser-py-module-level.test.js test/parser-php-module-level.test.js test/r14b-module-level-e2e.test.js test/annotation-taint-engine.test.js test/interproc-nested-call-taint.test.js test/catalog-xpath-injection.test.js test/catalog-ldap-injection.test.js test/catalog-xxe.test.js test/catalog-response-splitting.test.js test/catalog-code-injection.test.js test/parser-rb-control-flow.test.js test/catalog-ruby-p1.test.js test/callee-receiver-taint.test.js test/catalog-command-injection-p4.test.js test/catalog-xss-p4.test.js test/catalog-path-ssrf-p3.test.js test/catalog-ai-model-provider-precision.test.js test/catalog-orm-write.test.js test/dataflow/provenance-pipeline-integration.test.js test/dataflow-progress.test.js test/scan-progress.test.js",
69
69
  "test:mcp": "node --test test/mcp.test.js test/mcp-protocol-smoke.test.js test/mcp-audit.test.js test/audit-cli.test.js test/mcp-scratchpad.test.js test/mcp-offload.test.js test/sca-upgrade.test.js test/lsp-server.test.js test/mcp-dataflow-tools.test.js test/cli/governance-propose-edit.test.js test/cli/remediation-open-update.test.js test/cli/remediation-verify-reopen.test.js test/cli/dataflow-observations.test.js test/cli/federate-declare-list.test.js",
70
70
  "test:report": "node --test test/report-scan-invariants.test.js test/junit.test.js test/ci.test.js test/poc-generator.test.js test/verifier.test.js test/verifier-target.test.js test/annotator-errors.test.js test/scan-health.test.js test/finding-schema.test.js test/pipeline/finding-schema-provenance.test.js test/evidence-provenance.test.js test/report/provenance-output.test.js test/report/provenance-format-parity.test.js test/legacy-compat.test.js test/annotator-runner.test.js test/detector-runner.test.js test/detector-errors.test.js test/analyzer-supervisor.test.js test/cascade-worker-pool.test.js test/cascade-pool-wiring.test.js test/coverage-ledger.test.js test/coverage-ledger-completeness.test.js test/assurance-mode.test.js test/artifact-registry.test.js test/artifact-registry-completeness.test.js test/retention-policy.test.js test/state-lifecycle-report.test.js test/legal-hold.test.js test/production-feedback.test.js test/calibration-feedback.test.js test/encryption-provider.test.js test/grader-calibration.test.js test/pr-delta-gate.test.js test/vex.test.js test/report-render.test.js test/oscal-conformance.test.js test/cli-fix-apply.test.js test/apply-fix-service.test.js test/high-impact-approval-gate.test.js test/approver-registry.test.js test/suppression-exceptions.test.js test/fix-history.test.js test/producer-registry.test.js test/producer-collector.test.js test/enrichment-completion.test.js",
71
71
  "test:lineage": "node --test test/lineage/schema.test.js test/lineage/ids.test.js test/lineage/protection.test.js test/lineage/classification.test.js test/lineage/validate.test.js test/lineage/json-schema-parity.test.js test/lineage/flagship-fixture.test.js test/lineage/flagship-fixture-semantics.test.js test/lineage/field-identity.test.js test/lineage/engine-expr-resolver.test.js test/lineage/engine-walker.test.js test/lineage/engine-integration.test.js test/lineage/engine-receiver-identity.test.js test/lineage/summaries.test.js test/lineage/driver.test.js test/lineage/engine-provenance.test.js test/lineage/engine-provenance-interprocedural.test.js test/lineage/path-store.test.js test/lineage/path-query.test.js test/lineage/flow-grade.test.js test/lineage/source-registry.test.js test/lineage/sink-registry.test.js test/lineage/transform-catalog.test.js test/lineage/handling-analyzer.test.js test/lineage/registry-real-code.test.js test/lineage/source-seeding.test.js test/lineage/graph-builder.test.js test/lineage/coverage.test.js test/lineage/resolve-destination.test.js test/lineage/queue-detail.test.js test/lineage/index.test.js test/lineage/obligation-mapping.test.js test/lineage/obligation-predicates.test.js test/lineage/obligation-predicates-walkthrough.test.js test/lineage/transit-protection.test.js test/lineage/at-rest-protection.test.js test/lineage/protection-summary.test.js test/lineage/ac01-multi-sink.test.js test/lineage/policy-verdict.test.js test/lineage/governance-refs.test.js test/lineage/export-privacy.test.js test/lineage/export-json.test.js test/lineage/export-csv.test.js test/lineage/decision-story.test.js test/lineage/export-briefing.test.js test/lineage/graph-snapshot.test.js test/lineage/graph-diff.test.js test/lineage/drift-policy.test.js test/lineage/recipient-profile.test.js test/lineage/recipient-registry.test.js test/lineage/recipient-wiring.test.js test/lineage/redact-graph.test.js test/lineage-scan-wiring.test.js test/lineage-artifact-write.test.js test/bench-data-lineage-runner.test.js test/bundle-frontend.test.js test/bundle-frontend-golden.test.js test/generate-html-report.test.js test/export-image.test.js test/lineage/scenario.test.js test/lineage/scenario-engine.test.js test/lineage/scenario-diff.test.js test/lineage/scenario-no-obligation-wiring.test.js test/lineage/impact-assessment.test.js test/lineage/impact-engine.test.js test/lineage/impact-no-obligation-wiring.test.js test/lineage/governance-edit.test.js test/lineage/remediation.test.js test/lineage/runtime-observation.test.js test/lineage/observation-correlation.test.js test/lineage/observation-adapters.test.js test/lineage/observation-store.test.js test/lineage/runtime-corroboration-wiring.test.js test/lineage/cross-repo-link.test.js test/lineage/federation-loader.test.js test/lineage/cross-repo-link-wiring.test.js",
@@ -1492,6 +1492,18 @@ export function runTaintEngine(perFileIR, callGraph, opts = {}) {
1492
1492
  const fnLimit = opts.fnLimit || 5000;
1493
1493
  const deadlineMs = typeof opts.deadlineMs === 'number' ? opts.deadlineMs : Infinity;
1494
1494
  let n = 0;
1495
+ // Live progress for this engine's dominant per-function loop (below,
1496
+ // bounded by fnLimit) — the longest-running phase of a deep scan on any
1497
+ // real-sized project. Additive/opt-in: with no `opts.onProgress`, nothing
1498
+ // here runs and every existing caller is byte-identical to before this
1499
+ // existed. Only the pre-passes above (fixed-point empty-entry pre-pass,
1500
+ // class-field cross-taint pass, k=2 pass) are NOT instrumented — they run
1501
+ // before `fnList.length` is known to be the final total below, and adding
1502
+ // per-iteration reporting to all four loops was judged disproportionate
1503
+ // risk to this engine's own worklist for the UX gain; the operator sees
1504
+ // the phase-start message the caller prints before this function is ever
1505
+ // invoked, then live per-function progress once this loop begins.
1506
+ const onProgress = typeof opts.onProgress === 'function' ? opts.onProgress : null;
1495
1507
 
1496
1508
  // Premortem #7: instantiate the k=1 SummaryCache and seed it with each
1497
1509
  // function's empty-entry-state summary (returnTainted bit). The cache is
@@ -1666,9 +1678,11 @@ export function runTaintEngine(perFileIR, callGraph, opts = {}) {
1666
1678
  findings: ctx._findings,
1667
1679
  });
1668
1680
  }
1681
+ const _progressTotal = Math.min(fnList.length, fnLimit);
1669
1682
  for (const fn of fnList) {
1670
1683
  if (++n > fnLimit) break;
1671
1684
  if (Date.now() > deadlineMs) break; // global timeout
1685
+ if (onProgress) onProgress({ current: n, total: _progressTotal });
1672
1686
  // Module-level functions: analyze with an empty entry state. The function
1673
1687
  // discovers its own sources from req.body/process.env/etc. as it walks.
1674
1688
  const callContext = {
package/src/engine.js CHANGED
@@ -8206,11 +8206,12 @@ async function queryOSV(components,allFileContents){
8206
8206
  }
8207
8207
  }
8208
8208
 
8209
- if(queries.length){
8209
+ const _osvOffline=process.env.AGENTIC_SECURITY_OFFLINE==='1';
8210
+ if(queries.length&&!_osvOffline){
8210
8211
  for(let i=0;i<queries.length;i+=1000){
8211
8212
  const chunkQ=queries.slice(i,i+1000),chunkC=uncached.slice(i,i+1000);
8212
8213
  try{
8213
- const resp=await fetch('https://api.osv.dev/v1/querybatch',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({queries:chunkQ})});
8214
+ const resp=await fetch('https://api.osv.dev/v1/querybatch',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({queries:chunkQ}),signal:AbortSignal.timeout(8000)});
8214
8215
  const data=await resp.json();
8215
8216
  for(let idx=0;idx<(data.results||[]).length;idx++){
8216
8217
  const{comp,ck}=chunkC[idx];
@@ -8243,8 +8244,9 @@ async function queryOSV(components,allFileContents){
8243
8244
  }
8244
8245
  // Then fetch uncached vulns with bounded concurrency.
8245
8246
  async function _fetchOneVuln(vid){
8247
+ if(_osvOffline)return null;
8246
8248
  try {
8247
- const resp = await fetch(`https://api.osv.dev/v1/vulns/${vid}`);
8249
+ const resp = await fetch(`https://api.osv.dev/v1/vulns/${vid}`,{signal:AbortSignal.timeout(8000)});
8248
8250
  const d = await resp.json();
8249
8251
  const fixedVersions = new Set();
8250
8252
  const osvVulnFunctions = [];
@@ -8337,7 +8339,7 @@ async function queryRegistries(components){
8337
8339
  for(let i=0;i<npmNames.length;i+=CHUNK){
8338
8340
  await Promise.all(npmNames.slice(i,i+CHUNK).map(async name=>{
8339
8341
  try{
8340
- const resp=await fetch('https://registry.npmjs.org/'+name);
8342
+ const resp=await fetch('https://registry.npmjs.org/'+name,{signal:AbortSignal.timeout(8000)});
8341
8343
  if(!resp.ok)return;
8342
8344
  const d=await resp.json();
8343
8345
  const latest=d['dist-tags']?.latest||'';const lic=d.license||(latest&&d.versions?.[latest]?.license)||'';infoMap.set('npm:'+name,{latestVersion:latest,license:lic,versions:d.versions||{}});
@@ -8347,7 +8349,7 @@ async function queryRegistries(components){
8347
8349
  for(let i=0;i<pypiNames.length;i+=CHUNK){
8348
8350
  await Promise.all(pypiNames.slice(i,i+CHUNK).map(async name=>{
8349
8351
  try{
8350
- const resp=await fetch('https://pypi.org/pypi/'+encodeURIComponent(name)+'/json');
8352
+ const resp=await fetch('https://pypi.org/pypi/'+encodeURIComponent(name)+'/json',{signal:AbortSignal.timeout(8000)});
8351
8353
  if(!resp.ok)return;
8352
8354
  const d=await resp.json();
8353
8355
  const info=d.info||{};
@@ -8377,7 +8379,7 @@ async function queryRegistries(components){
8377
8379
  for(let i=0;i<packagistNames.length;i+=CHUNK){
8378
8380
  await Promise.all(packagistNames.slice(i,i+CHUNK).map(async name=>{
8379
8381
  try{
8380
- const resp=await fetch('https://packagist.org/packages/'+name+'.json');
8382
+ const resp=await fetch('https://packagist.org/packages/'+name+'.json',{signal:AbortSignal.timeout(8000)});
8381
8383
  if(!resp.ok)return;
8382
8384
  const d=await resp.json();
8383
8385
  const pkg=d.package||{};
@@ -8398,7 +8400,7 @@ async function queryRegistries(components){
8398
8400
  for(let i=0;i<cargoNames.length;i+=CHUNK){
8399
8401
  await Promise.all(cargoNames.slice(i,i+CHUNK).map(async name=>{
8400
8402
  try{
8401
- const resp=await fetch('https://crates.io/api/v1/crates/'+encodeURIComponent(name),{headers:CRATES_UA});
8403
+ const resp=await fetch('https://crates.io/api/v1/crates/'+encodeURIComponent(name),{headers:CRATES_UA,signal:AbortSignal.timeout(8000)});
8402
8404
  if(!resp.ok)return;
8403
8405
  const d=await resp.json();
8404
8406
  const versions={};
@@ -8415,7 +8417,7 @@ async function queryRegistries(components){
8415
8417
  for(let i=0;i<gemNames.length;i+=CHUNK){
8416
8418
  await Promise.all(gemNames.slice(i,i+CHUNK).map(async name=>{
8417
8419
  try{
8418
- const resp=await fetch('https://rubygems.org/api/v1/versions/'+encodeURIComponent(name)+'.json');
8420
+ const resp=await fetch('https://rubygems.org/api/v1/versions/'+encodeURIComponent(name)+'.json',{signal:AbortSignal.timeout(8000)});
8419
8421
  if(!resp.ok)return;
8420
8422
  const list=await resp.json();
8421
8423
  const versions={};
@@ -8433,7 +8435,7 @@ async function queryRegistries(components){
8433
8435
  for(let i=0;i<pubNames.length;i+=CHUNK){
8434
8436
  await Promise.all(pubNames.slice(i,i+CHUNK).map(async name=>{
8435
8437
  try{
8436
- const resp=await fetch('https://pub.dev/api/packages/'+encodeURIComponent(name),{headers:{Accept:'application/vnd.pub.v2+json'}});
8438
+ const resp=await fetch('https://pub.dev/api/packages/'+encodeURIComponent(name),{headers:{Accept:'application/vnd.pub.v2+json'},signal:AbortSignal.timeout(8000)});
8437
8439
  if(!resp.ok)return;
8438
8440
  const d=await resp.json();
8439
8441
  const versions={};
@@ -8453,7 +8455,7 @@ async function queryRegistries(components){
8453
8455
  await Promise.all(mavenComps.slice(i,i+CHUNK).map(async c=>{
8454
8456
  try{
8455
8457
  const q=encodeURIComponent(`g:"${c.group}" AND a:"${c.name}"`);
8456
- const resp=await fetch(`https://search.maven.org/solrsearch/select?q=${q}&rows=1&wt=json`);
8458
+ const resp=await fetch(`https://search.maven.org/solrsearch/select?q=${q}&rows=1&wt=json`,{signal:AbortSignal.timeout(8000)});
8457
8459
  if(!resp.ok)return;
8458
8460
  const d=await resp.json();
8459
8461
  const doc=(d.response?.docs||[])[0];
@@ -9211,12 +9213,23 @@ function _deterministicFileTimings(timings) {
9211
9213
  // deadlineMs hint that the inner loops check; if absent, we still cap
9212
9214
  // function count via fnLimit. Operators who suspect a hung run can
9213
9215
  // kill the process and re-run with AGENTIC_SECURITY_DEEP=0.
9216
+ setProgress({ phase: 'Deep analysis', current: 0, total: 0, file: `starting (budget ${Math.round(budgetMs / 1000)}s)` });
9214
9217
  const irFindings = runDeepAnalysis(perFile, callGraph, {
9215
9218
  fnLimit: parseInt(process.env.AGENTIC_SECURITY_DEEP_FN_LIMIT || '5000', 10),
9216
9219
  deadlineMs: t0 + budgetMs,
9217
9220
  // v0.69 — incremental cache inputs (used when AGENTIC_SECURITY_INCREMENTAL=1).
9218
9221
  scanRoot,
9219
9222
  fileContents: fc,
9223
+ // Live per-function progress from the engine's own dominant loop
9224
+ // (dataflow/engine.js's runTaintEngine) — the pre-passes before it
9225
+ // (fixed-point pre-pass, class-field pass, k=2 pass) aren't
9226
+ // individually instrumented (see that file's own onProgress
9227
+ // comment), so the terminal shows the "starting" message above
9228
+ // until this loop begins, then live current/total from here on.
9229
+ onProgress: (p) => setProgress({
9230
+ phase: 'Deep analysis', current: p.current, total: p.total,
9231
+ file: `${Math.round((Date.now() - t0) / 1000)}s elapsed`,
9232
+ }),
9220
9233
  });
9221
9234
  const elapsed = Date.now() - t0;
9222
9235
  if (elapsed > budgetMs) {
@@ -9302,7 +9315,15 @@ function _deterministicFileTimings(timings) {
9302
9315
  // if deep mode already built it, this is free; if not, this is what
9303
9316
  // first triggers the build (the whole reason this gate is independent).
9304
9317
  const { perFile, callGraph } = _sharedIR || (_sharedIR = await _buildIR());
9318
+ const _lineageT0 = Date.now();
9319
+ setProgress({ phase: 'Lineage graph', current: 0, total: 0, file: `starting (budget ${Math.round(_lineageBudgetMs / 1000)}s)` });
9305
9320
  const _lr = buildLineageGraph(callGraph, {
9321
+ // Live per-function progress from the field-identity driver's own
9322
+ // single pass over every function (src/lineage/driver.js).
9323
+ onProgress: (p) => setProgress({
9324
+ phase: 'Lineage graph', current: p.current, total: p.total,
9325
+ file: `${Math.round((Date.now() - _lineageT0) / 1000)}s elapsed`,
9326
+ }),
9306
9327
  // scanRoot can be null (e.g. an MCP scan_diff caller, or
9307
9328
  // runFullScan invoked directly with no scanRoot) — fall back to
9308
9329
  // undefined rather than inventing a repository name from the
@@ -9580,7 +9601,22 @@ function _deterministicFileTimings(timings) {
9580
9601
  // since this project's own annotators are deliberately built never to
9581
9602
  // throw (posture/CLAUDE.md's "no throwing" convention) — this closure just
9582
9603
  // supplies the local _annotatorErrors array.
9583
- const _runAnnotator = (phase, fn) => runAnnotatorAsync(_annotatorErrors, phase, fn);
9604
+ // Live progress for this whole annotator sequence (~52 `await
9605
+ // _runAnnotator(...)` call sites below, re-derive via `grep -c "await
9606
+ // _runAnnotator(" src/engine.js` rather than trusting this count to stay
9607
+ // current) — previously silent even though it can take a real fraction of
9608
+ // scan time on a large finding set. `_ANNOTATOR_TOTAL_ESTIMATE` is an
9609
+ // upper bound, not an exact count: several call sites below are
9610
+ // conditional (deep-mode-only, provenance-only, etc.), so a real scan
9611
+ // reports fewer steps than the total and the progress bar does not
9612
+ // necessarily reach it — that's the same "stale total, real motion" shape
9613
+ // the pre-existing "Linking" phase already accepts.
9614
+ const _ANNOTATOR_TOTAL_ESTIMATE = 52;
9615
+ let _annotatorIdx = 0;
9616
+ const _runAnnotator = (phase, fn) => {
9617
+ setProgress({ phase: 'Annotating', current: ++_annotatorIdx, total: _ANNOTATOR_TOTAL_ESTIMATE, file: phase });
9618
+ return runAnnotatorAsync(_annotatorErrors, phase, fn);
9619
+ };
9584
9620
  await _runAnnotator('annotateStableIds', () => annotateStableIds(finalFindings));
9585
9621
  await _runAnnotator("clusterByRootCause", () => { finalFindings = clusterByRootCause(finalFindings); });
9586
9622
  await _runAnnotator("demoteUnreachable", () => {
@@ -66,9 +66,17 @@ export function runFieldIdentityAnalysis(callGraph, opts = {}) {
66
66
  const fnList = callGraph && callGraph.functions
67
67
  ? [...callGraph.functions.values()].sort((a, b) => (a.qid < b.qid ? -1 : a.qid > b.qid ? 1 : 0))
68
68
  : [];
69
+ // Live progress, additive/opt-in — mirrors dataflow/engine.js's own
70
+ // `runTaintEngine` onProgress precedent exactly. Unlike that engine, this
71
+ // driver has only ONE pass over `fnList` (no fixed-point pre-passes), so
72
+ // every function this driver analyzes is reported, not just a dominant
73
+ // subset.
74
+ const onProgress = typeof opts.onProgress === 'function' ? opts.onProgress : null;
75
+ let _progressN = 0;
69
76
 
70
77
  const results = new Map();
71
78
  for (const fn of fnList) {
79
+ if (onProgress) onProgress({ current: ++_progressN, total: fnList.length });
72
80
  const lookupCallee = createCallGraphLookup(callGraph, fn.file);
73
81
  const resolveCallSummary = createCallSummaryResolver(cache, lookupCallee);
74
82
  // Path provenance (Sub-project C, increment 3, §13.7 item 14): thread
@@ -440,6 +440,7 @@ export function buildDataFlowGraph(callGraph, opts = {}) {
440
440
  recordHop: (h) => hops.push(h),
441
441
  seedEntryState: seedEntryStateFactory(seeds),
442
442
  ...(opts.maxContextsPerFn === undefined ? {} : { maxContextsPerFn: opts.maxContextsPerFn }),
443
+ ...(opts.onProgress ? { onProgress: opts.onProgress } : {}),
443
444
  });
444
445
  const store = new PathStore();
445
446
  store.addHops(hops);
@@ -271,6 +271,7 @@ export function buildLineageGraph(callGraph, opts = {}) {
271
271
  crossRepoLinkRecords,
272
272
  observationWindowStart: opts.observationWindowStart,
273
273
  observationWindowEnd: opts.observationWindowEnd,
274
+ onProgress: opts.onProgress,
274
275
  });
275
276
  return { status: 'complete', graph: built.graph, transitEvidence, failure: null, elapsedMs: Date.now() - t0 };
276
277
  } catch (e) {