@clear-capabilities/agentic-security-scanner 0.186.1 → 0.186.2

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
- 24e3e457c295e1d145cef330ac730645315f1d83fe83f7cb7a4865ad3ba910d1 agentic-security.mjs
1
+ 38adcd8324aa7552b7bf61f5ac662fe383ed41f0bcf7f6eb2cad89de080a88c5 agentic-security.mjs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clear-capabilities/agentic-security-scanner",
3
- "version": "0.186.1",
3
+ "version": "0.186.2",
4
4
  "description": "Scanner engine for the agentic-security Claude Code plugin: SAST, SCA with reachability and CISA KEV, secrets, IaC, Haskell and Nix/NixOS, prompt-injection, MCP/agent-tool audit, authZ analysis, SBOM, compliance attestation, and more.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -86,10 +86,10 @@
86
86
  "test:ollama-e2e": "AGENTIC_SECURITY_OLLAMA_E2E=1 node --test test/ollama-e2e.test.js",
87
87
  "test:glob": "node --test test/glob-compat.test.js",
88
88
  "test:sast": "node --test test/dag-precision.test.js 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/zip-slip-go.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/csharp-cross-file.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/java-structural-cross-file.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/java-ast-folding.test.js test/java-bench-extras.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 test/rust-sast.test.js test/java-deserialization-precision.test.js test/pipeline-env-secret.test.js test/mark-used-vuln-functions.test.js",
