@clear-capabilities/agentic-security-scanner 0.162.0 → 0.163.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/bin/agentic-security.js +87 -0
  3. package/dist/1340.index.js +1871 -0
  4. package/dist/3477.index.js +727 -0
  5. package/dist/3499.index.js +23 -3
  6. package/dist/4113.index.js +1 -1
  7. package/dist/5014.index.js +833 -0
  8. package/dist/5756.index.js +2 -2
  9. package/dist/6257.index.js +1 -1
  10. package/dist/6907.index.js +248 -0
  11. package/dist/6994.index.js +1 -1
  12. package/dist/7033.index.js +33 -5
  13. package/dist/7439.index.js +1822 -0
  14. package/dist/7838.index.js +1 -1
  15. package/dist/9560.index.js +2318 -23
  16. package/dist/957.index.js +1 -1
  17. package/dist/9999.index.js +43 -7
  18. package/dist/agentic-security.mjs +12 -12
  19. package/dist/agentic-security.mjs.sha256 +1 -1
  20. package/package.json +33 -6
  21. package/src/capabilities/CLAUDE.md +114 -0
  22. package/src/capabilities/address.js +73 -0
  23. package/src/capabilities/attack-coverage.js +93 -0
  24. package/src/capabilities/decide.js +256 -0
  25. package/src/capabilities/delegate.js +69 -0
  26. package/src/capabilities/egress.js +20 -0
  27. package/src/capabilities/hook-advice.js +50 -0
  28. package/src/capabilities/index.js +32 -0
  29. package/src/capabilities/manifest.js +344 -0
  30. package/src/capabilities/outbound.js +189 -0
  31. package/src/capabilities/paths.js +57 -0
  32. package/src/capabilities/probes.js +211 -0
  33. package/src/capabilities/proxy.js +182 -0
  34. package/src/capabilities/reasons.js +67 -0
  35. package/src/capabilities/receipts.js +356 -0
  36. package/src/capabilities/records.js +58 -0
  37. package/src/capabilities/recovery.js +367 -0
  38. package/src/capabilities/report.js +81 -0
  39. package/src/capabilities/runner.js +236 -0
  40. package/src/capabilities/secrets.js +26 -0
  41. package/src/capabilities/tool-gate.js +119 -0
  42. package/src/capabilities/tool-registry.js +60 -0
  43. package/src/dataflow/CLAUDE.md +30 -0
  44. package/src/dataflow/catalog.js +42 -1
  45. package/src/dataflow/engine.js +67 -2
  46. package/src/dataflow/guard-dominance.js +352 -0
  47. package/src/discovery/CLAUDE.md +9 -0
  48. package/src/discovery/index.js +15 -1
  49. package/src/discovery/lenses.js +18 -0
  50. package/src/engine.js +80 -15
  51. package/src/integrations/index.js +5 -2
  52. package/src/ir/CLAUDE.md +14 -0
  53. package/src/ir/implicit-handler-params.js +74 -0
  54. package/src/ir/parser-cs.js +20 -0
  55. package/src/ir/parser-go.js +30 -13
  56. package/src/ir/parser-java.js +11 -0
  57. package/src/language/nix-eval-isolation.js +33 -5
  58. package/src/lineage/CLAUDE.md +31 -0
  59. package/src/lineage/deployment/adapter-cloud.js +202 -0
  60. package/src/lineage/deployment/adapter-compose.js +90 -0
  61. package/src/lineage/deployment/adapter-kit.js +142 -0
  62. package/src/lineage/deployment/adapter-kubernetes.js +247 -0
  63. package/src/lineage/deployment/attack-paths.js +443 -0
  64. package/src/lineage/deployment/boundaries-run.js +223 -0
  65. package/src/lineage/deployment/boundary-graph.js +567 -0
  66. package/src/lineage/deployment/cross-repo.js +253 -0
  67. package/src/lineage/deployment/drift.js +383 -0
  68. package/src/lineage/deployment/ingest.js +221 -0
  69. package/src/lineage/deployment/projection.js +244 -0
  70. package/src/lineage/deployment/trace-correlation.js +541 -0
  71. package/src/lineage/source-registry.js +19 -0
  72. package/src/mcp/CLAUDE.md +5 -2
  73. package/src/mcp/invariant-tools.js +64 -0
  74. package/src/mcp/portfolio-tools.js +79 -0
  75. package/src/mcp/redact.js +15 -0
  76. package/src/mcp/server.js +24 -3
  77. package/src/mcp/tools.js +13 -1
  78. package/src/posture/CLAUDE.md +332 -1
  79. package/src/posture/accuracy-scorecard.js +95 -4
  80. package/src/posture/assurance/rollback.js +214 -0
  81. package/src/posture/assurance/rollout.js +200 -0
  82. package/src/posture/business-logic.js +26 -4
  83. package/src/posture/evaluation/bakeoff.js +148 -0
  84. package/src/posture/evaluation/custody.js +200 -0
  85. package/src/posture/evaluation/deployment-ablation.js +416 -0
  86. package/src/posture/evaluation/dev-cases.js +65 -0
  87. package/src/posture/evaluation/economics.js +85 -0
  88. package/src/posture/evaluation/gates.js +161 -0
  89. package/src/posture/evaluation/grouping.js +101 -0
  90. package/src/posture/evaluation/interval.js +132 -0
  91. package/src/posture/evaluation/invariant-ablation.js +325 -0
  92. package/src/posture/evaluation/labels.js +200 -0
  93. package/src/posture/evaluation/protocol.js +308 -0
  94. package/src/posture/evaluation/release-gate.js +209 -0
  95. package/src/posture/evaluation/report.js +158 -0
  96. package/src/posture/evaluation/runner.js +273 -0
  97. package/src/posture/evaluation/scan-child.js +80 -0
  98. package/src/posture/evaluation/score.js +174 -0
  99. package/src/posture/evaluation/synthetic.js +90 -0
  100. package/src/posture/evaluation/why-missed.js +219 -0
  101. package/src/posture/fleet.js +11 -2
  102. package/src/posture/invariants/cli.js +95 -0
  103. package/src/posture/invariants/coverage.js +164 -0
  104. package/src/posture/invariants/export.js +178 -0
  105. package/src/posture/invariants/expressions.js +46 -0
  106. package/src/posture/invariants/lifecycle.js +289 -0
  107. package/src/posture/invariants/project-input.js +55 -0
  108. package/src/posture/invariants/repair.js +340 -0
  109. package/src/posture/invariants/run.js +45 -0
  110. package/src/posture/invariants/scenarios.js +311 -0
  111. package/src/posture/invariants/schema.js +167 -0
  112. package/src/posture/invariants/shrink.js +407 -0
  113. package/src/posture/invariants/state-assertions.js +165 -0
  114. package/src/posture/logic-claims.js +12 -0
  115. package/src/posture/model-routing.js +40 -0
  116. package/src/posture/oracles/adapters.js +172 -1
  117. package/src/posture/oracles/conformance.js +3 -2
  118. package/src/posture/oracles/oracle.js +23 -3
  119. package/src/posture/oracles/registry.js +1 -1
  120. package/src/posture/portfolio/backend.js +279 -0
  121. package/src/posture/portfolio/bundle.js +314 -0
  122. package/src/posture/portfolio/cli.js +142 -0
  123. package/src/posture/portfolio/manifest.js +263 -0
  124. package/src/posture/portfolio/progress.js +267 -0
  125. package/src/posture/portfolio/resume.js +130 -0
  126. package/src/posture/portfolio/retention.js +207 -0
  127. package/src/posture/portfolio/scheduler.js +488 -0
  128. package/src/posture/portfolio/signing.js +155 -0
  129. package/src/posture/portfolio/wording.js +59 -0
  130. package/src/posture/portfolio/work-units.js +405 -0
  131. package/src/posture/replay/replay.js +1 -0
  132. package/src/posture/routing/adapter.js +140 -0
  133. package/src/posture/routing/calibration.js +278 -0
  134. package/src/posture/routing/canary.js +141 -0
  135. package/src/posture/routing/control.js +35 -0
  136. package/src/posture/routing/decide.js +211 -0
  137. package/src/posture/routing/drift.js +137 -0
  138. package/src/posture/routing/economics.js +185 -0
  139. package/src/posture/routing/feedback.js +207 -0
  140. package/src/posture/routing/index.js +31 -0
  141. package/src/posture/routing/outcomes.js +281 -0
  142. package/src/posture/routing/promotion.js +291 -0
  143. package/src/posture/routing/receipts.js +59 -0
  144. package/src/posture/routing/report.js +142 -0
  145. package/src/posture/routing/shadow.js +53 -0
  146. package/src/posture/specification-mining.js +26 -0
  147. package/src/posture/verification/patch-negative.js +16 -4
  148. package/src/posture/verification/patch-promotion.js +10 -2
  149. package/src/report/index.js +51 -1
  150. package/src/sandbox/CLAUDE.md +10 -0
  151. package/src/sandbox/backend-userspace.js +91 -13
  152. package/dist/5613.index.js +0 -500
  153. package/dist/6239.index.js +0 -469
