@clear-capabilities/agentic-security-scanner 0.195.21 → 0.195.23
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 +26 -0
- package/bin/agentic-security.js +5 -2
- package/dist/{7feb08356355c30181a1.json → 01087ded263953062654.json} +3 -3
- package/dist/550.index.js +9 -8
- package/dist/5620.index.js +59 -10
- package/dist/5937.index.js +88 -16
- package/dist/7838.index.js +32 -5
- package/dist/9441.index.js +50 -7
- package/dist/9824.index.js +19 -13
- package/dist/agentic-security.mjs +2 -2
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/package.json +3 -3
- package/src/discovery/CLAUDE.md +4 -0
- package/src/discovery/detector-spec-synthesis.js +203 -0
- package/src/discovery/llm-invoke.js +3 -3
- package/src/egress/transport.js +148 -0
- package/src/engine.js +9 -0
- package/src/integrations/index.js +18 -9
- package/src/llm-validator/index.js +4 -2
- package/src/llm-validator/local-endpoint.js +4 -1
- package/src/llm-validator/ollama-provider.js +8 -6
- package/src/pipeline/scan-health.js +15 -2
- package/src/posture/CLAUDE.md +1 -0
- package/src/posture/adversary-agent.js +27 -10
- package/src/posture/assurance/config.js +2 -0
- package/src/posture/assurance/decision.js +45 -0
- package/src/posture/assurance/rollout.js +3 -0
- package/src/posture/custom-rules.js +13 -1
- package/src/posture/fleet/cli.js +2 -4
- package/src/posture/fleet/fleet-manifest.js +4 -1
- package/src/posture/fleet/job-runner.js +28 -4
- package/src/posture/fleet/org-health.js +23 -0
- package/src/posture/fleet/scan-cache.js +1 -1
- package/src/posture/flow-narration.js +10 -8
- package/src/posture/llm-redteam.js +3 -1
- package/src/posture/provenance/coordinator.js +8 -0
- package/src/posture/provenance/origin-resolver.js +17 -4
- package/src/posture/rule-compiler/cli.js +56 -8
- package/src/posture/rule-compiler/corpus.js +10 -2
- package/src/posture/rule-compiler/ir.js +10 -1
- package/src/posture/rule-compiler/promotion.js +12 -2
- package/src/posture/rule-compiler/regression.js +1 -1
- package/src/posture/rule-compiler/store.js +27 -7
- package/src/posture/strategic-metrics.js +50 -7
- package/src/report/index.js +7 -6
- package/src/sca/llm-function-extract.js +17 -13
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,32 @@
|
|
|
9
9
|
> make the history less accurate, not more.
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
## 0.195.23 - GA programme, release C: one model transport, reviewed rule promotion, metrics with a scope, provenance that proves absence, fleet results that age
|
|
13
|
+
|
|
14
|
+
**Measured, 0.195.22:** `TIMINGS preflight=3s push=6s pr=4s checks=398s merge=5s verify=6s tag=2s release=161s npm=206s total=791s release-clock=174s`, shipped in 14 min 56 s on the second attempt (the first was stopped by the background gate's `ci-parity` check: a new deep-mode pin skipped under the hosted-CI switches until it set `DEEP_IN_CI` like the existing helper).
|
|
15
|
+
|
|
16
|
+
The next tranche of the GA plan that is code and tests: GA-06.3 (the model transport), GA-07.1 to 7.3 (the rule compiler's gates), GA-11.3 and 11.4 (strategic metrics), GA-05.2 and 5.4 (provenance parent boundaries) and GA-09.5 (fleet accounting). The lineage corpus was re-run on today's source for GA-03.1 and is still 17 of 24, with the same seven capability-tier failures the promotion record names (four source categories with no JavaScript catalog entry, an alias hop, an interprocedural return, an unsupported sink); that engine work is recorded as open, not done.
|
|
17
|
+
|
|
18
|
+
- **One transport for every model call.** `scanner/src/egress/transport.js` (`modelFetch`): no redirect is followed (a loopback endpoint answering 3xx to a remote host would have carried the prompt off the machine; eight call sites followed redirects by default), the reply is capped while it is read (every site read `res.json()` unbounded; 4 MiB by default, `AGENTIC_SECURITY_LLM_MAX_RESPONSE_BYTES`), every call has a deadline (four sites had none and could hold a scan open on a stalled connection), an optional process-wide wall budget (`AGENTIC_SECURITY_LLM_WALL_BUDGET_MS`), and proxy variables are documented as ignored. The validator, the Ollama provider, discovery, synthesis, the dependency function extractor, flow narration, the red-team sender, the adversary agent (its model call and its probes of the target) and the autopilot use it. The GA ledger check `egress-all-model-paths` now also fails on a model site that sends through a bare `fetch`, and a file that uses only the transport is still a candidate.
|
|
19
|
+
- **The `local` preset holds on every caller.** Flow narration, the dependency function extractor and the adversary agent read the raw endpoint variable and called it regardless of the preset; each resolves its provider as the validator does, so a non-loopback endpoint under `local` is refused there too, and a bare `OPENAI_API_KEY` is no longer attached to an arbitrary endpoint by the adversary agent. `0.0.0.0`, `[::]` and `http://0/` are refused as loopback (the unspecified address reaches a local interface by operating-system convention, not by its meaning); the contract page's table says so.
|
|
20
|
+
- **The rule compiler promotes by review.** `rules promote` needs `--reviewed-by <person>` (a model or agent name is not a reviewer) and records the reviewer and `--scope` in the ledger and the provenance. Promotion needs independent examples (`independentVulnerableCode`, `independentCleanCode`: outside the finding, never mutated; every vulnerable one detected, no safe one fired on), refuses a rule edited after its evaluation, an originating commit not in the repository's history, a hand-written rule file under the same id, and a promoted rule with the identical match. The lifecycle ledger is signed with the per-install key and never replaced by an empty one on a failed check; an unsigned pre-0.195.23 ledger is accepted once with `AGENTIC_SECURITY_RULES_UNSIGNED=1`. Every custom and compiled rule pattern now passes the SAST layer's superlinear-regex detector, not only the nested-quantifier heuristic (`(a|a)*b` was accepted). The CI templates run `rules regress` after the scan. Found on the way: the rule digest passed the top-level key list as the JSON replacer, which also filters nested objects, so `match.pattern` and every structural regex were digested as `{}`; the digest covers the whole rule now.
|
|
21
|
+
- **Strategic metrics state their scope.** The report carries `scope` (per-scan, the scan id and start time, the attempt window, and that it is not a trend), one status vocabulary on every metric (`measured`, `partial`, `unmeasured`; the learning rate was `not-measured`), and the remediation rate counts one attempt per finding (the latest; earlier ones reported as `repeated`), with `recorded`, `failed` and `window` beside the numerator and denominator. Five retries of one fix were five attempts before.
|
|
22
|
+
- **Provenance proves absence or says it cannot.** A parent commit whose replay failed counted as verified absence (`present: false` for any reason); it is now `partial` with reason `parent-not-inspectable`, and a `complete` result names its evidence of absence (`stableId-not-reproduced`, or `no-files-at-commit` for a file new in that commit).
|
|
23
|
+
- **Fleet results age, and a bad artifact is never green.** A cached repository result records when it was cached and is reused only inside the manifest's `cacheMaxAge` (7 days by default; a record with no time is never reused). An artifact that fails its hash check for an optional repository makes the organization degraded (it stayed green), the counts move from the state the repository had (a partial result's problem no longer decremented `complete`), and artifacts are written whole or not at all.
|
|
24
|
+
|
|
25
|
+
## 0.195.22 - GA programme, release B: every model path through the egress policy, one assurance decision on every surface, and unknown is not fresh
|
|
26
|
+
|
|
27
|
+
**Measured, 0.195.21:** `TIMINGS preflight=3s push=5s pr=4s checks=393s merge=5s verify=6s tag=2s release=223s npm=145s total=786s release-clock=236s`, shipped in 14 min 56 s on the third attempt (the first stopped at verify on the new expected-jobs rule because the check-runs query had never been paginated; the second stopped at the warm gate because the CodeQL summary check is not a workflow job). The npm check was re-run once with `--resume`.
|
|
28
|
+
|
|
29
|
+
The safety and semantics items of the GA plan that are code (GA-07.4, GA-07.5, GA-11.7, its day 5 and day 6, and the two contract failures its review found), built on the 0.195.21 ledger.
|
|
30
|
+
|
|
31
|
+
- **Detector-spec synthesis goes through the shared bounded model call.** `scripts/synthesize-detector.mjs` posted its prompt with a bare `fetch`: no egress policy, no redaction, no deadline, a regular-expression JSON extractor that could not parse the nested array it required, and an output path written anywhere. It is now a thin front over `scanner/src/discovery/detector-spec-synthesis.js`: the `detector-spec-synthesis` assurance feature (off by default), the egress policy evaluated BEFORE any sample file is read (a denied call reads nothing), bounded reads, a CSPRNG nonce, `guardedModelCall` (redaction, request cap, deadline with bounded retries, audit entry, output cap), the string-aware JSON parser the validator uses, and a closed-world validation of the proposal (identifiers only, so no field can carry a pattern; unknown fields, a wrong nonce and a bad argument index are refused with reasons, never with the raw reply). A proposal is written only inside the working directory, never under `scanner/src`, never over a file without `--force`; nothing installs it. Exit codes 0, 2, 3, 4. Eleven pins with an injected transport, and the `model-egress-policy` contract test now covers this path.
|
|
32
|
+
- **The autopilot's fix proposals too.** `scripts/autopilot.mjs` was the second model path the 0.195.21 egress check found: its whole-file fix prompt now goes through the egress policy (a denial leaves the finding NEEDS_REVIEW), the redactor and the audit log. The `model-egress-policy:EGRESS-ALL-PATHS` ledger record moves from `failed` to `passed`.
|
|
33
|
+
- **One assurance decision on every surface.** `posture/assurance/decision.js`: `deployable`, `needs_review`, `not_deployable`, or `unknown` when no scan health was recorded. The CLI ship verdict, the Slack, Discord and Teams digests and the pull-request comment all derive their wording from it; `digest` reads the scan health the last scan recorded. A findings file with no scan health now reads "cannot confirm", never "safe to deploy", and a scan object without scan health in the tests was re-pinned to that. The default wording of the three existing states is unchanged (the bounded wording stays the `portfolio-assurance` opt-in).
|
|
34
|
+
- **Unknown feed freshness is a condition.** `freshness.<feed>.stale` is tri-state and documented so; `null` for a feed the scan consulted (`consulted` items for the KEV catalog, `cvesChecked` for EPSS) because it was unavailable, never loaded or cached without a timestamp is a condition like staleness, the result is `partial` and strict mode fails closed on it. A feed the scan had nothing to look up in is not a condition, and neither is `offline-skipped`, the operator's own declared configuration. The catalog metadata is reset per scan so one scan cannot inherit another's. The test that asserted a boolean, and the offline clean-scan pin, now assert the tri-state and the feed-only conditions.
|
|
35
|
+
- **A suppression pragma now reaches privacy-flow findings.** The self-scan of the new synthesis module showed that `agentic-security-ignore` on a credential-to-HTTP line was inert: the privacy flows (`dataflow/privacy-taint.js`) are appended after both pragma passes, against the documented rule that a stage appending findings runs the filter after itself. A third pass runs after the privacy stage; pinned both ways with a deep-mode fixture, and the suppression is logged like every other.
|
|
36
|
+
- **The `proof doctor` exit code is documented.** 0 when an execution environment is usable, 1 when none is (the report is still printed), `--json` always 0. The contract test that demanded 0 on every host, and so failed on one without a confinement backend, now pins the documented contract; the CLI's behaviour is unchanged.
|
|
37
|
+
|
|
12
38
|
## 0.195.21 - The GA programme ledger: every shipped surface owned, every acceptance record machine-checked, every expected hosted job required
|
|
13
39
|
|
|
14
40
|
**Measured, 0.195.20:** `TIMINGS preflight=3s push=6s pr=1s checks=363s merge=5s verify=5s tag=2s release=192s npm=267s total=844s release-clock=204s`, shipped in 15 min 53 s on the second attempt (the first stopped in the hosted checks: the version bump had regenerated the scorecard before the support registry was re-measured, so the two carried different measurement dates; the scorecard was regenerated on the clean tree). The npm check was re-run once with `--resume`.
|
package/bin/agentic-security.js
CHANGED
|
@@ -3578,14 +3578,17 @@ async function cmdDigest(args) {
|
|
|
3578
3578
|
const summary = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
|
|
3579
3579
|
for (const f of (last.findings || [])) summary[f.severity || 'medium']++;
|
|
3580
3580
|
const project = args.flags.project || path.basename(target);
|
|
3581
|
+
// The digest states the shared assurance decision, which needs the scan health the last scan recorded; a findings file alone says "cannot confirm".
|
|
3582
|
+
let scanHealth = null;
|
|
3583
|
+
try { const ls = statePath(target, 'last-scan.json'); if (fs.existsSync(ls)) scanHealth = JSON.parse(await fsp.readFile(ls, 'utf8')).scanHealth || null; } catch { scanHealth = null; }
|
|
3581
3584
|
if (args.flags.slack) {
|
|
3582
|
-
const payload = buildSlackDigest(findings, summary, { project });
|
|
3585
|
+
const payload = buildSlackDigest(findings, summary, { project, scanHealth });
|
|
3583
3586
|
const r = await postWebhook(args.flags.slack, payload);
|
|
3584
3587
|
console.log(r.ok ? `✓ Slack digest sent` : `✗ Slack failed: ${r.reason || r.status}`);
|
|
3585
3588
|
return r.ok ? 0 : 4;
|
|
3586
3589
|
}
|
|
3587
3590
|
if (args.flags.discord) {
|
|
3588
|
-
const payload = buildDiscordDigest(findings, summary, { project });
|
|
3591
|
+
const payload = buildDiscordDigest(findings, summary, { project, scanHealth });
|
|
3589
3592
|
const r = await postWebhook(args.flags.discord, payload);
|
|
3590
3593
|
console.log(r.ok ? `✓ Discord digest sent` : `✗ Discord failed: ${r.reason || r.status}`);
|
|
3591
3594
|
return r.ok ? 0 : 4;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clear-capabilities/agentic-security-scanner",
|
|
3
|
-
"version": "0.195.
|
|
3
|
+
"version": "0.195.23",
|
|
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,7 +86,7 @@
|
|
|
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/todo-marker-words.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/vendor-java-parser-current.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/api-contract-scope.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/proof-fabric/generate-haskell-widened.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-transport.test.js test/local-preset-callers.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/api-contract-scope.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/accounting.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/proof-fabric/generate-haskell-widened.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/gates.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 test/dataflow-source-attribution.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
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",
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"verification:replay-example": "node ../scripts/verification-replay-example.mjs",
|
|
134
134
|
"test:lifecycle": "node --test test/ci-hang-protection.test.js test/gate-select.test.js test/ci-test-shards.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/trust-boundary.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/gate-warm.test.js test/docs-positioning.test.js test/dist-chunks-tracked.test.js test/ga-program.test.js test/workflow-confinement.test.js test/check-bundle-source.test.js test/ship.test.js test/release-prepare.test.js && node ../scripts/lint-command-descriptions.mjs",
|
|
135
135
|
"test:eval": "node --test test/independent-eval.test.js test/realworld-recall.test.js",
|
|
136
|
-
"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 test/context-intelligence/build-js.test.js test/context-intelligence/build-python-haskell.test.js test/context-intelligence/hie-adapter.test.js test/context-intelligence/store.test.js test/context-intelligence/review-queue.test.js test/context-intelligence/packer-egress.test.js test/context-intelligence/evaluation.test.js test/context-intelligence/queue-diff.test.js test/context-intelligence/cli.test.js test/context-intelligence/resilience.test.js test/context-intelligence/frameworks.test.js test/context-intelligence/skew-git-rls.test.js test/context-intelligence/premortem.test.js test/context-intelligence/git-diff-candidates.test.js",
|
|
136
|
+
"test:discovery": "node --test test/discovery-spec-synthesis.test.js 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 test/context-intelligence/build-js.test.js test/context-intelligence/build-python-haskell.test.js test/context-intelligence/hie-adapter.test.js test/context-intelligence/store.test.js test/context-intelligence/review-queue.test.js test/context-intelligence/packer-egress.test.js test/context-intelligence/evaluation.test.js test/context-intelligence/queue-diff.test.js test/context-intelligence/cli.test.js test/context-intelligence/resilience.test.js test/context-intelligence/frameworks.test.js test/context-intelligence/skew-git-rls.test.js test/context-intelligence/premortem.test.js test/context-intelligence/git-diff-candidates.test.js",
|
|
137
137
|
"eval:independent": "node ../bench/independent-eval/runner.mjs",
|
|
138
138
|
"eval:independent:gate": "node ../bench/independent-eval/runner.mjs --gate default",
|
|
139
139
|
"smoke": "node bin/agentic-security.js scan test/fixtures/vulnerable-js",
|
package/dist/550.index.js
CHANGED
|
@@ -287,8 +287,9 @@ function judgeCandidates(candidates, priorScan, triageFeedback) {
|
|
|
287
287
|
/* harmony export */ });
|
|
288
288
|
/* unused harmony exports defaultLlmInvoke, parseEndpoints, consensusOf, resolveLlmInvoke */
|
|
289
289
|
/* harmony import */ var _egress_policy_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(45712);
|
|
290
|
-
/* harmony import */ var
|
|
291
|
-
/* harmony import */ var
|
|
290
|
+
/* harmony import */ var _egress_transport_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(73785);
|
|
291
|
+
/* harmony import */ var _llm_validator_providers_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(38947);
|
|
292
|
+
/* harmony import */ var _llm_validator_ollama_provider_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(23837);
|
|
292
293
|
//
|
|
293
294
|
// Shared LLM endpoint caller. Both the hunter and the refutation panel need
|
|
294
295
|
// the same default endpoint caller when tests don't inject a mock. Two copies
|
|
@@ -300,6 +301,7 @@ function judgeCandidates(candidates, priorScan, triageFeedback) {
|
|
|
300
301
|
|
|
301
302
|
|
|
302
303
|
|
|
304
|
+
|
|
303
305
|
const DEFAULT_TIMEOUT_MS = 60000;
|
|
304
306
|
|
|
305
307
|
// agentic-security-ollama-offline-prd.md §32 — hunt is one of the highest-
|
|
@@ -326,7 +328,7 @@ async function defaultLlmInvoke(prompt, opts = {}) {
|
|
|
326
328
|
const timeoutMs = Number.isFinite(opts.timeoutMs) ? opts.timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
327
329
|
|
|
328
330
|
if (!opts.endpoint) {
|
|
329
|
-
const resolved = (0,
|
|
331
|
+
const resolved = (0,_llm_validator_providers_js__WEBPACK_IMPORTED_MODULE_2__.resolveProvider)({ role: opts.role || 'hunt' });
|
|
330
332
|
// A REFUSAL (a preset was explicitly configured and declined — e.g. a
|
|
331
333
|
// non-loopback Ollama host, or `local`'s own non-loopback refusal) must
|
|
332
334
|
// propagate here, not silently fall through to the legacy raw-endpoint
|
|
@@ -338,7 +340,7 @@ async function defaultLlmInvoke(prompt, opts = {}) {
|
|
|
338
340
|
if (!resolved.ok && resolved.reason) throw new Error(resolved.reason);
|
|
339
341
|
if (resolved.ok && resolved.config.provider === 'ollama') {
|
|
340
342
|
const oc = resolved.config.ollama;
|
|
341
|
-
const r = await (0,
|
|
343
|
+
const r = await (0,_llm_validator_ollama_provider_js__WEBPACK_IMPORTED_MODULE_3__/* .callOllamaChat */ .L5)({
|
|
342
344
|
host: resolved.config.endpoint,
|
|
343
345
|
model: resolved.config.model,
|
|
344
346
|
messages: [{ role: 'user', content: prompt }],
|
|
@@ -365,12 +367,11 @@ async function defaultLlmInvoke(prompt, opts = {}) {
|
|
|
365
367
|
// Absent, it falls back to the single configured endpoint — so the ordinary
|
|
366
368
|
// single-model path is byte-identical to what it was before consensus existed.
|
|
367
369
|
const endpoint = opts.endpoint || process.env.AGENTIC_SECURITY_LLM_ENDPOINT;
|
|
368
|
-
const res = await
|
|
370
|
+
const res = await (0,_egress_transport_js__WEBPACK_IMPORTED_MODULE_1__/* .modelFetch */ .Ye)(endpoint, {
|
|
369
371
|
method: 'POST',
|
|
370
372
|
headers: { 'content-type': 'application/json' },
|
|
371
373
|
body: JSON.stringify({ prompt }),
|
|
372
|
-
|
|
373
|
-
});
|
|
374
|
+
}, { timeoutMs });
|
|
374
375
|
if (!res.ok) throw new Error(`llm endpoint returned ${res.status}`);
|
|
375
376
|
const body = await res.json();
|
|
376
377
|
return typeof body === 'string' ? body : (body?.text ?? JSON.stringify(body));
|
|
@@ -513,7 +514,7 @@ function resolveLlmInvokeWithDecision(opts = {}) {
|
|
|
513
514
|
// exist, per the block comment above). Checked BEFORE the legacy
|
|
514
515
|
// raw-endpoint fallback below, matching providers.js's own precedence
|
|
515
516
|
// (ollama/local checked before a bare BYO endpoint).
|
|
516
|
-
const resolved = (0,
|
|
517
|
+
const resolved = (0,_llm_validator_providers_js__WEBPACK_IMPORTED_MODULE_2__.resolveProvider)({ role: opts.role || 'hunt' });
|
|
517
518
|
if (!resolved.ok && resolved.reason) {
|
|
518
519
|
// A REFUSAL (non-loopback ollama/local, explicitly configured and
|
|
519
520
|
// declined) is itself a policy decision — same shape as an egress
|
package/dist/5620.index.js
CHANGED
|
@@ -674,9 +674,7 @@ function runOfJob(store, id) {
|
|
|
674
674
|
async function finishRun({ args, root, store, runId, manifest, manifestFile, interrupted }) {
|
|
675
675
|
const { artifacts, problems } = (0,_job_runner_js__WEBPACK_IMPORTED_MODULE_8__/* .loadArtifacts */ .kZ)({ store, runId, root });
|
|
676
676
|
const jobs = store.listJobs(runId);
|
|
677
|
-
const health = (0,_org_health_js__WEBPACK_IMPORTED_MODULE_9__/* .computeOrgHealth */ .WB)({ manifest, jobs });
|
|
678
|
-
for (const p of problems) { const r = health.repositories.find((x) => x.id === p.repoId); if (r) { r.state = 'failed'; r.error = p.problem; } }
|
|
679
|
-
if (problems.length) { health.counts.complete -= problems.filter((p) => health.repositories.find((x) => x.id === p.repoId)).length; health.counts.failed += problems.length; if (health.assurance !== 'red' && manifest.repositories.some((r) => r.required && problems.some((p) => p.repoId === r.id))) health.assurance = 'red'; health.reasons.push(`${problems.length} result(s) could not be verified: ${problems.map((p) => `${p.repoId} (${p.problem})`).join(', ')}`); }
|
|
677
|
+
const health = (0,_org_health_js__WEBPACK_IMPORTED_MODULE_9__/* .applyArtifactProblems */ .Dh)((0,_org_health_js__WEBPACK_IMPORTED_MODULE_9__/* .computeOrgHealth */ .WB)({ manifest, jobs }), manifest, problems);
|
|
680
678
|
|
|
681
679
|
let previous = null;
|
|
682
680
|
const rollupFile = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_6__.statePath)(root, ROLLUP_FILE);
|
|
@@ -1433,7 +1431,7 @@ function blastRadius(graph, repoId) {
|
|
|
1433
1431
|
|
|
1434
1432
|
|
|
1435
1433
|
|
|
1436
|
-
const FLEET_MANIFEST_SCHEMA_KEYS = Object.freeze(['organization', 'repositories', 'workers', 'perRepoTimeout', 'retries', 'resources']);
|
|
1434
|
+
const FLEET_MANIFEST_SCHEMA_KEYS = Object.freeze(['organization', 'repositories', 'workers', 'perRepoTimeout', 'retries', 'resources', 'cacheMaxAge']);
|
|
1437
1435
|
const REPO_KEYS = Object.freeze(['id', 'path', 'required', 'kind', 'internetFacing', 'environment', 'dataClasses', 'trustZone', 'calls', 'produces', 'consumes', 'reads', 'writes', 'providers', 'aliases']);
|
|
1438
1436
|
const RESOURCE_KEYS = Object.freeze(['id', 'kind', 'dataClasses', 'trustZone', 'internetFacing', 'environment', 'aliases']);
|
|
1439
1437
|
const REPO_KINDS = Object.freeze(['service', 'library', 'frontend', 'worker', 'gateway']);
|
|
@@ -1512,12 +1510,15 @@ function validateFleetManifest(doc, { baseDir = '.' } = {}) {
|
|
|
1512
1510
|
if (doc.workers != null && !(Number.isInteger(doc.workers) && doc.workers >= 1 && doc.workers <= 32)) errors.push('workers must be an integer in 1..32');
|
|
1513
1511
|
if (doc.retries != null && !(Number.isInteger(doc.retries) && doc.retries >= 0 && doc.retries <= 5)) errors.push('retries must be an integer in 0..5');
|
|
1514
1512
|
if (doc.perRepoTimeout != null && parseDuration(doc.perRepoTimeout, null) == null) errors.push(`perRepoTimeout is not a valid duration: ${doc.perRepoTimeout}`);
|
|
1513
|
+
if (doc.cacheMaxAge != null && parseDuration(doc.cacheMaxAge, null) == null) errors.push(`cacheMaxAge is not a valid duration: ${doc.cacheMaxAge}`);
|
|
1515
1514
|
if (errors.length) return { ok: false, errors };
|
|
1516
1515
|
return {
|
|
1517
1516
|
ok: true, errors: [],
|
|
1518
1517
|
manifest: {
|
|
1519
1518
|
organization: doc.organization, repositories: repos, resources,
|
|
1520
1519
|
workers: doc.workers ?? 4, retries: doc.retries ?? 1, perRepoTimeoutMs: parseDuration(doc.perRepoTimeout, 20 * 60000),
|
|
1520
|
+
// GA-09: a cached result older than this is stale and is not reused (the feeds it was enriched with have moved on); 7 days by default
|
|
1521
|
+
cacheMaxAgeMs: parseDuration(doc.cacheMaxAge, 7 * 24 * 3600000),
|
|
1521
1522
|
},
|
|
1522
1523
|
};
|
|
1523
1524
|
}
|
|
@@ -1554,7 +1555,7 @@ __webpack_require__.a(__webpack_module__, async (__webpack_handle_async_dependen
|
|
|
1554
1555
|
/* harmony export */ nY: () => (/* binding */ planRun),
|
|
1555
1556
|
/* harmony export */ zD: () => (/* binding */ reclaimDeadWorkers)
|
|
1556
1557
|
/* harmony export */ });
|
|
1557
|
-
/* unused harmony
|
|
1558
|
+
/* unused harmony exports DEFAULTS, DEFAULT_CACHE_MAX_AGE_MS, cacheFreshness */
|
|
1558
1559
|
/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(73024);
|
|
1559
1560
|
/* harmony import */ var node_os__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(48161);
|
|
1560
1561
|
/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(76760);
|
|
@@ -1637,6 +1638,21 @@ function planRun({ manifest, manifestHash, store, runId = null, config = {}, now
|
|
|
1637
1638
|
* Run (or continue) a planned run until no job is queued or leased by a live worker. Returns when the work is done, the signal
|
|
1638
1639
|
* aborts, or `maxWaitMs` passes with only other workers' leases outstanding.
|
|
1639
1640
|
*/
|
|
1641
|
+
const DEFAULT_CACHE_MAX_AGE_MS = 7 * 24 * 3600000;
|
|
1642
|
+
|
|
1643
|
+
/**
|
|
1644
|
+
* Is a cache hit fresh enough to reuse (GA-09)? A record with no readable `cachedAt` (written before 0.195.23) is never fresh, and a
|
|
1645
|
+
* record older than `maxAgeMs` (the manifest's `cacheMaxAge`, 7 days by default) is stale. Returns `{ fresh, cacheAgeMs }`.
|
|
1646
|
+
*/
|
|
1647
|
+
function cacheFreshness(hit, maxAgeMs, nowMs) {
|
|
1648
|
+
if (!hit) return { fresh: false, cacheAgeMs: null };
|
|
1649
|
+
const t = typeof hit.cachedAt === 'string' ? Date.parse(hit.cachedAt) : NaN;
|
|
1650
|
+
if (Number.isNaN(t)) return { fresh: false, cacheAgeMs: null };
|
|
1651
|
+
const cacheAgeMs = Math.max(0, nowMs - t);
|
|
1652
|
+
const max = Number.isFinite(maxAgeMs) && maxAgeMs > 0 ? maxAgeMs : DEFAULT_CACHE_MAX_AGE_MS;
|
|
1653
|
+
return { fresh: cacheAgeMs <= max, cacheAgeMs };
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1640
1656
|
async function runJobs({ manifest, store, runId, root, scan = childScan, scanOptions = {}, workers = manifest.workers, leaseMs = DEFAULTS.leaseMs, heartbeatMs = DEFAULTS.heartbeatMs, retryDelayMs = DEFAULTS.retryDelayMs, pollMs = DEFAULTS.pollMs, maxWaitMs = null, signal, now = () => Date.now(), onEvent = () => {}, cacheDir = null, artifactDir = null, useCache = true }) {
|
|
1641
1657
|
const repoById = new Map(manifest.repositories.map((r) => [r.id, r]));
|
|
1642
1658
|
const cacheD = cacheDir ?? (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_6__.statePath)(root, 'fleet', 'cache');
|
|
@@ -1646,7 +1662,11 @@ async function runJobs({ manifest, store, runId, root, scan = childScan, scanOpt
|
|
|
1646
1662
|
const writeArtifact = (job, payload) => {
|
|
1647
1663
|
const text = JSON.stringify({ schema: 'agentic-security/fleet-scan-artifact', version: 1, runId, repoId: job.repoId, epoch: job.epoch, commit: job.commit, ...payload });
|
|
1648
1664
|
const file = node_path__WEBPACK_IMPORTED_MODULE_2__.join(artD, `${job.repoId}.${job.epoch}.json`);
|
|
1649
|
-
|
|
1665
|
+
// written whole or not at all (GA-09): a worker killed mid-write leaves no half artifact for the hash check to find, only a
|
|
1666
|
+
// stray temp file, and the job stays leased until the lease expires and another worker redoes it
|
|
1667
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
1668
|
+
node_fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(tmp, text, { mode: 0o600 });
|
|
1669
|
+
node_fs__WEBPACK_IMPORTED_MODULE_0__.renameSync(tmp, file);
|
|
1650
1670
|
return { file, sha256: sha(text) };
|
|
1651
1671
|
};
|
|
1652
1672
|
|
|
@@ -1668,11 +1688,16 @@ async function runJobs({ manifest, store, runId, root, scan = childScan, scanOpt
|
|
|
1668
1688
|
idleSince = null;
|
|
1669
1689
|
const repo = repoById.get(job.repoId);
|
|
1670
1690
|
onEvent({ type: 'start', repo: job.repoId, attempt: job.attempts });
|
|
1671
|
-
const
|
|
1691
|
+
const hit = useCache ? (0,_scan_cache_js__WEBPACK_IMPORTED_MODULE_7__/* .readCache */ .xe)(cacheD, job.cacheKey) : null;
|
|
1692
|
+
// GA-09: a hit is reused only while it is fresh. A result with no recorded time (written before 0.195.23) or older than the
|
|
1693
|
+
// manifest's `cacheMaxAge` is stale: it is scanned again, never folded into a green organization as if it were current.
|
|
1694
|
+
const { fresh, cacheAgeMs } = cacheFreshness(hit, manifest.cacheMaxAgeMs, now());
|
|
1695
|
+
const cached = fresh ? hit : null;
|
|
1696
|
+
if (hit && !cached) onEvent({ type: 'cache-stale', repo: job.repoId, cacheAgeMs });
|
|
1672
1697
|
if (cached) {
|
|
1673
|
-
const a = writeArtifact(job, { entry: cached.entry, findings: cached.findings, findingsTruncated: !!cached.findingsTruncated, lineage: cached.lineage ?? null, cached: true });
|
|
1698
|
+
const a = writeArtifact(job, { entry: cached.entry, findings: cached.findings, findingsTruncated: !!cached.findingsTruncated, lineage: cached.lineage ?? null, cached: true, cachedAt: cached.cachedAt, cacheAgeMs });
|
|
1674
1699
|
const status = cached.entry?.scanHealth && cached.entry.scanHealth.status !== 'complete' ? 'partial' : 'succeeded';
|
|
1675
|
-
if (store.complete(job.jobId, job.epoch, { status, artifactSha256: a.sha256, summary: { total: cached.entry?.total ?? null, cached: true, artifact: node_path__WEBPACK_IMPORTED_MODULE_2__.basename(a.file) }, now: now() })) onEvent({ type: 'done', repo: job.repoId, cached: true, status });
|
|
1700
|
+
if (store.complete(job.jobId, job.epoch, { status, artifactSha256: a.sha256, summary: { total: cached.entry?.total ?? null, cached: true, cacheAgeMs, artifact: node_path__WEBPACK_IMPORTED_MODULE_2__.basename(a.file) }, now: now() })) onEvent({ type: 'done', repo: job.repoId, cached: true, status });
|
|
1676
1701
|
continue;
|
|
1677
1702
|
}
|
|
1678
1703
|
const ac = new AbortController();
|
|
@@ -1946,6 +1971,7 @@ function summarizeLineage(graph) {
|
|
|
1946
1971
|
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
1947
1972
|
|
|
1948
1973
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1974
|
+
/* harmony export */ Dh: () => (/* binding */ applyArtifactProblems),
|
|
1949
1975
|
/* harmony export */ Vp: () => (/* binding */ renderOrgHealth),
|
|
1950
1976
|
/* harmony export */ WB: () => (/* binding */ computeOrgHealth)
|
|
1951
1977
|
/* harmony export */ });
|
|
@@ -1998,6 +2024,29 @@ function computeOrgHealth({ manifest, jobs }) {
|
|
|
1998
2024
|
return { counts, assurance, reasons, repositories: repos };
|
|
1999
2025
|
}
|
|
2000
2026
|
|
|
2027
|
+
/**
|
|
2028
|
+
* Fold artifact problems (a result whose file is missing or does not match its recorded hash) into the health (GA-09). The repository
|
|
2029
|
+
* becomes `failed`; a required one turns the organization red, an optional one makes it degraded (it used to stay green); the counts
|
|
2030
|
+
* move from whatever state the repository had, not always from `complete`. Returns the same object, changed in place.
|
|
2031
|
+
*/
|
|
2032
|
+
function applyArtifactProblems(health, manifest, problems) {
|
|
2033
|
+
if (!Array.isArray(problems) || !problems.length) return health;
|
|
2034
|
+
const stateKey = { complete: 'complete', partial: 'partial', failed: 'failed', 'timed-out': 'timedOut', cancelled: 'cancelled', 'not-run': 'notRun' };
|
|
2035
|
+
let requiredHit = false; let optionalHit = false;
|
|
2036
|
+
for (const p of problems) {
|
|
2037
|
+
const r = health.repositories.find((x) => x.id === p.repoId);
|
|
2038
|
+
if (!r) continue;
|
|
2039
|
+
if (r.state !== 'failed') { health.counts[stateKey[r.state]]--; health.counts.failed++; }
|
|
2040
|
+
r.state = 'failed'; r.error = p.problem;
|
|
2041
|
+
const required = manifest.repositories.some((m) => m.id === p.repoId && m.required);
|
|
2042
|
+
if (required) requiredHit = true; else optionalHit = true;
|
|
2043
|
+
}
|
|
2044
|
+
if (requiredHit) health.assurance = 'red';
|
|
2045
|
+
else if (optionalHit && health.assurance === 'green') health.assurance = 'degraded';
|
|
2046
|
+
health.reasons.push(`${problems.length} result(s) could not be verified: ${problems.map((p) => `${p.repoId} (${p.problem})`).join(', ')}`);
|
|
2047
|
+
return health;
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2001
2050
|
const n = (x) => x.toLocaleString('en-US');
|
|
2002
2051
|
function renderOrgHealth(h) {
|
|
2003
2052
|
const c = h.counts;
|
|
@@ -2131,7 +2180,7 @@ function writeCache(dir, key, payload) {
|
|
|
2131
2180
|
if (!key || !/^[0-9a-f]{64}$/.test(key)) return false;
|
|
2132
2181
|
try {
|
|
2133
2182
|
node_fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
2134
|
-
const body = { schema: 'agentic-security/fleet-scan-cache', version: 1, key, ...payload };
|
|
2183
|
+
const body = { schema: 'agentic-security/fleet-scan-cache', version: 1, key, cachedAt: new Date().toISOString(), ...payload };
|
|
2135
2184
|
const doc = { ...body, digest: sha(JSON.stringify(body)) };
|
|
2136
2185
|
const tmp = node_path__WEBPACK_IMPORTED_MODULE_1__.join(dir, `.${key}.${process.pid}.tmp`);
|
|
2137
2186
|
node_fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(tmp, JSON.stringify(doc), { mode: 0o600 });
|
package/dist/5937.index.js
CHANGED
|
@@ -82,10 +82,12 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
82
82
|
|
|
83
83
|
// EXTERNAL MODULE: external "node:fs"
|
|
84
84
|
var external_node_fs_ = __webpack_require__(73024);
|
|
85
|
-
// EXTERNAL MODULE: ./src/posture/state-dir.js
|
|
86
|
-
var state_dir = __webpack_require__(31174);
|
|
87
85
|
// EXTERNAL MODULE: external "node:path"
|
|
88
86
|
var external_node_path_ = __webpack_require__(76760);
|
|
87
|
+
// EXTERNAL MODULE: external "node:child_process"
|
|
88
|
+
var external_node_child_process_ = __webpack_require__(31421);
|
|
89
|
+
// EXTERNAL MODULE: ./src/posture/state-dir.js
|
|
90
|
+
var state_dir = __webpack_require__(31174);
|
|
89
91
|
// EXTERNAL MODULE: external "node:crypto"
|
|
90
92
|
var external_node_crypto_ = __webpack_require__(77598);
|
|
91
93
|
// EXTERNAL MODULE: ./src/posture/rule-compiler/ir.js
|
|
@@ -149,6 +151,8 @@ function verifyLedger(ledger) {
|
|
|
149
151
|
function historyFor(ledger, ruleId) { return ledger.entries.filter((e) => e.ruleId === ruleId); }
|
|
150
152
|
function stateOf(ledger, ruleId) { return currentState(ledger, ruleId); }
|
|
151
153
|
|
|
154
|
+
// EXTERNAL MODULE: ./src/posture/integrity.js
|
|
155
|
+
var integrity = __webpack_require__(71130);
|
|
152
156
|
// EXTERNAL MODULE: ./src/posture/rule-pack-signing.js
|
|
153
157
|
var rule_pack_signing = __webpack_require__(99527);
|
|
154
158
|
;// CONCATENATED MODULE: ./src/posture/rule-compiler/store.js
|
|
@@ -164,25 +168,45 @@ var rule_pack_signing = __webpack_require__(99527);
|
|
|
164
168
|
|
|
165
169
|
|
|
166
170
|
|
|
171
|
+
|
|
167
172
|
const DIR = 'rule-compiler';
|
|
168
173
|
const EXT = { javascript: 'js', typescript: 'ts', python: 'py', go: 'go', ruby: 'rb', java: 'java', rust: 'rs', csharp: 'cs', php: 'php', any: 'txt' };
|
|
169
174
|
|
|
170
175
|
function ruleDir(scanRoot, id) { return (0,state_dir.statePath)(scanRoot, DIR, id); }
|
|
171
176
|
|
|
172
|
-
|
|
177
|
+
/**
|
|
178
|
+
* The lifecycle ledger is hash-chained (lifecycle.js) AND signed with the per-install HMAC key (the same key as last-scan.json),
|
|
179
|
+
* since 0.195.23 (GA-07): the chain alone could be recomputed by anyone who could edit the file. A ledger that fails either check,
|
|
180
|
+
* or that cannot be parsed, is returned WITH `tampered: true` and its reason, and `saveLedger` refuses to write it, so a bad ledger
|
|
181
|
+
* is never quietly replaced by a fresh one and its history lost. An unsigned ledger with entries (written before 0.195.23) is
|
|
182
|
+
* accepted only with AGENTIC_SECURITY_RULES_UNSIGNED=1, the same switch that accepts an unsigned rules override, and is signed on
|
|
183
|
+
* its next save.
|
|
184
|
+
*/
|
|
185
|
+
function loadLedger(scanRoot, env = process.env) {
|
|
173
186
|
const f = (0,state_dir.statePath)(scanRoot, DIR, 'ledger.json');
|
|
174
187
|
if (!external_node_fs_.existsSync(f)) return newLedger();
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
188
|
+
let text;
|
|
189
|
+
try { text = external_node_fs_.readFileSync(f, 'utf8'); } catch (e) { return { ...newLedger(), tampered: true, tamperReason: `cannot read the ledger: ${e.message}` }; }
|
|
190
|
+
let ledger;
|
|
191
|
+
try { ledger = JSON.parse(text); } catch (e) { return { ...newLedger(), tampered: true, tamperReason: `the ledger is not valid JSON: ${e.message}` }; }
|
|
192
|
+
if (!ledger || !Array.isArray(ledger.entries)) return { ...newLedger(), tampered: true, tamperReason: 'the ledger has no entries array' };
|
|
193
|
+
const v = verifyLedger(ledger);
|
|
194
|
+
if (!v.ok) return { ...ledger, tampered: true, tamperReason: v.reason };
|
|
195
|
+
const sig = (0,integrity/* verifyLastScan */.Ef)(text, `${f}.sig`);
|
|
196
|
+
if (sig === false) return { ...ledger, tampered: true, tamperReason: 'the ledger signature does not verify under this install key' };
|
|
197
|
+
if (sig === null && ledger.entries.length && env.AGENTIC_SECURITY_RULES_UNSIGNED !== '1') {
|
|
198
|
+
return { ...ledger, tampered: true, tamperReason: 'the ledger is unsigned (written before 0.195.23 or by another tool); set AGENTIC_SECURITY_RULES_UNSIGNED=1 once to accept and re-sign it' };
|
|
199
|
+
}
|
|
200
|
+
return ledger;
|
|
180
201
|
}
|
|
181
202
|
|
|
182
203
|
function saveLedger(scanRoot, ledger) {
|
|
204
|
+
if (ledger?.tampered) return { ok: false, reason: `refusing to overwrite a ledger that failed its integrity check (${ledger.tamperReason})` };
|
|
183
205
|
if (!(0,state_dir.ensureStateDir)(scanRoot)) return { ok: false, reason: 'no safe state directory for this project' };
|
|
184
206
|
const f = (0,state_dir.statePath)(scanRoot, DIR, 'ledger.json');
|
|
185
|
-
|
|
207
|
+
const text = JSON.stringify(ledger, null, 2);
|
|
208
|
+
const ok = (0,state_dir.safeWriteState)(f, text) && (0,state_dir.safeWriteState)(`${f}.sig`, (0,integrity/* signLastScan */.lU)(text));
|
|
209
|
+
return { ok };
|
|
186
210
|
}
|
|
187
211
|
|
|
188
212
|
function saveIR(scanRoot, ir) {
|
|
@@ -455,6 +479,8 @@ var reproducer = __webpack_require__(37055);
|
|
|
455
479
|
|
|
456
480
|
|
|
457
481
|
|
|
482
|
+
|
|
483
|
+
|
|
458
484
|
function loadFinding(root, id) {
|
|
459
485
|
const p = (0,state_dir.statePath)(root, 'last-scan.json');
|
|
460
486
|
if (!external_node_fs_.existsSync(p)) return null;
|
|
@@ -469,6 +495,12 @@ function readJsonArg(pathOrInline) {
|
|
|
469
495
|
|
|
470
496
|
async function cmdRules(args, root) {
|
|
471
497
|
const sub = args._[1];
|
|
498
|
+
// GA-07: a ledger that failed its integrity check (broken chain, bad or missing signature) refuses EVERY command, not only the
|
|
499
|
+
// ones that change state; nothing below can read a tampered history as fact or write over it.
|
|
500
|
+
if (['synthesize', 'evaluate', 'promote', 'status', 'rollback', 'cost', 'regress'].includes(sub)) {
|
|
501
|
+
const guard = loadLedger(root);
|
|
502
|
+
if (guard.tampered) { console.error(`Refusing: rule lifecycle ledger failed its integrity check (${guard.tamperReason}).`); return 4; }
|
|
503
|
+
}
|
|
472
504
|
if (sub === 'synthesize') return cmdSynthesize(args, root);
|
|
473
505
|
if (sub === 'evaluate') return cmdEvaluate(args, root);
|
|
474
506
|
if (sub === 'promote') return cmdPromote(args, root);
|
|
@@ -476,7 +508,7 @@ async function cmdRules(args, root) {
|
|
|
476
508
|
if (sub === 'rollback') return cmdRollback(args, root);
|
|
477
509
|
if (sub === 'cost') return cmdCost(args, root);
|
|
478
510
|
if (sub === 'regress') return cmdRegress(args, root);
|
|
479
|
-
console.error('usage: rules synthesize <finding-id> --spec <file.json> [--auto] [--max-attempts N] | evaluate <rule-id> | promote <rule-id> | status [rule-id] | rollback <rule-id> | cost <rule-id>');
|
|
511
|
+
console.error('usage: rules synthesize <finding-id> --spec <file.json> [--auto] [--max-attempts N] | evaluate <rule-id> | promote <rule-id> --reviewed-by <person> [--scope <text>] | status [rule-id] | rollback <rule-id> | cost <rule-id> | regress [rule-id]');
|
|
480
512
|
return 4;
|
|
481
513
|
}
|
|
482
514
|
|
|
@@ -495,7 +527,7 @@ async function cmdSynthesize(args, root) {
|
|
|
495
527
|
// The candidate pattern is the model's or the person's, when they gave one. Without one, or with --auto, the synthesis loop proposes
|
|
496
528
|
// from the vulnerable and patched code, scores each attempt on the real corpus and its mutations, and revises (see proposal.js).
|
|
497
529
|
let finalSpec = spec; let synthesis = null;
|
|
498
|
-
const corpusSpec = { originalCode: spec.originalCode, patchedCode: spec.patchedCode ?? null, nearbyCleanCode: spec.nearbyCleanCode ?? [], protectedVariantsCode: spec.protectedVariantsCode ?? [] };
|
|
530
|
+
const corpusSpec = { originalCode: spec.originalCode, patchedCode: spec.patchedCode ?? null, nearbyCleanCode: spec.nearbyCleanCode ?? [], protectedVariantsCode: spec.protectedVariantsCode ?? [], independentVulnerableCode: spec.independentVulnerableCode ?? [], independentCleanCode: spec.independentCleanCode ?? [] };
|
|
499
531
|
const leak = (0,promotion/* checkLeakage */.r_)(JSON.stringify(corpusSpec), { benchmarkNames: args.flags['benchmark-names'] ? String(args.flags['benchmark-names']).split(',') : [], fileNames: spec.fileNames ?? [] });
|
|
500
532
|
if (!leak.ok) { console.error(`Refusing: the material for this rule shows benchmark or answer-key signals (${leak.offendingTerms.join('; ')}). Nothing was written.`); return 4; }
|
|
501
533
|
if (args.flags.auto || (!spec.match && !spec.sink)) {
|
|
@@ -554,7 +586,7 @@ async function cmdEvaluate(args, root) {
|
|
|
554
586
|
originatingFinding: ir.provenance.originatingFindingId, originatingCommit: ir.provenance.originatingCommit, evidenceState: ir.provenance.evidenceState,
|
|
555
587
|
generatingModel: ir.provenance.model, promptConfigVersion: ir.provenance.promptConfigVersion,
|
|
556
588
|
positiveCorpusHash: corpusHash(corpus.positives), negativeCorpusHash: corpusHash(corpus.negatives),
|
|
557
|
-
benchmarkResults: { precision: gate.evaluation.score.precision, recall: gate.evaluation.score.recall, tp: gate.evaluation.score.tp, fp: gate.evaluation.score.fp, fn: gate.evaluation.score.fn, tn: gate.evaluation.score.tn, protectedFailures: gate.evaluation.score.protectedFailures, thresholds: gate.evaluation.thresholds, gate: gate.pass ? 'passed' : 'failed', reasons: gate.reasons },
|
|
589
|
+
benchmarkResults: { precision: gate.evaluation.score.precision, recall: gate.evaluation.score.recall, tp: gate.evaluation.score.tp, fp: gate.evaluation.score.fp, fn: gate.evaluation.score.fn, tn: gate.evaluation.score.tn, protectedFailures: gate.evaluation.score.protectedFailures, independent: gate.independent, thresholds: gate.evaluation.thresholds, gate: gate.pass ? 'passed' : 'failed', reasons: gate.reasons },
|
|
558
590
|
leakageCheck: leakage, mutatorCoverage: (0,mutation/* mutatorCoverage */.xv)(corpusSpec.originalCode), discoveryCost: corpusSpec.discoveryCost ?? prev?.discoveryCost ?? null,
|
|
559
591
|
promotionEvent: prev?.promotionEvent ?? null, evaluatedAt: new Date().toISOString(),
|
|
560
592
|
});
|
|
@@ -570,23 +602,63 @@ async function cmdEvaluate(args, root) {
|
|
|
570
602
|
function isStr(v) { return typeof v === 'string' && v.length > 0; }
|
|
571
603
|
const fmtPct = (n) => (n == null ? 'unmeasured' : `${(n * 100).toFixed(1)}%`);
|
|
572
604
|
|
|
605
|
+
/** Does this commit exist in the project's history? `true`, `false`, or `null` when the project is not a git repository. */
|
|
606
|
+
function commitExists(root, sha) {
|
|
607
|
+
if (!external_node_fs_.existsSync(external_node_path_.join(root, '.git'))) return null;
|
|
608
|
+
try { (0,external_node_child_process_.execFileSync)('git', ['cat-file', '-e', `${sha}^{commit}`], { cwd: root, stdio: 'ignore' }); return true; } catch { return false; }
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
const NOT_A_REVIEWER = /^(?:agent|model|auto|bot|llm|ai)$/i;
|
|
612
|
+
|
|
613
|
+
// Promotion is a reviewed, human decision (GA-07). It needs the reviewer's name, a rule that is exactly the one that was evaluated, a
|
|
614
|
+
// provenance that checks out, and no conflict with a rule that already exists; a model's recommendation on its own promotes nothing.
|
|
573
615
|
async function cmdPromote(args, root) {
|
|
574
616
|
const id = args._[2];
|
|
575
|
-
if (!id) { console.error('usage: rules promote <rule-id>'); return 4; }
|
|
617
|
+
if (!id) { console.error('usage: rules promote <rule-id> --reviewed-by <person> [--scope <text>] [--reason <text>]'); return 4; }
|
|
618
|
+
const reviewer = args.flags['reviewed-by'];
|
|
619
|
+
if (!isStr(reviewer) || NOT_A_REVIEWER.test(reviewer.trim())) {
|
|
620
|
+
console.error('usage: rules promote <rule-id> --reviewed-by <person>. A promotion records the person who reviewed the rule and its scope; a model or agent recommendation is not a review, so nothing is promoted without a named reviewer.');
|
|
621
|
+
return 4;
|
|
622
|
+
}
|
|
576
623
|
const ledger = loadLedger(root);
|
|
577
624
|
if (ledger.tampered) { console.error(`Refusing: rule lifecycle ledger failed its integrity check (${ledger.tamperReason}).`); return 4; }
|
|
578
625
|
if (stateOf(ledger, id) !== 'VALIDATED') { console.error(`Rule ${id} is not VALIDATED (run rules evaluate first); refusing to promote.`); return 4; }
|
|
579
626
|
const ir = loadIR(root, id);
|
|
580
627
|
if (!ir) { console.error(`No rule IR found for ${id}.`); return 4; }
|
|
628
|
+
// the rule promoted must be the rule evaluated: an IR edited after `rules evaluate` has no evidence
|
|
629
|
+
const prov = loadProvenance(root, id);
|
|
630
|
+
if (!prov) { console.error(`Promotion refused: no evaluation record for ${id}; run rules evaluate first.`); return 4; }
|
|
631
|
+
if (prov.ruleHash !== (0,rule_compiler_ir/* ruleIRDigest */.GE)(ir)) { console.error(`Promotion refused: the rule ${id} changed after it was evaluated (evaluated ${String(prov.ruleHash).slice(0, 12)}, now ${(0,rule_compiler_ir/* ruleIRDigest */.GE)(ir).slice(0, 12)}); run rules evaluate again.`); return 4; }
|
|
632
|
+
// a named originating commit must be real history, not a typed-in string
|
|
633
|
+
const commit = ir.provenance?.originatingCommit;
|
|
634
|
+
if (commit) {
|
|
635
|
+
const exists = commitExists(root, commit);
|
|
636
|
+
if (exists === false) { console.error(`Promotion refused: originating commit ${commit} is not in this repository's history (invalid provenance).`); return 4; }
|
|
637
|
+
if (exists === null) { console.error(`Promotion refused: originating commit ${commit} cannot be verified because this project is not a git repository.`); return 4; }
|
|
638
|
+
}
|
|
639
|
+
// conflicts: a hand-written rule file with the same id, or a promoted rule with the identical match
|
|
640
|
+
const live = (0,state_dir.statePath)(root, 'rules', `${id}.yml`);
|
|
641
|
+
let firstLine = null; // null: no file there (or unreadable, which is treated as absent below only when the read fails with ENOENT)
|
|
642
|
+
try { firstLine = external_node_fs_.readFileSync(live, 'utf8').split('\n')[0]; } catch (e) { if (e.code !== 'ENOENT') firstLine = ''; }
|
|
643
|
+
if (firstLine !== null && !firstLine.startsWith('# Compiled by the rule compiler')) { console.error(`Promotion refused: a rule file that the compiler did not write already exists at ${live}; choose another rule id or remove that file deliberately.`); return 4; }
|
|
644
|
+
for (const other of promotedRuleIds(ledger)) {
|
|
645
|
+
if (other === id) continue;
|
|
646
|
+
const oir = loadIR(root, other);
|
|
647
|
+
if (oir && JSON.stringify(oir.match) === JSON.stringify(ir.match) && JSON.stringify(oir.languages) === JSON.stringify(ir.languages)) {
|
|
648
|
+
console.error(`Promotion refused: ${id} duplicates the promoted rule ${other} (identical match on the same languages); roll one back or narrow this one.`);
|
|
649
|
+
return 4;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
581
652
|
// other rules may have been promoted since this one was evaluated: hold it to the false-positive corpus as it is NOW
|
|
582
653
|
const fpNow = falsePositiveHits(ir, sharedFalsePositiveCorpus(root, ledger, id));
|
|
583
654
|
if (fpNow.length) { console.error(`Promotion refused: ${id} fires on ${fpNow.length} item(s) of the shared false-positive corpus (${fpNow.slice(0, 3).map((h) => h.label).join(', ')}). Re-evaluate or narrow the rule.`); return 1; }
|
|
584
655
|
const pub = publishCustomRule(root, ir);
|
|
585
656
|
if (!pub.ok) { console.error(`Promotion refused: ${pub.reason}`); return 4; }
|
|
586
|
-
const
|
|
657
|
+
const scope = isStr(args.flags.scope) ? args.flags.scope : null;
|
|
658
|
+
const review = { reviewer: reviewer.trim(), scope, independent: prov.benchmarkResults?.independent ?? null };
|
|
659
|
+
const t = recordTransition(ledger, { ruleId: id, from: 'VALIDATED', to: 'PROMOTED', reason: args.flags.reason || 'promoted', evidence: review, actor: args.flags.actor || reviewer.trim() });
|
|
587
660
|
saveLedger(root, ledger);
|
|
588
|
-
|
|
589
|
-
if (prov) saveProvenance(root, id, { ...prov, promotionEvent: { at: new Date().toISOString(), actor: args.flags.actor || 'operator', reason: args.flags.reason || 'promoted', ruleHash: (0,rule_compiler_ir/* ruleIRDigest */.GE)(ir) } });
|
|
661
|
+
saveProvenance(root, id, { ...prov, promotionEvent: { at: new Date().toISOString(), actor: args.flags.actor || reviewer.trim(), reviewer: reviewer.trim(), scope, reason: args.flags.reason || 'promoted', ruleHash: (0,rule_compiler_ir/* ruleIRDigest */.GE)(ir) } });
|
|
590
662
|
console.log(`Rule ${id}: VALIDATED -> PROMOTED. Published to ${pub.file}.`);
|
|
591
663
|
// Publishing is not trusting. Rule packs are signature-checked so a rule dropped into a repository cannot run in someone's CI; sign this
|
|
592
664
|
// one with the operator's key when there is one, and say plainly whether the scanner will load it.
|