audit-tools 0.42.1 → 0.43.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.
Files changed (224) hide show
  1. package/dispatch/merge-results.mjs +229 -140
  2. package/dispatch/validate-result.mjs +98 -40
  3. package/dist/audit/cli/conceptualDispatch.d.ts.map +1 -1
  4. package/dist/audit/cli/conceptualDispatch.js +35 -3
  5. package/dist/audit/cli/conceptualDispatch.js.map +1 -1
  6. package/dist/audit/cli/dispatch/hostHandoff.d.ts +9 -1
  7. package/dist/audit/cli/dispatch/hostHandoff.d.ts.map +1 -1
  8. package/dist/audit/cli/dispatch/hostHandoff.js +94 -38
  9. package/dist/audit/cli/dispatch/hostHandoff.js.map +1 -1
  10. package/dist/audit/cli/nextStepCommand.d.ts +64 -0
  11. package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
  12. package/dist/audit/cli/nextStepCommand.js +877 -783
  13. package/dist/audit/cli/nextStepCommand.js.map +1 -1
  14. package/dist/audit/cli/nextStepHelpers.d.ts +12 -0
  15. package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
  16. package/dist/audit/cli/nextStepHelpers.js +34 -1
  17. package/dist/audit/cli/nextStepHelpers.js.map +1 -1
  18. package/dist/audit/cli/steps.d.ts +2 -2
  19. package/dist/audit/extractors/graph.d.ts +28 -2
  20. package/dist/audit/extractors/graph.d.ts.map +1 -1
  21. package/dist/audit/extractors/graph.js +122 -11
  22. package/dist/audit/extractors/graph.js.map +1 -1
  23. package/dist/audit/extractors/graphRoutes.d.ts +8 -0
  24. package/dist/audit/extractors/graphRoutes.d.ts.map +1 -1
  25. package/dist/audit/extractors/graphRoutes.js +71 -4
  26. package/dist/audit/extractors/graphRoutes.js.map +1 -1
  27. package/dist/audit/io/artifacts.d.ts +55 -0
  28. package/dist/audit/io/artifacts.d.ts.map +1 -1
  29. package/dist/audit/io/artifacts.js +189 -12
  30. package/dist/audit/io/artifacts.js.map +1 -1
  31. package/dist/audit/io/toolingManifest.d.ts +11 -0
  32. package/dist/audit/io/toolingManifest.d.ts.map +1 -1
  33. package/dist/audit/io/toolingManifest.js +13 -3
  34. package/dist/audit/io/toolingManifest.js.map +1 -1
  35. package/dist/audit/orchestrator/advance.d.ts +64 -0
  36. package/dist/audit/orchestrator/advance.d.ts.map +1 -1
  37. package/dist/audit/orchestrator/advance.js +191 -57
  38. package/dist/audit/orchestrator/advance.js.map +1 -1
  39. package/dist/audit/orchestrator/charterClarificationExecutor.d.ts.map +1 -1
  40. package/dist/audit/orchestrator/charterClarificationExecutor.js +55 -21
  41. package/dist/audit/orchestrator/charterClarificationExecutor.js.map +1 -1
  42. package/dist/audit/orchestrator/flowCoverage.d.ts.map +1 -1
  43. package/dist/audit/orchestrator/flowCoverage.js +7 -10
  44. package/dist/audit/orchestrator/flowCoverage.js.map +1 -1
  45. package/dist/audit/orchestrator/flowPlanning.d.ts +54 -1
  46. package/dist/audit/orchestrator/flowPlanning.d.ts.map +1 -1
  47. package/dist/audit/orchestrator/flowPlanning.js +77 -18
  48. package/dist/audit/orchestrator/flowPlanning.js.map +1 -1
  49. package/dist/audit/orchestrator/flowRequeue.d.ts.map +1 -1
  50. package/dist/audit/orchestrator/flowRequeue.js +6 -10
  51. package/dist/audit/orchestrator/flowRequeue.js.map +1 -1
  52. package/dist/audit/orchestrator/requeueFold.d.ts.map +1 -1
  53. package/dist/audit/orchestrator/requeueFold.js +18 -5
  54. package/dist/audit/orchestrator/requeueFold.js.map +1 -1
  55. package/dist/audit/orchestrator/staleness.d.ts +24 -1
  56. package/dist/audit/orchestrator/staleness.d.ts.map +1 -1
  57. package/dist/audit/orchestrator/staleness.js +147 -16
  58. package/dist/audit/orchestrator/staleness.js.map +1 -1
  59. package/dist/audit/orchestrator/syntaxResolutionExecutor.d.ts +26 -0
  60. package/dist/audit/orchestrator/syntaxResolutionExecutor.d.ts.map +1 -1
  61. package/dist/audit/orchestrator/syntaxResolutionExecutor.js +97 -12
  62. package/dist/audit/orchestrator/syntaxResolutionExecutor.js.map +1 -1
  63. package/dist/audit/orchestrator/taskBuilder.d.ts.map +1 -1
  64. package/dist/audit/orchestrator/taskBuilder.js +111 -21
  65. package/dist/audit/orchestrator/taskBuilder.js.map +1 -1
  66. package/dist/audit/orchestrator/trivialAudit.d.ts +17 -1
  67. package/dist/audit/orchestrator/trivialAudit.d.ts.map +1 -1
  68. package/dist/audit/orchestrator/trivialAudit.js +31 -4
  69. package/dist/audit/orchestrator/trivialAudit.js.map +1 -1
  70. package/dist/audit/types/analyzerCapability.d.ts +6 -6
  71. package/dist/audit/types/charterRegister.d.ts +30 -12
  72. package/dist/audit/types/charterRegister.d.ts.map +1 -1
  73. package/dist/audit/types/charterRegister.js +22 -9
  74. package/dist/audit/types/charterRegister.js.map +1 -1
  75. package/dist/audit/validation/anchorGrounding.d.ts.map +1 -1
  76. package/dist/audit/validation/anchorGrounding.js +17 -0
  77. package/dist/audit/validation/anchorGrounding.js.map +1 -1
  78. package/dist/audit/validation/auditResults.d.ts +17 -0
  79. package/dist/audit/validation/auditResults.d.ts.map +1 -1
  80. package/dist/audit/validation/auditResults.js +50 -17
  81. package/dist/audit/validation/auditResults.js.map +1 -1
  82. package/dist/remediate/contractPipeline/cyclicSeamResolution.d.ts +48 -0
  83. package/dist/remediate/contractPipeline/cyclicSeamResolution.d.ts.map +1 -1
  84. package/dist/remediate/contractPipeline/cyclicSeamResolution.js +128 -0
  85. package/dist/remediate/contractPipeline/cyclicSeamResolution.js.map +1 -1
  86. package/dist/remediate/contractPipeline/derive.d.ts +8 -5
  87. package/dist/remediate/contractPipeline/derive.d.ts.map +1 -1
  88. package/dist/remediate/contractPipeline/derive.js +8 -16
  89. package/dist/remediate/contractPipeline/derive.js.map +1 -1
  90. package/dist/remediate/index.d.ts.map +1 -1
  91. package/dist/remediate/index.js +43 -2
  92. package/dist/remediate/index.js.map +1 -1
  93. package/dist/remediate/intent/intentOrdering.d.ts +13 -5
  94. package/dist/remediate/intent/intentOrdering.d.ts.map +1 -1
  95. package/dist/remediate/intent/intentOrdering.js +56 -25
  96. package/dist/remediate/intent/intentOrdering.js.map +1 -1
  97. package/dist/remediate/phases/close.d.ts +57 -2
  98. package/dist/remediate/phases/close.d.ts.map +1 -1
  99. package/dist/remediate/phases/close.js +260 -36
  100. package/dist/remediate/phases/close.js.map +1 -1
  101. package/dist/remediate/state/disposition.d.ts +26 -4
  102. package/dist/remediate/state/disposition.d.ts.map +1 -1
  103. package/dist/remediate/state/itemStatus.d.ts +33 -6
  104. package/dist/remediate/state/itemStatus.d.ts.map +1 -1
  105. package/dist/remediate/state/itemStatus.js +154 -39
  106. package/dist/remediate/state/itemStatus.js.map +1 -1
  107. package/dist/remediate/state/types.d.ts +41 -2
  108. package/dist/remediate/state/types.d.ts.map +1 -1
  109. package/dist/remediate/state/types.js.map +1 -1
  110. package/dist/remediate/steps/contractPipeline.d.ts +287 -15
  111. package/dist/remediate/steps/contractPipeline.d.ts.map +1 -1
  112. package/dist/remediate/steps/contractPipeline.js +1655 -981
  113. package/dist/remediate/steps/contractPipeline.js.map +1 -1
  114. package/dist/remediate/steps/dispatch/hostHandoff.d.ts +137 -2
  115. package/dist/remediate/steps/dispatch/hostHandoff.d.ts.map +1 -1
  116. package/dist/remediate/steps/dispatch/hostHandoff.js +713 -59
  117. package/dist/remediate/steps/dispatch/hostHandoff.js.map +1 -1
  118. package/dist/remediate/steps/finalGate.d.ts +136 -37
  119. package/dist/remediate/steps/finalGate.d.ts.map +1 -1
  120. package/dist/remediate/steps/finalGate.js +120 -86
  121. package/dist/remediate/steps/finalGate.js.map +1 -1
  122. package/dist/remediate/steps/gateCommands.d.ts +8 -0
  123. package/dist/remediate/steps/gateCommands.d.ts.map +1 -1
  124. package/dist/remediate/steps/gateCommands.js +40 -11
  125. package/dist/remediate/steps/gateCommands.js.map +1 -1
  126. package/dist/remediate/steps/nextStep.d.ts +96 -5
  127. package/dist/remediate/steps/nextStep.d.ts.map +1 -1
  128. package/dist/remediate/steps/nextStep.js +668 -147
  129. package/dist/remediate/steps/nextStep.js.map +1 -1
  130. package/dist/remediate/steps/types.d.ts +4 -1
  131. package/dist/remediate/steps/types.d.ts.map +1 -1
  132. package/dist/remediate/steps/types.js +10 -0
  133. package/dist/remediate/steps/types.js.map +1 -1
  134. package/dist/remediate/validation/artifacts.d.ts +20 -0
  135. package/dist/remediate/validation/artifacts.d.ts.map +1 -1
  136. package/dist/remediate/validation/artifacts.js +239 -13
  137. package/dist/remediate/validation/artifacts.js.map +1 -1
  138. package/dist/remediate/validation/contractPipelineGates.d.ts +58 -0
  139. package/dist/remediate/validation/contractPipelineGates.d.ts.map +1 -1
  140. package/dist/remediate/validation/contractPipelineGates.js +143 -27
  141. package/dist/remediate/validation/contractPipelineGates.js.map +1 -1
  142. package/dist/shared/analyzers/acquisitionEngine.d.ts +72 -25
  143. package/dist/shared/analyzers/acquisitionEngine.d.ts.map +1 -1
  144. package/dist/shared/analyzers/acquisitionEngine.js +149 -15
  145. package/dist/shared/analyzers/acquisitionEngine.js.map +1 -1
  146. package/dist/shared/analyzers/binaryAcquisition.d.ts +27 -2
  147. package/dist/shared/analyzers/binaryAcquisition.d.ts.map +1 -1
  148. package/dist/shared/analyzers/binaryAcquisition.js +149 -43
  149. package/dist/shared/analyzers/binaryAcquisition.js.map +1 -1
  150. package/dist/shared/analyzers/candidates.d.ts +9 -8
  151. package/dist/shared/analyzers/candidates.d.ts.map +1 -1
  152. package/dist/shared/analyzers/candidates.js +96 -64
  153. package/dist/shared/analyzers/candidates.js.map +1 -1
  154. package/dist/shared/analyzers/normalizeExternal.d.ts +40 -12
  155. package/dist/shared/analyzers/normalizeExternal.d.ts.map +1 -1
  156. package/dist/shared/analyzers/normalizeExternal.js +74 -18
  157. package/dist/shared/analyzers/normalizeExternal.js.map +1 -1
  158. package/dist/shared/analyzers/rubocop.d.ts +14 -13
  159. package/dist/shared/analyzers/rubocop.d.ts.map +1 -1
  160. package/dist/shared/analyzers/rubocop.js +29 -6
  161. package/dist/shared/analyzers/rubocop.js.map +1 -1
  162. package/dist/shared/analyzers/types.d.ts +196 -13
  163. package/dist/shared/analyzers/types.d.ts.map +1 -1
  164. package/dist/shared/analyzers/types.js +122 -9
  165. package/dist/shared/analyzers/types.js.map +1 -1
  166. package/dist/shared/decompose/charterClarification.d.ts +12 -1
  167. package/dist/shared/decompose/charterClarification.d.ts.map +1 -1
  168. package/dist/shared/decompose/charterClarification.js +11 -4
  169. package/dist/shared/decompose/charterClarification.js.map +1 -1
  170. package/dist/shared/decompose/charterExtraction.d.ts +20 -10
  171. package/dist/shared/decompose/charterExtraction.d.ts.map +1 -1
  172. package/dist/shared/decompose/charterExtraction.js +52 -23
  173. package/dist/shared/decompose/charterExtraction.js.map +1 -1
  174. package/dist/shared/intent/freeFormIntentInterpreter.d.ts +12 -2
  175. package/dist/shared/intent/freeFormIntentInterpreter.d.ts.map +1 -1
  176. package/dist/shared/intent/freeFormIntentInterpreter.js +27 -22
  177. package/dist/shared/intent/freeFormIntentInterpreter.js.map +1 -1
  178. package/dist/shared/intent/pathScope.d.ts +12 -1
  179. package/dist/shared/intent/pathScope.d.ts.map +1 -1
  180. package/dist/shared/intent/pathScope.js +56 -19
  181. package/dist/shared/intent/pathScope.js.map +1 -1
  182. package/dist/shared/intent/sharedIntentData.d.ts +19 -1
  183. package/dist/shared/intent/sharedIntentData.d.ts.map +1 -1
  184. package/dist/shared/intent/sharedIntentData.js +33 -8
  185. package/dist/shared/intent/sharedIntentData.js.map +1 -1
  186. package/dist/shared/io/fileLock.d.ts +12 -0
  187. package/dist/shared/io/fileLock.d.ts.map +1 -1
  188. package/dist/shared/io/fileLock.js +48 -5
  189. package/dist/shared/io/fileLock.js.map +1 -1
  190. package/dist/shared/io/json.d.ts +13 -0
  191. package/dist/shared/io/json.d.ts.map +1 -1
  192. package/dist/shared/io/json.js +19 -1
  193. package/dist/shared/io/json.js.map +1 -1
  194. package/dist/shared/steps/stepEmissionScaffold.d.ts +69 -0
  195. package/dist/shared/steps/stepEmissionScaffold.d.ts.map +1 -0
  196. package/dist/shared/steps/stepEmissionScaffold.js +83 -0
  197. package/dist/shared/steps/stepEmissionScaffold.js.map +1 -0
  198. package/dist/shared/submission/handRecovery.d.ts.map +1 -1
  199. package/dist/shared/submission/handRecovery.js +69 -4
  200. package/dist/shared/submission/handRecovery.js.map +1 -1
  201. package/dist/shared/submission/submissionIdentity.d.ts +10 -1
  202. package/dist/shared/submission/submissionIdentity.d.ts.map +1 -1
  203. package/dist/shared/submission/submissionIdentity.js +12 -3
  204. package/dist/shared/submission/submissionIdentity.js.map +1 -1
  205. package/dist/shared/submission/submissionLedger.d.ts +43 -2
  206. package/dist/shared/submission/submissionLedger.d.ts.map +1 -1
  207. package/dist/shared/submission/submissionLedger.js +50 -7
  208. package/dist/shared/submission/submissionLedger.js.map +1 -1
  209. package/dist/shared/tooling/allowlistedExec.d.ts +9 -0
  210. package/dist/shared/tooling/allowlistedExec.d.ts.map +1 -1
  211. package/dist/shared/tooling/allowlistedExec.js +19 -2
  212. package/dist/shared/tooling/allowlistedExec.js.map +1 -1
  213. package/dist/shared/types/charter.d.ts +24 -0
  214. package/dist/shared/types/charter.d.ts.map +1 -1
  215. package/dist/shared/types/charter.js +9 -0
  216. package/dist/shared/types/charter.js.map +1 -1
  217. package/dist/shared/types/remediationOutcome.d.ts +282 -9
  218. package/dist/shared/types/remediationOutcome.d.ts.map +1 -1
  219. package/dist/shared/types/remediationOutcome.js +174 -1
  220. package/dist/shared/types/remediationOutcome.js.map +1 -1
  221. package/package.json +2 -1
  222. package/remediate-code.mjs +15 -0
  223. package/wrapper/remediate-code-wrapper-install-hosts.mjs +45 -4
  224. package/wrapper/remediate-code-wrapper-install-renderers.mjs +12 -2
