@clear-capabilities/agentic-security-scanner 0.158.0 → 0.160.0
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.
- package/CHANGELOG.md +39 -0
- package/dist/1919.index.js +5 -2
- package/dist/2862.index.js +29 -9
- package/dist/3531.index.js +1 -1
- package/dist/4171.index.js +4 -4
- package/dist/{8551.index.js → 7033.index.js} +415 -22
- package/dist/9560.index.js +3 -1
- package/dist/agentic-security.mjs +15 -15
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/package.json +11 -6
- package/src/engine.js +6 -1
- package/src/language/CLAUDE.md +48 -1
- package/src/language/assurance.js +21 -4
- package/src/language/context.js +2 -0
- package/src/language/cvss.js +91 -0
- package/src/language/fix-lifecycle.js +114 -21
- package/src/language/haskell-adapter.js +4 -3
- package/src/language/haskell-advisory-feed.js +15 -0
- package/src/language/haskell-boundaries.js +220 -0
- package/src/language/haskell-cpp.js +460 -0
- package/src/language/haskell-ir.js +6 -3
- package/src/language/haskell-models.js +4 -3
- package/src/language/haskell-parser.js +122 -38
- package/src/language/haskell-sca.js +10 -6
- package/src/language/haskell-supply.js +42 -8
- package/src/language/haskell-web.js +128 -23
- package/src/language/nix-advisory-feed.js +275 -0
- package/src/language/nix-fix.js +162 -24
- package/src/language/nix-ir.js +16 -12
- package/src/language/nix-sca.js +71 -12
- package/src/language/nixos-eval-forms.js +162 -0
- package/src/language/nixos-module-resolver.js +346 -51
- package/src/language/resolved-pass.js +57 -3
- package/src/lsp/server.js +5 -2
- package/src/mcp/tools.js +3 -1
- package/src/posture/fix-history.js +30 -3
- package/src/report/index.js +4 -1
- package/dist/1310.index.js +0 -3161
- package/dist/2376.index.js +0 -3151
- package/dist/3526.index.js +0 -1019
- package/dist/7310.index.js +0 -520
- package/dist/8520.index.js +0 -13
- package/dist/9091.index.js +0 -3135
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
6a0bcec455607538bd4485ce3b9cd5a266f51daf636b0ef6260cdc3bacf01776 agentic-security.mjs
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clear-capabilities/agentic-security-scanner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.160.0",
|
|
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",
|
|
@@ -64,7 +64,8 @@
|
|
|
64
64
|
"build": "node scripts/vendor-java-parser.mjs && ncc build bin/agentic-security.js -o dist --minify -e web-tree-sitter -e tree-sitter-wasms && rm -rf dist/compliance-frameworks && mkdir -p dist/compliance-frameworks && cp src/posture/compliance-frameworks/*.json dist/compliance-frameworks/ && node scripts/copy-frontend.mjs && mv dist/index.js dist/agentic-security.mjs && rm -f dist/package.json && chmod +x dist/agentic-security.mjs && node -e \"const fs=require('fs');const p='dist/agentic-security.mjs';const c=fs.readFileSync(p,'utf8');if(!c.startsWith('#!'))fs.writeFileSync(p,'#!/usr/bin/env node\\n'+c);\" && node -e \"const fs=require('fs');const c=require('crypto');const h=c.createHash('sha256').update(fs.readFileSync('dist/agentic-security.mjs')).digest('hex');fs.writeFileSync('dist/agentic-security.mjs.sha256',h+' agentic-security.mjs\\n');\"",
|
|
65
65
|
"prepare": "node scripts/prepare.mjs",
|
|
66
66
|
"prepublishOnly": "npm run build && node ../scripts/sync-scanner-changelog.mjs && node ../scripts/release-check.mjs",
|
|
67
|
-
"test": "node ../scripts/run-unit-tests.mjs
|
|
67
|
+
"test": "node ../scripts/run-unit-tests.mjs",
|
|
68
|
+
"test:extras": "AGENTIC_SECURITY_CPP_DATAFLOW=1 node --test test/cpp-dataflow.test.js && node --experimental-test-module-mocks --test test/fault-injection.test.js && node --experimental-test-module-mocks --test test/detector-fault-injection.test.js && node --experimental-test-module-mocks --test test/detector-fault-injection-k8s-admission.test.js && node --experimental-test-module-mocks --test test/lineage-fault-injection.test.js && npm run test:python",
|
|
68
69
|
"loop": "node ../scripts/loop-engineering/run.mjs",
|
|
69
70
|
"test:loop": "node --test --test-concurrency=1 ../scripts/loop-engineering/test/loop-manifest.test.js ../scripts/loop-engineering/test/loop-watchdog.test.js ../scripts/loop-engineering/test/loop-background.test.js ../scripts/loop-engineering/test/loop-dashboard.test.js ../scripts/loop-engineering/test/loop-evidence.test.js ../scripts/loop-engineering/test/loop-recovery.test.js ../scripts/loop-engineering/test/loop-remote.test.js ../scripts/loop-engineering/test/loop-runbook.test.js",
|
|
70
71
|
"test:python": "node ../scripts/run-python-tests.mjs",
|
|
@@ -72,21 +73,22 @@
|
|
|
72
73
|
"test:ollama-e2e": "AGENTIC_SECURITY_OLLAMA_E2E=1 node --test test/ollama-e2e.test.js",
|
|
73
74
|
"test:glob": "node --test test/glob-compat.test.js",
|
|
74
75
|
"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/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",
|
|
75
|
-
"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/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",
|
|
76
|
+
"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/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",
|
|
76
77
|
"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",
|
|
77
78
|
"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",
|
|
78
79
|
"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",
|
|
79
80
|
"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",
|
|
80
81
|
"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",
|
|
81
82
|
"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",
|
|
82
|
-
"test:haskell": "node --test test/haskell/haskell-injection.test.js test/haskell/haskell-ir.test.js test/haskell/haskell-manifests.test.js test/haskell/haskell-parser.test.js test/haskell/haskell-remediation.test.js test/haskell/haskell-resolved-graph.test.js test/haskell/haskell-sca.test.js test/haskell/haskell-advisory-feed.test.js test/haskell/haskell-security-rules.test.js test/haskell/haskell-taint.test.js",
|
|
83
|
-
"test:nix": "node --test test/nix/nix-build-trust.test.js test/nix/nix-eval-isolation.test.js test/nix/nix-input-inventory.test.js test/nix/nix-parser-ir.test.js test/nix/nix-remediation.test.js test/nix/nix-resolved-closure.test.js test/nix/nix-sca-patches.test.js test/nix/nix-haskell-closure-names.test.js test/nix/nix-script-taint.test.js test/nix/nix-secrets-store.test.js test/nix/nixos-hardening.test.js test/nix/nixos-module-resolution.test.js",
|
|
83
|
+
"test:haskell": "node --test test/haskell/haskell-injection.test.js test/haskell/haskell-ir.test.js test/haskell/haskell-manifests.test.js test/haskell/haskell-parser.test.js test/haskell/haskell-remediation.test.js test/haskell/haskell-resolved-graph.test.js test/haskell/haskell-sca.test.js test/haskell/haskell-sca-severity.test.js test/haskell/haskell-web-guards.test.js test/haskell/haskell-advisory-feed.test.js test/haskell/haskell-security-rules.test.js test/haskell/haskell-taint.test.js test/haskell/haskell-boundaries.test.js test/haskell/haskell-live-feed-scan.test.js",
|
|
84
|
+
"test:nix": "node --test test/nix/nix-build-trust.test.js test/nix/nix-eval-isolation.test.js test/nix/nix-input-inventory.test.js test/nix/nix-parser-ir.test.js test/nix/nix-remediation.test.js test/nix/nix-resolved-closure.test.js test/nix/nix-sca-patches.test.js test/nix/nix-sca-severity.test.js test/nix/nix-haskell-closure-names.test.js test/nix/nix-script-taint.test.js test/nix/nix-secrets-store.test.js test/nix/nixos-hardening.test.js test/nix/nixos-module-resolution.test.js test/nix/nix-fix-multifile.test.js test/nix/nixos-evaluator-forms.test.js test/nix/nix-advisory-feed.test.js",
|
|
84
85
|
"test:language": "node --test test/language/capability-ledger.test.js test/language/language-accuracy-regression.test.js test/language/language-aibom.test.js test/language/language-assurance.test.js test/language/language-bom.test.js test/language/language-compliance.test.js test/language/language-contracts.test.js test/language/language-corpora-integrity.test.js test/language/language-discovery.test.js test/language/language-doc-coverage.test.js test/language/language-evidence-posture.test.js test/language/language-explorer.test.js test/language/language-gap-fixes.test.js test/language/language-gap-fixes-2.test.js test/language/language-governance.test.js test/language/language-integrations.test.js test/language/language-llm-agent.test.js test/language/language-local-ai.test.js test/language/language-polyglot-bridges.test.js test/language/language-privacy-lineage.test.js test/language/language-proof-remediation.test.js test/language/language-report-formats.test.js test/language/language-secrets.test.js test/language/language-trust-boundary.test.js",
|
|
85
86
|
"test:language-stress": "node --test --test-concurrency=1 test/language/language-stress-offline.test.js",
|
|
86
87
|
"test:language-tools": "node --test test/haskell/haskell-web-auth.test.js test/haskell/haskell-support-gate.test.js",
|
|
87
88
|
"bench:language-support:check": "node ../bench/language-support/check.mjs",
|
|
89
|
+
"bench:live-feed": "node ../bench/live-feed/run.mjs",
|
|
88
90
|
"bench:language-support:perf": "node ../bench/language-support/perf.mjs",
|
|
89
|
-
"test:lifecycle": "node --test test/pre-bash-guard.test.js test/lsp-protocol-smoke.test.js test/ide-surfaces.test.js test/detector-liveness.test.js test/bench-watchdog.test.js test/ci-parity.test.js test/dead-code.test.js test/no-dead-modules.test.js test/no-orphan-scripts.test.js test/no-stray-state.test.js test/tree-integrity.test.js test/stop-hook.test.js test/plugin-self-check.test.js test/skills-registry.test.js test/bodyguard.test.js test/cache-invalidator-guard.test.js test/dispatch-pre-tool.test.js test/dispatch-user-prompt.test.js test/session-start-model-capture.test.js test/sandbox.test.js test/sandbox-escape.test.js test/ci-templates.test.js test/agent-mcp-tools.test.js test/triage-command.test.js test/no-orphan-tests.test.js test/supply-command.test.js test/posture-command.test.js test/labs-command.test.js test/compliance-command.test.js test/check-doc-drift.test.js test/dist-chunks-tracked.test.js && node ../scripts/lint-command-descriptions.mjs",
|
|
91
|
+
"test:lifecycle": "node --test test/ci-hang-protection.test.js test/pre-bash-guard.test.js test/lsp-protocol-smoke.test.js test/ide-surfaces.test.js test/detector-liveness.test.js test/bench-watchdog.test.js test/ci-parity.test.js test/dead-code.test.js test/no-dead-modules.test.js test/no-orphan-scripts.test.js test/no-stray-state.test.js test/tree-integrity.test.js test/stop-hook.test.js test/plugin-self-check.test.js test/skills-registry.test.js test/bodyguard.test.js test/cache-invalidator-guard.test.js test/dispatch-pre-tool.test.js test/dispatch-user-prompt.test.js test/session-start-model-capture.test.js test/sandbox.test.js test/sandbox-escape.test.js test/ci-templates.test.js test/agent-mcp-tools.test.js test/triage-command.test.js test/no-orphan-tests.test.js test/supply-command.test.js test/posture-command.test.js test/labs-command.test.js test/compliance-command.test.js test/check-doc-drift.test.js test/dist-chunks-tracked.test.js && node ../scripts/lint-command-descriptions.mjs test/workflow-confinement.test.js test/check-bundle-source.test.js test/ship.test.js",
|
|
90
92
|
"test:eval": "node --test test/independent-eval.test.js test/realworld-recall.test.js",
|
|
91
93
|
"test:discovery": "node --test test/discovery-partition.test.js test/discovery-lenses.test.js test/discovery-hunter.test.js test/discovery-confirm.test.js test/discovery-disprove.test.js test/discovery-judge.test.js test/discovery-run.test.js test/discovery-wiring.test.js test/discovery-llm-invoke.test.js test/local-only-mode.test.js",
|
|
92
94
|
"eval:independent": "node ../bench/independent-eval/runner.mjs",
|
|
@@ -125,6 +127,8 @@
|
|
|
125
127
|
"bench:memory": "node ../bench/memory/runner.mjs",
|
|
126
128
|
"bench:memory:check": "node ../bench/memory/runner.mjs --check",
|
|
127
129
|
"bench:memory:update-baseline": "node ../bench/memory/runner.mjs --update-baseline",
|
|
130
|
+
"check:bundle-source": "node ../scripts/check-bundle-source.mjs",
|
|
131
|
+
"ship": "node ../scripts/ship.mjs",
|
|
128
132
|
"bench:self-scan": "node ../bench/self-scan/measure.mjs",
|
|
129
133
|
"bench:self-scan:check": "node ../bench/self-scan/check.mjs",
|
|
130
134
|
"bench:nist-800-171-labels:check": "node ../bench/nist-800-171-labels/check.mjs",
|
|
@@ -186,6 +190,7 @@
|
|
|
186
190
|
"release:check": "node ../scripts/release-check.mjs",
|
|
187
191
|
"release:check:fast": "node ../scripts/release-check.mjs --fast",
|
|
188
192
|
"gate:prepush": "node ../scripts/pre-push-gate.mjs",
|
|
193
|
+
"gate:trace": "node ../scripts/gate-trace-reads.mjs",
|
|
189
194
|
"gate:prepush:install": "node ../scripts/pre-push-gate.mjs --install-hook",
|
|
190
195
|
"bench:independent": "node ../bench/independent/runner.mjs",
|
|
191
196
|
"bench:independent:fetch": "node ../bench/independent/fetch.mjs",
|
package/src/engine.js
CHANGED
|
@@ -8436,6 +8436,9 @@ function genHAR(routes,sources){const baseUrl="http://localhost:3000";const entr
|
|
|
8436
8436
|
|
|
8437
8437
|
async function queryRegistries(components){
|
|
8438
8438
|
const infoMap=new Map();
|
|
8439
|
+
// Registry metadata (latest version, deprecation, age) is optional enrichment. Offline mode (--no-network, --deterministic, AGENTIC_SECURITY_OFFLINE=1)
|
|
8440
|
+
// must not touch the network for it: found by the live Hackage feed bench, where an "offline" scan still fetched registry.npmjs.org/jquery.
|
|
8441
|
+
if(process.env.AGENTIC_SECURITY_OFFLINE==='1')return infoMap;
|
|
8439
8442
|
const npmNames=[...new Set(components.filter(c=>c.ecosystem==='npm').map(c=>c.name))];
|
|
8440
8443
|
const pypiNames=[...new Set(components.filter(c=>c.ecosystem==='pypi').map(c=>c.name))];
|
|
8441
8444
|
const CHUNK=8;
|
|
@@ -9229,6 +9232,7 @@ function _deterministicFileTimings(timings) {
|
|
|
9229
9232
|
// X-010: Hackage and Nix components, dependency edges and target provenance. Kept beside (not inside) the ordinary
|
|
9230
9233
|
// component list so the existing consumers are untouched; the BOM emitters and the SBOM diff read it explicitly.
|
|
9231
9234
|
try{if(process.env.AGENTIC_SECURITY_HACKAGE_ADVISORIES_LIVE==='1'){const{prefetchHackageFeed}=await import('./language/haskell-supply.js');const{resolvedHackageComponents,nixHaskellPackageNames}=await import('./language/resolved-pass.js');let _rc=[],_nx=[];try{_rc=resolvedHackageComponents(allFileContents).components||[];}catch(_){}try{_nx=nixHaskellPackageNames(allFileContents);}catch(_){}await prefetchHackageFeed(allFileContents,{resolvedComponents:_rc,extraNames:_nx});}}catch(_){/* the live feed is optional: a failure leaves the scan on whatever snapshot exists */}
|
|
9235
|
+
try{if(process.env.AGENTIC_SECURITY_NIX_ADVISORIES_LIVE==='1'){const{prefetchNixAdvisoryFeed}=await import('./language/resolved-pass.js');await prefetchNixAdvisoryFeed(allFileContents);}}catch(_){/* the live feed is optional: a failure leaves the scan on whatever snapshot exists */}
|
|
9232
9236
|
let _languageBom=null;try{if(Object.keys(allFileContents).some(f=>/\.(?:l?hs|nix)$|\.cabal$|(?:^|\/)(?:cabal\.project(?:\.freeze)?|package\.yaml|stack\.yaml(?:\.lock)?|flake\.lock)$/i.test(f))){const{languageBom}=await import('./language/bom.js');const{resolvedHaskellGraph,nixClosureOf}=await import('./language/resolved-pass.js');const _rg=resolvedHaskellGraph(allFileContents);const _nc=nixClosureOf(allFileContents);_languageBom=languageBom(allFileContents,{...(_rg?{resolved:_rg.graph}:{}),...(_nc&&!_nc.refused.length?{closure:_nc.closure}:{})});}}catch(_){_languageBom=null;}
|
|
9233
9237
|
aF.push(...(runDetector(_detectorErrors,'<project>','scanDbTaintCrossFile',()=>scanDbTaintCrossFile(fc))||[]));
|
|
9234
9238
|
aF.push(...(runDetector(_detectorErrors,'<project>','scanCsharpCrossFile',()=>scanCsharpCrossFile(fc))||[]));
|
|
@@ -11031,6 +11035,7 @@ function _deterministicFileTimings(timings) {
|
|
|
11031
11035
|
if (Object.keys(allFileContents).some(f => /\.(?:l?hs|hs-boot|hsc|nix)$|\.cabal$|(?:^|\/)(?:cabal\.project|package\.yaml|stack\.yaml)/i.test(f))) {
|
|
11032
11036
|
const { assessLanguageAssurance } = await import('./language/assurance.js');
|
|
11033
11037
|
const { configuredAdvisoryDb } = await import('./language/haskell-supply.js');
|
|
11038
|
+
const { liveFeedOptionalState } = await import('./language/haskell-advisory-feed.js');
|
|
11034
11039
|
const env = process.env;
|
|
11035
11040
|
const { resolvedHackageComponents, analyzeNixClosure, runSelectedNixEval } = await import('./language/resolved-pass.js');
|
|
11036
11041
|
let _languageSupplyGaps = [];
|
|
@@ -11044,7 +11049,7 @@ function _deterministicFileTimings(timings) {
|
|
|
11044
11049
|
sizeSkipped,
|
|
11045
11050
|
supplyGaps: _languageSupplyGaps,
|
|
11046
11051
|
licenseUnavailable: ((_languageBom && _languageBom.components) || []).filter((c) => c && !c.license && !(Array.isArray(c.licenses) && c.licenses.length)).length,
|
|
11047
|
-
optional: { 'nix-eval': { selected: env.AGENTIC_SECURITY_NIX_EVAL === '1', result: _nixEvalResult }, 'cabal-plan': { selected: false }, 'hackage-live':
|
|
11052
|
+
optional: { 'nix-eval': { selected: env.AGENTIC_SECURITY_NIX_EVAL === '1', result: _nixEvalResult }, 'cabal-plan': { selected: false }, 'hackage-live': liveFeedOptionalState(env)},
|
|
11048
11053
|
})).languageCoverage;
|
|
11049
11054
|
}
|
|
11050
11055
|
} catch (e) { _languageCoverage = { totals: null, byKind: null, conditions: [`language assurance could not be computed: ${String((e && e.message) || e)}`] }; }
|
package/src/language/CLAUDE.md
CHANGED
|
@@ -31,6 +31,31 @@ or a capability.** Product-facing guides: `docs/guides/haskell.md`, `docs/guides
|
|
|
31
31
|
queried (`covered`); a package it did not cover is `feed-incomplete` and a stale one `feed-stale`, in BOTH matchers
|
|
32
32
|
(`evaluateComponents` and `nix-sca.js`). Any new consumer of an `AdvisoryDb` must check `db.coverage(name)` before saying "no advisory".
|
|
33
33
|
The snapshot lives in the operator configuration directory, never the project (`trusted-inputs.js`).
|
|
34
|
+
- **Auth guards must stop the handler.** In `haskell-web.js` a Scotty `status 40x` only sets the code, so both the named-guard path (`guardSummary`) and the inline path (`handlerFacts`) need a halting call (`finish`, `raise`, `raiseStatus`, `redirect`; `finish` is an IR identifier with no line of its own). WAI, Servant and Yesod inline guards order the credential READ against the first sensitive call, because a tail-position rejection reports the enclosing line (a disclosed gap, pinned in `test/haskell/haskell-web-guards.test.js`). A WAI `responseLBS` rejection counts only when handed back (`respond`/`return`).
|
|
35
|
+
- **Severity is the advisory's own** (`cvss.js`): CVSS v3.x base score, else a named `database_specific.severity`, else `medium` with the basis stated. Never guess from an unparseable or v4 vector.
|
|
36
|
+
- **Option fixes work on the effective configuration, across files.** `nix-fix.js` edits EVERY contributing definition of an option
|
|
37
|
+
(all winners at the winning priority, plus conditional branches holding the weak literal), never one line: editing one of two
|
|
38
|
+
equal-priority winners turns a finding into a module-system conflict that a rescan alone reports as "fixed". Verification is
|
|
39
|
+
the `effective` gate (`makeEffectiveCheck`: resolve the option again over the patched tree). A plan may carry `edits` (several
|
|
40
|
+
files); `runFixLifecycle` applies them through `writeManyWithBackup` (checks everything and backs up everything before the
|
|
41
|
+
first write, rolls back on a failed write) and records one history entry per file sharing `languageGroupId`; `undoFix` and
|
|
42
|
+
`posture/fix-history.js` `undoLast`/`revertEntryById` restore a group as a unit. A winner outside the root or not a single
|
|
43
|
+
literal is refused with an `override` suggestion (`overrideSuggestion`), never an automatic edit. Any new consumer of a fix
|
|
44
|
+
plan (LSP, MCP, CLI) must honour `plan.edits`: `apply_fix` writes one file, so a multi-file fix is not offered there.
|
|
45
|
+
- **Boundaries are narrowed only by sound, closed rules.** `haskell-cpp.js` decides a CPP conditional only from the file, a project-stated
|
|
46
|
+
compiler (`with-compiler` pin; `tested-with` only when every item is an exact version and all agree, recorded as an assumption) or the hull
|
|
47
|
+
of cabal `build-depends` bounds; an unknown macro is undecided, never 0, and an undecided conditional keeps every branch. `haskell-boundaries.js`
|
|
48
|
+
accepts a TH declaration splice only when the generator is IMPORTED from its upstream module (not shadowed/hidden) and every token is a name
|
|
49
|
+
quote, literal, documented setting or restricted option update; a quasi-quote only when it is a raw-string or non-interpolating quoter. The
|
|
50
|
+
accepted kinds (`th-safe-splice`, `quasiquote-inert`) are disclosed, never in the adapter's opaque set, and `preprocessForSyntax` feeds the same
|
|
51
|
+
decisions to the semantic IR. Widening any allowlist needs a both-directions test in `test/haskell/haskell-boundaries.test.js`.
|
|
52
|
+
- **The Nix feed is the same contract over a different source.** `nix-advisory-feed.js` uses the NVD CVE API 2.0 keyed by CPE
|
|
53
|
+
`vendor:product` (OSV has no nixpkgs ecosystem), behind `AGENTIC_SECURITY_NIX_ADVISORIES_LIVE=1`. Coverage is per CPE identity
|
|
54
|
+
(`NixAdvisoryData.cpeCoverage`), and `nix-sca.js` reports an uncovered identity, or a component with no CPE, as `unknown` with
|
|
55
|
+
`feedCoverage: 'incomplete'`, never `not-affected`. A snapshot with no `covered` table (pinned, hand-written) is matched exactly as
|
|
56
|
+
before. The prefetch (`prefetchNixAdvisoryFeed`, `resolved-pass.js`) asks only for identities `closureIdentities` says the matcher
|
|
57
|
+
will use; metadata comes only from the operator (`AGENTIC_SECURITY_NIX_META`). NVD is rate limited (5/30 s keyless): never raise
|
|
58
|
+
the request caps or lower the spacing in `nix-advisory-feed.js` without re-reading the NVD limits.
|
|
34
59
|
- **Pragma** (`pragma.js`): comment-aware, line-scoped, exact rule-id match, logged. A line-less finding cannot be suppressed.
|
|
35
60
|
|
|
36
61
|
## Module map
|
|
@@ -38,13 +63,34 @@ or a capability.** Product-facing guides: `docs/guides/haskell.md`, `docs/guides
|
|
|
38
63
|
| Group | Files |
|
|
39
64
|
|---|---|
|
|
40
65
|
| Shared | `discovery.js` (sources, manifests, explicit exports, exclusions, import graph, invalidation digests), `contracts.js`, `assurance.js` (scan-health inputs, conditions, limitations), `engine-pass.js` (language supply chain wired into the engine), `resolved-pass.js` (plan / Stack export / Nix closure / opt-in evaluation reachable from the CLI), `context.js` (project context for partial scans, fix previews and dependency upgrades, model prompt extras), `state-artifacts.js`, `pragma.js`, `secrets.js`, `bom.js`, `bom-validate.js`, `aibom.js`, `compliance-map.js`, `bridges.js`, `witness.js`, `fix-lifecycle.js` (the one fix lifecycle: path, syntax, rescan, compile, backup, history, undo) |
|
|
41
|
-
| Haskell | `haskell-parser.js`, `haskell-grammar.js`, `haskell-adapter.js`, `haskell-ir.js`, `haskell-models.js` (the single registry of sources, sinks, sanitizers; `dataflow/catalog-haskell.js` is generated from it), `haskell-guards.js`, `haskell-security-rules.js`, `haskell-web.js`, `haskell-findings.js`, `haskell-syntax.js`, `haskell-sweep.js`, `haskell-disclosure.js`, `haskell-llm.js`, `haskell-manifests.js`, `haskell-resolved-graph.js`, `haskell-sca.js`, `haskell-advisory-feed.js` (the opt-in live Hackage feed: OSV fetch, per-package coverage, operator-only snapshot), `haskell-supply.js`, `haskell-fix.js` |
|
|
66
|
+
| Haskell | `haskell-parser.js`, `haskell-grammar.js`, `haskell-adapter.js`, `haskell-ir.js`, `haskell-models.js` (the single registry of sources, sinks, sanitizers; `dataflow/catalog-haskell.js` is generated from it), `haskell-guards.js`, `haskell-security-rules.js`, `haskell-web.js`, `haskell-findings.js`, `haskell-syntax.js`, `haskell-sweep.js`, `haskell-disclosure.js`, `haskell-llm.js`, `haskell-manifests.js`, `haskell-resolved-graph.js`, `haskell-sca.js`, `cvss.js` (CVSS v3.x base-score calculator and advisory-severity selection, shared by the Haskell and Nix matchers; v4 is not scored and says so), `haskell-advisory-feed.js` (the opt-in live Hackage feed: OSV fetch, per-package coverage, operator-only snapshot), `haskell-supply.js`, `haskell-fix.js` |
|
|
67
|
+
| Haskell | `haskell-parser.js`, `haskell-cpp.js` (three-valued CPP conditional evaluation + project context from cabal), `haskell-boundaries.js` (closed set of safe TH declaration splices and inert quasi-quotes), `haskell-grammar.js`, `haskell-adapter.js`, `haskell-ir.js`, `haskell-models.js` (the single registry of sources, sinks, sanitizers; `dataflow/catalog-haskell.js` is generated from it), `haskell-guards.js`, `haskell-security-rules.js`, `haskell-web.js`, `haskell-findings.js`, `haskell-syntax.js`, `haskell-sweep.js`, `haskell-disclosure.js`, `haskell-llm.js`, `haskell-manifests.js`, `haskell-resolved-graph.js`, `haskell-sca.js`, `haskell-advisory-feed.js` (the opt-in live Hackage feed: OSV fetch, per-package coverage, operator-only snapshot), `haskell-supply.js`, `haskell-fix.js` |
|
|
42
68
|
| Nix | `nix-parser.js`, `nix-grammar.js`, `nix-ir.js`, `nix-adapter.js`, `nixos-module-resolver.js`, `nixos-option-catalog.js`, `nixos-hardening.js`, `nix-build-trust.js`, `nix-secrets.js`, `nix-script-taint.js`, `nix-privacy.js`, `nix-agents.js`, `nix-inventory.js`, `nix-closure.js`, `nix-sca.js`, `nix-eval-isolation.js`, `nix-fix.js` |
|
|
69
|
+
| Haskell | `haskell-parser.js`, `haskell-grammar.js`, `haskell-adapter.js`, `haskell-ir.js`, `haskell-models.js` (the single registry of sources, sinks, sanitizers; `dataflow/catalog-haskell.js` is generated from it), `haskell-guards.js`, `haskell-security-rules.js`, `haskell-web.js`, `haskell-findings.js`, `haskell-syntax.js`, `haskell-sweep.js`, `haskell-disclosure.js`, `haskell-llm.js`, `haskell-manifests.js`, `haskell-resolved-graph.js`, `haskell-sca.js`, `haskell-advisory-feed.js` (the opt-in live Hackage feed: OSV fetch, per-package coverage, operator-only snapshot), `haskell-supply.js`, `haskell-fix.js` |
|
|
70
|
+
| Nix | `nix-parser.js`, `nix-grammar.js`, `nix-ir.js`, `nix-adapter.js`, `nixos-module-resolver.js`, `nixos-eval-forms.js`, `nixos-option-catalog.js`, `nixos-hardening.js`, `nix-build-trust.js`, `nix-secrets.js`, `nix-script-taint.js`, `nix-privacy.js`, `nix-agents.js`, `nix-inventory.js`, `nix-closure.js`, `nix-sca.js`, `nix-eval-isolation.js`, `nix-fix.js` |
|
|
71
|
+
| Haskell | `haskell-parser.js`, `haskell-grammar.js`, `haskell-adapter.js`, `haskell-ir.js`, `haskell-models.js` (the single registry of sources, sinks, sanitizers; `dataflow/catalog-haskell.js` is generated from it), `haskell-guards.js`, `haskell-security-rules.js`, `haskell-web.js`, `haskell-findings.js`, `haskell-syntax.js`, `haskell-sweep.js`, `haskell-disclosure.js`, `haskell-llm.js`, `haskell-manifests.js`, `haskell-resolved-graph.js`, `haskell-sca.js`, `haskell-advisory-feed.js` (the opt-in live Hackage feed: OSV fetch, per-package coverage, operator-only snapshot), `haskell-supply.js`, `haskell-fix.js` |
|
|
72
|
+
| Nix | `nix-parser.js`, `nix-grammar.js`, `nix-ir.js`, `nix-adapter.js`, `nixos-module-resolver.js`, `nixos-option-catalog.js`, `nixos-hardening.js`, `nix-build-trust.js`, `nix-secrets.js`, `nix-script-taint.js`, `nix-privacy.js`, `nix-agents.js`, `nix-inventory.js`, `nix-closure.js`, `nix-sca.js`, `nix-advisory-feed.js`, `nix-eval-isolation.js`, `nix-fix.js` |
|
|
43
73
|
| Measurement | `accuracy.js` (family-scoped scoring, per-layer), `support-registry.js` (status rules, promotion refusals, frozen-hash demotion) |
|
|
44
74
|
|
|
45
75
|
Related, outside this directory: `dataflow/catalog-haskell.js`, `lineage/haskell-view.js`, `lineage/nix-view.js`,
|
|
46
76
|
`ir/` Haskell/Nix adapters, `report/` format handling, `egress/redact.js`, `llm-validator/`, `discovery/` (hunt partitions Nix).
|
|
47
77
|
|
|
78
|
+
## NixOS option evaluator (soundness rules)
|
|
79
|
+
|
|
80
|
+
`nixos-module-resolver.js` `evalExpr` is a soundness-first subset; `nixos-eval-forms.js` holds its value classes and the
|
|
81
|
+
**allow-list** of library functions (there is no deny-list to forget an entry in). Rules to keep when extending it:
|
|
82
|
+
|
|
83
|
+
- **Any unknown part makes the whole value unknown.** Never default, never pick a branch you cannot decide.
|
|
84
|
+
- **Scope is a correctness issue.** Lexical bindings (let, lambda) beat every `with`; innermost `with` beats outer; the module's
|
|
85
|
+
own `let`s are IR bindings (`ir.bindings`, `scope: 'let'`) and are used only when unique in the file, not also a function
|
|
86
|
+
parameter, not in a `rec` set, and when their `letSpan` encloses `env.pos` (the absolute span of the text being evaluated).
|
|
87
|
+
`evalSpan` on a definition (set by `nix-ir.js` when a leaf sits under let/with/assert only) makes the resolver evaluate the
|
|
88
|
+
whole wrapper. A priority/condition/merge combinator clears it, because those are the collector's job.
|
|
89
|
+
- **Final values must be plain data** (`sealed`/`isPlain`): a closure, partial application or namespace is `unknown`. A
|
|
90
|
+
priority wrapper inside a value is unknown (priority is not recoverable); at the top of a definition the collector reads it.
|
|
91
|
+
- **Bounded**: `maxEvaluations`, `maxExprDepth`, `maxValueSize` are caps that surface as `truncated`, not as a guess.
|
|
92
|
+
- Assumption stated, not proven: `lib` is nixpkgs' `lib` whenever the module declares a `lib` parameter and the file does not rebind it.
|
|
93
|
+
|
|
48
94
|
## Tests and benches
|
|
49
95
|
|
|
50
96
|
| Scope | Command | Notes |
|
|
@@ -55,6 +101,7 @@ Related, outside this directory: `dataflow/catalog-haskell.js`, `lineage/haskell
|
|
|
55
101
|
| Stress | `npm run test:language-stress` | offline scale and a peak-memory ceiling; excluded from `npm test` (it must own the machine) |
|
|
56
102
|
| Needs a compiler | `npm run test:language-tools` | HS-006.AC01 and the support gate; excluded from `npm test`; **fails** without `ghc` |
|
|
57
103
|
| Support registry | `npm run bench:language-support:check` | recomputes the registry from the STORED measurement; fails on any difference |
|
|
104
|
+
| Live feed | `npm run bench:live-feed -- <fetch\|plan\|scan\|merge\|sample\|report>` | `bench/live-feed/`: the opt-in Hackage feed against real projects and real OSV. Needs the network and is NOT in `npm test` or any gate. `RESULTS.md` is a dated measurement; labels in it are model-assessed |
|
|
58
105
|
|
|
59
106
|
The support registry is measured **once per promotion** on a frozen holdout (`bench/language-support/promote.mjs`); never tune
|
|
60
107
|
against the holdout, and any further holdout run counts as repeated use. A change to the engine, the corpus or a label changes the
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
import { runLanguageAnalysis, reconcileLanguageLedger, languageHealth } from './contracts.js';
|
|
21
21
|
import { createHaskellAdapter } from './haskell-adapter.js';
|
|
22
|
+
import { deriveCppContext } from './haskell-cpp.js';
|
|
22
23
|
import { createNixAdapter } from './nix-adapter.js';
|
|
23
24
|
import { analyzeHaskellManifests } from './haskell-manifests.js';
|
|
24
25
|
import { packageOfModule } from './haskell-models.js';
|
|
@@ -71,14 +72,21 @@ export async function assessLanguageAssurance(input = {}) {
|
|
|
71
72
|
// 1. parse adapters over every language source
|
|
72
73
|
// Boundaries that do not make a file unresolved but that a reader must be told about: CPP (every branch was parsed, the
|
|
73
74
|
// chosen one is not known) and FFI (the foreign code is not analysed).
|
|
75
|
+
const DISCLOSED_KINDS = new Set(['cpp', 'ffi', 'th-safe-splice', 'quasiquote-inert']);
|
|
74
76
|
const disclosed = new Map(); // boundary kind -> {count, files:Set}
|
|
75
77
|
const projectModules = new Set(); const importedModules = new Map(); // module -> files
|
|
76
78
|
const onParse = (file, parse) => {
|
|
77
79
|
if (parse && parse.module && parse.module.name) projectModules.add(parse.module.name);
|
|
78
80
|
for (const i of (parse && parse.imports) || []) if (i && i.module) { const e = importedModules.get(i.module) || new Set(); e.add(file); importedModules.set(i.module, e); }
|
|
79
|
-
for (const b of (parse && parse.boundaries) || [])
|
|
81
|
+
for (const b of (parse && parse.boundaries) || []) {
|
|
82
|
+
if (!DISCLOSED_KINDS.has(b.kind)) continue;
|
|
83
|
+
const e = disclosed.get(b.kind) || { count: 0, files: new Set(), decided: 0, undecided: 0, assumptions: new Set() };
|
|
84
|
+
e.count += b.count || 1; e.files.add(file);
|
|
85
|
+
if (b.kind === 'cpp') { e.decided += b.decided || 0; e.undecided += b.undecided || 0; for (const a of b.assumptions || []) e.assumptions.add(a); }
|
|
86
|
+
disclosed.set(b.kind, e);
|
|
87
|
+
}
|
|
80
88
|
};
|
|
81
|
-
const adapters = input.adapters || [createHaskellAdapter({ onParse }), createNixAdapter()];
|
|
89
|
+
const adapters = input.adapters || [createHaskellAdapter({ onParse, cpp: deriveCppContext(files) }), createNixAdapter()];
|
|
82
90
|
const run = await runLanguageAnalysis({ files, adapters, timeoutMs: input.timeoutMs || 0 });
|
|
83
91
|
const reconcile = reconcileLanguageLedger(run.ledger, files);
|
|
84
92
|
const base = languageHealth({ ledger: run.ledger, outcomes: run.outcomes });
|
|
@@ -97,8 +105,17 @@ export async function assessLanguageAssurance(input = {}) {
|
|
|
97
105
|
for (const o of opaque) { const k = String(o.detail).replace(/^opaque-boundary:\s*/, ''); kinds[k] = (kinds[k] || 0) + 1; }
|
|
98
106
|
for (const [k, n] of Object.entries(kinds).sort()) limitations.push({ kind: 'opaque-boundary', boundary: k, count: n, note: 'a documented limit of static analysis: this code is not analysed, and is not reported clean' });
|
|
99
107
|
}
|
|
100
|
-
const DISCLOSED_NOTE = {
|
|
101
|
-
|
|
108
|
+
const DISCLOSED_NOTE = {
|
|
109
|
+
cpp: 'preprocessor conditionals: a conditional the file or the project decides keeps only its live branch, every other one keeps all of its branches, and which branch is compiled is then not known',
|
|
110
|
+
ffi: 'foreign declarations: the foreign code is not analysed and its effects are not modelled',
|
|
111
|
+
'th-safe-splice': 'declaration-level Template Haskell splices of a known generator applied to names and literals only: assumed to be the upstream generator, nothing is run and the generated declarations are not modelled',
|
|
112
|
+
'quasiquote-inert': 'quasi-quotes of a known raw-string or non-interpolating quoter: read as a string literal on the assumption that the quoter is the upstream one',
|
|
113
|
+
};
|
|
114
|
+
for (const [k, e] of [...disclosed.entries()].sort()) {
|
|
115
|
+
const extra = k === 'cpp' ? { decidedConditionals: e.decided, undecidedConditionals: e.undecided, ...(e.assumptions.size ? { assumptions: [...e.assumptions].sort() } : {}) } : {};
|
|
116
|
+
const assumed = k === 'cpp' && e.assumptions.size ? `; some conditionals were decided on a stated project assumption (${[...e.assumptions].sort().join(', ')}), so a branch dead under it was not analysed` : '';
|
|
117
|
+
limitations.push({ kind: 'opaque-boundary', boundary: k, count: e.count, files: [...e.files].sort().slice(0, 20), ...extra, note: `a documented limit of static analysis (${DISCLOSED_NOTE[k]}${assumed})` });
|
|
118
|
+
}
|
|
102
119
|
// Imported modules this scan has no model for: their functions are ordinary, opaque calls (never a source, sink or
|
|
103
120
|
// sanitizer), so a taint flow through them is widened and disclosed on the finding. Listed so a reader knows how much of the
|
|
104
121
|
// import surface the models cover. A limitation, not a condition: most real projects import unmodelled modules.
|
package/src/language/context.js
CHANGED
|
@@ -98,6 +98,8 @@ export async function languageFixPreview(finding, files, { apply = false, root =
|
|
|
98
98
|
status: res.status, applied: res.applied === true, backup: res.backup || null,
|
|
99
99
|
label: plan.label || null, tier: res.tier || plan.tier || null,
|
|
100
100
|
file: plan.file, before: plan.before, after: plan.after,
|
|
101
|
+
// A fix that spans several files lists every one of them; `file`/`before`/`after` stay the first for single-file callers.
|
|
102
|
+
edits: Array.isArray(plan.edits) && plan.edits.length > 1 ? plan.edits.map((e) => ({ file: e.file, before: e.before, after: e.after })) : null,
|
|
101
103
|
diff: res.preview || hsDiff(plan.file, plan.before, plan.after),
|
|
102
104
|
gates: res.gates || null, reason: (res.status === 'verified' || res.status === 'applied') ? null : (res.reason || null),
|
|
103
105
|
explanation: plan.explanation || null, consequences: res.consequences || plan.consequences || [],
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// CVSS v3.x base-score calculator and advisory-severity selection for the Haskell and Nix SCA matchers.
|
|
2
|
+
// Pure: no I/O. Never invents a rating: a vector that cannot be parsed, or a CVSS version this module does not compute
|
|
3
|
+
// (v4 needs lookup tables that are not shipped), yields no score and says why.
|
|
4
|
+
|
|
5
|
+
const W = {
|
|
6
|
+
AV: { N: 0.85, A: 0.62, L: 0.55, P: 0.2 },
|
|
7
|
+
AC: { L: 0.77, H: 0.44 },
|
|
8
|
+
UI: { N: 0.85, R: 0.62 },
|
|
9
|
+
CIA: { H: 0.56, L: 0.22, N: 0 },
|
|
10
|
+
};
|
|
11
|
+
const PR = { U: { N: 0.85, L: 0.62, H: 0.27 }, C: { N: 0.85, L: 0.68, H: 0.5 } };
|
|
12
|
+
const REQUIRED = ['AV', 'AC', 'PR', 'UI', 'S', 'C', 'I', 'A'];
|
|
13
|
+
|
|
14
|
+
// CVSS 3.1 Roundup (spec appendix A, integer arithmetic so float error cannot move a score across a boundary).
|
|
15
|
+
function roundUp31(x) {
|
|
16
|
+
const i = Math.round(x * 100000);
|
|
17
|
+
return i % 10000 === 0 ? i / 100000 : (Math.floor(i / 10000) + 1) / 10;
|
|
18
|
+
}
|
|
19
|
+
const roundUp30 = (x) => Math.ceil(x * 10) / 10;
|
|
20
|
+
|
|
21
|
+
/** @returns {{ok:true, version:string, score:number, vector:string}|{ok:false, reason:string}} */
|
|
22
|
+
export function cvssV3BaseScore(vector) {
|
|
23
|
+
if (typeof vector !== 'string') return { ok: false, reason: 'the CVSS vector is not a string' };
|
|
24
|
+
const parts = vector.trim().split('/');
|
|
25
|
+
const m = /^CVSS:(3\.[01])$/.exec(parts[0] || '');
|
|
26
|
+
if (!m) return { ok: false, reason: /^CVSS:4/.test(parts[0] || '') ? 'CVSS v4 vectors are not scored by this tool' : 'the vector is not a CVSS v3.0/v3.1 vector' };
|
|
27
|
+
const version = m[1];
|
|
28
|
+
const metrics = {};
|
|
29
|
+
for (const p of parts.slice(1)) {
|
|
30
|
+
const kv = /^([A-Za-z]+):([A-Za-z])$/.exec(p);
|
|
31
|
+
if (!kv || kv[1] in metrics) return { ok: false, reason: `malformed or repeated metric "${p}"` };
|
|
32
|
+
metrics[kv[1]] = kv[2];
|
|
33
|
+
}
|
|
34
|
+
for (const k of REQUIRED) if (!(k in metrics)) return { ok: false, reason: `missing base metric ${k}` };
|
|
35
|
+
if (metrics.S !== 'C' && metrics.S !== 'U') return { ok: false, reason: `invalid scope value "${metrics.S}"` };
|
|
36
|
+
const changed = metrics.S === 'C';
|
|
37
|
+
const av = W.AV[metrics.AV], ac = W.AC[metrics.AC], ui = W.UI[metrics.UI];
|
|
38
|
+
const c = W.CIA[metrics.C], i = W.CIA[metrics.I], a = W.CIA[metrics.A];
|
|
39
|
+
const pr = PR[metrics.S][metrics.PR];
|
|
40
|
+
if ([av, ac, ui, c, i, a, pr].some((x) => x === undefined)) return { ok: false, reason: 'an unknown value in a base metric' };
|
|
41
|
+
const iss = 1 - (1 - c) * (1 - i) * (1 - a);
|
|
42
|
+
const impact = changed ? 7.52 * (iss - 0.029) - 3.25 * Math.pow(iss - 0.02, 15) : 6.42 * iss;
|
|
43
|
+
const expl = 8.22 * av * ac * pr * ui;
|
|
44
|
+
const up = version === '3.1' ? roundUp31 : roundUp30;
|
|
45
|
+
const score = impact <= 0 ? 0 : changed ? up(Math.min(1.08 * (impact + expl), 10)) : up(Math.min(impact + expl, 10));
|
|
46
|
+
return { ok: true, version, score, vector: vector.trim() };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function levelFromScore(score) {
|
|
50
|
+
if (!(score > 0)) return null;
|
|
51
|
+
return score >= 9 ? 'critical' : score >= 7 ? 'high' : score >= 4 ? 'medium' : 'low';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const NAMED = { critical: 'critical', high: 'high', moderate: 'medium', medium: 'medium', low: 'low' };
|
|
55
|
+
export const normalizeSeverityName = (s) => (typeof s === 'string' ? NAMED[s.trim().toLowerCase()] || null : null);
|
|
56
|
+
|
|
57
|
+
export const NO_RATING_BASIS = 'the advisory carries no severity rating';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Pick the advisory's own severity from an OSV record: CVSS vectors at record level and on each affected entry, then
|
|
61
|
+
* database_specific.severity (record, then affected). The highest parseable CVSS score wins; a named severity is used
|
|
62
|
+
* only when no vector could be scored. Returns {level:null, basis} when nothing usable exists.
|
|
63
|
+
*/
|
|
64
|
+
export function advisorySeverity(rec) {
|
|
65
|
+
const vectors = [];
|
|
66
|
+
const named = [];
|
|
67
|
+
const take = (sevArr, dbs) => {
|
|
68
|
+
for (const s of Array.isArray(sevArr) ? sevArr : []) if (s && typeof s.score === 'string') vectors.push(s.score);
|
|
69
|
+
if (dbs && typeof dbs.severity === 'string') named.push(dbs.severity);
|
|
70
|
+
};
|
|
71
|
+
if (rec && typeof rec === 'object') {
|
|
72
|
+
take(rec.severity, rec.database_specific);
|
|
73
|
+
for (const a of Array.isArray(rec.affected) ? rec.affected : []) if (a && typeof a === 'object') take(a.severity, a.database_specific);
|
|
74
|
+
}
|
|
75
|
+
let best = null; const why = [];
|
|
76
|
+
for (const v of vectors) {
|
|
77
|
+
const r = cvssV3BaseScore(v);
|
|
78
|
+
if (r.ok) { if (!best || r.score > best.score) best = r; } else why.push(r.reason);
|
|
79
|
+
}
|
|
80
|
+
if (best) {
|
|
81
|
+
const level = levelFromScore(best.score);
|
|
82
|
+
if (level) return { level, score: best.score, vector: best.vector, basis: `CVSS v${best.version} base score ${best.score.toFixed(1)} from the advisory` };
|
|
83
|
+
why.push('the CVSS base score is 0.0 (no impact)');
|
|
84
|
+
}
|
|
85
|
+
for (const n of named) {
|
|
86
|
+
const level = normalizeSeverityName(n);
|
|
87
|
+
if (level) return { level, score: null, vector: null, basis: `severity "${n}" stated by the advisory (database_specific)` };
|
|
88
|
+
why.push(`unrecognised severity "${String(n).slice(0, 40)}"`);
|
|
89
|
+
}
|
|
90
|
+
return { level: null, score: null, vector: null, basis: why.length ? `${NO_RATING_BASIS} that could be used (${[...new Set(why)].join('; ')})` : NO_RATING_BASIS };
|
|
91
|
+
}
|