@@ -1,500 +0,0 @@
1
- export const id = 5613;
2
- export const ids = [5613];
3
- export const modules = {
4
-
5
- /***/ 95613:
6
- /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
7
-
8
-
9
- // EXPORTS
10
- __webpack_require__.d(__webpack_exports__, {
11
- verifyPatchNegative: () => (/* binding */ verifyPatchNegative)
12
- });
13
-
14
- // EXTERNAL MODULE: ./src/posture/assurance/identity.js
15
- var identity = __webpack_require__(41877);
16
- // EXTERNAL MODULE: ./src/posture/assurance/schema-kit.js
17
- var schema_kit = __webpack_require__(53353);
18
- // EXTERNAL MODULE: ./src/posture/assurance/config.js
19
- var assurance_config = __webpack_require__(90385);
20
- // EXTERNAL MODULE: ./src/sandbox/capabilities.js
21
- var capabilities = __webpack_require__(60450);
22
- // EXTERNAL MODULE: ./src/posture/oracles/oracle.js + 4 modules
23
- var oracles_oracle = __webpack_require__(80219);
24
- // EXTERNAL MODULE: ./src/posture/oracles/registry.js + 1 modules
25
- var registry = __webpack_require__(56239);
26
- ;// CONCATENATED MODULE: ./src/posture/replay/replay.js
27
- // Replay manifests and environment identity (X-203).
28
- //
29
- // Extends the existing proof-of-concept sandbox path (a payload run under the
30
- // confinement backend, judged by an observed effect) with an identity for the run
31
- // and a way to repeat it. It is NOT a second sandbox or a second runner: a replay
32
- // is an oracle run (`oracles/oracle.js`), which goes through `runInBoundary` and
33
- // therefore through the supervised process tree, output cap and cleanup of
34
- // CORE-003. What this module adds is the pinned, validated description of the run.
35
- //
36
- // A manifest pins: the repository commit, the patch hash, the fixture hash, the
37
- // toolchain (and container digest when there is one), the oracle id, version and
38
- // logic digest, the inputs and the budgets. Replaying it on the same supported
39
- // environment reproduces the verdict, and the identical verification record id.
40
- //
41
- // Honesty rules, each with a test:
42
- // - A manifest is REJECTED, and nothing executes, when a content hash does not
43
- // match the content, when the oracle changed since the manifest was made, when
44
- // its scope asks for more than the oracle's declared scope (network, another
45
- // oracle, a write outside the workspace) or when a budget exceeds the oracle's
46
- // ceiling. The manifest is closed-world, so a field such as a model verdict
47
- // cannot ride along.
48
- // - A missing toolchain, container image or container runtime, or a disabled
49
- // feature, is a typed PREREQUISITE and the attempt is resumable. Nothing is
50
- // substituted for the execution that did not happen: the outcome is `not-run`
51
- // (or `unsupported` when this build can never meet it), with no evidence.
52
- // - This build never fetches anything. A prerequisite whose acquisition would
53
- // need the network is reported as such, with the network denied.
54
- // - Container execution is not implemented. A manifest pinning a container
55
- // digest is therefore `unsupported` here, never run outside the container it
56
- // names.
57
- // - Toolchain identity is exact (runtime version, platform, architecture). A
58
- // different patch release is a different environment, reported as an unmet
59
- // prerequisite rather than silently tolerated.
60
-
61
-
62
-
63
-
64
-
65
-
66
- const REPLAY_SCHEMA = 'agentic-security/replay-manifest';
67
- const ATTEMPT_SCHEMA = 'agentic-security/replay-attempt';
68
- const MAX_ATTEMPTS = 10;
69
-
70
- const ALLOWED = ['schema', 'schemaVersion', 'id', 'hypothesisId', 'repository', 'patch', 'fixture', 'toolchain', 'oracle', 'entry', 'inputs', 'inputsDigest', 'budgets', 'scope', 'expected'];
71
- const REQUIRED = ['schema', 'schemaVersion', 'id', 'hypothesisId', 'repository', 'patch', 'fixture', 'toolchain', 'oracle', 'entry', 'inputs', 'inputsDigest', 'budgets', 'scope'];
72
- const ID_FIELDS = ALLOWED.filter((k) => k !== 'id');
73
- const REPLAY_BUDGET_KEYS = ['timeoutMs', 'graceMs', 'maxOutputBytes'];
74
- const EXPECTED_OUTCOMES = ['confirmed', 'refuted', 'inconclusive'];
75
-
76
- /** The pinned scope a replay may have: exactly the oracle it names, no network, workspace-only writes. */
77
- function allowedScope(oracleId) {
78
- return { executes: [oracleId], network: false, writes: 'workspace-only' };
79
- }
80
-
81
- /** Sanitized identity of the execution environment: facts about the toolchain, nothing about the host. */
82
- function environmentIdentity(overrides = {}) {
83
- const base = {
84
- runtime: 'node', version: process.versions.node, platform: process.platform, arch: process.arch,
85
- containerDigest: null, backend: (0,capabilities/* detectBackend */.kS)(),
86
- };
87
- const env = { ...base, ...overrides };
88
- return { ...env, toolchainDigest: (0,identity/* digestOf */.ol)({ runtime: env.runtime, version: env.version, platform: env.platform, arch: env.arch, containerDigest: env.containerDigest }) };
89
- }
90
-
91
- /**
92
- * Build a manifest from the pieces of a verification. The oracle identity and the
93
- * environment come from this build, not from the caller.
94
- */
95
- function createReplayManifest({ hypothesisId, commit, fixtureFiles, patchFiles = null, oracleId, entry, inputs, budgets = {}, expected, environment }) {
96
- const oracle = registry.getOracle(oracleId);
97
- if (!oracle) throw new Error(`unknown oracle '${oracleId}'`);
98
- const env = environment || environmentIdentity();
99
- const m = {
100
- schema: REPLAY_SCHEMA, schemaVersion: schema_kit/* SCHEMA_VERSION */.f$, hypothesisId,
101
- repository: { commit },
102
- patch: patchFiles && Object.keys(patchFiles).length ? { digest: (0,identity/* digestOf */.ol)(patchFiles) } : null,
103
- fixture: { digest: (0,identity/* digestOf */.ol)(fixtureFiles) },
104
- toolchain: { runtime: env.runtime, version: env.version, platform: env.platform, arch: env.arch, containerDigest: env.containerDigest ?? null },
105
- oracle: { id: oracle.id, version: oracle.version, logicDigest: oracle.logicDigest },
106
- entry, inputs, inputsDigest: (0,identity/* digestOf */.ol)(inputs),
107
- budgets: { timeoutMs: oracle.budgets.timeoutMs, graceMs: oracle.budgets.graceMs, maxOutputBytes: oracle.budgets.maxOutputBytes, ...budgets },
108
- scope: allowedScope(oracle.id),
109
- };
110
- if (expected) m.expected = expected;
111
- m.id = manifestId(m);
112
- return m;
113
- }
114
-
115
- function manifestId(m) { return (0,identity/* semanticId */.YN)('rpl', m, ID_FIELDS); }
116
-
117
- function err(errors, code, path, message) { errors.push({ code, path, message }); }
118
-
119
- /**
120
- * Validate a manifest against the content it describes. Rejects, and the caller
121
- * must not execute, on any error. Pure: reads no file and runs nothing.
122
- */
123
- function validateReplayManifest(m, { fixtureFiles, patchFiles = null } = {}) {
124
- const errors = [];
125
- if (!(0,schema_kit/* isPlainObject */.Qd)(m)) { err(errors, 'NOT_AN_OBJECT', '', 'manifest must be an object'); return { ok: false, errors }; }
126
- if (m.schema !== REPLAY_SCHEMA) { err(errors, 'SCHEMA_MISMATCH', 'schema', `expected '${REPLAY_SCHEMA}'`); return { ok: false, errors }; }
127
- if (typeof m.schemaVersion !== 'string' || m.schemaVersion.split('.')[0] !== '1') { err(errors, 'UNSUPPORTED_MAJOR', 'schemaVersion', 'only major version 1 is supported'); return { ok: false, errors }; }
128
- for (const k of Object.keys(m)) if (!ALLOWED.includes(k)) err(errors, 'UNKNOWN_FIELD', k, `field '${k}' is not part of a replay manifest`);
129
- for (const k of REQUIRED) if (m[k] === undefined) err(errors, 'MISSING_FIELD', k, `required field '${k}' is missing`);
130
- if (errors.length) return { ok: false, errors };
131
-
132
- if (typeof m.hypothesisId !== 'string' || !m.hypothesisId) err(errors, 'BAD_TYPE', 'hypothesisId', 'must be a non-empty string');
133
- if (!(0,schema_kit/* isPlainObject */.Qd)(m.repository) || !(0,schema_kit/* isCommit */.WM)(m.repository.commit)) err(errors, 'BAD_COMMIT', 'repository.commit', 'a replay pins an exact 40 or 64 character commit');
134
- if (!(0,schema_kit/* isPlainObject */.Qd)(m.fixture) || !(0,schema_kit/* isDigest */.Bc)(m.fixture.digest)) err(errors, 'BAD_DIGEST', 'fixture.digest', 'must be sha256:<64 hex>');
135
- else if (!(0,schema_kit/* isPlainObject */.Qd)(fixtureFiles) || (0,identity/* digestOf */.ol)(fixtureFiles) !== m.fixture.digest) err(errors, 'HASH_MISMATCH', 'fixture.digest', 'the fixture content does not match its pinned hash');
136
- const havePatch = (0,schema_kit/* isPlainObject */.Qd)(patchFiles) && Object.keys(patchFiles).length > 0;
137
- if (m.patch === null) {
138
- if (havePatch) err(errors, 'HASH_MISMATCH', 'patch', 'patch content was supplied but the manifest pins no patch');
139
- } else if (!(0,schema_kit/* isPlainObject */.Qd)(m.patch) || !(0,schema_kit/* isDigest */.Bc)(m.patch.digest)) err(errors, 'BAD_DIGEST', 'patch.digest', 'must be null or { digest: sha256:<64 hex> }');
140
- else if (!havePatch || (0,identity/* digestOf */.ol)(patchFiles) !== m.patch.digest) err(errors, 'HASH_MISMATCH', 'patch.digest', 'the patch content does not match its pinned hash');
141
- if (!(0,schema_kit/* isDigest */.Bc)(m.inputsDigest) || !(0,schema_kit/* isPlainObject */.Qd)(m.inputs) || (0,identity/* digestOf */.ol)(m.inputs) !== m.inputsDigest) err(errors, 'HASH_MISMATCH', 'inputsDigest', 'the inputs do not match their pinned hash');
142
-
143
- // Paths are part of the allowed execution scope: a fixture or patch that names a file outside the workspace is refused here,
144
- // before anything can run, even when its hash matches.
145
- for (const [label, files] of [['fixture', fixtureFiles], ['patch', patchFiles]]) {
146
- for (const rel of Object.keys((0,schema_kit/* isPlainObject */.Qd)(files) ? files : {})) {
147
- if (!(0,oracles_oracle/* isSafeRelativePath */.VH)(rel)) err(errors, 'SCOPE_VIOLATION', `${label}.files`, `path ${JSON.stringify(String(rel).slice(0, 60))} is not a safe relative path inside the workspace`);
148
- }
149
- }
150
- if (typeof m.entry === 'string' && (0,schema_kit/* isPlainObject */.Qd)(fixtureFiles) && !(m.entry in { ...fixtureFiles, ...((0,schema_kit/* isPlainObject */.Qd)(patchFiles) ? patchFiles : {}) })) err(errors, 'SCOPE_VIOLATION', 'entry', 'the entry must be one of the pinned files');
151
-
152
- const tc = m.toolchain;
153
- if (!(0,schema_kit/* isPlainObject */.Qd)(tc) || tc.runtime !== 'node' || typeof tc.version !== 'string' || typeof tc.platform !== 'string' || typeof tc.arch !== 'string') err(errors, 'BAD_TYPE', 'toolchain', 'needs runtime node, version, platform and arch');
154
- else if (tc.containerDigest !== null && !(0,schema_kit/* isDigest */.Bc)(tc.containerDigest)) err(errors, 'BAD_DIGEST', 'toolchain.containerDigest', 'must be null or sha256:<64 hex>');
155
-
156
- const oracle = (0,schema_kit/* isPlainObject */.Qd)(m.oracle) ? registry.getOracle(m.oracle.id) : null;
157
- if (!oracle) err(errors, 'UNKNOWN_ORACLE', 'oracle.id', 'the manifest names an oracle this build does not have');
158
- else {
159
- if (m.oracle.version !== oracle.version || m.oracle.logicDigest !== oracle.logicDigest) err(errors, 'ORACLE_MISMATCH', 'oracle', 'the oracle version or logic digest differs from the pinned one: this is not the oracle the manifest was made with');
160
- const sc = m.scope;
161
- const want = allowedScope(oracle.id);
162
- if (!(0,schema_kit/* isPlainObject */.Qd)(sc) || Object.keys(sc).some((k) => !(k in want))) err(errors, 'SCOPE_VIOLATION', 'scope', 'unknown scope keys');
163
- else {
164
- if (JSON.stringify(sc.executes) !== JSON.stringify(want.executes)) err(errors, 'SCOPE_VIOLATION', 'scope.executes', 'a replay may execute only the oracle it names');
165
- if (sc.network !== false) err(errors, 'SCOPE_VIOLATION', 'scope.network', 'replay grants no network access');
166
- if (sc.writes !== 'workspace-only') err(errors, 'SCOPE_VIOLATION', 'scope.writes', 'replay writes only inside its workspace');
167
- }
168
- const b = m.budgets;
169
- if (!(0,schema_kit/* isPlainObject */.Qd)(b)) err(errors, 'BAD_TYPE', 'budgets', 'must be an object');
170
- else {
171
- for (const k of Object.keys(b)) if (!REPLAY_BUDGET_KEYS.includes(k)) err(errors, 'UNKNOWN_FIELD', `budgets.${k}`, 'not a replay budget');
172
- for (const k of REPLAY_BUDGET_KEYS) {
173
- if (!Number.isInteger(b[k]) || b[k] < 1) err(errors, 'BAD_TYPE', `budgets.${k}`, 'must be a positive integer');
174
- else if (b[k] > oracle.budgets[k]) err(errors, 'BUDGET_EXCEEDED', `budgets.${k}`, `exceeds the oracle ceiling of ${oracle.budgets[k]}`);
175
- }
176
- }
177
- }
178
- if (typeof m.entry !== 'string' || !m.entry) err(errors, 'BAD_TYPE', 'entry', 'must be a non-empty string');
179
- if (m.expected !== undefined && (!(0,schema_kit/* isPlainObject */.Qd)(m.expected) || Object.keys(m.expected).some((k) => k !== 'outcome') || !EXPECTED_OUTCOMES.includes(m.expected.outcome))) err(errors, 'BAD_TYPE', 'expected', `must be { outcome: one of ${EXPECTED_OUTCOMES.join(', ')} }`);
180
- if (m.id !== manifestId(m)) err(errors, 'ID_MISMATCH', 'id', 'the manifest id does not match its content');
181
- return { ok: errors.length === 0, errors };
182
- }
183
-
184
- // ---------------------------------------------------------------- prerequisites
185
-
186
- /**
187
- * Typed prerequisites that are not met on this host. `resumable` is true when
188
- * meeting it is something an operator can do (install a toolchain, enable the
189
- * feature) and false when this build cannot meet it at all.
190
- */
191
- function unmetPrerequisites(m, host = environmentIdentity()) {
192
- const out = [];
193
- const tc = m.toolchain;
194
- if (tc.containerDigest !== null) {
195
- out.push({ kind: 'container-runtime', id: tc.containerDigest, state: 'unsupported', resumable: false, reason: 'container execution is not implemented in this build; the run is never executed outside the container the manifest names' });
196
- out.push({ kind: 'container-image', id: tc.containerDigest, state: 'missing', resumable: false, reason: 'this build neither holds nor pulls container images' });
197
- out.push({ kind: 'network', id: 'image-acquisition', state: 'denied', resumable: false, reason: 'acquiring a container image needs network access, which replay does not grant' });
198
- }
199
- if (tc.version !== host.version || tc.platform !== host.platform || tc.arch !== host.arch) {
200
- out.push({
201
- kind: 'toolchain', id: `${tc.runtime}@${tc.version} ${tc.platform}/${tc.arch}`, state: 'missing', resumable: true,
202
- reason: `this host runs ${host.runtime}@${host.version} ${host.platform}/${host.arch}; the manifest pins an exact toolchain`,
203
- });
204
- out.push({ kind: 'network', id: 'toolchain-acquisition', state: 'denied', resumable: true, reason: 'installing the pinned toolchain needs network access, which replay does not grant; install it out of band and resume' });
205
- }
206
- return out;
207
- }
208
-
209
- function nextAttempt(resume, manifestId_) {
210
- if (resume === undefined || resume === null) return { n: 1, history: [] };
211
- if (!(0,schema_kit/* isPlainObject */.Qd)(resume) || resume.schema !== ATTEMPT_SCHEMA || resume.manifestId !== manifestId_) return { error: 'the attempt does not belong to this manifest' };
212
- if (resume.status !== 'awaiting-prerequisites') return { error: `an attempt in status '${resume.status}' is not resumable` };
213
- if (!Number.isInteger(resume.attempt) || resume.attempt < 1 || !Array.isArray(resume.history)) return { error: 'the attempt record is malformed' };
214
- if (resume.attempt >= MAX_ATTEMPTS) return { error: `the attempt limit of ${MAX_ATTEMPTS} was reached` };
215
- return { n: resume.attempt + 1, history: resume.history.slice(-MAX_ATTEMPTS) };
216
- }
217
-
218
- function attemptRecord(manifestId_, n, history, status, entry) {
219
- return { schema: ATTEMPT_SCHEMA, manifestId: manifestId_, attempt: n, status, history: [...history, { attempt: n, ...entry }] };
220
- }
221
-
222
- /**
223
- * Replay a manifest. Never throws.
224
- *
225
- * @param {object} bundle { manifest, fixtureFiles, patchFiles? }
226
- * @param {object} [o]
227
- * @param {object} [o.resume] an attempt returned earlier with status 'awaiting-prerequisites'
228
- * @param {object} [o.hostEnvironment] environment identity override (test seam)
229
- * @param {object} [o.config] assurance config (the verification-oracles feature is off by default)
230
- * @param {object} [o.runOptions] passed to runOracle (test seams: deps, probeEnv, signal)
231
- * @returns {Promise<object>} { status: 'completed'|'awaiting-prerequisites'|'rejected', executed, outcome, record, receipt, reproduced, prerequisites, attempt, errors }
232
- */
233
- async function replayManifest(bundle, o = {}) {
234
- const { manifest, fixtureFiles, patchFiles = null } = bundle || {};
235
- const valid = validateReplayManifest(manifest, { fixtureFiles, patchFiles });
236
- if (!valid.ok) return { status: 'rejected', executed: false, outcome: null, record: null, receipt: null, reproduced: null, prerequisites: [], attempt: null, errors: valid.errors };
237
-
238
- const step = nextAttempt(o.resume, manifest.id);
239
- if (step.error) return { status: 'rejected', executed: false, outcome: null, record: null, receipt: null, reproduced: null, prerequisites: [], attempt: null, errors: [{ code: 'ATTEMPT_REJECTED', path: 'resume', message: step.error }] };
240
-
241
- const request = {
242
- oracleId: manifest.oracle.id, hypothesisId: manifest.hypothesisId, commit: manifest.repository.commit,
243
- files: { ...fixtureFiles, ...(patchFiles || {}) }, entry: manifest.entry, inputs: manifest.inputs, attempt: step.n,
244
- budgets: manifest.budgets,
245
- };
246
- const waiting = (prerequisites, outcome, reason) => {
247
- const record = (0,oracles_oracle/* recordWithoutExecution */.Wp)(manifest.oracle.id, request, outcome, reason, registry);
248
- return {
249
- status: 'awaiting-prerequisites', executed: false, outcome, record, receipt: null, reproduced: null, prerequisites, errors: [],
250
- attempt: attemptRecord(manifest.id, step.n, step.history, 'awaiting-prerequisites', { outcome, prerequisites: prerequisites.map((p) => `${p.kind}:${p.state}`) }),
251
- };
252
- };
253
-
254
- const unmet = unmetPrerequisites(manifest, o.hostEnvironment || environmentIdentity());
255
- if (unmet.length) {
256
- const never = unmet.some((p) => !p.resumable);
257
- return waiting(unmet, never ? 'unsupported' : 'not-run', `replay prerequisite(s) not met: ${unmet.map((p) => `${p.kind} ${p.id} (${p.state})`).join('; ')}; nothing was executed`);
258
- }
259
-
260
- const run = await (0,oracles_oracle/* runOracle */.qm)(request, { config: o.config, ...(o.runOptions || {}) });
261
- if (run.status === 'rejected') return { status: 'rejected', executed: false, outcome: null, record: null, receipt: null, reproduced: null, prerequisites: [], attempt: null, errors: (run.errors || []).map((m) => ({ code: 'REQUEST_REJECTED', path: '', message: m })) };
262
- if (!run.executed) {
263
- const feature = run.status === 'disabled';
264
- const prereq = feature
265
- ? [{ kind: 'feature', id: oracles_oracle/* FEATURE_ID */.DU, state: 'disabled', resumable: true, reason: run.reason }]
266
- : (run.prerequisites || [{ id: 'trust-boundary', reason: run.reason }]).map((p) => ({ kind: p.id === 'trust-boundary' ? 'trust-boundary' : 'oracle-prerequisite', id: p.id, state: 'unmet', resumable: false, reason: p.reason }));
267
- return waiting(prereq, run.outcome === 'unsupported' ? 'unsupported' : 'not-run', run.reason);
268
- }
269
- const reproduced = manifest.expected ? run.outcome === manifest.expected.outcome : null;
270
- return {
271
- status: 'completed', executed: true, outcome: run.outcome, record: run.record, receipt: run.receipt, reproduced, disclosure: run.disclosure,
272
- prerequisites: [], errors: [], run: run.run, environment: run.environment,
273
- attempt: attemptRecord(manifest.id, step.n, step.history, 'completed', { outcome: run.outcome }),
274
- };
275
- }
276
-
277
- // EXTERNAL MODULE: ./src/posture/verification/patch-promotion.js
278
- var patch_promotion = __webpack_require__(51487);
279
- // EXTERNAL MODULE: ./src/posture/verification/repair-records.js
280
- var repair_records = __webpack_require__(38899);
281
- ;// CONCATENATED MODULE: ./src/posture/verification/patch-negative.js
282
- // Patch-negative verification (X-204).
283
- //
284
- // A re-scan that no longer fires proves the DETECTOR went quiet; a cosmetic edit can do that. A repair is `verified-fix` here
285
- // only when three things are shown, each by an executed oracle run in an equivalent disposable environment:
286
- //
287
- // 1. original-positive the original revision reproduces the exploit (oracle outcome: confirmed)
288
- // 2. patched-negative the patched revision no longer does, same oracle (oracle outcome: refuted)
289
- // 3. functional-regression declared legitimate behaviour is intact on the patched revision, with the same expectations
290
- // holding on the original first (a baseline), so a wrong expectation is reported rather than blamed on the patch.
291
- //
292
- // All four runs (the baseline is one) go through `replayManifest`, so each is pinned by commit, fixture hash, patch hash,
293
- // toolchain, oracle version and inputs, executes inside the trust boundary, and issues a verifier receipt. The result is then
294
- // handed to `promotePatch`, which re-derives the diff and revision from the proposal and refuses any receipt that does not
295
- // match them. `verified-fix` needs the promotion; nothing else grants it.
296
- //
297
- // A failure never degrades to a vague "not verified": it names the SPECIFIC step that is incomplete and a typed failure code:
298
- // original-not-reproduced the original did not reproduce under the oracle (nothing to fix, or the scenario is wrong)
299
- // patched-still-exploitable the exploit still works on the patched revision
300
- // patched-build-broken the patched revision did not load or its benign control failed
301
- // patched-negative-inconclusive the patched run decided nothing
302
- // functional-omitted no functional check was supplied
303
- // functional-baseline-invalid the declared expectations do not hold on the ORIGINAL revision
304
- // functional-regression-detected the patched revision behaves differently from the declared expectations
305
- // oracle-changed the oracle, its version or its inputs differ between the original and patched runs
306
- // revision-unbound no exact commit: a verdict cannot be tied to a revision
307
- // prerequisite-unmet a toolchain, feature or isolation prerequisite is missing; resumable where stated
308
- // environment-mismatch the runs were not in equivalent environments
309
- // promotion-refused the receipts do not match the exact proposed diff and revision
310
- //
311
- // Scope, stated so no caller overclaims: the exploit scenario and the functional cases are the REQUESTER's; this verifies the
312
- // declared scenario and cases, not that the patch is correct elsewhere. Linux is not claimed (the oracle platform statements
313
- // stay `unverified`). Receipts are valid inside this process only (see patch-promotion.js).
314
-
315
-
316
-
317
-
318
-
319
-
320
-
321
-
322
- const PATCH_NEGATIVE_FEATURE = 'patch-negative-verification';
323
- const FUNCTIONAL_ORACLE = 'functional-regression';
324
-
325
- const STEPS = Object.freeze(['original-positive', 'patched-negative', 'functional-baseline', 'functional-regression']);
326
-
327
- const ROLE_OF_STEP = Object.freeze({ 'original-positive': 'original', 'patched-negative': 'patched', 'functional-baseline': 'functionalBaseline', 'functional-regression': 'functional' });
328
- const EXPECTED = Object.freeze({ 'original-positive': 'confirmed', 'patched-negative': 'refuted', 'functional-baseline': 'refuted', 'functional-regression': 'refuted' });
329
-
330
- const stepResult = (step, status, extra = {}) => ({ step, status, expected: EXPECTED[step], outcome: null, code: null, reason: null, recordId: null, receiptDigest: null, ...extra });
331
-
332
- function replayCode(run) {
333
- const first = (run.errors || [])[0];
334
- if (!first) return 'manifest-rejected';
335
- if (first.code === 'ORACLE_MISMATCH') return 'oracle-changed';
336
- if (first.code === 'HASH_MISMATCH') return 'content-hash-mismatch';
337
- return 'manifest-rejected';
338
- }
339
-
340
- function classify(step, run) {
341
- if (run.status === 'rejected') return { status: 'incomplete', code: replayCode(run), reason: (run.errors || []).map((e) => e.message).join('; ').slice(0, 300) || 'the replay manifest was rejected' };
342
- if (run.status === 'awaiting-prerequisites') {
343
- const resumable = (run.prerequisites || []).every((p) => p.resumable);
344
- return { status: 'incomplete', code: 'prerequisite-unmet', outcome: run.outcome ?? null, resumable, reason: `${(run.prerequisites || []).map((p) => `${p.kind} ${p.id} (${p.state})`).join('; ') || 'a prerequisite is unmet'}; nothing was executed${resumable ? ' (resumable)' : ''}` };
345
- }
346
- const outcome = run.outcome;
347
- const observed = run.receipt?.observed || {};
348
- const loadBroken = observed.targetLoaded === false || observed.benignCompleted === false;
349
- if (outcome === 'error') return { status: 'incomplete', code: 'harness-error', reason: String(run.record?.reason || 'the oracle run failed').slice(0, 300), outcome };
350
- if (outcome === EXPECTED[step]) return { status: 'passed', code: null, reason: run.record?.reason ?? null, outcome };
351
- const reason = String(run.record?.reason || '').slice(0, 300);
352
- switch (step) {
353
- case 'original-positive':
354
- return { status: 'failed', code: 'original-not-reproduced', reason: `the original revision did not reproduce the exploit (outcome '${outcome}'): ${reason}`, outcome };
355
- case 'patched-negative':
356
- if (outcome === 'confirmed') return { status: 'failed', code: 'patched-still-exploitable', reason: `the exploit still works on the patched revision: ${reason}`, outcome };
357
- return loadBroken
358
- ? { status: 'failed', code: 'patched-build-broken', reason: `the patched revision did not load or its benign control failed: ${reason}`, outcome }
359
- : { status: 'failed', code: 'patched-negative-inconclusive', reason: `the patched run decided nothing (outcome '${outcome}'): ${reason}`, outcome };
360
- case 'functional-baseline':
361
- return { status: 'failed', code: 'functional-baseline-invalid', reason: `the declared functional expectations do not hold on the original revision (outcome '${outcome}'): ${reason}`, outcome };
362
- default:
363
- if (outcome === 'confirmed') return { status: 'failed', code: 'functional-regression-detected', reason: `the patched revision behaves differently from the declared expectations: ${reason}`, outcome };
364
- return loadBroken
365
- ? { status: 'failed', code: 'patched-build-broken', reason: `the patched revision did not load for the functional check: ${reason}`, outcome }
366
- : { status: 'failed', code: 'functional-inconclusive', reason: `the functional check decided nothing (outcome '${outcome}'): ${reason}`, outcome };
367
- }
368
- }
369
-
370
- function summaryOf(steps, verified, incomplete, code) {
371
- const label = (s) => ({ passed: 'PASS', failed: 'FAIL', incomplete: 'INCOMPLETE', 'not-run': 'not run' })[s.status];
372
- const lines = steps.map((s) => `${s.step}: ${label(s)}${s.code ? ` (${s.code})` : ''}${s.reason && s.status !== 'passed' ? ` - ${s.reason}` : ''}`);
373
- lines.push(verified
374
- ? 'verified-fix: the exploit reproduced on the original revision, did not reproduce on the patched revision, and the declared functional cases still hold. Only the declared scenario and cases were exercised.'
375
- : `NOT verified-fix: incomplete step '${incomplete}'${code ? ` (${code})` : ''}.`);
376
- return lines.join('\n');
377
- }
378
-
379
- /**
380
- * Run the three-part patch-negative verification for one proposed patch. Never throws.
381
- *
382
- * @param {object} req
383
- * @param {string} req.hypothesisId the finding's stable id
384
- * @param {string} req.commit exact revision the patch is proposed against (40 or 64 hex)
385
- * @param {object} req.original { files, entry, oracleId, inputs, budgets? } the exploit scenario on the original files
386
- * @param {object} req.patch { files } the proposed diff: the new content of each changed file
387
- * @param {object} [req.patched] { oracleId?, inputs?, entry? }: must equal the original's; anything else is `oracle-changed`
388
- * @param {object} [req.functional] { inputs, budgets? } for the functional-regression oracle; omitting it prevents verified-fix
389
- * @param {object} [req.pinnedOracle] { id, version, logicDigest } the oracle identity the requester recorded earlier
390
- * @param {object[]} [req.ledger] earlier repair records to extend
391
- * @param {object} [o] { config, runOptions } config is the assurance config; runOptions go to the oracle runner (test seams)
392
- */
393
- async function verifyPatchNegative(req, o = {}) {
394
- const config = o.config || (0,assurance_config/* resolveAssuranceConfig */.cc)({ env: process.env });
395
- const gate = (0,assurance_config/* featureStatus */.FX)(config, PATCH_NEGATIVE_FEATURE);
396
- const steps = STEPS.map((s) => stepResult(s, 'not-run', { reason: 'not reached' }));
397
- const base = {
398
- status: 'not-verified-fix', verifiedFix: false, incompleteStep: null, failureCode: null, reason: null, steps,
399
- patchDigest: null, promotion: null, receipts: null, records: {}, verificationRecord: null, repairRecords: Array.isArray(req?.ledger) ? req.ledger : [], summary: '',
400
- };
401
- if (gate.status !== 'ok') {
402
- return { ...base, status: 'disabled', incompleteStep: 'feature-gate', failureCode: gate.code || 'disabled', reason: `${PATCH_NEGATIVE_FEATURE} is not available: ${gate.reason}`, summary: `patch-negative verification did not run: ${gate.reason}` };
403
- }
404
- const refuse = (step, code, reason, extra = {}) => {
405
- const rejected = req && (0,schema_kit/* isPlainObject */.Qd)(req.patch) && (0,schema_kit/* isPlainObject */.Qd)(req.patch.files) && Object.keys(req.patch.files).length && typeof req.hypothesisId === 'string'
406
- ? ledgerFor(base.repairRecords, req, base.patchDigest ?? (0,identity/* digestOf */.ol)(req.patch.files), { rejected: { step, code, reason } }) : { records: base.repairRecords };
407
- return { ...base, ...extra, patchDigest: req?.patch?.files ? (0,identity/* digestOf */.ol)(req.patch.files) : null, incompleteStep: step, failureCode: code, reason, repairRecords: rejected.records, summary: summaryOf(steps, false, step, code) };
408
- };
409
-
410
- // ---- shape and preconditions that need no execution
411
- const patchFiles = req?.patch?.files;
412
- if (!(0,schema_kit/* isPlainObject */.Qd)(req) || typeof req.hypothesisId !== 'string' || !req.hypothesisId || !(0,schema_kit/* isPlainObject */.Qd)(req.original) || !(0,schema_kit/* isPlainObject */.Qd)(req.original.files)
413
- || typeof req.original.entry !== 'string' || typeof req.original.oracleId !== 'string' || !(0,schema_kit/* isPlainObject */.Qd)(req.original.inputs)
414
- || !(0,schema_kit/* isPlainObject */.Qd)(patchFiles) || Object.keys(patchFiles).length === 0) {
415
- return refuse('input-validation', 'bad-request', 'a request needs a hypothesis id, the original files, entry, oracle and inputs, and a non-empty patch');
416
- }
417
- if (!(0,schema_kit/* isCommit */.WM)(req.commit)) return refuse('input-validation', 'revision-unbound', 'no exact commit was given: a verdict cannot be tied to a revision');
418
- const original = req.original;
419
- const oracle = registry.getOracle(original.oracleId);
420
- if (!oracle) return refuse('input-validation', 'unknown-oracle', `the exploit oracle '${String(original.oracleId).slice(0, 60)}' is not registered`);
421
- if (oracle.id === FUNCTIONAL_ORACLE) return refuse('input-validation', 'bad-request', 'the exploit oracle cannot be the functional-regression oracle');
422
- const patched = (0,schema_kit/* isPlainObject */.Qd)(req.patched) ? req.patched : {};
423
- if ((patched.oracleId !== undefined && patched.oracleId !== original.oracleId) || (patched.inputs !== undefined && (0,identity/* digestOf */.ol)(patched.inputs) !== (0,identity/* digestOf */.ol)(original.inputs)) || (patched.entry !== undefined && patched.entry !== original.entry)) {
424
- return refuse('oracle-consistency', 'oracle-changed', 'the patched run names a different oracle, entry or inputs than the original run: a changed oracle cannot show the exploit is closed');
425
- }
426
- const pin = req.pinnedOracle;
427
- if (pin !== undefined && (!(0,schema_kit/* isPlainObject */.Qd)(pin) || pin.id !== oracle.id || pin.version !== oracle.version || pin.logicDigest !== oracle.logicDigest)) {
428
- return refuse('oracle-consistency', 'oracle-changed', 'the oracle differs from the identity the requester pinned (id, version or logic digest)');
429
- }
430
- const fn = req.functional;
431
- if (!(0,schema_kit/* isPlainObject */.Qd)(fn) || !(0,schema_kit/* isPlainObject */.Qd)(fn.inputs)) {
432
- return refuse('functional-regression', 'functional-omitted', 'no functional regression check was supplied: a patch that was never checked for behaviour cannot be a verified fix');
433
- }
434
-
435
- const patchDigest = (0,identity/* digestOf */.ol)(patchFiles);
436
- base.patchDigest = patchDigest;
437
- let ledger = ledgerFor(base.repairRecords, req, patchDigest, {}).records; // proposed
438
- const common = { hypothesisId: req.hypothesisId, commit: req.commit };
439
- const plan = [
440
- ['original-positive', { oracleId: original.oracleId, entry: original.entry, inputs: original.inputs, patchFiles: null, budgets: original.budgets }],
441
- ['patched-negative', { oracleId: original.oracleId, entry: original.entry, inputs: original.inputs, patchFiles, budgets: original.budgets }],
442
- ['functional-baseline', { oracleId: FUNCTIONAL_ORACLE, entry: original.entry, inputs: fn.inputs, patchFiles: null, budgets: fn.budgets }],
443
- ['functional-regression', { oracleId: FUNCTIONAL_ORACLE, entry: original.entry, inputs: fn.inputs, patchFiles, budgets: fn.budgets }],
444
- ];
445
- const runs = {};
446
- let failed = null;
447
- for (const [i, [step, spec]] of plan.entries()) {
448
- if (failed) continue;
449
- let run;
450
- try {
451
- const manifest = createReplayManifest({ ...common, fixtureFiles: original.files, patchFiles: spec.patchFiles, oracleId: spec.oracleId, entry: spec.entry, inputs: spec.inputs, budgets: spec.budgets || {}, expected: { outcome: EXPECTED[step] } });
452
- run = await replayManifest({ manifest, fixtureFiles: original.files, patchFiles: spec.patchFiles }, { config: o.config || config, runOptions: o.runOptions });
453
- } catch (e) {
454
- run = { status: 'rejected', errors: [{ code: 'RUN_FAILED', message: String(e?.message || e).slice(0, 200) }] };
455
- }
456
- const c = classify(step, run);
457
- steps[i] = stepResult(step, c.status, { ...c, recordId: run.record?.id ?? null, receiptDigest: run.receipt?.receiptDigest ?? null });
458
- if (run.executed && run.receipt) runs[ROLE_OF_STEP[step]] = run;
459
- if (c.status !== 'passed') failed = { step, ...c };
460
- }
461
- base.records = Object.fromEntries(Object.entries(runs).map(([k, r]) => [k, r.record]));
462
- if (failed) {
463
- ledger = ledgerFor(ledger, req, patchDigest, { rejected: { step: failed.step, code: failed.code, reason: failed.reason } }).records;
464
- const original0 = base.records.original ? (0,repair_records/* withRepairStatus */.m$)(base.records.original, (0,repair_records/* verificationRepairFor */.Kf)(ledger, req.hypothesisId, patchDigest)) : null;
465
- return { ...base, incompleteStep: failed.step, failureCode: failed.code, reason: failed.reason, resumable: failed.resumable ?? false, repairRecords: ledger, verificationRecord: original0, summary: summaryOf(steps, false, failed.step, failed.code) };
466
- }
467
-
468
- // ---- the receipts must match the exact proposed diff and revision before anything is promoted
469
- const receipts = Object.fromEntries(Object.entries(runs).map(([k, r]) => [k, r.receipt]));
470
- const promotion = (0,patch_promotion/* promotePatch */.l)({ proposal: { hypothesisId: req.hypothesisId, revision: req.commit, originalFiles: original.files, patchFiles }, receipts });
471
- if (!promotion.ok) {
472
- const envBroken = promotion.reasons.some((r) => r.code === 'environment-mismatch');
473
- const code = envBroken ? 'environment-mismatch' : promotion.reasons.some((r) => r.code === 'oracle-changed') ? 'oracle-changed' : 'promotion-refused';
474
- const step = envBroken ? 'environment-equivalence' : code === 'oracle-changed' ? 'oracle-consistency' : 'promotion';
475
- const reason = promotion.reasons.map((r) => r.message).join('; ').slice(0, 400);
476
- ledger = ledgerFor(ledger, req, patchDigest, { rejected: { step, code, reason } }).records;
477
- return { ...base, promotion, incompleteStep: step, failureCode: code, reason, repairRecords: ledger, verificationRecord: base.records.original ? (0,repair_records/* withRepairStatus */.m$)(base.records.original, (0,repair_records/* verificationRepairFor */.Kf)(ledger, req.hypothesisId, patchDigest)) : null, summary: summaryOf(steps, false, step, code) };
478
- }
479
- const promoted = (0,repair_records/* recordPromotion */.Zw)(ledger, promotion, { verificationRecordId: base.records.patched?.id ?? null });
480
- ledger = promoted.records;
481
- const verificationRecord = (0,repair_records/* withRepairStatus */.m$)(base.records.original, (0,repair_records/* verificationRepairFor */.Kf)(ledger, req.hypothesisId, patchDigest, base.records.patched?.id));
482
- return {
483
- ...base, status: 'verified-fix', verifiedFix: true, promotion, receipts, repairRecords: ledger, verificationRecord,
484
- reason: 'verified', summary: summaryOf(steps, true, null, null),
485
- };
486
- }
487
-
488
- // The ledger for one verification: always starts with a `proposed` record, and records a rejection when verification stopped.
489
- function ledgerFor(records, req, patchDigest, { rejected } = {}) {
490
- let list = Array.isArray(records) ? records : [];
491
- const fields = { hypothesisId: req.hypothesisId, revision: (0,schema_kit/* isCommit */.WM)(req.commit) ? req.commit : null, diffDigest: patchDigest };
492
- if (!list.some((r) => r.hypothesisId === fields.hypothesisId && r.diffDigest === patchDigest)) list = (0,repair_records/* appendRepairRecord */.f7)(list, { ...fields, kind: 'proposed', reason: 'a patch was proposed for verification' }).records;
493
- if (rejected) list = (0,repair_records/* appendRepairRecord */.f7)(list, { ...fields, kind: 'rejected', step: rejected.step, reason: `${rejected.code}: ${String(rejected.reason || '').slice(0, 300)}` }).records;
494
- return { records: list };
495
- }
496
-
497
-
498
- /***/ })
499
-
500
- };