@@ -2,6 +2,7 @@ import { existsSync, readFileSync, rmSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { runTracked } from "../tooling/exec.js";
4
4
  import { normalizeGenericExternalResults, normalizeGenericExternalEdges, } from "./normalizeExternal.js";
5
+ import { readParseOutcome, } from "./types.js";
5
6
  import { resolveBinary, } from "./binaryAcquisition.js";
6
7
  /**
7
8
  * F5 — external analyzer acquisition engine.
@@ -94,24 +95,77 @@ function runnerPrefix(runner, spec) {
94
95
  case "binary": return [];
95
96
  }
96
97
  }
98
+ /**
99
+ * The denial vocabulary. An operator refusal and a tool nobody has decided on are
100
+ * DIFFERENT causes and must be distinguishable in the persisted status record — a
101
+ * single conflated string cannot tell an operator that their own decline was the
102
+ * reason. Every CONSENT-channel reason names "consent"; `setting_skip` deliberately
103
+ * does not, because it comes from the settings channel (`analyzers.<id> = "skip"`)
104
+ * and is not a consent decision at all.
105
+ */
106
+ export const ANALYZER_DENIAL_REASONS = {
107
+ /** `analyzers.<id> = "skip"` — the settings channel, not the consent record. */
108
+ setting_skip: "setting=skip",
109
+ /** A recorded, durable operator refusal. Terminal: no token overrides it. */
110
+ consent_declined: "consent declined by the operator for this analyzer (recorded decision)",
111
+ /** No decision recorded and no token presented — nobody has said yes OR no. */
112
+ consent_not_decided: "consent not recorded for this analyzer (not yet decided; no consent token for this run)",
113
+ /** A token was presented, but it was issued for a different analyzer. */
114
+ consent_token_scope: "consent token was not issued for this analyzer (scoped consent covers other tools only)",
115
+ };
116
+ /**
117
+ * Does this consent input authorize THIS candidate?
118
+ *
119
+ * A scoped grant authorizes exactly the tools it names — a grant obtained by offering
120
+ * tool A cannot admit tool B. The legacy bare string carries no scope, so it can only
121
+ * be read as run-wide; it is accepted for compatibility with the acquisition entry
122
+ * point that still issues one, and is deliberately reported distinctly here so the
123
+ * unscoped case is visible rather than indistinguishable from a scoped grant.
124
+ */
125
+ function consentTokenAdmits(consentToken, candidateId) {
126
+ if (consentToken === undefined || consentToken === null)
127
+ return "absent";
128
+ if (typeof consentToken === "string") {
129
+ return consentToken.trim().length > 0 ? "admit" : "absent";
130
+ }
131
+ if (typeof consentToken.value !== "string" || consentToken.value.trim().length === 0) {
132
+ return "absent";
133
+ }
134
+ if (!Array.isArray(consentToken.tools))
135
+ return "out_of_scope";
136
+ return consentToken.tools.includes(candidateId) ? "admit" : "out_of_scope";
137
+ }
97
138
  /**
98
139
  * Single subprocess-SPAWN admission chokepoint. Returns the reason a spawn is
99
- * NOT admitted, or `undefined` when admitted. The DEFAULT set is admitted
100
- * without a token; EVERY other candidate — including `permanent`/`ephemeral`
101
- * pre-installed tools — requires EITHER a recorded "granted" decision OR a
102
- * per-run consent token (CE-005, revised with Item B).
140
+ * NOT admitted, or `undefined` when admitted.
141
+ *
142
+ * ORDER IS THE CONTRACT. A recorded `"declined"` is consulted FIRST — before the
143
+ * settings channel, before the DEFAULT-set short-circuit, and before any consent
144
+ * token — so an operator refusal is a veto for EVERY candidate, including a
145
+ * default-set member, and no token can override it. It also outranks
146
+ * `setting=skip`: both refuse, but only one of them is the operator's own decision,
147
+ * and the REASON is what tells them so. Only then: `skip`, then the DEFAULT set
148
+ * runs unprompted, a recorded `"granted"` admits, and finally a consent token
149
+ * admits the candidate it was issued for.
103
150
  */
104
151
  export function admitSpawn(candidate, setting, consentToken, recordedDecision) {
152
+ // A recorded refusal is terminal and is read BEFORE anything else — including the
153
+ // settings channel, which would otherwise mask the operator's own decision behind
154
+ // a reason that names a config value instead of their decline.
155
+ if (recordedDecision === "declined")
156
+ return ANALYZER_DENIAL_REASONS.consent_declined;
105
157
  if (setting === "skip")
106
- return "setting=skip";
158
+ return ANALYZER_DENIAL_REASONS.setting_skip;
107
159
  if (candidate.defaultRun)
108
160
  return undefined;
109
- // Admission: default set ∨ recorded "granted" ∨ per-run token
110
161
  if (recordedDecision === "granted")
111
162
  return undefined;
112
- if (consentToken && consentToken.trim().length > 0)
163
+ const tokenVerdict = consentTokenAdmits(consentToken, candidate.id);
164
+ if (tokenVerdict === "admit")
113
165
  return undefined;
114
- return "non-default tool requires consent (declined or not yet decided)";
166
+ if (tokenVerdict === "out_of_scope")
167
+ return ANALYZER_DENIAL_REASONS.consent_token_scope;
168
+ return ANALYZER_DENIAL_REASONS.consent_not_decided;
115
169
  }
116
170
  /**
117
171
  * The run-safety gate, written once: capability-probe the runner, then (if the
@@ -260,9 +314,11 @@ export function runExternalAnalyzer(candidate, root, options = {}) {
260
314
  /* best-effort */
261
315
  }
