@clear-capabilities/agentic-security-scanner 0.174.0 → 0.176.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 +23 -0
- package/bin/agentic-security.js +199 -28
- package/dist/2066.index.js +850 -0
- package/dist/2199.index.js +1 -1
- package/dist/2584.index.js +3332 -0
- package/dist/2923.index.js +13 -0
- package/dist/2946.index.js +81 -0
- package/dist/3196.index.js +27 -0
- package/dist/3727.index.js +292 -0
- package/dist/4168.index.js +509 -0
- package/dist/4281.index.js +993 -0
- package/dist/4978bec8fdf5c733dc85.json +283 -0
- package/dist/5099.index.js +96 -0
- package/dist/5616.index.js +1471 -0
- package/dist/5620.index.js +2370 -0
- package/dist/5817.index.js +714 -0
- package/dist/6333.index.js +98 -0
- package/dist/6655.index.js +3221 -0
- package/dist/7838.index.js +446 -974
- package/dist/818.index.js +4 -3
- package/dist/83.index.js +159 -0
- package/dist/8551.index.js +82 -0
- package/dist/8633.index.js +93 -0
- package/dist/8714.index.js +76 -76
- package/dist/8825.index.js +84 -0
- package/dist/932.index.js +186 -0
- package/dist/9560.index.js +358 -19
- package/dist/9800.index.js +6 -1
- package/dist/agentic-security.mjs +10 -10
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/dist/df1e8683e7eda7b2b79c.js +29 -0
- package/package.json +7 -6
- package/src/artifact/CLAUDE.md +4 -0
- package/src/artifact/artifact-evidence.js +63 -0
- package/src/artifact/cosign.js +61 -0
- package/src/artifact/engine-source.js +72 -0
- package/src/artifact/oci-layout.js +47 -0
- package/src/artifact/registry.js +213 -0
- package/src/capabilities/tool-registry.js +2 -0
- package/src/language/haskell-security-rules.js +1 -1
- package/src/language/nixos-hardening.js +37 -0
- package/src/lineage/CLAUDE.md +4 -0
- package/src/lineage/identity-token.js +11 -0
- package/src/lineage/observation-adapters.js +13 -0
- package/src/lineage/runtime-edge-states.js +139 -0
- package/src/lineage/runtime-explorer-view.js +82 -0
- package/src/lineage/runtime-observation.js +11 -0
- package/src/mcp/CLAUDE.md +3 -1
- package/src/mcp/proof-tools.js +132 -0
- package/src/mcp/server.js +1 -1
- package/src/mcp/tools.js +3 -1
- package/src/posture/CLAUDE.md +23 -0
- package/src/posture/artifact-registry.js +4 -0
- package/src/posture/dnr/attack-facts.js +31 -0
- package/src/posture/dnr/cli.js +138 -0
- package/src/posture/dnr/detection-ir.js +123 -0
- package/src/posture/dnr/exposure-window.js +134 -0
- package/src/posture/dnr/hunt.js +84 -0
- package/src/posture/dnr/log-reader.js +189 -0
- package/src/posture/dnr/matchers.js +90 -0
- package/src/posture/dnr/outputs.js +262 -0
- package/src/posture/dnr/payload-classes.js +120 -0
- package/src/posture/dnr/redact.js +25 -0
- package/src/posture/dnr/store.js +57 -0
- package/src/posture/dnr/validate.js +64 -0
- package/src/posture/dnr/view.js +51 -0
- package/src/posture/evaluation/lab/arm-ollama.js +88 -0
- package/src/posture/evaluation/lab/arms.js +142 -0
- package/src/posture/evaluation/lab/cli.js +135 -0
- package/src/posture/evaluation/lab/dataset.js +139 -0
- package/src/posture/evaluation/lab/materialize.js +44 -0
- package/src/posture/evaluation/lab/neutralize.js +144 -0
- package/src/posture/evaluation/lab/report.js +176 -0
- package/src/posture/evaluation/lab/run.js +225 -0
- package/src/posture/evaluation/lab/score.js +135 -0
- package/src/posture/evaluation/lab/scoreboard.js +48 -0
- package/src/posture/evaluation/lab/stats.js +41 -0
- package/src/posture/evaluation/lab/store.js +53 -0
- package/src/posture/fleet/cli.js +248 -63
- package/src/posture/fleet/discover-edges.js +135 -0
- package/src/posture/fleet/enterprise-graph.js +148 -0
- package/src/posture/fleet/fleet-graph.js +9 -4
- package/src/posture/fleet/fleet-manifest.js +50 -5
- package/src/posture/fleet/job-runner.js +153 -0
- package/src/posture/fleet/job-store.js +136 -0
- package/src/posture/fleet/org-health.js +56 -0
- package/src/posture/fleet/scan-cache.js +112 -0
- package/src/posture/fleet/scan-child.js +29 -0
- package/src/posture/proof-fabric/cli.js +34 -6
- package/src/posture/proof-fabric/container.js +57 -0
- package/src/posture/proof-fabric/fix-proof.js +2 -1
- package/src/posture/proof-fabric/generate-python.js +129 -0
- package/src/posture/proof-fabric/generate.js +213 -0
- package/src/posture/proof-fabric/reproducer.js +3 -0
- package/src/posture/proof-fabric/runner.js +20 -11
- package/src/posture/proof-fabric/siblings.js +77 -0
- package/src/posture/routing/policy-router.js +103 -0
- package/src/posture/rule-compiler/cli.js +64 -6
- package/src/posture/rule-compiler/corpus.js +10 -2
- package/src/posture/rule-compiler/mutation.js +72 -1
- package/src/posture/rule-compiler/promotion.js +21 -5
- package/src/posture/rule-compiler/proposal.js +132 -0
- package/src/posture/rule-compiler/store.js +16 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
ccbccaa1ca1f3c6b8f1332e15cb9ee82fa2c4712cc68d0eb2c47051aaa1f7989 agentic-security.mjs
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Child-process entry for ONE repository's scan inside a fleet run (PRD 4, requirement 4: one hung repository must not stop the
|
|
2
|
+
// fleet). `node scan-child.js <repoPath>`. It exists as its own process so the controller can kill a scan that does not finish,
|
|
3
|
+
// together with everything the scan started; an in-process scan cannot be interrupted.
|
|
4
|
+
//
|
|
5
|
+
// It runs the scan through the existing `runFleet` for a single repository, so the per-repository entry (finding counts, owners
|
|
6
|
+
// from CODEOWNERS, scan health, policy drift, provenance debt) is exactly what a fleet entry has always been, and prints that entry
|
|
7
|
+
// plus a slim copy of the findings between markers. Scan state writes are disabled (`AGENTIC_SECURITY_NO_STATE=1`, set by the
|
|
8
|
+
// controller): scanning a repository for the fleet must not change that repository.
|
|
9
|
+
import { runFleet } from '../fleet.js';
|
|
10
|
+
import { runScan } from '../../runScan.js';
|
|
11
|
+
|
|
12
|
+
export const BEGIN = '@@FLEET-SCAN-BEGIN@@';
|
|
13
|
+
export const END = '@@FLEET-SCAN-END@@';
|
|
14
|
+
const MAX_FINDINGS = 5000;
|
|
15
|
+
|
|
16
|
+
const slim = (f) => ({ id: f.id ?? null, stableId: f.stableId ?? null, severity: f.severity ?? null, cwe: f.cwe ?? null, family: f.family ?? null, vuln: f.vuln ?? null, file: f.file ?? null, line: Number.isInteger(f.line) ? f.line : null, parser: f.parser ?? null });
|
|
17
|
+
|
|
18
|
+
async function main(repoPath) {
|
|
19
|
+
let captured = null;
|
|
20
|
+
const res = await runFleet({ repos: [repoPath], concurrency: 1, resume: false, runScan: async (p) => { const r = await runScan(p, { provenance: false }); captured = r.scan; return r; } });
|
|
21
|
+
const entry = res.results?.[0];
|
|
22
|
+
if (!entry) throw new Error('the scan produced no entry');
|
|
23
|
+
const findings = (captured?.findings ?? []).slice(0, MAX_FINDINGS).map(slim);
|
|
24
|
+
process.stdout.write(`${BEGIN}${JSON.stringify({ entry, findings, findingsTruncated: (captured?.findings?.length ?? 0) > MAX_FINDINGS })}${END}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (process.argv[1] && import.meta.url === new URL(`file://${process.argv[1]}`).href) {
|
|
28
|
+
main(process.argv[2]).then(() => process.exit(0), (e) => { process.stderr.write(String(e?.stack || e).slice(0, 4000)); process.exit(1); });
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clear-capabilities/agentic-security-scanner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.176.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",
|
|
@@ -85,15 +85,15 @@
|
|
|
85
85
|
"test:ollama-e2e": "AGENTIC_SECURITY_OLLAMA_E2E=1 node --test test/ollama-e2e.test.js",
|
|
86
86
|
"test:glob": "node --test test/glob-compat.test.js",
|
|
87
87
|
"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/zip-slip-go.test.js test/redos-anchoring.test.js test/path-guard-validator-call.test.js test/redos-nfa.test.js test/weak-randomness.test.js test/csharp-pipeline.test.js test/csharp-cross-file.test.js test/post-quantum-crypto.test.js test/web3-advanced.test.js test/cloud-iam-k8s.test.js test/crypto-protocol.test.js test/ml-supply-chain.test.js test/mcp-audit-scan.test.js test/wrong-context-sanitizer.test.js test/sanitizer-context.test.js test/frontend-hygiene.test.js test/csv-injection.test.js test/stored-taint.test.js test/tree-sitter-sinks.test.js test/kotlin-structural.test.js test/ruby-php-structural.test.js test/java-csharp-structural.test.js test/java-structural-cross-file.test.js test/guard-recognition.test.js test/guard-window-identifier-correlation.test.js test/js-python-framework-structural.test.js test/go-structural.test.js test/secret-concat.test.js test/secret-redaction.test.js test/xss-reflected-multilang.test.js test/code-injection-multilang.test.js test/xxe-multilang.test.js test/xpath-injection-multilang.test.js test/gapfill-batch13.test.js test/agent-untrusted-flow.test.js test/api-authz.test.js test/event-entrypoint.test.js test/iac-terraform.test.js test/cross-service.test.js test/rbac-consistency.test.js test/adversarial-robustness.test.js test/secret-entropy.test.js test/comment-strip.test.js test/juliet-path-filter-gate.test.js test/java-bench-shape-opt-in.test.js test/java-ast-folding.test.js test/java-bench-extras.test.js test/reachability-missing-callgraph-data.test.js test/rate-limit.test.js test/auth-signals.test.js test/convention-deviation.test.js test/resource-exhaustion.test.js test/resource-exhaustion-realworld.test.js test/redirect-toctou.test.js test/redirect-toctou-realworld.test.js test/codegen-sink.test.js test/ownership-authz.test.js test/ownership-authz-realworld.test.js test/t21-precision-audit.test.js test/secrets-coverage.test.js test/prompt-injection-payloads.test.js test/iac-cloud-templates.test.js test/ruby-path-join.test.js test/sast/manifest-line-tracking.test.js test/rust-sast.test.js test/java-deserialization-precision.test.js test/pipeline-env-secret.test.js test/mark-used-vuln-functions.test.js",
|
|
88
|
-
"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/temp-leak-guard.test.js test/release-workflow.test.js test/release-workflow-structure.test.js test/independent-population.test.js test/why-missed.test.js test/independent-scoring.test.js test/evidence-bundle.test.js test/obligation-evidence-pack.test.js test/policy-bundle.test.js test/discovery-memory.test.js test/mttr.test.js test/license-policy.test.js test/aibom.test.js test/sbom.test.js test/api-inventory.test.js test/iam-policy.test.js test/container.test.js test/container-runtime.test.js test/image-packages.test.js test/kev.test.js test/dep-confusion.test.js test/sca-deprecated.test.js test/sca-batch.test.js test/composite-risk.test.js test/epss-enrich.test.js test/sca-coverage.test.js test/gradle-deps.test.js test/sca-route-reachable.test.js test/sca-policy.test.js test/sca-verdict.test.js test/install-script.test.js test/sca-linked-findings.test.js test/packs.test.js test/flow-narration.test.js test/regression-test-gen.test.js test/deterministic-fix.test.js test/falsification.test.js test/verification-separation.test.js test/logic-claims.test.js test/attestation.test.js test/verify-attestation-cli.test.js test/comparison.test.js test/determinism-cross-machine.test.js test/fix-honesty-gate.test.js test/model-routing.test.js test/root-cause-sweep.test.js test/entrypoint-inventory.test.js test/relevance.test.js test/untrusted.test.js test/agent-hardening.test.js test/rule-synthesis.test.js test/policy-gate.test.js test/agents-memory.test.js test/cve-lookup.test.js test/cve-alert-daemon.test.js test/fix-verify-loop.test.js test/fix-verify-tests.test.js test/fix-acceptance.test.js test/exploitability-probability.test.js test/history-scan.test.js test/viral-features.test.js test/viral-v074.test.js test/state-dir.test.js test/ignore-pragma.test.js test/license-graph.test.js test/secret-live-check.test.js test/attack-taxonomy.test.js test/triage-memory.test.js test/pr-augment.test.js test/chat-batch2.test.js test/chat-batch3.test.js test/chat-batch4.test.js test/chat-batch5.test.js test/chat-batch6.test.js test/risk-scenario-disclosure.test.js test/egress-policy.test.js test/egress-policy-completeness.test.js test/egress-policy-integration.test.js test/router.test.js test/legacy-alias-redirect.test.js test/cache-economics.test.js test/coverage-report.test.js test/corpus-status.test.js test/provenance.test.js test/secret-history.test.js test/execution-proof.test.js test/fix-metrics.test.js test/corpus-enroll.test.js test/prove-findings.test.js test/corpus-match.test.js test/corpus-provenance.test.js test/learning-quorum.test.js test/llm-cache-integrity.test.js test/proof-artifact.test.js test/providers.test.js test/fleet.test.js test/autopilot.test.js test/autopilot-cli.test.js test/verifier-independence.test.js test/integrity-legacy-key.test.js test/suppression-visibility.test.js test/cost-ceiling.test.js test/local-endpoint.test.js test/ollama-provider.test.js test/ollama-capabilities.test.js test/ollama-offline-egress.test.js test/ollama-fix-proposal.test.js test/ollama-explain-proposal.test.js test/ollama-poc-proposal.test.js test/ollama-model-probe.test.js test/ollama-agent-tools.test.js test/ollama-agent-loop.test.js test/ollama-e2e.test.js test/ollama-oom-feedback.test.js test/ollama-doc-drift.test.js test/model-trust.test.js test/vuln-archaeology.test.js test/scan-checkpoint.test.js test/llm-redact.test.js test/world-class-batch2.test.js test/world-class-modules.test.js test/privacy-ir-adapter.test.js test/privacy-taxonomy.test.js test/privacy-sink-policy.test.js test/privacy-governance.test.js test/privacy-inventory.test.js test/integration-end-to-end.test.js test/streak-cli-wiring.test.js test/stack-playbook.test.js test/machine-output-flag.test.js test/stdout-flush.test.js test/format-determinism.test.js test/only-flag-channels.test.js test/confidence.test.js test/security-trend.test.js test/calibration-drift.test.js test/validator-metrics.test.js test/clustering-ir-taint-line.test.js test/concurrency-cwe.test.js test/compliance-mapping-liveness.test.js test/module-artifact-liveness.test.js test/supply-chain-provenance-completeness.test.js test/compliance-severity-threshold.test.js test/compliance-severity-policy.test.js test/compliance-evidence-binding.test.js test/compliance-evidence-signing.test.js test/compliance-file-contains.test.js test/label-isolation.test.js test/evidence-grade-wording.test.js test/llm-model-status.test.js test/egress-policy-constraints.test.js test/egress-redact.test.js test/egress-audit.test.js test/egress-approved-providers.test.js test/family-registry.test.js test/coverage-strength.test.js test/framework-provenance.test.js test/framework-provenance-controlrefs.test.js test/third-party-verification.test.js test/proof-coverage.test.js test/calibration-holdout.test.js test/independent-population-gate.test.js test/catalog-freshness.test.js test/incremental-parity.test.js test/surface-smoke.test.js test/fix-coverage.test.js test/raw-source-carveout.test.js test/mlbom-conformance.test.js test/deploy-gate-replay.test.js test/sbom-conformance.test.js test/unscored-claims.test.js test/mcp-rug-pull.test.js test/agent-boundary-taint.test.js test/confinement-adversarial.test.js test/comment-strip-cost.test.js test/reachability-claim.test.js test/entrypoint-breadth.test.js test/dep-file-admission.test.js test/custom-rules-freshness.test.js test/posture/provenance-schema.test.js test/posture/provenance-cache.test.js test/helpers/build-git-fixture.test.js test/posture/provenance-git-evidence.test.js test/posture/provenance-dag-walk.test.js test/posture/provenance-confidence.test.js test/posture/provenance-predicate-replay.test.js test/posture/provenance-origin-resolver.test.js test/posture/provenance-ai-authorship.test.js test/posture/provenance-branch-entry.test.js test/posture/provenance-evidence-attribution.test.js test/posture/provenance-lifecycle.test.js test/posture/provenance-missing-control-resolver.test.js test/posture/provenance-missing-control-wiring.test.js test/posture/provenance-coordinator.test.js test/posture/provenance-sca-origin.test.js test/posture/provenance-transitive-sca.test.js test/posture/provenance-coordinator-sca.test.js test/posture/provenance-providers.test.js test/posture/provenance-evidence-bundle.test.js test/posture/provenance-repo-lineage.test.js test/posture/provenance-secrets-logic.test.js test/cli/provenance-flags.test.js test/cli/attest-provenance.test.js test/cli/attest-obligations.test.js test/cli/models.test.js test/cli/setup-llm.test.js test/cli/fix-retry.test.js test/cli/compliance-walkthrough-lineage.test.js test/cli/dataflow-export-privacy.test.js test/cli/dataflow-export-briefing.test.js test/cli/lineage-snapshot-persist.test.js test/cli/dataflow-diff.test.js test/cli/dataflow-watch.test.js test/cli/dataflow-recipients.test.js test/cli/dataflow-coverage.test.js test/security/provenance-safety.test.js test/security/provenance-injection.test.js test/posture/remediation-ledger.test.js test/posture/assurance-baseline.test.js test/posture/assurance-contracts.test.js test/posture/assurance-config.test.js test/evidence-issuer.test.js test/load-factor.test.js test/proof-fabric/core.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/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/cli/artifact-provenance-cli.test.js",
|
|
88
|
+
"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/temp-leak-guard.test.js test/release-workflow.test.js test/release-workflow-structure.test.js test/independent-population.test.js test/why-missed.test.js test/independent-scoring.test.js test/evidence-bundle.test.js test/obligation-evidence-pack.test.js test/policy-bundle.test.js test/discovery-memory.test.js test/mttr.test.js test/license-policy.test.js test/aibom.test.js test/sbom.test.js test/api-inventory.test.js test/iam-policy.test.js test/container.test.js test/container-runtime.test.js test/image-packages.test.js test/kev.test.js test/dep-confusion.test.js test/sca-deprecated.test.js test/sca-batch.test.js test/composite-risk.test.js test/epss-enrich.test.js test/sca-coverage.test.js test/gradle-deps.test.js test/sca-route-reachable.test.js test/sca-policy.test.js test/sca-verdict.test.js test/install-script.test.js test/sca-linked-findings.test.js test/packs.test.js test/flow-narration.test.js test/regression-test-gen.test.js test/deterministic-fix.test.js test/falsification.test.js test/verification-separation.test.js test/logic-claims.test.js test/attestation.test.js test/verify-attestation-cli.test.js test/comparison.test.js test/determinism-cross-machine.test.js test/fix-honesty-gate.test.js test/model-routing.test.js test/root-cause-sweep.test.js test/entrypoint-inventory.test.js test/relevance.test.js test/untrusted.test.js test/agent-hardening.test.js test/rule-synthesis.test.js test/policy-gate.test.js test/agents-memory.test.js test/cve-lookup.test.js test/cve-alert-daemon.test.js test/fix-verify-loop.test.js test/fix-verify-tests.test.js test/fix-acceptance.test.js test/exploitability-probability.test.js test/history-scan.test.js test/viral-features.test.js test/viral-v074.test.js test/state-dir.test.js test/ignore-pragma.test.js test/license-graph.test.js test/secret-live-check.test.js test/attack-taxonomy.test.js test/triage-memory.test.js test/pr-augment.test.js test/chat-batch2.test.js test/chat-batch3.test.js test/chat-batch4.test.js test/chat-batch5.test.js test/chat-batch6.test.js test/risk-scenario-disclosure.test.js test/egress-policy.test.js test/egress-policy-completeness.test.js test/egress-policy-integration.test.js test/router.test.js test/legacy-alias-redirect.test.js test/cache-economics.test.js test/coverage-report.test.js test/corpus-status.test.js test/provenance.test.js test/secret-history.test.js test/execution-proof.test.js test/fix-metrics.test.js test/corpus-enroll.test.js test/prove-findings.test.js test/corpus-match.test.js test/corpus-provenance.test.js test/learning-quorum.test.js test/llm-cache-integrity.test.js test/proof-artifact.test.js test/providers.test.js test/fleet.test.js test/autopilot.test.js test/autopilot-cli.test.js test/verifier-independence.test.js test/integrity-legacy-key.test.js test/suppression-visibility.test.js test/cost-ceiling.test.js test/local-endpoint.test.js test/ollama-provider.test.js test/ollama-capabilities.test.js test/ollama-offline-egress.test.js test/ollama-fix-proposal.test.js test/ollama-explain-proposal.test.js test/ollama-poc-proposal.test.js test/ollama-model-probe.test.js test/ollama-agent-tools.test.js test/ollama-agent-loop.test.js test/ollama-e2e.test.js test/ollama-oom-feedback.test.js test/ollama-doc-drift.test.js test/model-trust.test.js test/vuln-archaeology.test.js test/scan-checkpoint.test.js test/llm-redact.test.js test/world-class-batch2.test.js test/world-class-modules.test.js test/privacy-ir-adapter.test.js test/privacy-taxonomy.test.js test/privacy-sink-policy.test.js test/privacy-governance.test.js test/privacy-inventory.test.js test/integration-end-to-end.test.js test/streak-cli-wiring.test.js test/stack-playbook.test.js test/machine-output-flag.test.js test/stdout-flush.test.js test/format-determinism.test.js test/only-flag-channels.test.js test/confidence.test.js test/security-trend.test.js test/calibration-drift.test.js test/validator-metrics.test.js test/clustering-ir-taint-line.test.js test/concurrency-cwe.test.js test/compliance-mapping-liveness.test.js test/module-artifact-liveness.test.js test/supply-chain-provenance-completeness.test.js test/compliance-severity-threshold.test.js test/compliance-severity-policy.test.js test/compliance-evidence-binding.test.js test/compliance-evidence-signing.test.js test/compliance-file-contains.test.js test/label-isolation.test.js test/evidence-grade-wording.test.js test/llm-model-status.test.js test/egress-policy-constraints.test.js test/egress-redact.test.js test/egress-audit.test.js test/egress-approved-providers.test.js test/family-registry.test.js test/coverage-strength.test.js test/framework-provenance.test.js test/framework-provenance-controlrefs.test.js test/third-party-verification.test.js test/proof-coverage.test.js test/calibration-holdout.test.js test/independent-population-gate.test.js test/catalog-freshness.test.js test/incremental-parity.test.js test/surface-smoke.test.js test/fix-coverage.test.js test/raw-source-carveout.test.js test/mlbom-conformance.test.js test/deploy-gate-replay.test.js test/sbom-conformance.test.js test/unscored-claims.test.js test/mcp-rug-pull.test.js test/agent-boundary-taint.test.js test/confinement-adversarial.test.js test/comment-strip-cost.test.js test/reachability-claim.test.js test/entrypoint-breadth.test.js test/dep-file-admission.test.js test/custom-rules-freshness.test.js test/posture/provenance-schema.test.js test/posture/provenance-cache.test.js test/helpers/build-git-fixture.test.js test/posture/provenance-git-evidence.test.js test/posture/provenance-dag-walk.test.js test/posture/provenance-confidence.test.js test/posture/provenance-predicate-replay.test.js test/posture/provenance-origin-resolver.test.js test/posture/provenance-ai-authorship.test.js test/posture/provenance-branch-entry.test.js test/posture/provenance-evidence-attribution.test.js test/posture/provenance-lifecycle.test.js test/posture/provenance-missing-control-resolver.test.js test/posture/provenance-missing-control-wiring.test.js test/posture/provenance-coordinator.test.js test/posture/provenance-sca-origin.test.js test/posture/provenance-transitive-sca.test.js test/posture/provenance-coordinator-sca.test.js test/posture/provenance-providers.test.js test/posture/provenance-evidence-bundle.test.js test/posture/provenance-repo-lineage.test.js test/posture/provenance-secrets-logic.test.js test/cli/provenance-flags.test.js test/cli/attest-provenance.test.js test/cli/attest-obligations.test.js test/cli/models.test.js test/cli/setup-llm.test.js test/cli/fix-retry.test.js test/cli/compliance-walkthrough-lineage.test.js test/cli/dataflow-export-privacy.test.js test/cli/dataflow-export-briefing.test.js test/cli/lineage-snapshot-persist.test.js test/cli/dataflow-diff.test.js test/cli/dataflow-watch.test.js test/cli/dataflow-recipients.test.js test/cli/dataflow-coverage.test.js test/security/provenance-safety.test.js test/security/provenance-injection.test.js test/posture/remediation-ledger.test.js test/posture/assurance-baseline.test.js test/posture/assurance-contracts.test.js test/posture/assurance-config.test.js test/evidence-issuer.test.js test/load-factor.test.js test/fleet/job-store.test.js test/fleet/enterprise-graph.test.js test/fleet/discover-edges.test.js test/fleet/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/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/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/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/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",
|
|
89
89
|
"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",
|
|
90
90
|
"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",
|
|
91
91
|
"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",
|
|
92
|
-
"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 test/lineage/runtime-assurance.test.js test/cli/runtime-twin-cli.test.js",
|
|
92
|
+
"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 test/lineage/runtime-assurance.test.js test/lineage/runtime-edge-states.test.js test/lineage/runtime-explorer-view.test.js test/cli/runtime-explorer-cli.test.js test/cli/runtime-identity-cli.test.js test/cli/runtime-twin-cli.test.js",
|
|
93
93
|
"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",
|
|
94
94
|
"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",
|
|
95
|
-
"test:haskell": "node --test test/haskell/haskell-models-extended.test.js test/haskell/haskell-rules-extended.test.js 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 test/haskell/haskell-supply-bounds.test.js test/haskell/haskell-ir-scaling.test.js",
|
|
96
|
-
"test:nix": "node --test test/nix/nixos-hardening-extended.test.js 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 test/nix/nix-fix-prewrite.test.js",
|
|
95
|
+
"test:haskell": "node --test test/haskell/haskell-weak-hash-names.test.js test/haskell/haskell-models-extended.test.js test/haskell/haskell-rules-extended.test.js 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 test/haskell/haskell-supply-bounds.test.js test/haskell/haskell-ir-scaling.test.js",
|
|
96
|
+
"test:nix": "node --test test/nix/nixos-hardening-daemon.test.js test/nix/nixos-hardening-extended.test.js 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 test/nix/nix-fix-prewrite.test.js",
|
|
97
97
|
"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",
|
|
98
98
|
"test:language-stress": "node --test --test-concurrency=1 test/language/language-stress-offline.test.js",
|
|
99
99
|
"test:language-tools": "node --test test/haskell/haskell-web-auth.test.js test/haskell/haskell-support-gate.test.js",
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
"verification:conformance:check": "node ../scripts/verification-conformance-check.mjs",
|
|
131
131
|
"verification:conformance:static": "node ../scripts/verification-conformance-check.mjs --static",
|
|
132
132
|
"verification:replay-example": "node ../scripts/verification-replay-example.mjs",
|
|
133
|
-
"test:lifecycle": "node --test test/ci-hang-protection.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/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",
|
|
133
|
+
"test:lifecycle": "node --test test/ci-hang-protection.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/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 test/release-prepare.test.js",
|
|
134
134
|
"test:eval": "node --test test/independent-eval.test.js test/realworld-recall.test.js",
|
|
135
135
|
"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
136
|
"eval:independent": "node ../bench/independent-eval/runner.mjs",
|
|
@@ -173,6 +173,7 @@
|
|
|
173
173
|
"bench:memory:check": "node ../bench/memory/runner.mjs --check",
|
|
174
174
|
"bench:memory:update-baseline": "node ../bench/memory/runner.mjs --update-baseline",
|
|
175
175
|
"check:bundle-source": "node ../scripts/check-bundle-source.mjs",
|
|
176
|
+
"release:prepare": "node ../scripts/release-prepare.mjs",
|
|
176
177
|
"ship": "node ../scripts/ship.mjs",
|
|
177
178
|
"bench:self-scan": "node ../bench/self-scan/measure.mjs",
|
|
178
179
|
"bench:self-scan:check": "node ../bench/self-scan/check.mjs",
|
package/src/artifact/CLAUDE.md
CHANGED
|
@@ -98,3 +98,7 @@ registry reference are **NOT implemented** — only `docker save`/OCI-layout TAR
|
|
|
98
98
|
(same precedent as `fleet/`, `rule-compiler/`, `proof-fabric/` — not large enough for its own scoped script).
|
|
99
99
|
`test/helpers/build-tar-fixture.js` is a test-only tar/OCI-archive WRITER (production code only ever reads
|
|
100
100
|
tar, via `safe-tar.js`) — mirrors `build-git-fixture.js`'s role for the lineage/deployment suites.
|
|
101
|
+
|
|
102
|
+
## Image sources, cosign and evidence (PRD 5 gap closure)
|
|
103
|
+
|
|
104
|
+
`registry.js` (explicit remote OCI fetch; builds an OCI layout via `oci-layout.js`), `engine-source.js` (`docker|podman save`), `cosign.js` (delegated verification, digest-bound, `unavailable` is never `verified`) and `artifact-evidence.js` (Ed25519 bundle, top-level-key allowlist). All three sources end in the same `parseImageArchive`. Registry credentials live in a class that refuses to serialize; never log or put them in an error.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// A signed, portable evidence bundle for one image scan (PRD 5; the sibling-bundle pattern of provenance-evidence-bundle.js).
|
|
2
|
+
// Ed25519, verifiable with only the public key, same key material and the same defence as its siblings: an ALLOWLIST of top-level
|
|
3
|
+
// keys is signed, and a bundle with any other key is refused, because a signature covers only the bytes it was computed over.
|
|
4
|
+
//
|
|
5
|
+
// What it carries is what the scan found, and nothing that is secret: secret findings are reported by layer, path and kind, never by
|
|
6
|
+
// value. What it proves is that the record is unmodified since signing. It does not prove the scan was complete or the image safe;
|
|
7
|
+
// the truncation flags and the signature state travel inside it so a reader can see how much was and was not checked.
|
|
8
|
+
import * as crypto from 'node:crypto';
|
|
9
|
+
import { ensureKeyPair, keyPaths, canonicalJson } from '../posture/evidence-bundle.js';
|
|
10
|
+
|
|
11
|
+
export const ARTIFACT_BUNDLE_SCHEMA = 'agentic-security/artifact-evidence@1';
|
|
12
|
+
const PROVES = 'This bundle\'s contents are exactly what was signed at attestation time.';
|
|
13
|
+
const DOES_NOT_PROVE = 'This bundle does NOT prove the image is free of vulnerabilities or secrets: read `scan.truncated` and `scan.vulnerabilityLookup` for how much was checked, and `signature` for whether the image\'s own signature was verified. It proves the RECORD is unmodified, not that the conclusions are complete.';
|
|
14
|
+
const MAX_ITEMS = 500;
|
|
15
|
+
|
|
16
|
+
export function buildArtifactEvidenceBundle(record, { engineVersion = null, source = null, signatureResult = null } = {}) {
|
|
17
|
+
if (!record?.inventory?.digest) return null;
|
|
18
|
+
const inv = record.inventory;
|
|
19
|
+
const vulns = (record.vulnerabilities || []).filter((v) => v?.type === 'vulnerable_dep');
|
|
20
|
+
return {
|
|
21
|
+
schema: ARTIFACT_BUNDLE_SCHEMA,
|
|
22
|
+
artifact: {
|
|
23
|
+
digest: inv.digest, digestKind: inv.digestKind ?? null, format: inv.format ?? null, os: inv.os ?? null, architecture: inv.architecture ?? null,
|
|
24
|
+
labels: inv.buildLabels ?? inv.labels ?? null, source: source ? { kind: source.kind ?? null, registry: source.registry ?? null, repository: source.repository ?? null, reference: source.reference ?? null, runtime: source.runtime ?? null } : null,
|
|
25
|
+
},
|
|
26
|
+
scan: {
|
|
27
|
+
scannedAt: record.scannedAt ?? null,
|
|
28
|
+
packages: { os: inv.osPackages?.length ?? 0, app: inv.appPackages?.length ?? 0 },
|
|
29
|
+
vulnerabilities: vulns.slice(0, MAX_ITEMS).map((v) => ({ id: v.id ?? v.vulnId ?? null, package: v.package ?? v.name ?? null, version: v.version ?? null, severity: v.severity ?? null, cve: v.cve ?? null, kev: v.kev ?? null })),
|
|
30
|
+
secrets: (record.secrets?.deletedButRecoverable || []).slice(0, MAX_ITEMS).map((s) => ({ layer: s.layerIndex ?? s.addedInLayer ?? null, path: s.path ?? null, kind: s.kind ?? s.type ?? s.vuln ?? null })),
|
|
31
|
+
truncated: { materialization: !!inv.materializationTruncated, vulnerabilitiesListed: Math.min(vulns.length, MAX_ITEMS), vulnerabilitiesTotal: vulns.length, secretsListed: Math.min(record.secrets?.deletedButRecoverable?.length ?? 0, MAX_ITEMS), secretsTotal: record.secrets?.deletedButRecoverable?.length ?? 0 },
|
|
32
|
+
vulnerabilityLookup: record.vulnerabilityLookup ?? 'osv (cached or live; see scannedAt)',
|
|
33
|
+
},
|
|
34
|
+
signature: signatureResult ? { state: signatureResult.state ?? null, via: signatureResult.via ?? null, reason: signatureResult.reason ?? null } : { state: 'not-checked', via: null, reason: 'no signature verification was requested for this bundle' },
|
|
35
|
+
engine: { engineVersion },
|
|
36
|
+
proves: PROVES,
|
|
37
|
+
doesNotProve: DOES_NOT_PROVE,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function signArtifactEvidenceBundle(bundle, privateKeyPem) {
|
|
42
|
+
const sig = crypto.sign(null, Buffer.from(canonicalJson(bundle), 'utf8'), privateKeyPem);
|
|
43
|
+
return { ...bundle, attestation: { algorithm: 'ed25519', canonicalisation: ARTIFACT_BUNDLE_SCHEMA, value: sig.toString('base64') } };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const TOP_LEVEL = new Set(['schema', 'artifact', 'scan', 'signature', 'engine', 'proves', 'doesNotProve', 'attestation']);
|
|
47
|
+
|
|
48
|
+
export function verifyArtifactEvidenceBundle(bundle, publicKeyPem) {
|
|
49
|
+
if (!bundle || typeof bundle !== 'object') return { ok: false, reason: 'bundle is not an object' };
|
|
50
|
+
if (bundle.schema !== ARTIFACT_BUNDLE_SCHEMA) return { ok: false, reason: `unrecognised schema: ${bundle.schema}` };
|
|
51
|
+
const unknown = Object.keys(bundle).filter((k) => !TOP_LEVEL.has(k));
|
|
52
|
+
if (unknown.length) return { ok: false, reason: `unrecognised top-level key(s) not covered by the signature: ${unknown.join(', ')}` };
|
|
53
|
+
const att = bundle.attestation;
|
|
54
|
+
if (!att?.value) return { ok: false, reason: 'bundle is unsigned' };
|
|
55
|
+
if (att.algorithm !== 'ed25519') return { ok: false, reason: `unsupported algorithm: ${att.algorithm}` };
|
|
56
|
+
if (!publicKeyPem) return { ok: false, reason: 'no public key supplied' };
|
|
57
|
+
const { attestation, ...unsigned } = bundle;
|
|
58
|
+
let ok = false;
|
|
59
|
+
try { ok = crypto.verify(null, Buffer.from(canonicalJson(unsigned), 'utf8'), publicKeyPem, Buffer.from(att.value, 'base64')); } catch (e) { return { ok: false, reason: `verification error: ${e.message}` }; }
|
|
60
|
+
return ok ? { ok: true, reason: null } : { ok: false, reason: 'signature does not match the bundle contents — it was modified after signing' };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { ensureKeyPair, keyPaths };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Signature verification by DELEGATION to cosign (PRD 5, requirement 5: "Sigstore, cosign"). This module does not implement keyless
|
|
2
|
+
// verification (certificate chains, transparency-log proofs, identity matching); cosign does, and this runs it and reads its answer.
|
|
3
|
+
//
|
|
4
|
+
// The state is one of verified | invalid | missing | unavailable, and the rules are conservative:
|
|
5
|
+
// * the check is bound to the DIGEST we scanned (`<repo>@sha256:...`), never to a tag, so a signature for some other image cannot
|
|
6
|
+
// be mistaken for this one;
|
|
7
|
+
// * `verified` needs cosign to exit 0 AND its output to name that exact digest in a signature payload. Exit 0 with a different (or no)
|
|
8
|
+
// digest is `invalid`;
|
|
9
|
+
// * a cosign that is not installed, that timed out, or that could not reach what it needed is `unavailable` and says so. It is never
|
|
10
|
+
// read as verified, and never as invalid either: a check that did not run is not a failed check;
|
|
11
|
+
// * the key is passed as a temporary file (mode 0600, removed afterwards) and the child gets a scrubbed environment.
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import os from 'node:os';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import { superviseSpawn } from '../sandbox/supervise.js';
|
|
16
|
+
import { scrubEnv } from '../sandbox/trust-domains.js';
|
|
17
|
+
|
|
18
|
+
const DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
|
|
19
|
+
const REPO_RE = /^[A-Za-z0-9][A-Za-z0-9.\-_/:]{0,300}$/;
|
|
20
|
+
|
|
21
|
+
function findTool(name, pathEnv = process.env.PATH || '') {
|
|
22
|
+
for (const dir of pathEnv.split(path.delimiter)) {
|
|
23
|
+
if (!dir) continue;
|
|
24
|
+
const p = path.join(dir, name);
|
|
25
|
+
try { fs.accessSync(p, fs.constants.X_OK); if (fs.statSync(p).isFile()) return fs.realpathSync(p); } catch { /* next */ }
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** @param {{repository: string, digest: string, publicKeyPem?: string, certificateIdentity?: string, certificateOidcIssuer?: string}} o */
|
|
31
|
+
export async function verifyWithCosign({ repository, digest, publicKeyPem = null, certificateIdentity = null, certificateOidcIssuer = null, timeoutMs = 60_000, signal, pathEnv = process.env.PATH } = {}) {
|
|
32
|
+
const na = (reason) => ({ state: 'unavailable', via: 'cosign', reason });
|
|
33
|
+
if (!DIGEST_RE.test(String(digest))) return na('there is no sha256 image digest to verify a signature against');
|
|
34
|
+
if (!REPO_RE.test(String(repository ?? '')) || String(repository).includes('..') || String(repository).startsWith('-')) return na('the repository name is not valid');
|
|
35
|
+
const keyless = !!(certificateIdentity && certificateOidcIssuer);
|
|
36
|
+
if (!publicKeyPem && !keyless) return na('no verification material: give a public key, or a certificate identity and OIDC issuer for keyless verification');
|
|
37
|
+
if (publicKeyPem && keyless) return na('give either a public key or a keyless identity, not both');
|
|
38
|
+
const bin = findTool('cosign', pathEnv);
|
|
39
|
+
if (!bin) return na('cosign is not installed; nothing was verified');
|
|
40
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'cosign-'));
|
|
41
|
+
try {
|
|
42
|
+
const args = ['verify'];
|
|
43
|
+
if (publicKeyPem) { const kf = path.join(dir, 'key.pub'); fs.writeFileSync(kf, publicKeyPem, { mode: 0o600 }); args.push('--key', kf); } else args.push('--certificate-identity', certificateIdentity, '--certificate-oidc-issuer', certificateOidcIssuer);
|
|
44
|
+
args.push(`${repository}@${digest}`);
|
|
45
|
+
const r = await superviseSpawn(bin, args, { cwd: dir, env: scrubEnv(process.env), timeoutMs, signal, maxOutputBytes: 2 * 1024 * 1024 });
|
|
46
|
+
if (r.spawnError) return na(`could not start cosign: ${r.spawnError}`);
|
|
47
|
+
if (r.timedOut) return na('cosign did not answer in time');
|
|
48
|
+
if (r.cancelled) return na('cancelled');
|
|
49
|
+
const err = String(r.stderr).toLowerCase();
|
|
50
|
+
if (r.exitCode === 0) {
|
|
51
|
+
let payloads = [];
|
|
52
|
+
try { const j = JSON.parse(r.stdout); payloads = Array.isArray(j) ? j : [j]; } catch { /* handled below */ }
|
|
53
|
+
const matching = payloads.filter((p) => p?.critical?.image?.['docker-manifest-digest'] === digest);
|
|
54
|
+
if (matching.length) return { state: 'verified', via: 'cosign', mode: keyless ? 'keyless' : 'key', signatures: matching.length, identity: keyless ? certificateIdentity : null, reason: null };
|
|
55
|
+
return { state: 'invalid', via: 'cosign', reason: 'cosign reported success but none of the verified signatures names this image digest' };
|
|
56
|
+
}
|
|
57
|
+
if (/no signatures found|no matching signatures|no signatures associated|manifest unknown/.test(err)) return { state: 'missing', via: 'cosign', reason: 'no signature exists for this digest' };
|
|
58
|
+
if (/invalid signature|signature verification failed|crypto\/ecdsa|verification failed|certificate identity|none of the expected identities/.test(err)) return { state: 'invalid', via: 'cosign', reason: 'cosign rejected the signature or the identity' };
|
|
59
|
+
return na(`cosign could not complete the check (exit ${r.exitCode}): ${String(r.stderr).trim().split('\n').pop()?.slice(0, 160) ?? ''}`);
|
|
60
|
+
} finally { try { fs.rmSync(dir, { recursive: true, force: true }); } catch { /* best effort */ } }
|
|
61
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Read an image from a LOCAL container engine (`docker save` / `podman save`), for `image scan --engine <name>` (PRD 5, requirement 1:
|
|
2
|
+
// "local image"). The engine produces a docker-archive tar, which then goes through the same hardened parser as any other archive.
|
|
3
|
+
//
|
|
4
|
+
// Nothing here runs the image: `save` only exports it. The engine is a process like any other in this codebase, so it has what the
|
|
5
|
+
// shared contract asks of one: a timeout, cancellation, process-group cleanup, and a byte cap on what it may produce. The cap
|
|
6
|
+
// matters because the output is streamed to a temporary file and counted as it arrives: an engine (or a mislabelled "engine") that
|
|
7
|
+
// writes without end is stopped at the cap instead of filling the disk. The temporary file is removed on every exit path.
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import os from 'node:os';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { spawn } from 'node:child_process';
|
|
12
|
+
|
|
13
|
+
export class EngineError extends Error {
|
|
14
|
+
constructor(message, code) { super(message); this.name = 'EngineError'; this.code = code; }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const ENGINE_LIMITS = Object.freeze({ timeoutMs: 5 * 60_000, maxBytes: 2 * 1024 * 1024 * 1024 });
|
|
18
|
+
const RUNTIMES = Object.freeze(['docker', 'podman']);
|
|
19
|
+
// a reference, never an option: it must start with a letter or digit, so it can never be read as a flag
|
|
20
|
+
const REF_RE = /^[A-Za-z0-9][A-Za-z0-9._\/:@+-]{0,254}$/;
|
|
21
|
+
|
|
22
|
+
function findTool(name, pathEnv = process.env.PATH || '') {
|
|
23
|
+
for (const dir of pathEnv.split(path.delimiter)) {
|
|
24
|
+
if (!dir) continue;
|
|
25
|
+
const p = path.join(dir, name);
|
|
26
|
+
try { fs.accessSync(p, fs.constants.X_OK); if (fs.statSync(p).isFile()) return fs.realpathSync(p); } catch { /* next */ }
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function saveFromEngine(ref, { runtime = 'docker', limits = ENGINE_LIMITS, signal = null, pathEnv = process.env.PATH } = {}) {
|
|
32
|
+
const L = { ...ENGINE_LIMITS, ...limits };
|
|
33
|
+
if (!RUNTIMES.includes(runtime)) return Promise.reject(new EngineError(`the container engine must be one of ${RUNTIMES.join(', ')}`, 'bad_runtime'));
|
|
34
|
+
if (!REF_RE.test(String(ref ?? '')) || String(ref).includes('..')) return Promise.reject(new EngineError('not a valid image reference', 'bad_reference'));
|
|
35
|
+
const bin = findTool(runtime, pathEnv);
|
|
36
|
+
if (!bin) return Promise.reject(new EngineError(`${runtime} is not installed or not on PATH; nothing was read`, 'engine_unavailable'));
|
|
37
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'engine-save-'));
|
|
38
|
+
const file = path.join(dir, 'image.tar');
|
|
39
|
+
const cleanup = () => { try { fs.rmSync(dir, { recursive: true, force: true }); } catch { /* best effort */ } };
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
const out = fs.createWriteStream(file, { mode: 0o600 });
|
|
42
|
+
out.on('error', (e) => fail(new EngineError(`could not write the export: ${e.code ?? e.message}`, 'engine_error')));
|
|
43
|
+
const child = spawn(bin, ['save', ref], { detached: true, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
44
|
+
let bytes = 0; let stderr = ''; let settled = false; let reason = null;
|
|
45
|
+
const kill = () => { try { process.kill(-child.pid, 'SIGKILL'); } catch { try { child.kill('SIGKILL'); } catch { /* gone */ } } };
|
|
46
|
+
const fail = (e) => { if (settled) return; settled = true; clearTimeout(timer); signal?.removeEventListener('abort', onAbort); kill(); out.destroy(); cleanup(); reject(e); };
|
|
47
|
+
const timer = setTimeout(() => { reason = 'timeout'; fail(new EngineError(`${runtime} save did not finish within ${Math.round(L.timeoutMs / 1000)}s`, 'timeout')); }, L.timeoutMs);
|
|
48
|
+
const onAbort = () => fail(new EngineError('cancelled', 'cancelled'));
|
|
49
|
+
if (signal) { if (signal.aborted) { onAbort(); return; } signal.addEventListener('abort', onAbort, { once: true }); }
|
|
50
|
+
child.stdout.on('data', (d) => {
|
|
51
|
+
if (settled) return;
|
|
52
|
+
bytes += d.length;
|
|
53
|
+
if (bytes > L.maxBytes) { fail(new EngineError(`the image export is larger than ${L.maxBytes} bytes`, 'too_large')); return; }
|
|
54
|
+
out.write(d);
|
|
55
|
+
});
|
|
56
|
+
child.stderr.on('data', (d) => { if (stderr.length < 4096) stderr += d; });
|
|
57
|
+
child.on('error', (e) => fail(new EngineError(`could not start ${runtime}: ${e.code ?? e.message}`, 'engine_unavailable')));
|
|
58
|
+
child.on('close', (code) => {
|
|
59
|
+
if (settled) return;
|
|
60
|
+
out.end(() => {
|
|
61
|
+
if (settled) return;
|
|
62
|
+
if (code !== 0) return fail(new EngineError(`${runtime} save failed: ${stderr.trim().split('\n').pop()?.slice(0, 200) || `exit ${code}`}`, /no such image|not found|unable to find/i.test(stderr) ? 'not_found' : 'engine_error'));
|
|
63
|
+
try {
|
|
64
|
+
const buf = fs.readFileSync(file);
|
|
65
|
+
settled = true; clearTimeout(timer); signal?.removeEventListener('abort', onAbort); cleanup();
|
|
66
|
+
resolve({ tar: buf, source: { kind: 'engine', runtime, reference: ref, bytes: buf.length } });
|
|
67
|
+
} catch (e) { fail(new EngineError(`could not read the exported image: ${e.code ?? e.message}`, 'engine_error')); }
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
void reason;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Assemble an OCI image-layout archive (a plain tar) from a manifest, a config and layer blobs that were already fetched and
|
|
2
|
+
// digest-verified. The result is exactly the shape `image-archive.js` reads from a local `oci-archive`, so a remote image and a local
|
|
3
|
+
// one go through ONE parser and the same size and path guards. Nothing is extracted to disk.
|
|
4
|
+
import crypto from 'node:crypto';
|
|
5
|
+
|
|
6
|
+
const BLOCK = 512;
|
|
7
|
+
|
|
8
|
+
function octal(n, len) { return n.toString(8).padStart(len - 1, '0') + '\0'; }
|
|
9
|
+
|
|
10
|
+
/** A single ustar entry. Names here are generated by this module (`blobs/sha256/<hex>`), never taken from the network. */
|
|
11
|
+
function tarEntry(name, data) {
|
|
12
|
+
if (Buffer.byteLength(name) > 100) throw new Error('tar entry name too long');
|
|
13
|
+
const header = Buffer.alloc(BLOCK, 0);
|
|
14
|
+
header.write(name, 0, 'utf8');
|
|
15
|
+
header.write(octal(0o644, 8), 100);
|
|
16
|
+
header.write(octal(0, 8), 108); header.write(octal(0, 8), 116);
|
|
17
|
+
header.write(octal(data.length, 12), 124);
|
|
18
|
+
header.write(octal(0, 12), 136);
|
|
19
|
+
header.fill(0x20, 148, 156);
|
|
20
|
+
header.write('0', 156);
|
|
21
|
+
header.write('ustar\0', 257); header.write('00', 263);
|
|
22
|
+
let sum = 0; for (const b of header) sum += b;
|
|
23
|
+
header.write(octal(sum, 7), 148); header[155] = 0x20;
|
|
24
|
+
const pad = (BLOCK - (data.length % BLOCK)) % BLOCK;
|
|
25
|
+
return Buffer.concat([header, data, Buffer.alloc(pad, 0)]);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const sha256Hex = (buf) => crypto.createHash('sha256').update(buf).digest('hex');
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {{manifest: Buffer, config: Buffer, layers: Buffer[]}} img bytes exactly as the registry served them
|
|
32
|
+
* @returns {{tar: Buffer, manifestDigest: string}}
|
|
33
|
+
*/
|
|
34
|
+
export function buildOciArchive({ manifest, config, layers, mediaType = 'application/vnd.oci.image.manifest.v1+json' }) {
|
|
35
|
+
const manifestHex = sha256Hex(manifest);
|
|
36
|
+
const index = Buffer.from(JSON.stringify({ schemaVersion: 2, manifests: [{ mediaType, digest: `sha256:${manifestHex}`, size: manifest.length }] }));
|
|
37
|
+
const parts = [
|
|
38
|
+
tarEntry('oci-layout', Buffer.from(JSON.stringify({ imageLayoutVersion: '1.0.0' }))),
|
|
39
|
+
tarEntry('index.json', index),
|
|
40
|
+
tarEntry(`blobs/sha256/${manifestHex}`, manifest),
|
|
41
|
+
tarEntry(`blobs/sha256/${sha256Hex(config)}`, config),
|
|
42
|
+
];
|
|
43
|
+
const seen = new Set([manifestHex, sha256Hex(config)]);
|
|
44
|
+
for (const l of layers) { const h = sha256Hex(l); if (seen.has(h)) continue; seen.add(h); parts.push(tarEntry(`blobs/sha256/${h}`, l)); }
|
|
45
|
+
parts.push(Buffer.alloc(BLOCK * 2, 0));
|
|
46
|
+
return { tar: Buffer.concat(parts), manifestDigest: `sha256:${manifestHex}` };
|
|
47
|
+
}
|