89
- "test:posture": "node --test test/contracts/root-cause-sweep.contract.test.js test/contracts/model-validation.contract.test.js test/contracts/agentic-discovery.contract.test.js test/contracts/local-models.contract.test.js test/contracts/dependency-finding.contract.test.js test/contracts/taint-flow.contract.test.js test/contracts/runtime-corroboration.contract.test.js test/compliance-coverage.test.js test/contracts/blast-radius.contract.test.js test/contracts/federation.contract.test.js test/contracts/eval-lab-report.contract.test.js test/contracts/fleet.contract.test.js test/contracts/rule-compiler.contract.test.js test/contracts/release-assurance.contract.test.js test/contracts/dnr.contract.test.js test/contracts/strategic-metrics.contract.test.js test/contracts/exploit-proof.contract.test.js test/contracts/artifact-provenance.contract.test.js test/dnr/artifact-join.test.js test/rule-pack-signing.test.js 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/temp-leak-guard.test.js test/release-workflow.test.js test/release-workflow-structure.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/ollama-provider.test.js test/ollama-capabilities.test.js test/ollama-offline-egress.test.js test/ollama-fix-proposal.test.js test/ollama-explain-proposal.test.js test/ollama-poc-proposal.test.js test/ollama-model-probe.test.js test/ollama-agent-tools.test.js test/ollama-agent-loop.test.js test/ollama-e2e.test.js test/ollama-oom-feedback.test.js test/ollama-doc-drift.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/models.test.js test/cli/setup-llm.test.js test/cli/fix-retry.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 test/posture/assurance-baseline.test.js test/posture/assurance-contracts.test.js test/posture/assurance-config.test.js test/evidence-issuer.test.js test/load-factor.test.js test/fleet/job-store.test.js test/fleet/enterprise-graph.test.js test/fleet/discover-edges.test.js test/fleet/code-boundaries.test.js test/fleet/job-runner.test.js test/fleet/fleet-org-cli.test.js test/eval-lab/dataset-neutralize.test.js test/eval-lab/arms-score-stats.test.js test/eval-lab/run-report.test.js test/eval-lab/router.test.js test/eval-lab/arm-ollama.test.js test/eval-lab/import-independent.test.js test/cli/eval-lab-cli.test.js test/dnr/ir-and-outputs.test.js test/dnr/logs-and-hunt.test.js test/dnr/window-store-view.test.js test/dnr/exploit-correlation.test.js test/cli/dnr-cli.test.js test/proof-fabric/core.test.js test/proof-fabric/container.test.js test/proof-fabric/generate.test.js test/proof-fabric/siblings.test.js test/proof-fabric/generate-python.test.js test/cli/proof-lifecycle-demo.test.js test/mcp-proof.test.js test/proof-fabric/fix-store-runner.test.js test/proof-fabric/fixtures.test.js test/cli/proof-fabric-cli.test.js test/rule-compiler/core.test.js test/rule-compiler/synthesis.test.js test/rule-compiler/structure.test.js test/cli/rule-compiler-cli.test.js test/fleet/fleet-graph.test.js test/fleet/fleet-manifest.test.js test/fleet/fleet-cli.test.js test/artifact/safe-tar.test.js test/artifact/image-archive.test.js test/artifact/filesystem.test.js test/artifact/layer-secrets.test.js test/artifact/inventory.test.js test/artifact/vuln-correlate.test.js test/artifact/signature.test.js test/artifact/provenance-graph.test.js test/artifact/mismatch.test.js test/artifact/vex.test.js test/artifact/registry.test.js test/artifact/sources-cosign-evidence.test.js test/cli/artifact-sources-cli.test.js test/cli/artifact-provenance-cli.test.js test/witness-bundle.test.js",
89
+ "test:posture": "node --test test/contracts/root-cause-sweep.contract.test.js test/contracts/model-validation.contract.test.js test/contracts/agentic-discovery.contract.test.js test/contracts/local-models.contract.test.js test/contracts/dependency-finding.contract.test.js test/contracts/taint-flow.contract.test.js test/contracts/runtime-corroboration.contract.test.js test/compliance-coverage.test.js test/contracts/blast-radius.contract.test.js test/contracts/federation.contract.test.js test/contracts/eval-lab-report.contract.test.js test/contracts/fleet.contract.test.js test/contracts/rule-compiler.contract.test.js test/contracts/release-assurance.contract.test.js test/contracts/dnr.contract.test.js test/contracts/strategic-metrics.contract.test.js test/contracts/exploit-proof.contract.test.js test/contracts/artifact-provenance.contract.test.js test/dnr/artifact-join.test.js test/rule-pack-signing.test.js 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/temp-leak-guard.test.js test/release-workflow.test.js test/release-workflow-structure.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/ollama-provider.test.js test/ollama-capabilities.test.js test/ollama-offline-egress.test.js test/ollama-fix-proposal.test.js test/ollama-explain-proposal.test.js test/ollama-poc-proposal.test.js test/ollama-model-probe.test.js test/ollama-agent-tools.test.js test/ollama-agent-loop.test.js test/ollama-e2e.test.js test/ollama-oom-feedback.test.js test/ollama-doc-drift.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/models.test.js test/cli/setup-llm.test.js test/cli/fix-retry.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 test/posture/assurance-baseline.test.js test/posture/assurance-contracts.test.js test/posture/assurance-config.test.js test/evidence-issuer.test.js test/load-factor.test.js test/fleet/job-store.test.js test/fleet/enterprise-graph.test.js test/fleet/discover-edges.test.js test/fleet/code-boundaries.test.js test/fleet/job-runner.test.js test/fleet/fleet-org-cli.test.js test/eval-lab/dataset-neutralize.test.js test/eval-lab/arms-score-stats.test.js test/eval-lab/run-report.test.js test/eval-lab/router.test.js test/eval-lab/arm-ollama.test.js test/eval-lab/import-independent.test.js test/cli/eval-lab-cli.test.js test/dnr/ir-and-outputs.test.js test/dnr/logs-and-hunt.test.js test/dnr/window-store-view.test.js test/dnr/exploit-correlation.test.js test/cli/dnr-cli.test.js test/proof-fabric/core.test.js test/proof-fabric/container.test.js test/proof-fabric/generate.test.js test/proof-fabric/siblings.test.js test/proof-fabric/generate-python.test.js test/proof-fabric/generate-haskell.test.js test/cli/proof-lifecycle-demo.test.js test/mcp-proof.test.js test/proof-fabric/fix-store-runner.test.js test/proof-fabric/fixtures.test.js test/cli/proof-fabric-cli.test.js test/rule-compiler/core.test.js test/rule-compiler/synthesis.test.js test/rule-compiler/structure.test.js test/cli/rule-compiler-cli.test.js test/fleet/fleet-graph.test.js test/fleet/fleet-manifest.test.js test/fleet/fleet-cli.test.js test/artifact/safe-tar.test.js test/artifact/image-archive.test.js test/artifact/filesystem.test.js test/artifact/layer-secrets.test.js test/artifact/inventory.test.js test/artifact/vuln-correlate.test.js test/artifact/signature.test.js test/artifact/provenance-graph.test.js test/artifact/mismatch.test.js test/artifact/vex.test.js test/artifact/registry.test.js test/artifact/sources-cosign-evidence.test.js test/cli/artifact-sources-cli.test.js test/cli/artifact-provenance-cli.test.js test/witness-bundle.test.js",
90
90
  "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-rust.test.js test/rust-taint-flow.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 test/sard-leakage-pipeline.test.js test/sard-split-scoring.test.js test/sard-llm-isolation.test.js test/sard-mutation-adversarial.test.js test/sard-baseline-adaptive-tolerance.test.js test/sard-independent-holdout.test.js test/sard-flow-aware-scoring.test.js test/sard-macro-score-support-floor.test.js test/sard-php-split.test.js test/parser-java-nary-concat.test.js test/sard-naive-baseline.test.js test/field-taint-cross-method.test.js test/field-taint-engine-unit.test.js test/coercion-sanitizer-kill.test.js test/constant-propagation-path-sensitivity.test.js test/parser-java-assignments.test.js test/catalog-java-sard.test.js test/parser-cs-juliet-shapes.test.js test/catalog-cs-sard-p2.test.js test/sard-cwe-key-merge.test.js test/parser-php-backtick.test.js test/parser-php-include.test.js test/php-include-merge.test.js test/parser-php-array-field-taint.test.js test/parser-php-cond-assign.test.js test/parser-rust-redos.test.js test/multi-sink-taint-chain.test.js test/static-field-cross-class-call-string.test.js test/regex-guard-narrowing.test.js test/object-instance-field-taint.test.js test/param-type-inference.test.js test/smt-path-feasibility.test.js test/cross-service-taint.test.js test/dataflow-expr-taint-scaling.test.js test/evaluation/guard-dominance.test.js test/evaluation/engine-mechanisms.test.js test/rx-exec-receiver.test.js test/incremental-dependency.test.js test/incremental-integrity.test.js test/demand-query.test.js test/ir-cache.test.js test/canonicalize-parity.test.js",