262
316
  }
263
- let items;
317
+ const stderrText = typeof result.stderr === "string" ? result.stderr : "";
318
+ const stderrSnippet = stderrText.trim().length > 0 ? { stderr_snippet: stderrText.slice(0, 500) } : {};
319
+ let parsed;
264
320
  try {
265
- items = candidate.parse(parseInput);
321
+ parsed = readParseOutcome(candidate.parse(parseInput));
266
322
  }
267
323
  catch (error) {
268
324
  return {
@@ -275,13 +331,21 @@ export function runExternalAnalyzer(candidate, root, options = {}) {
275
331
  exit_code: result.status,
276
332
  error: error instanceof Error ? error.message : String(error),
277
333
  output_snippet: result.stdout.slice(0, 200),
334
+ ...stderrSnippet,
278
335
  duration_ms: result.duration_ms,
279
336
  },
280
337
  };
281
338
  }
282
- // readSource: content-anchored lead provenance (item C). Repo-rooted, degrade
283
- // to no-provenance on any read failure — never blocks normalization.
339
+ const items = parsed.items;
340
+ // readSource: content-anchored lead provenance (item C). Paths are normalized to
341
+ // repo-relative FIRST (an absolute-path emitter would otherwise make `join(root,
342
+ // path)` name nothing, silently dropping provenance); a read that still fails is
343
+ // COUNTED onto the status, so a broken read seam is distinguishable from an item
344
+ // that legitimately carries no anchor.
345
+ let sourceReadFailures = 0;
346
+ let normalizerDroppedItems = 0;
284
347
  const normalized = normalizeGenericExternalResults(candidate.id, items, {
348
+ repoRoot: root,
285
349
  readSource: (path) => {
286
350
  try {
287
351
  return readFileSync(join(root, path), "utf8");
@@ -290,10 +354,77 @@ export function runExternalAnalyzer(candidate, root, options = {}) {
290
354
  return undefined;
291
355
  }
292
356
  },
357
+ onDiagnostics: (diagnostics) => {
358
+ sourceReadFailures = diagnostics.source_read_failures;
359
+ normalizerDroppedItems = diagnostics.dropped_items;
360
+ },
293
361
  });
294
362
  const edges = normalizeGenericExternalEdges(items);
295
363
  if (edges.length > 0)
296
364
  normalized.graph_edges = edges;
365
+ // Rows the PARSER could not use plus items the NORMALIZER discarded (missing path
366
+ // or summary) are the same question to a consumer — "how much did this run fail to
367
+ // report?" — so they land on one field. Counting only the parser's half left a run
368
+ // whose every item was dropped at normalization reading as a clean scan.
369
+ const droppedRows = (parsed.dropped_rows ?? 0) + normalizerDroppedItems;
370
+ const degradationFields = {
371
+ exit_code: result.status,
372
+ ...(droppedRows > 0 ? { dropped_rows: droppedRows } : {}),
373
+ ...(sourceReadFailures > 0 ? { source_read_failures: sourceReadFailures } : {}),
374
+ ...stderrSnippet,
375
+ duration_ms: result.duration_ms,
376
+ };
377
+ // AFFIRMATION, never a success-shaped empty. Zero items is only "success" when the
378
+ // run itself was clean: the tool exited 0, said nothing on stderr it did not also
379
+ // say on stdout, parsed, and dropped nothing. Every other zero-item outcome names
380
+ // its cause — the exit code and stderr are in hand right here, which is exactly
381
+ // why leaving them unconsulted made a broken analyzer read as a clean repo.
382
+ if (normalized.results.length === 0) {
383
+ // A NULL exit status means the child never exited on its own — it was killed by a
384
+ // signal (SIGKILL/OOM). `RunTrackedResult` carries no signal field, so null is the
385
+ // only trace of it, and it is emphatically not "exited cleanly". Treating it as
386
+ // clean also made the classification OS-divergent: win32 surfaces the same kill as
387
+ // a non-zero status, so the identical event would have been failed there and
388
+ // success on POSIX.
389
+ const exitMissing = result.status === null || result.status === undefined;
390
+ const exitedNonZero = exitMissing || result.status !== 0;
391
+ const stderrOnly = !exitedNonZero && stderrText.trim().length > 0 && parseInput.trim().length === 0;
392
+ if (exitedNonZero || stderrOnly) {
393
+ return {
394
+ results: emptyResults(candidate.id),
395
+ status: {
396
+ tool: candidate.id,
397
+ command,
398
+ resolved: true,
399
+ status: "failed",
400
+ error: exitMissing
401
+ ? "analyzer terminated without an exit status (killed by a signal) and produced no parsable findings"
402
+ : exitedNonZero
403
+ ? `analyzer exited ${result.status} with no parsable findings`
404
+ : "analyzer produced no output other than stderr",
405
+ output_snippet: result.stdout.slice(0, 200),
406
+ ...degradationFields,
407
+ },
408
+ };
409
+ }
410
+ if (parsed.parse_failed || droppedRows > 0) {
411
+ return {
412
+ results: emptyResults(candidate.id),
413
+ status: {
414
+ tool: candidate.id,
415
+ command,
416
+ resolved: true,
417
+ status: "parse_error",
418
+ error: parsed.note ??
419
+ (parsed.parse_failed
420
+ ? "analyzer output could not be parsed"
421
+ : `analyzer output parsed with ${droppedRows} unusable row(s)`),
422
+ output_snippet: parseInput.slice(0, 200),
423
+ ...degradationFields,
424
+ },
425
+ };
426
+ }
427
+ }
297
428
  return {
298
429
  results: normalized,
299
430
  status: {
@@ -301,8 +432,8 @@ export function runExternalAnalyzer(candidate, root, options = {}) {
301
432
  command,
302
433
  resolved: true,
303
434
  status: normalized.results.length > 0 ? "findings" : "success",
304
- exit_code: result.status,
305
- duration_ms: result.duration_ms,
435
+ ...(parsed.note !== undefined ? { error: parsed.note } : {}),
436
+ ...degradationFields,
306
437
  },
307
438
  };
308
439
  }
@@ -361,10 +492,13 @@ export async function resolveBinaryCandidates(candidates, root, options = {}) {
361
492
  resolvedBinaries[candidate.id] = resolution.command;
362
493
  }
363
494
  else {
495
+ // A supply-chain event gets its OWN status member: "the release asset did not
496
+ // match the pinned checksums" must never be flattened into the same record as
497
+ // "this machine is offline", which is all a shared `not_resolved` could say.
364
498
  unresolvedStatuses.push({
365
499
  tool: candidate.id,
366
500
  resolved: false,
367
- status: "not_resolved",
501
+ status: resolution.reason === "checksum_mismatch" ? "checksum_mismatch" : "not_resolved",
368
502
  error: resolution.note ?? "binary unavailable",
369
503
  });
370
504
  }
@@ -1 +1 @@
1
- {"version":3,"file":"acquisitionEngine.js","sourceRoot":"","sources":["../../../src/shared/analyzers/acquisitionEngine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"acquisitionEngine.js","sourceRoot":"","sources":["../../../src/shared/analyzers/acquisitionEngine.ts"],"names":[],"mappings":"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"}
@@ -15,7 +15,24 @@ import { type RunTrackedResult } from "../tooling/exec.js";
15
15
  * is SHA256-verified against the official release checksums BEFORE it is extracted
16
16
  * or executed; the fetcher is injected so the engine is testable without network
17
17
  * and an absent network degrades cleanly. A checksum mismatch is fatal-to-this-tool
18
- * (returns `unavailable`), never executed.
18
+ * (returns `unavailable` with reason `checksum_mismatch`), never executed.
19
+ *
20
+ * The cache branch is held to the SAME bar as the download branch, on EVERY
21
+ * resolution, in two layers that only work together:
22
+ * - LOCATION. The default cache root is per-user (`<homedir>/.audit-tools/bincache`,
23
+ * created 0o700 where modes are honoured), never the shared temp dir. The path is
24
+ * fully derivable from public pinned constants, so "a file exists there" is only
25
+ * meaningful when the directory is not writable by other local processes.
26
+ * - INTEGRITY. Each successful download records the executable's digest in a cache
27
+ * manifest beside it, and a cache hit is only a hit when the bytes still hash to
28
+ * that recorded digest. Anything else — no manifest, an unreadable manifest, a
29
+ * digest mismatch, or a version dir left behind by a failed extraction — is PURGED
30
+ * and re-acquired rather than executed.
31
+ *
32
+ * The manifest alone is NOT provenance: anyone who can write the cache dir can write a
33
+ * self-consistent binary+manifest pair. It detects drift and partial writes; the
34
+ * location layer is what makes writing the pair privileged in the first place. A
35
+ * caller passing its own `cacheDir` owns that directory's permissions.
19
36
  */
20
37
  /** Injected network fetch: returns the URL's bytes, or `null` when unavailable. */
21
38
  export interface BinaryFetcher {
@@ -57,15 +74,23 @@ export interface BinarySpec {
57
74
  export interface BinaryResolveOptions {
58
75
  fetch?: BinaryFetcher;
59
76
  run?: BinaryCommandRunner;
60
- /** Root cache dir for downloaded binaries; default `<tmpdir>/audit-tools-bincache`. */
77
+ /** Root cache dir for downloaded binaries; default `<homedir>/.audit-tools/bincache`. */
61
78
  cacheDir?: string;
62
79
  platform?: NodeJS.Platform;
63
80
  arch?: string;
64
81
  }
82
+ /**
83
+ * WHY a binary could not be resolved, as a machine-readable member rather than a
84
+ * free-text note. `checksum_mismatch` is a supply-chain event and must never be
85
+ * indistinguishable from `offline` in the persisted record.
86
+ */
87
+ export type BinaryUnavailableReason = "offline" | "no_asset_for_platform" | "download_failed" | "download_empty" | "no_checksum_for_asset" | "checksum_mismatch" | "extract_failed" | "not_found_in_archive" | "write_failed";
65
88
  export interface BinaryResolution {
66
89
  status: "path" | "cached" | "downloaded" | "unavailable";
67
90
  /** Resolved executable (PATH name or absolute cached path); null when unavailable. */
68
91
  command: string | null;
92
+ /** Discriminated cause when `status === "unavailable"`. */
93
+ reason?: BinaryUnavailableReason;
69
94
  note?: string;
70
95
  }
71
96
  /** Parse a `<sha256>␠␠<asset>` checksums file for one asset's expected digest. */
@@ -1 +1 @@
1
- {"version":3,"file":"binaryAcquisition.d.ts","sourceRoot":"","sources":["../../../src/shared/analyzers/binaryAcquisition.ts"],"names":[],"mappings":"AAYA,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEvE;;;;;;;;;;;;;;;;;GAiBG;AAEH,mFAAmF;AACnF,MAAM,WAAW,aAAa;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;CAC3C;AAED,0FAA0F;AAC1F,MAAM,WAAW,mBAAmB;IAClC,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAC;CACjD;AAED,0EAA0E;AAC1E,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACjE;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;IACzD,gFAAgF;IAChF,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9C;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,GAAG,CAAC,EAAE,mBAAmB,CAAC;IAC1B,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,aAAa,CAAC;IACzD,sFAAsF;IACtF,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAUD,kFAAkF;AAClF,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAMf;AAMD;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,gBAAgB,CAAC,CAiI3B"}
1
+ {"version":3,"file":"binaryAcquisition.d.ts","sourceRoot":"","sources":["../../../src/shared/analyzers/binaryAcquisition.ts"],"names":[],"mappings":"AAcA,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,mFAAmF;AACnF,MAAM,WAAW,aAAa;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;CAC3C;AAED,0FAA0F;AAC1F,MAAM,WAAW,mBAAmB;IAClC,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAC;CACjD;AAED,0EAA0E;AAC1E,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACjE;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;IACzD,gFAAgF;IAChF,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9C;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,GAAG,CAAC,EAAE,mBAAmB,CAAC;IAC1B,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAC/B,SAAS,GACT,uBAAuB,GACvB,iBAAiB,GACjB,gBAAgB,GAChB,uBAAuB,GACvB,mBAAmB,GACnB,gBAAgB,GAChB,sBAAsB,GACtB,cAAc,CAAC;AAEnB,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,aAAa,CAAC;IACzD,sFAAsF;IACtF,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA+ID,kFAAkF;AAClF,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAMf;AAMD;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,gBAAgB,CAAC,CAiJ3B"}
@@ -1,14 +1,122 @@
1
1
  import { createHash } from "node:crypto";
2
- import { chmodSync, existsSync, mkdirSync, readdirSync, rmSync, statSync, writeFileSync, } from "node:fs";
3
- import { join } from "node:path";
4
- import { tmpdir } from "node:os";
2
+ import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync, } from "node:fs";
3
+ import { isAbsolute, join, relative } from "node:path";
4
+ import { homedir } from "node:os";
5
+ import { AUDIT_TOOLS_DIRNAME } from "../io/auditToolsPaths.js";
5
6
  import { runTracked } from "../tooling/exec.js";
7
+ /**
8
+ * Per-USER cache root, deliberately NOT the system temp dir. Defaults to
9
+ * `~/.audit-tools/bincache`; `AUDIT_TOOLS_BINARY_CACHE` overrides it so a run can be
10
+ * pinned to an isolated cache — the same override shape as
11
+ * {@link analyzerCacheRoot}'s `AUDIT_TOOLS_ANALYZER_CACHE`, and what lets a test
12
+ * exercise the DEFAULT path without ever writing to the real home directory.
13
+ *
14
+ * The digest manifest beside a cached binary proves the bytes match what the manifest
15
+ * says — but an attacker who can write the cache dir writes BOTH, so a self-consistent
16
+ * pair inside a world-writable location proves nothing. The manifest only has meaning
17
+ * when the directory it lives in is not attacker-writable, which is what moving the
18
+ * default root under the user's home buys. `cacheDir` remains overridable per call for
19
+ * a caller that has its own private location.
20
+ *
21
+ * Consequence, deliberate: caches warmed under the old `<tmpdir>/audit-tools-bincache`
22
+ * are simply never consulted again — the first resolution under the new root
23
+ * re-downloads, or degrades to `unavailable` offline.
24
+ */
6
25
  function defaultCacheDir() {
7
- return join(tmpdir(), "audit-tools-bincache");
26
+ const override = process.env.AUDIT_TOOLS_BINARY_CACHE;
27
+ if (override && override.trim().length > 0)
28
+ return override;
29
+ return join(homedir(), AUDIT_TOOLS_DIRNAME, "bincache");
30
+ }
31
+ /**
32
+ * Create the cache root restricted to its owner where the platform honours modes.
33
+ * On win32 the mode is ignored (ACLs govern), and the per-user home root is the
34
+ * protection there.
35
+ *
36
+ * ⚠ The mode applies AT CREATION ONLY. An existing directory keeps whatever mode it
37
+ * already has — `mkdirSync` does not chmod one it did not create — so a root that was
38
+ * created loosely by something else is not repaired here.
39
+ */
40
+ function ensureCacheRoot(cacheDir) {
41
+ try {
42
+ mkdirSync(cacheDir, { recursive: true, mode: 0o700 });
43
+ }
44
+ catch {
45
+ /* a later mkdir of the version dir surfaces any real failure */
46
+ }
8
47
  }
9
48
  function exeName(binaryName, platform) {
10
49
  return platform === "win32" ? `${binaryName}.exe` : binaryName;
11
50
  }
51
+ /** `unavailable` with its cause carried in BOTH forms — machine member + human note. */
52
+ function unavailable(reason, note) {
53
+ return { status: "unavailable", command: null, reason, note };
54
+ }
55
+ /**
56
+ * Cache manifest filename. Written beside the cached executable at download time and
57
+ * the ONLY evidence that these bytes came from a checksum-verified acquisition.
58
+ */
59
+ const CACHE_MANIFEST_FILENAME = ".audit-tools-binary.json";
60
+ /** Remove a cache version dir wholesale; best-effort, never throws. */
61
+ function purgeVersionDir(versionDir) {
62
+ try {
63
+ rmSync(versionDir, { recursive: true, force: true });
64
+ }
65
+ catch {
66
+ /* best-effort — a later resolution re-verifies regardless */
67
+ }
68
+ }
69
+ function writeCacheManifest(versionDir, spec, executablePath) {
70
+ try {
71
+ const manifest = {
72
+ binaryName: spec.binaryName,
73
+ version: spec.version,
74
+ executable_relative_path: relative(versionDir, executablePath).replace(/\\/g, "/"),
75
+ executable_sha256: sha256(readFileSync(executablePath)),
76
+ };
77
+ writeFileSync(join(versionDir, CACHE_MANIFEST_FILENAME), `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
78
+ }
79
+ catch {
80
+ /* An unwritable manifest simply means the next resolution re-downloads. */
81
+ }
82
+ }
83
+ /**
84
+ * The cached executable's path — but ONLY when its bytes still hash to the digest
85
+ * recorded when it was acquired. A missing, unreadable, or mismatched manifest, an
86
+ * escaping relative path, or drifted bytes all return null and the caller purges:
87
+ * filename existence is never sufficient to execute.
88
+ */
89
+ function verifiedCachedExecutable(versionDir, spec) {
90
+ let manifest;
91
+ try {
92
+ manifest = JSON.parse(readFileSync(join(versionDir, CACHE_MANIFEST_FILENAME), "utf8"));
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ if (!manifest ||
98
+ manifest.binaryName !== spec.binaryName ||
99
+ manifest.version !== spec.version ||
100
+ typeof manifest.executable_relative_path !== "string" ||
101
+ manifest.executable_relative_path.length === 0 ||
102
+ typeof manifest.executable_sha256 !== "string" ||
103
+ manifest.executable_sha256.length !== 64) {
104
+ return null;
105
+ }
106
+ const executablePath = join(versionDir, manifest.executable_relative_path);
107
+ const containment = relative(versionDir, executablePath);
108
+ if (containment.startsWith("..") || isAbsolute(containment))
109
+ return null;
110
+ try {
111
+ if (sha256(readFileSync(executablePath)) !== manifest.executable_sha256.toLowerCase()) {
112
+ return null;
113
+ }
114
+ }
115
+ catch {
116
+ return null;
117
+ }
118
+ return executablePath;
119
+ }
12
120
  /** Parse a `<sha256>␠␠<asset>` checksums file for one asset's expected digest. */
13
121
  export function expectedSha256For(checksumsText, assetName) {
14
122
  for (const line of checksumsText.split(/\r?\n/)) {
@@ -31,29 +139,34 @@ export async function resolveBinary(spec, options = {}) {
31
139
  const arch = options.arch ?? process.arch;
32
140
  const run = options.run ?? ((argv, cwd) => runTracked(argv, { cwd }));
33
141
  const cacheDir = options.cacheDir ?? defaultCacheDir();
34
- // 1. PATH — already installed.
142
+ // 1. PATH — already installed. Nothing below this point runs, so a tool the machine
143
+ // already has must not cause a cache directory to be created as a side effect.
35
144
  const probe = run(spec.versionProbeArgs, process.cwd());
36
145
  if (!probe.error && probe.status === 0) {
37
146
  return { status: "path", command: spec.binaryName };
38
147
  }
39
- // 2. cache — a previously-downloaded pinned binary.
148
+ // 2. cache — a previously-downloaded pinned binary, RE-VERIFIED on every
149
+ // resolution. The cache path is derivable from public pinned constants, so a
150
+ // file at the expected name is a claim, not a proof: it is executed only when its
151
+ // bytes still match the digest recorded at acquisition. Anything else — including
152
+ // a version dir a failed extraction left behind — is purged and re-acquired.
40
153
  const versionDir = join(cacheDir, `${spec.binaryName}-${spec.version}`);
41
- const cachedPath = join(versionDir, exeName(spec.binaryName, platform));
42
- if (existsSync(cachedPath)) {
43
- return { status: "cached", command: cachedPath };
154
+ if (existsSync(versionDir)) {
155
+ const verified = verifiedCachedExecutable(versionDir, spec);
156
+ if (verified)
157
+ return { status: "cached", command: verified };
158
+ // Unverifiable bytes, or a dir a failed extraction left behind: purge so nothing
159
+ // half-written or pre-planted can become a later "cache hit".
160
+ purgeVersionDir(versionDir);
44
161
  }
45
162
  // 3. download — pinned release asset, SHA256-verified, then extracted.
46
163
  const fetch = options.fetch;
47
164
  if (!fetch) {
48
- return { status: "unavailable", command: null, note: "no fetcher configured (offline)" };
165
+ return unavailable("offline", "no fetcher configured (offline)");
49
166
  }
50
167
  const assetName = spec.assetFor(platform, arch);
51
168
  if (!assetName) {
52
- return {
53
- status: "unavailable",
54
- command: null,
55
- note: `no release asset for ${platform}/${arch}`,
56
- };
169
+ return unavailable("no_asset_for_platform", `no release asset for ${platform}/${arch}`);
57
170
  }
58
171
  let assetBytes;
59
172
  let checksumsBytes;
@@ -65,27 +178,25 @@ export async function resolveBinary(spec, options = {}) {
65
178
  assetBytes = await fetch(spec.releaseUrlForAsset(assetName));
66
179
  }
67
180
  catch (error) {
68
- return {
69
- status: "unavailable",
70
- command: null,
71
- note: `download failed: ${error instanceof Error ? error.message : String(error)}`,
72
- };
181
+ return unavailable("download_failed", `download failed: ${error instanceof Error ? error.message : String(error)}`);
73
182
  }
74
183
  if (!checksumsBytes || !assetBytes) {
75
- return { status: "unavailable", command: null, note: "download returned no bytes" };
184
+ return unavailable("download_empty", "download returned no bytes");
76
185
  }
77
186
  const expected = expectedSha256For(Buffer.from(checksumsBytes).toString("utf8"), assetName);
78
187
  if (!expected) {
79
- return { status: "unavailable", command: null, note: `no checksum for ${assetName}` };
188
+ return unavailable("no_checksum_for_asset", `no checksum for ${assetName}`);
80
189
  }
81
190
  const actual = sha256(assetBytes);
82
191
  if (actual !== expected) {
83
- return {
84
- status: "unavailable",
85
- command: null,
86
- note: `checksum mismatch for ${assetName} (expected ${expected}, got ${actual})`,
87
- };
192
+ return unavailable("checksum_mismatch", `checksum mismatch for ${assetName} (expected ${expected}, got ${actual})`);
88
193
  }
194
+ // Only here — past the PATH probe, past a cache miss, past verification — is
195
+ // anything about to be WRITTEN. Creating the root any earlier would grow an empty
196
+ // cache directory on every resolution that never caches anything: a tool already on
197
+ // PATH, an offline degrade, an unsupported platform. Read paths only ever ask
198
+ // whether the directory exists.
199
+ ensureCacheRoot(cacheDir);
89
200
  // Non-archived asset (e.g. osv-scanner): the verified bytes ARE the
90
201
  // executable — write directly to the cached path, no `tar` involved.
91
202
  if (spec.archived === false) {
@@ -101,14 +212,12 @@ export async function resolveBinary(spec, options = {}) {
101
212
  /* best-effort */
102
213
  }
103
214
  }
215
+ writeCacheManifest(versionDir, spec, resolved);
104
216
  return { status: "downloaded", command: resolved };
105
217
  }
106
218
  catch (error) {
107
- return {
108
- status: "unavailable",
109
- command: null,
110
- note: `write error: ${error instanceof Error ? error.message : String(error)}`,
111
- };
219
+ purgeVersionDir(versionDir);
220
+ return unavailable("write_failed", `write error: ${error instanceof Error ? error.message : String(error)}`);
112
221
  }
113
222
  }
114
223
  // Verified — write the archive and extract it with the system `tar` (bsdtar
@@ -120,24 +229,20 @@ export async function resolveBinary(spec, options = {}) {
120
229
  const extract = run(["tar", "-xf", archivePath, "-C", versionDir], versionDir);
121
230
  rmSync(archivePath, { force: true });
122
231
  if (extract.error || extract.status !== 0) {
123
- return {
124
- status: "unavailable",
125
- command: null,
126
- note: `extract failed: ${extract.error?.message ?? `tar exit ${extract.status}`}`,
127
- };
232
+ // Whatever tar managed to write before failing must NOT survive as a cache hit.
233
+ purgeVersionDir(versionDir);
234
+ return unavailable("extract_failed", `extract failed: ${extract.error?.message ?? `tar exit ${extract.status}`}`);
128
235
  }
129
236
  }
130
237
  catch (error) {
131
- return {
132
- status: "unavailable",
133
- command: null,
134
- note: `extract error: ${error instanceof Error ? error.message : String(error)}`,
135
- };
238
+ purgeVersionDir(versionDir);
239
+ return unavailable("extract_failed", `extract error: ${error instanceof Error ? error.message : String(error)}`);
136
240
  }
137
241
  // Locate the executable (archives may nest it); chmod +x on POSIX.
138
242
  const resolved = findExecutable(versionDir, exeName(spec.binaryName, platform));
139
243
  if (!resolved) {
140
- return { status: "unavailable", command: null, note: "binary not found in archive" };
244
+ purgeVersionDir(versionDir);
245
+ return unavailable("not_found_in_archive", "binary not found in archive");
141
246
  }
142
247
  if (platform !== "win32") {
143
248
  try {
@@ -147,6 +252,7 @@ export async function resolveBinary(spec, options = {}) {
147
252
  /* best-effort */
148
253
  }
149
254
  }
255
+ writeCacheManifest(versionDir, spec, resolved);
150
256
  return { status: "downloaded", command: resolved };
151
257
  }
152
258
  /** Shallow-then-recursive search for `name` under `dir`. */