91
91
  "test:mcp": "node --test test/mcp.test.js test/mcp-apply-fix-multifile.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 test/capabilities/tools.test.js",
92
- "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/git-history-batch.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",
92
+ "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/git-history-batch.test.js test/default-scan-drift.test.js test/bundle-optional-deps.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",
93
93
  "test:lineage": "node --test test/lineage/analysis-completion.test.js 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 test/lineage/runtime-assurance.test.js test/lineage/runtime-edge-states.test.js test/lineage/runtime-explorer-view.test.js test/cli/runtime-explorer-cli.test.js test/cli/runtime-identity-cli.test.js test/cli/runtime-twin-cli.test.js test/lineage/cut-planner.test.js test/lineage/scc.test.js test/lineage/scc-solver.test.js test/graph/graph-views.test.js test/lineage/dag07-completion.test.js test/lineage/owned-build.test.js test/dataflow/boundary-propagation.test.js test/lineage/boundary-contract.test.js test/lineage/correlation-v2.test.js test/lineage/path-control-evidence.test.js test/lineage/smt-z3-backend.test.js test/cli/dag-commands.test.js",
94
94
  "test:bench-modules": "node --test test/phase4-harness.test.js test/pipeline.test.js test/proof-corpus-lib.test.js test/proof-corpus-runner.test.js",
95
95
  "test:server": "node --test test/server/graph-loader.test.js test/server/security.test.js test/server/routes.test.js test/server/http-server.test.js test/server/cmd-explore.test.js test/server/cmd-dataflow-export.test.js test/server/static-assets.test.js test/server/dataflow-scenario-cli.test.js test/server/dataflow-impact-cli.test.js",
@@ -132,7 +132,7 @@ export async function cmdProof(args, root) {
132
132
  function doctor(args) {
133
133
  const tools = hostTools();
134
134
  const rows = LANGUAGES.map((l) => ({ lang: l, ...languageSupport(l, tools) }));
135
- const envs = ['javascript', 'python'].map((l) => ({ lang: l, ...selectEnvironment({ lang: l }) }));
135
+ const envs = ['javascript', 'python', 'haskell'].map((l) => ({ lang: l, ...selectEnvironment({ lang: l }) }));
136
136
  if (args.flags.json) { console.log(JSON.stringify({ tools, languages: rows, environments: envs }, null, 2)); return 0; }
137
137
  console.log('Proof fabric doctor');
138
138
  for (const r of rows) console.log(` ${r.lang.padEnd(11)} ${r.supported ? 'supported' : `unsupported (${r.reason})`}`);
@@ -20,9 +20,9 @@ import { scrubEnv } from '../../sandbox/trust-domains.js';
20
20
  export const CONTAINER_ROOT = '/work';
21
21
  // the image's own toolchain directories matter: the Temurin image puts the JDK at /opt/java/openjdk/bin and sets it through ENV, which a
22
22
  // bare PATH override throws away (found by the first run against a real engine: `javac: not found`)
23
- const CONTAINER_PATH = '/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin';
23
+ const CONTAINER_PATH = '/opt/java/openjdk/bin:/opt/ghc/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin';
24
24
  // the interpreter names inside the image; the host paths the runner uses locally mean nothing in there
25
- export const CONTAINER_TOOLS = Object.freeze({ node: 'node', python: 'python3', java: 'java', javac: 'javac', cc: 'gcc', dotnet: 'dotnet' });
25
+ export const CONTAINER_TOOLS = Object.freeze({ node: 'node', python: 'python3', java: 'java', javac: 'javac', cc: 'gcc', dotnet: 'dotnet', ghc: 'ghc', runghc: 'runghc' });
26
26
 
27
27
  export function containerArgs({ image, name, hostRoot, argv, env = {}, limits, user = null }) {
28
28
  if (!image || !name || !hostRoot || !Array.isArray(argv) || !argv.length) throw new Error('container run needs image, name, root and argv');
@@ -0,0 +1,205 @@
1
+ // Reproducer generation for Haskell (PRD 1), the third language of `generate.js`. Same contract as JavaScript and Python: a
2
+ // DETERMINISTIC proposal built from the flagged file alone, then run through the ordinary runner, oracle, 3-of-3 repetition and
3
+ // independent replay. A generated reproducer is a proposal that execution either confirms or does not.
4
+ //
5
+ // The program is run by GHC's interpreter (`ghc -e`), not compiled. Why: it needs no C compiler and no linker (so no dependence on
6
+ // the platform's developer tools), it leaves no object files or binaries to account for, it starts in about half a second where a
7
+ // compile-then-run takes a second or more, and there is one process tree to confine instead of a build stage followed by a run
8
+ // stage. Interpreted bytecode calls the same installed libraries a compiled program would, so a shell string reaches the same
9
+ // `System.Process` either way. The tradeoff is stated, not hidden: a program whose behaviour depends on compiled code (FFI, an
10
+ // optimisation-sensitive race) is refused, and `-O` is never in play. A hand-written reproducer may still use `build`/`run` with
11
+ // `{{GHC}}` to compile; both paths run under the same sandbox, timeout and output cap.
12
+ //
13
+ // Two shapes, as in the other languages:
14
+ // script the file reads `getArgs`: it is run as `:main "<payload>"`, so the payload arrives as the first argument;
15
+ // function a top-level function around the flagged line that has a type signature of `String`/`FilePath` parameters and an `IO`
16
+ // result: `ghc -e 'fn "<payload>" ...'` loads the module with every top-level name in scope (the module need not export
17
+ // it) and calls it with the payload in every parameter.
18
+ //
19
+ // Only what the proof environment can load is accepted: the file's imports must be modules of the packages that ship with GHC (the
20
+ // global package database, read from the installed GHC) or other `.hs` files in the repository. A web framework, a database binding
21
+ // or any Hackage package is refused with the package named where it is known. Template Haskell, quasi-quotes, CPP, the foreign
22
+ // function interface and compiler-plugin options are refused too: they run code at load time, before the payload is involved.
23
+ //
24
+ // Classes: command injection (CWE-78) and path traversal by a write (CWE-22). SSRF (CWE-918) is refused for Haskell on purpose: no
25
+ // HTTP client ships with GHC, so a request-making program necessarily imports a package the stdlib-only rule already refuses, and
26
+ // nothing could be proven honestly. Nothing is executed on a refusal.
27
+ import fs from 'node:fs';
28
+ import path from 'node:path';
29
+ import { spawnSync } from 'node:child_process';
30
+ import { parseHaskell } from '../../language/haskell-parser.js';
31
+ import { validateReproducer } from './reproducer.js';
32
+ import { hostTools } from './runner.js';
33
+
34
+ const MAX_SOURCE = 256 * 1024;
35
+ const MAX_FILES = 8;
36
+ const fail = (reason, extra = {}) => ({ ok: false, reason, ...extra });
37
+
38
+ // Well-known packages that are NOT part of a GHC install, by module prefix, so a refusal can name the package to install.
39
+ const THIRD_PARTY = [
40
+ ['Web.Scotty', 'scotty'], ['Network.Wai', 'wai'], ['Network.HTTP.Types', 'http-types'], ['Network.HTTP.Client', 'http-client'],
41
+ ['Network.HTTP.Simple', 'http-conduit'], ['Network.HTTP.Conduit', 'http-conduit'], ['Network.Wreq', 'wreq'], ['Network.Socket', 'network'],
42
+ ['Servant', 'servant'], ['Yesod', 'yesod'], ['Snap', 'snap'], ['Happstack', 'happstack-server'], ['Data.Aeson', 'aeson'],
43
+ ['Database.SQLite.Simple', 'sqlite-simple'], ['Database.PostgreSQL.Simple', 'postgresql-simple'], ['Database.Persist', 'persistent'],
44
+ ['Database.MySQL', 'mysql-simple'], ['System.Random', 'random'], ['Data.Vector', 'vector'], ['Data.Hashable', 'hashable'],
45
+ ['Data.HashMap', 'unordered-containers'], ['Control.Lens', 'lens'], ['Test.', 'a test framework'], ['Turtle', 'turtle'],
46
+ ['Shelly', 'shelly'], ['System.Process.Typed', 'typed-process'], ['Conduit', 'conduit'], ['Control.Monad.Logger', 'monad-logger'],
47
+ ['Options.Applicative', 'optparse-applicative'], ['Data.Text.Lazy.Builder', null],
48
+ ];
49
+
50
+ const libCache = new Map();
51
+ /** The modules the installed GHC exposes from its global package database (what a program can import with no extra packages). */
52
+ export function bootModuleSet(ghc) {
53
+ if (libCache.has(ghc)) return libCache.get(ghc);
54
+ let set = null;
55
+ try {
56
+ const r = spawnSync(ghc, ['--print-libdir'], { encoding: 'utf8', timeout: 10_000 });
57
+ const dir = r.status === 0 ? path.join(r.stdout.trim(), 'package.conf.d') : null;
58
+ if (dir && fs.existsSync(dir)) {
59
+ set = new Set();
60
+ for (const f of fs.readdirSync(dir)) {
61
+ if (!f.endsWith('.conf')) continue;
62
+ const text = fs.readFileSync(path.join(dir, f), 'utf8');
63
+ if (/^exposed:\s*False/m.test(text)) continue;
64
+ const m = /^exposed-modules:\s*\n?([\s\S]*?)(?=^\S)/m.exec(text);
65
+ if (!m) continue;
66
+ for (const tok of m[1].split(/[\s,]+/)) if (/^[A-Z][\w']*(?:\.[A-Z][\w']*)*$/.test(tok)) set.add(tok);
67
+ }
68
+ if (!set.has('Prelude')) set = null; // a database that does not even list Prelude was not read correctly
69
+ }
70
+ } catch { set = null; }
71
+ libCache.set(ghc, set);
72
+ return set;
73
+ }
74
+
75
+ function readInside(root, rel) {
76
+ let real; try { real = fs.realpathSync(path.resolve(root, rel)); } catch { return null; }
77
+ const base = fs.realpathSync(root);
78
+ if (!(real === base || real.startsWith(base + path.sep))) return null;
79
+ const st = fs.statSync(real);
80
+ return st.isFile() && st.size <= MAX_SOURCE ? { real, text: fs.readFileSync(real, 'utf8') } : null;
81
+ }
82
+
83
+ /** Split a type on its top-level arrows (arrows inside parentheses or brackets belong to a function-typed argument). */
84
+ function splitArrows(type) {
85
+ const parts = []; let depth = 0; let cur = '';
86
+ for (let i = 0; i < type.length; i++) {
87
+ const c = type[i];
88
+ if ('([{'.includes(c)) depth++; else if (')]}'.includes(c)) depth--;
89
+ if (depth === 0 && c === '-' && type[i + 1] === '>') { parts.push(cur.trim()); cur = ''; i++; continue; }
90
+ cur += c;
91
+ }
92
+ parts.push(cur.trim());
93
+ return parts;
94
+ }
95
+
96
+ // Compile-time code execution and options that change what runs before the payload is involved.
97
+ function loadTimeHazard(text) {
98
+ if (/\{-#\s*LANGUAGE[^#]*\b(?:TemplateHaskell|TemplateHaskellQuotes|QuasiQuotes|CPP|ForeignFunctionInterface|CApiFFI)\b/i.test(text)) return 'it enables Template Haskell, quasi-quotes, CPP or the foreign function interface, which run or require code at load time';
99
+ if (/\{-#\s*OPTIONS(?:_GHC)?\b[^#]*(?:-fplugin|-pgm|-opt[a-zA-Z]|-F\b|-cpp|-fobject-code)/i.test(text)) return 'its OPTIONS_GHC pragma names a plugin, a preprocessor or an external program';
100
+ if (/^\s*foreign\s+(?:import|export)\b/m.test(text)) return 'it uses the foreign function interface';
101
+ return null;
102
+ }
103
+
104
+ function classify(mod, pkg, boot) {
105
+ if (pkg) return { ok: false, name: String(pkg).replace(/^"|"$/g, '') };
106
+ if (boot.has(mod)) return { ok: true };
107
+ for (const [prefix, name] of THIRD_PARTY) if (mod === prefix || mod.startsWith(prefix.endsWith('.') ? prefix : `${prefix}.`)) return { ok: false, name: name ?? mod };
108
+ return { ok: false, name: mod };
109
+ }
110
+
111
+ /** @param {{finding: object, root: string, cls: {name: string, payload: string, oracle: object, network?: string, watch?: object, needsHs?: RegExp}, bootModules?: Set<string>}} o */
112
+ export function generateHaskellReproducer({ finding, root, cls, bootModules }) {
113
+ const rel = String(finding.file);
114
+ if (cls.name === 'ssrf') return fail('ssrf: no HTTP client ships with GHC, so any program that makes a request imports a package outside the proof environment; this class is not proven for Haskell');
115
+ const src = readInside(root, rel);
116
+ if (!src) return fail('the flagged file is missing, outside the repository, or too large');
117
+ const hazard = loadTimeHazard(src.text);
118
+ if (hazard) return fail(`the flagged file is refused: ${hazard}`);
119
+ const info = parseHaskell(src.text);
120
+ if (!info || info.status !== 'parsed') return fail('the flagged file could not be parsed as Haskell');
121
+ const lines = src.text.split('\n');
122
+ const sinkLine = lines[finding.line - 1] ?? '';
123
+ const around = lines.slice(Math.max(0, finding.line - 3), finding.line + 2).join('\n');
124
+ if (cls.needsHs && !cls.needsHs.test(sinkLine) && !cls.needsHs.test(around)) return fail(`${cls.name}: the flagged code is not a write, and this class is only proven for write sinks`);
125
+
126
+ const tools = hostTools();
127
+ const boot = bootModules ?? (tools.ghc ? bootModuleSet(tools.ghc) : null);
128
+ if (!boot) return fail('no working GHC was found to list the modules the proof environment can import (install ghc, or run `agentic-security proof doctor`)');
129
+
130
+ // the entry module is placed at its module path so that other modules can import it; Main goes to Main.hs
131
+ const modName = info.module?.name ?? 'Main';
132
+ const entry = `${modName.replaceAll('.', '/')}.hs`;
133
+ const rootReal = fs.realpathSync(root);
134
+ const entryDir = path.dirname(src.real);
135
+ const modRel = modName.replaceAll('.', path.sep);
136
+ const srcRoot = src.real.endsWith(`${modRel}.hs`) ? src.real.slice(0, src.real.length - modRel.length - 3) : `${entryDir}${path.sep}`;
137
+ const searchRoots = [...new Set([srcRoot.replace(/[\\/]$/, ''), ...['src', 'app', 'lib', ''].map((d) => path.join(rootReal, d))])];
138
+ const sources = {}; const external = []; const seen = new Set([modName]);
139
+ let count = 0;
140
+ const visit = (imports) => {
141
+ for (const imp of imports) {
142
+ const mod = imp.module;
143
+ if (seen.has(mod)) continue;
144
+ seen.add(mod);
145
+ let local = null;
146
+ for (const base of searchRoots) { const cand = path.join(base, `${mod.replaceAll('.', '/')}.hs`); const r = readInside(root, path.relative(rootReal, cand)); if (r) { local = r; break; } }
147
+ if (local && !imp.package) {
148
+ if (++count > MAX_FILES) return fail(`the file pulls in more than ${MAX_FILES} repository modules`);
149
+ const dep = parseHaskell(local.text);
150
+ if (!dep || dep.status !== 'parsed') return fail(`the module ${mod} could not be parsed as Haskell`);
151
+ const h = loadTimeHazard(local.text); if (h) return fail(`the module ${mod} is refused: ${h}`);
152
+ sources[`${mod.replaceAll('.', '/')}.hs`] = path.relative(rootReal, local.real);
153
+ const r = visit(dep.imports ?? []); if (r) return r;
154
+ continue;
155
+ }
156
+ const c = classify(mod, imp.package, boot);
157
+ if (!c.ok) external.push(c.name);
158
+ }
159
+ return null;
160
+ };
161
+ const bad = visit(info.imports ?? []);
162
+ if (bad) return bad;
163
+ if (external.length) return fail(`the flagged code needs ${[...new Set(external)].slice(0, 4).join(', ')}, which is not available in the proof environment; only the packages that ship with GHC and files in the repository can be loaded`, { missing: [...new Set(external)] });
164
+ sources[entry] = rel;
165
+
166
+ const assumptions = [];
167
+ const base = { schema: 'agentic-security/reproducer', version: 1, findingId: String(finding.stableId ?? finding.id ?? 'generated'), lang: 'haskell', oracle: cls.oracle, network: cls.network ?? 'none', ...(cls.watch ? { watch: cls.watch } : {}) };
168
+ if (cls.watch) assumptions.push('the write target is assumed to be one directory below the working directory (the payload is ../escaped.txt); if the code uses another base, the proof will not confirm it');
169
+ const ghcRun = (expr) => ['{{GHC}}', '-ignore-dot-ghci', '-e', expr, entry];
170
+ const literal = (s) => JSON.stringify(s); // payloads are fixed strings with no quote or backslash; this is a plain Haskell string literal
171
+
172
+ // shape 1: a program that reads its payload from the command line
173
+ const hasMain = (info.functions ?? []).some((f) => f.scope === 'top' && f.name === 'main');
174
+ if (/\bgetArgs\b/.test(src.text) && hasMain) {
175
+ assumptions.push('the payload is passed as the first and only command-line argument; a program that expects other arguments will not reach the flagged line');
176
+ const reproducer = { ...base, sources, run: ghcRun(`:main ${literal(cls.payload)}`) };
177
+ const errs = validateReproducer(reproducer);
178
+ return errs.length ? fail(`the generated reproducer is invalid: ${errs[0]}`) : { ok: true, reproducer, basis: { shape: 'script', class: cls.name, entry: rel, line: finding.line, assumptions } };
179
+ }
180
+
181
+ // shape 2: a top-level function around the flagged line
182
+ const fn = (info.functions ?? []).filter((f) => f.scope === 'top' && f.name !== 'main' && /^[a-z_][\w']*$/.test(f.name)).find((f) => {
183
+ const end = Math.max(f.span.endLine, ...(f.clauses ?? []).map((c) => c.span?.endLine ?? 0));
184
+ return f.span.startLine <= finding.line && end >= finding.line;
185
+ });
186
+ if (!fn) return fail('the flagged line is not inside a top-level function, and the file does not read getArgs in a main');
187
+ const sig = (info.signatures ?? []).find((s) => s.scope === 'top' && s.names.includes(fn.name));
188
+ if (!sig) return fail(`${fn.name} has no type signature, so the proof cannot tell what to pass it`);
189
+ const sigText = lines.slice(sig.span.startLine - 1, sig.span.endLine).join(' ');
190
+ const m = new RegExp(`${fn.name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[^:]*::\\s*([\\s\\S]*)$`).exec(sigText);
191
+ if (!m) return fail(`the type signature of ${fn.name} could not be read`);
192
+ const type = m[1].replace(/--.*$/, '').trim();
193
+ if (type.includes('=>') || /\bforall\b/.test(type)) return fail(`${fn.name} is polymorphic or constrained (${type.slice(0, 60)}), so the proof cannot choose its arguments`);
194
+ const parts = splitArrows(type);
195
+ const result = parts[parts.length - 1]; const params = parts.slice(0, -1);
196
+ if (!/^IO\b/.test(result)) return fail(`${fn.name} returns ${result.slice(0, 40)}, not IO, so calling it would not perform the flagged operation`);
197
+ if (!params.length) return fail(`${fn.name} takes no parameters, so the payload has no way in`);
198
+ const bad2 = params.find((p) => !/^(?:String|FilePath|\[Char\])$/.test(p));
199
+ if (bad2) return fail(`${fn.name} takes a parameter of type ${bad2.slice(0, 40)}; only String and FilePath can be filled with a payload`);
200
+ assumptions.push('the payload is passed in every parameter (a String has no request-like stand-in), which is an approximation of how the function is really called');
201
+ const call = `${fn.name} ${params.map(() => literal(cls.payload)).join(' ')} >>= \\_ -> return ()`;
202
+ const reproducer = { ...base, sources, run: ghcRun(call) };
203
+ const errs = validateReproducer(reproducer);
204
+ return errs.length ? fail(`the generated reproducer is invalid: ${errs[0]}`) : { ok: true, reproducer, basis: { shape: 'function', class: cls.name, entry: rel, line: finding.line, function: `${fn.name}(${params.length} String)`, assumptions } };
205
+ }
@@ -6,7 +6,7 @@
6
6
  // independent replay as any other. A generated reproducer is not a verdict; it is a proposal that is either confirmed by execution
7
7
  // or not.
8
8
  //
9
- // What this is not: a general exploit generator. It handles JavaScript (here) and Python (`generate-python.js`), and only code the proof environment can actually load:
9
+ // What this is not: a general exploit generator. It handles JavaScript (here), Python (`generate-python.js`) and Haskell (`generate-haskell.js`), and only code the proof environment can actually load:
10
10
  // the file's imports must be Node built-ins or relative files inside the repository (a package from node_modules is not there in
11
11
  // the sandbox, so a handler that needs `express` is refused, with the package named). Anything outside that returns `{ ok: false }`
12
12
  // with the reason, and nothing is executed.
@@ -27,10 +27,11 @@ import { builtinModules } from 'node:module';
27
27
  import { parse } from '@babel/parser';
28
28
  import { validateReproducer } from './reproducer.js';
29
29
  import { generatePythonReproducer } from './generate-python.js';
30
+ import { generateHaskellReproducer } from './generate-haskell.js';
30
31
 
31
32
  const CLASSES = {
32
33
  'CWE-78': { name: 'command-injection', payload: 'x; touch {{CANARY:command}}', oracle: { type: 'command_execution', params: { canary: 'command' } } },
33
- 'CWE-22': { needsPy: /\bopen\s*\([^)]*['"][wax]b?\+?['"]|\.write_(?:text|bytes)\s*\(|\bshutil\.(?:copy|move)/, name: 'path-traversal', payload: '../escaped.txt', oracle: { type: 'filesystem_mutation', params: { canary: 'fs' } }, watch: { fs: 'escaped.txt' }, needs: /\b(?:writeFile|writeFileSync|appendFile|appendFileSync|createWriteStream)\b/ },
34
+ 'CWE-22': { needsPy: /\bopen\s*\([^)]*['"][wax]b?\+?['"]|\.write_(?:text|bytes)\s*\(|\bshutil\.(?:copy|move)/, name: 'path-traversal', payload: '../escaped.txt', oracle: { type: 'filesystem_mutation', params: { canary: 'fs' } }, watch: { fs: 'escaped.txt' }, needsHs: /\b(?:writeFile|appendFile|copyFile|copyFileWithMetadata|renameFile|openBinaryFile)\b|\b(?:openFile|withFile|withBinaryFile)\b[^\n]*\b(?:WriteMode|AppendMode|ReadWriteMode)\b/, needs: /\b(?:writeFile|writeFileSync|appendFile|appendFileSync|createWriteStream)\b/ },
34
35
  'CWE-918': { name: 'ssrf', payload: '{{CALLBACK_URL}}', oracle: { type: 'outbound_callback' }, network: 'callback' },
35
36
  };
36
37
  const MAX_SOURCE = 256 * 1024;
@@ -138,9 +139,11 @@ export function generateReproducer({ finding, root }) {
138
139
  if (!cls) return fail(`no payload and oracle exist for ${cwe ?? 'this finding'}; supported: ${Object.keys(CLASSES).join(', ')} (others need a database, a deserializer or a native harness)`);
139
140
  const rel = String(finding?.file ?? '');
140
141
  const isPy = /\.py$/i.test(rel);
141
- if (!isPy && !/\.(?:js|mjs|cjs)$/i.test(rel)) return fail(`no harness builder for ${path.extname(rel) || 'this file type'}; JavaScript and Python only`);
142
+ const isHs = /\.hs$/i.test(rel);
143
+ if (!isPy && !isHs && !/\.(?:js|mjs|cjs)$/i.test(rel)) return fail(`no harness builder for ${path.extname(rel) || 'this file type'}; JavaScript, Python and Haskell only`);
142
144
  if (!Number.isInteger(finding?.line)) return fail('the finding has no line number');
143
145
  if (isPy) return generatePythonReproducer({ finding, root, cls });
146
+ if (isHs) return generateHaskellReproducer({ finding, root, cls });
144
147
  const src = readSource(root, rel);
145
148
  if (!src) return fail('the flagged file is missing, outside the repository, or too large');
146
149
  const ast = parseSource(src.text);
@@ -8,12 +8,12 @@ import { validateAttackFacts } from '../dnr/attack-facts.js';
8
8
 
9
9
  const REPRODUCER_SCHEMA = 'agentic-security/reproducer';
10
10
  const REPRODUCER_VERSION = 1;
11
- export const LANGUAGES = Object.freeze(['javascript', 'typescript', 'python', 'java', 'c', 'cpp', 'csharp']);
11
+ export const LANGUAGES = Object.freeze(['javascript', 'typescript', 'python', 'java', 'c', 'cpp', 'csharp', 'haskell']);
12
12
  export const MAX_FILES = 64;
13
13
  export const MAX_FILE_BYTES = 256 * 1024;
14
14
  const MAX_TOTAL_BYTES = 1024 * 1024;
15
15
  const PLACEHOLDER_RE = /\{\{([A-Z_]+)(?::([a-z0-9_-]{1,32}))?\}\}/g;
16
- const ALLOWED_PLACEHOLDERS = new Set(['NONCE', 'SECRET', 'CANARY', 'CALLBACK_URL', 'CALLBACK_PORT', 'ROOT', 'NODE', 'PYTHON', 'JAVA', 'JAVAC', 'CC']);
16
+ const ALLOWED_PLACEHOLDERS = new Set(['NONCE', 'SECRET', 'CANARY', 'CALLBACK_URL', 'CALLBACK_PORT', 'ROOT', 'NODE', 'PYTHON', 'JAVA', 'JAVAC', 'CC', 'GHC', 'RUNGHC']);
17
17
 
18
18
  export function isSafeRelPath(rel) {
19
19
  if (typeof rel !== 'string' || !rel || rel.length > 200) return false;
@@ -105,6 +105,8 @@ export function substitute(text, ctx) {
105
105
  case 'JAVA': return ctx.tools.java ?? whole;
106
106
  case 'JAVAC': return ctx.tools.javac ?? whole;
107
107
  case 'CC': return ctx.tools.cc ?? whole;
108
+ case 'GHC': return ctx.tools.ghc ?? whole;
109
+ case 'RUNGHC': return ctx.tools.runghc ?? whole;
108
110
  default: return whole;
109
111
  }
110
112
  });
@@ -24,13 +24,13 @@ export const DEFAULT_LIMITS = Object.freeze({
24
24
 
25
25
  const CONTAINER_IMAGES = Object.freeze({
26
26
  javascript: 'node:24-slim', typescript: 'node:24-slim', python: 'python:3-slim', java: 'eclipse-temurin:21',
27
- c: 'gcc:latest', cpp: 'gcc:latest', csharp: 'mcr.microsoft.com/dotnet/sdk:8.0',
27
+ c: 'gcc:latest', cpp: 'gcc:latest', csharp: 'mcr.microsoft.com/dotnet/sdk:8.0', haskell: 'haskell:9',
28
28
  });
29
29
 
30
30
  const SIGNALS = { 134: 'SIGABRT', 135: 'SIGBUS', 136: 'SIGFPE', 132: 'SIGILL', 139: 'SIGSEGV' };
31
31
 
32
32
  // only language toolchains are probed; the container engine has its own, richer health check (`container.js`)
33
- const PROBED_TOOLS = new Set(['java', 'javac', 'python3', 'cc', 'gcc', 'dotnet']);
33
+ const PROBED_TOOLS = new Set(['java', 'javac', 'python3', 'cc', 'gcc', 'dotnet', 'ghc', 'runghc']);
34
34
  const probeCache = new Map();
35
35
  /** A launcher that exists is not a toolchain that works: macOS ships /usr/bin/java and /usr/bin/python3 as stubs that only prompt for an
36
36
  * install. A tool counts only if it answers its version flag, within a short timeout, with exit 0. */
@@ -61,12 +61,12 @@ function findTool(name, pathEnv = process.env.PATH || '') {
61
61
  }
62
62
 
63
63
  export function hostTools() {
64
- return { node: process.execPath, python: findTool('python3'), java: findTool('java'), javac: findTool('javac'), cc: findTool('cc') || findTool('gcc'), dotnet: findTool('dotnet') };
64
+ return { node: process.execPath, python: findTool('python3'), java: findTool('java'), javac: findTool('javac'), cc: findTool('cc') || findTool('gcc'), dotnet: findTool('dotnet'), ghc: findTool('ghc'), runghc: findTool('runghc') };
65
65
  }
66
66
 
67
67
  /** Language -> tools it needs. Missing tools make the language `unsupported` with a typed reason, never a pass. */
68
68
  export function languageSupport(lang, tools = hostTools()) {
69
- const need = { javascript: ['node'], typescript: ['node'], python: ['python'], java: ['java', 'javac'], c: ['cc'], cpp: ['cc'], csharp: ['dotnet'] }[lang];
69
+ const need = { javascript: ['node'], typescript: ['node'], python: ['python'], java: ['java', 'javac'], c: ['cc'], cpp: ['cc'], csharp: ['dotnet'], haskell: ['ghc', 'runghc'] }[lang];
70
70
  if (!need) return { supported: false, reason: `unsupported language: ${lang}` };
71
71
  const missing = need.filter((t) => !tools[t]);
72
72
  return missing.length ? { supported: false, reason: `missing toolchain: ${missing.join(', ')}` } : { supported: true, reason: null };