chainlesschain 0.166.90 → 0.166.91

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 (172) hide show
  1. package/README.md +9 -7
  2. package/package.json +3 -3
  3. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  4. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  5. package/src/assets/web-panel/assets/{AIOps-CZzXRe1-.js → AIOps-DgV7xb8F.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-_AZfbW1Q.js → ActionButton-CgANpkKu.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-CzaUx_wv.js → Analytics-DnvpX7RB.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-xHEeeD-m.js → AppLayout-C2bHccBM.js} +4 -4
  9. package/src/assets/web-panel/assets/{Artifacts-DmTbtudE.js → Artifacts-BIhijC9g.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-Cn4ng4fo.js → Audit-CKRjWGdp.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-DLUY1VD2.js → BackgroundAgents-CblYtgBE.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-B2v--wB6.js → Backup-Cq35b78a.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-Bgih7yAv.js → BaseInput-DcB7NoRz.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-1MiiA3yA.js → Chat-tc3b-s7i.js} +5 -5
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CPLynmbb.js → ChatBubbleRenderer-fcc_Tvqu.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-DsyBa_NO.js → Checkbox-BLD5bH5u.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-B7WCFx9H.js → Codegen-BLOsoazN.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-D2x4GBGm.js → Col-Bdr7JwIx.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-Rnwg9nea.js → Community-C84BsWE0.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-BPczlrRh.js → Compact-Dzdwd04z.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-Br1L_wGU.js → Compliance-CCG-R0EV.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-DlsWB_oS.js → Cowork-BYj72SK0.js} +3 -3
  23. package/src/assets/web-panel/assets/{Cron-BWo_KGpG.js → Cron-B6iKAwOf.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-Cug7N8ge.js → Crosschain-BJ-oDC6u.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-CMbyOZJN.js → DID-BnMckGLr.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-C4dl_UaE.js → Dashboard-Cyje-gCO.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-CBrC7M-9.js → Dropdown-BpNlenjK.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer-DTq7tU4b.js → EmailListRenderer-BhonO7Nv.js} +1 -1
  29. package/src/assets/web-panel/assets/{EvolutionSettings-DWP3csxS.js → EvolutionSettings-DVoNU-Id.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DZl7zuv_.js → FamilyGuardDashboard-tdn-KC67.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-W-GSlVK5.js → Federation--EEVrHhz.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-DMB7xYFV.js → FormItemContext-Cy8zr0-4.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-DNv8GEoq.js → GenericCardRenderer-BuUhpgFi.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-BZ0Bbzw6.js → Git-Ctd3E5Pe.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-BNEdcOM5.js → Governance-Ce7dV6aU.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-C8249gIz.js → Inference-CD1vExIH.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-ngzebU3e.js → KnowledgeGraph-Dn64OdQ7.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-CP15th-f.js → Logs-PmElVRrT.js} +2 -2
  39. package/src/assets/web-panel/assets/{MarkdownRenderer-CW3B3JDq.js → MarkdownRenderer-BFiVKf5t.js} +1 -1
  40. package/src/assets/web-panel/assets/{Marketplace-CaH59OsY.js → Marketplace-OW4jTXwx.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-C07vnJev.js → McpTools-BEq2Ib4x.js} +3 -3
  42. package/src/assets/web-panel/assets/{Memory-CqAOkVAS.js → Memory-Can_P2oK.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-qp7mZimq.js → MobileBridge-DJ8R-dn3.js} +1 -1
  44. package/src/assets/web-panel/assets/{MobileProjects-DKhbqvTw.js → MobileProjects-B7kV9GOt.js} +1 -1
  45. package/src/assets/web-panel/assets/{Mtc-CRYCnWXv.js → Mtc-BfxamolS.js} +4 -4
  46. package/src/assets/web-panel/assets/{MtcAudit-Z08IrKws.js → MtcAudit-DHtuv7av.js} +4 -4
  47. package/src/assets/web-panel/assets/{Multisig-BWdatUnH.js → Multisig-DLkLpvxc.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-BKWiCZ_m.js → NLProgramming-u4XtJTIt.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-Bgpzk3sm.js → Notes-BwuuPJLS.js} +3 -3
  50. package/src/assets/web-panel/assets/{NotificationSettings-DvtZEktR.js → NotificationSettings-HEeu-E9v.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-CBcy0szc.js → OrderTableRenderer-BtvN-Qwh.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-DRRL6vW1.js → Organization-Yh-czs3b.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-COmfB8Ns.js → Overflow-DmE8mYVM.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-BqMq_DSa.js → P2P-CWVck8WN.js} +2 -2
  55. package/src/assets/web-panel/assets/PdhVaultBrowser-DgFqekod.js +7 -0
  56. package/src/assets/web-panel/assets/{Permissions-DzYkjmV_.js → Permissions-BtJBVOHV.js} +4 -4
  57. package/src/assets/web-panel/assets/{PersonalDataHub-BBTcxBbN.js → PersonalDataHub-6VBObXzd.js} +4 -4
  58. package/src/assets/web-panel/assets/{Pipeline-eRkYFSbO.js → Pipeline-D222FmqY.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-Ch7IFKBh.js → Privacy-Bi9FMikp.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-Ci8EcBYg.js → ProjectInit-Bo52H47H.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-B4lYHFbI.js → ProjectSettings-BPkesfOc.js} +2 -2
  62. package/src/assets/web-panel/assets/{Projects-zkE5cCo_.js → Projects-GynohSFX.js} +1 -1
  63. package/src/assets/web-panel/assets/{Providers-BKDVD3_e.js → Providers-DVdMg04n.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-BromrHlf.js → QrScannerModal-DqJCb595.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-CCgoY1gR.js → QuickAsk-J7loQbXi.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-DCPZvpq7.js → Recommend-BI5aURVc.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-DPnFP8HU.js → RemoteSession-BN2sqGvz.js} +3 -3
  68. package/src/assets/web-panel/assets/{Reputation-l6r8ytAs.js → Reputation-BGOND-Fi.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-ke9Mk1cx.js → Row-77dfwaUk.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-DQOEzUEn.js → RssFeed-FtBAxS3g.js} +2 -2
  71. package/src/assets/web-panel/assets/{Search-BqgA0aUz.js → Search-BaYVLFb7.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-FeGD_jqV.js → Security-LE3Vv6ab.js} +3 -3
  73. package/src/assets/web-panel/assets/{Services-4kiYYAjZ.js → Services-C5pP-Whz.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-BbU8Xegs.js → Skeleton-CLqKUVsF.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-Dl2bUMUL.js → Skills-BPjN0SX5.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-xRGALeaZ.js → Sla-14jD70kg.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-DZfd4RDm.js → SpeechSettings-Dr9ij42W.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-BRtCV9Ga.js → SyncSettings-BzLHP7B8.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-DVRQklfG.js → Tasks-YqV9b0rV.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-BbhE5jt5.js → Templates-CxxAE4PK.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-qXPDNKbK.js → Tenant-CRb3PcKJ.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-CV48Ks7E.js → Terminal-CTzPpBaP.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-BLGfJIDr.js → TimelineRenderer-DjFUj_hy.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-7G9H6Hrt.js → Tokens-Bbb8tPvx.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger--F64N11F.js → Trigger-CSeWGM0W.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-Cq1r-D_y.js → Trust-JgESMBo3.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-Dqyu4RVh.js → UkeySign-CiObLk0T.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-DuFmWH_B.js → VideoEditing-CFEZaQ2x.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-C3mg7EWP.js → Wallet-DR8ZGDNn.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-CDK-Aj_X.js → WebAuthn-DxZukvu7.js} +5 -5
  91. package/src/assets/web-panel/assets/{WorkflowEditor--K7K-T1F.js → WorkflowEditor-CKgSZQwn.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-BQDcS6VP.js → chat-CTxEQE66.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-BKxJL2-T.js → colors-CAjKMUu3.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-CFjQAMbY.js → compact-item-BXuz49at.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-DbgCsdQd.js → createContext-CFN_Hwr9.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-CfB8DxT2.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-BhkaOBNv.js → hasIn-BwoSBSfP.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-D-Yh3-1z.js → index-B0QbLlWn.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BfGGsAU7.js → index-B2o_BBjg.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CoOu7sdP.js → index-B2tEnBPx.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BRqlCTrz.js → index-B7kp-zRE.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CB4oHynY.js → index-B9yR7zqr.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DEwHywz9.js → index-BK4ftQ4d.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Du_SxxBY.js → index-Bj4hIiLW.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DFt48Z-x.js → index-BmQITjMU.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DdcrixaQ.js → index-BmXpdcHI.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BuWPqSGT.js → index-Bqv_Cray.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DmYK9Tqt.js → index-Bu2P6u8m.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-T9ka3Xj3.js → index-Bw9s2d3c.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-COGy6wXn.js → index-C8er4W9u.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-sKfUUldY.js → index-CB3kVd9c.js} +1 -1
  112. package/src/assets/web-panel/assets/index-CCsRfd0k.js +1 -0
  113. package/src/assets/web-panel/assets/{index-Dhfa_BIl.js → index-CF9lWi1o.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CRtUDiXx.js → index-CN53dE_u.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-D2Zb-Kd1.js → index-CSmFby3Q.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DP1NrM9J.js → index-CehdwJ_Q.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-aPdVzagA.js → index-Cgk0YEiq.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-3YutaXnp.js → index-Cp5y7lX_.js} +1 -1
  119. package/src/assets/web-panel/assets/index-CsmiZIQ4.js +1 -0
  120. package/src/assets/web-panel/assets/{index-C0DzhUOX.js → index-DTX9CJPx.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-bMX8BBLE.js → index-DViK2bkv.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-Dn2QSsuI.js → index-DY-gBSm8.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BNjYPJNU.js → index-DjF5BOZx.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CE506mgj.js → index-DmkbAADP.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-De7daEnc.js → index-DpdDnZX_.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-3uR0ThJO.js → index-Dv7V2kg6.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CUs7XpUO.js → index-DxunxaTw.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-3djsY75k.js → index-F2E5RCwz.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-D9sVcw6v.js → index-IY9bd5az.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DJ2OiRvh.js → index-IahILygB.js} +3 -3
  131. package/src/assets/web-panel/assets/{index-DjmVlpap.js → index-T3MTE6jB.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-CSUDlsIr.js → index-Tz5dheZa.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-B4LlAJqc.js → index-_ZtCyUdz.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-CJoXgJ2N.js → index-o9DpkZKf.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-7BY44UEv.js → index-t2Ch_JKn.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-DvWWFJHJ.js → index-u9_DM3ZC.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-wrqabmui.js → initDefaultProps-BoiGJDoO.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-BoyB3ilP.js → motion-5eL4E0pA.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-Cq31cSFE.js → move-DjggDi_1.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-BkxNt-8H.js → mtc-parser-Ce8Vo2T3.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-DofGni53.js → omit-D1yOBaO2.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-BnluLL16.js → pickAttrs-8NLceQe8.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-C-yegJSP.js → placementArrow-CsIdBRmQ.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-CD3ziNhu.js → responsiveObserve-GM5NE8En.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-ToZO4gQ1.js → slide-44yj3u49.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-DFVmDmVl.js → statusUtils-B8tqtWcX.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-De0Y8g1O.js → styleChecker-NhDPBbyB.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-wBKIYFKX.js → useFlexGapSupport-C8Qz1GtN.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-CP9nmUMJ.js → useFs-ClUv4kih.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-vFGrVDyp.js → usePersonalDataHub-BwkOVEh6.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-BcBIjvjH.js → vnode--gMF33R0.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-DnXDAQxA.js → zoom-DXg3TqOP.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/command-help-index.json +1 -1
  155. package/src/commands/agent-process-ownership.js +121 -0
  156. package/src/commands/agent.js +2 -0
  157. package/src/commands/hub.js +86 -9
  158. package/src/data/changelog.json +15 -2
  159. package/src/lib/audit-logger.js +46 -20
  160. package/src/lib/checkpoint-restore-saga.js +11 -1
  161. package/src/lib/eval/verify01-host-evidence.js +36 -3
  162. package/src/lib/process-execution-broker/index.js +91 -1
  163. package/src/lib/process-execution-broker/platform-sandbox.js +42 -0
  164. package/src/lib/process-execution-broker/windows-native-evaluator-capabilities.js +757 -0
  165. package/src/lib/process-execution-broker/windows-native-evaluator.js +316 -0
  166. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  167. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  168. package/src/lib/process-execution-broker/windows-sandbox.cs +383 -11
  169. package/src/assets/web-panel/assets/PdhVaultBrowser-BX7iNvle.js +0 -7
  170. package/src/assets/web-panel/assets/devWarning-DlIv9Mbc.js +0 -1
  171. package/src/assets/web-panel/assets/index-BC972Grv.js +0 -1
  172. package/src/assets/web-panel/assets/index-CVifyQqL.js +0 -1
@@ -0,0 +1,757 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { createHash } from "node:crypto";
5
+ import { createWindowsNativeEvaluator } from "./windows-native-evaluator.js";
6
+
7
+ const SCHEMA = "chainlesschain.windows-native-evaluator-capabilities/v1";
8
+ const PREFIX = "CC_NATIVE_CAPABILITIES:";
9
+ const HASH = /^sha256:[a-f0-9]{64}$/u;
10
+ const JOURNAL_FILE = "capability-journal.jsonl";
11
+ const JOURNAL_MAX_BYTES = 64 * 1024;
12
+ const PROBES = [
13
+ "scratch-environment",
14
+ "esm",
15
+ "worker-threads",
16
+ "child-inherited-stdio",
17
+ "child-file-stdio",
18
+ "child-pipe-stdio",
19
+ "child-fork-ipc",
20
+ ];
21
+ const sha256 = (value) =>
22
+ `sha256:${createHash("sha256").update(value).digest("hex")}`;
23
+ const requireCondition = (condition, message) => {
24
+ if (!condition) throw new Error(`Native capability diagnostic: ${message}`);
25
+ };
26
+
27
+ // These are diagnostic fixtures, never candidate answers or a replacement test runner.
28
+ const FIXTURES = Object.freeze({
29
+ "esm-probe.mjs": 'export const marker = "native-esm-ok";\n',
30
+ "worker-probe.cjs":
31
+ 'const {parentPort,threadId}=require("node:worker_threads"); parentPort.postMessage({marker:"native-worker-ok",threadId,pid:process.pid});\n',
32
+ "child-probe.cjs":
33
+ 'const fs=require("node:fs"); const value=JSON.stringify({marker:"native-child-ok",pid:process.pid}); if(process.argv[2])fs.writeFileSync(process.argv[2],value,{flag:"wx"}); else process.stdout.write(value);\n',
34
+ "fork-probe.cjs":
35
+ 'if(typeof process.send!=="function")process.exit(72); process.send({marker:"native-fork-ok",pid:process.pid},error=>{if(error)process.exitCode=73;process.disconnect();});\n',
36
+ "anchor.txt": "private-native-capability-input\n",
37
+ });
38
+
39
+ function checkSource(probeTimeoutMs) {
40
+ return `
41
+ const fs=require('node:fs');
42
+ const journalFd=fs.openSync(process.argv[3]+'/'+${JSON.stringify(JOURNAL_FILE)},'wx',0o600);
43
+ let journalBytes=0,journalSequence=0;
44
+ const journalStart=Date.now();
45
+ function journal(event,extra={}){
46
+ const bytes=Buffer.from(JSON.stringify({version:1,sequence:journalSequence+1,event,pid:process.pid,elapsedMs:Date.now()-journalStart,...extra})+'\\n');
47
+ if(bytes.length>16384||journalBytes+bytes.length>${JOURNAL_MAX_BYTES}||journalSequence>=17)throw new Error('Capability journal bound exceeded');
48
+ let offset=0;while(offset<bytes.length){const written=fs.writeSync(journalFd,bytes,offset,bytes.length-offset);if(written<=0)throw new Error('Capability journal write stalled');offset+=written;}
49
+ fs.fsyncSync(journalFd);journalBytes+=bytes.length;journalSequence++;
50
+ }
51
+ journal('initialization-started');
52
+ const path=require('node:path'),os=require('node:os');
53
+ const crypto=require('node:crypto'),cp=require('node:child_process');
54
+ const {pathToFileURL}=require('node:url'),{Worker}=require('node:worker_threads');
55
+ const workspace=process.argv[2],scratch=process.argv[3],timeout=${probeTimeoutMs};
56
+ const observations=[];
57
+ const hash=value=>'sha256:'+crypto.createHash('sha256').update(value).digest('hex');
58
+ journal('initialization-settled');
59
+ function settled(value){journal('settled',{id:value.id,observation:value});observations.push(value);}
60
+ function observe(id,operation){
61
+ const start=Date.now();
62
+ journal('started',{id});
63
+ return Promise.resolve().then(operation).then(value=>{
64
+ const output=String(value.output??'');
65
+ settled({id,status:value.supported?'supported':value.timedOut?'timed-out':['EACCES','EPERM'].includes(value.errorCode)?'blocked':'failed',timedOut:value.timedOut===true,code:value.code??null,signal:value.signal??null,errorCode:value.errorCode??null,error:value.error??null,output,outputSha256:hash(output),details:value.details??{},elapsedMs:Date.now()-start});
66
+ },error=>{
67
+ const output=String(error.stack||error);
68
+ settled({id,status:['EACCES','EPERM'].includes(error.code)?'blocked':'failed',timedOut:false,code:null,signal:null,errorCode:error.code??null,error:String(error.message||error),output,outputSha256:hash(output),details:{},elapsedMs:Date.now()-start});
69
+ });
70
+ }
71
+ function childResult(result,output){
72
+ let payload=null;try{payload=JSON.parse(output);}catch{}
73
+ return {supported:!result.error&&!result.signal&&result.status===0&&payload?.marker==='native-child-ok'&&Number.isSafeInteger(payload.pid)&&payload.pid!==process.pid,code:result.status,signal:result.signal,errorCode:result.error?.code??null,error:result.error?.message??null,timedOut:result.error?.code==='ETIMEDOUT',output,details:{stderr:result.stderr?.toString('utf8')||'',payload}};
74
+ }
75
+ function asyncProbe(create,valid){
76
+ return new Promise(resolve=>{
77
+ let child,settled=false,message=null,error=null,timedOut=false;
78
+ const done=(code,signal)=>{if(settled)return;settled=true;clearTimeout(timer);resolve({supported:!timedOut&&!error&&code===0&&!signal&&valid(message),timedOut,code,signal,errorCode:error?.code??null,error:error?String(error.stack||error):null,output:message===null?'':JSON.stringify(message),details:{message}});};
79
+ const timer=setTimeout(()=>{timedOut=true;if(child instanceof Worker)child.terminate().catch(()=>{});else child?.kill();done(null,null);},timeout);
80
+ try{child=create();child.on('message',value=>{message=value;});child.once('error',value=>{error=value;done(null,null);});child.once('exit',done);}catch(value){error=value;done(null,null);}
81
+ });
82
+ }
83
+ (async()=>{
84
+ await observe('scratch-environment',()=>{
85
+ const inheritedKeys=Object.keys(process.env).sort();
86
+ const credentialKeys=inheritedKeys.filter(key=>/TOKEN|SECRET|PASSWORD|CREDENTIAL|API_KEY|AUTHORIZATION/i.test(key));
87
+ const derived={TMP:path.join(scratch,'tmp'),TEMP:path.join(scratch,'tmp'),HOME:path.join(scratch,'home'),USERPROFILE:path.join(scratch,'home'),APPDATA:path.join(scratch,'home','AppData','Roaming'),LOCALAPPDATA:path.join(scratch,'home','AppData','Local')};
88
+ for(const directory of new Set(Object.values(derived)))fs.mkdirSync(directory,{recursive:true});
89
+ for(const [key,value]of Object.entries(derived))process.env[key]=value;
90
+ const proofs=[];
91
+ for(const [key,value]of Object.entries(derived)){const file=path.join(value,key+'.txt');fs.writeFileSync(file,key,{flag:'wx'});proofs.push({key,path:value,value:fs.readFileSync(file,'utf8')});}
92
+ const details={credentialKeys,inheritedKeys,derived,proofs,tmpdir:os.tmpdir(),homedir:os.homedir(),credentialsAbsent:credentialKeys.length===0,nodeOptionsAbsent:!Object.hasOwn(process.env,'NODE_OPTIONS')};
93
+ return {supported:details.credentialsAbsent&&details.nodeOptionsAbsent&&os.tmpdir()===derived.TEMP&&os.homedir()===derived.USERPROFILE,code:0,output:JSON.stringify(details),details};
94
+ });
95
+ await observe('esm',async()=>{
96
+ let timer;
97
+ try{return await Promise.race([
98
+ import(pathToFileURL(path.join(workspace,'esm-probe.mjs')).href).then(value=>({supported:value.marker==='native-esm-ok',code:0,output:JSON.stringify({marker:value.marker})})),
99
+ new Promise(resolve=>{timer=setTimeout(()=>resolve({supported:false,timedOut:true,code:null,errorCode:'ETIMEDOUT',error:'ESM import deadline exceeded',output:''}),timeout);})
100
+ ]);}finally{clearTimeout(timer);}
101
+ });
102
+ await observe('worker-threads',()=>asyncProbe(()=>new Worker(path.join(workspace,'worker-probe.cjs'),{execArgv:['--preserve-symlinks','--preserve-symlinks-main']}),value=>value?.marker==='native-worker-ok'&&value.pid===process.pid&&Number.isSafeInteger(value.threadId)&&value.threadId>0));
103
+ await observe('child-inherited-stdio',()=>{
104
+ const proof=path.join(scratch,'inherited-child.json');
105
+ const result=cp.spawnSync(process.execPath,['--preserve-symlinks','--preserve-symlinks-main',path.join(workspace,'child-probe.cjs'),proof],{stdio:'inherit',windowsHide:true,timeout});
106
+ return childResult(result,fs.existsSync(proof)?fs.readFileSync(proof,'utf8'):'');
107
+ });
108
+ await observe('child-file-stdio',()=>{
109
+ const outputFile=path.join(scratch,'fd-stdout.txt'),errorFile=path.join(scratch,'fd-stderr.txt');
110
+ const out=fs.openSync(outputFile,'wx'),err=fs.openSync(errorFile,'wx');let result;
111
+ try{result=cp.spawnSync(process.execPath,['--preserve-symlinks','--preserve-symlinks-main',path.join(workspace,'child-probe.cjs')],{stdio:['ignore',out,err],windowsHide:true,timeout});}finally{fs.closeSync(out);fs.closeSync(err);}
112
+ result.stderr=fs.readFileSync(errorFile);return childResult(result,fs.readFileSync(outputFile,'utf8'));
113
+ });
114
+ await observe('child-pipe-stdio',()=>{
115
+ const result=cp.spawnSync(process.execPath,['--preserve-symlinks','--preserve-symlinks-main',path.join(workspace,'child-probe.cjs')],{windowsHide:true,encoding:'utf8',timeout,maxBuffer:65536});
116
+ return childResult(result,result.stdout||'');
117
+ });
118
+ await observe('child-fork-ipc',()=>asyncProbe(()=>cp.fork(path.join(workspace,'fork-probe.cjs'),[],{execArgv:['--preserve-symlinks','--preserve-symlinks-main'],windowsHide:true,stdio:['inherit','inherit','inherit','ipc']}),value=>value?.marker==='native-fork-ok'&&Number.isSafeInteger(value.pid)&&value.pid!==process.pid));
119
+ journal('completed');
120
+ process.stdout.write(${JSON.stringify(PREFIX)}+JSON.stringify({version:1,pid:process.pid,workspace,scratch,observations})+'\\n');
121
+ })().catch(error=>{console.error(error.stack||error);process.exitCode=74;}).finally(()=>fs.closeSync(journalFd));
122
+ `;
123
+ }
124
+
125
+ function validateJournal(report, complete) {
126
+ const artifact = report.journal;
127
+ if (!artifact) {
128
+ requireCondition(!complete, "completed target omitted its journal");
129
+ return { available: false, records: [], lastPhase: null, complete: false };
130
+ }
131
+ requireCondition(
132
+ artifact.name === JOURNAL_FILE &&
133
+ typeof artifact.raw === "string" &&
134
+ Buffer.byteLength(artifact.raw) <= JOURNAL_MAX_BYTES &&
135
+ artifact.sha256 === sha256(artifact.raw),
136
+ "journal byte binding or bound changed",
137
+ );
138
+ const boundary = artifact.raw.lastIndexOf("\n");
139
+ const lines = boundary < 0 ? [] : artifact.raw.slice(0, boundary).split("\n");
140
+ const tail = artifact.raw.slice(boundary + 1);
141
+ const expected = [
142
+ { event: "initialization-started" },
143
+ { event: "initialization-settled" },
144
+ ...PROBES.flatMap((id) => [
145
+ { event: "started", id },
146
+ { event: "settled", id },
147
+ ]),
148
+ { event: "completed" },
149
+ ];
150
+ requireCondition(lines.length <= expected.length, "journal has extra events");
151
+ let previousElapsed = -1;
152
+ const records = lines.map((line, index) => {
153
+ requireCondition(
154
+ Buffer.byteLength(line) <= 16384,
155
+ "journal event exceeds bound",
156
+ );
157
+ const row = JSON.parse(line),
158
+ wanted = expected[index];
159
+ requireCondition(
160
+ row.version === 1 &&
161
+ row.sequence === index + 1 &&
162
+ row.pid === report.settlement.targetPid &&
163
+ row.event === wanted.event &&
164
+ row.id === wanted.id &&
165
+ Number.isSafeInteger(row.elapsedMs) &&
166
+ row.elapsedMs >= previousElapsed,
167
+ "journal phase, sequence or process identity differs",
168
+ );
169
+ previousElapsed = row.elapsedMs;
170
+ if (row.event === "settled") {
171
+ const observed = row.observation;
172
+ requireCondition(
173
+ observed?.id === row.id &&
174
+ typeof observed.output === "string" &&
175
+ sha256(observed.output) === observed.outputSha256 &&
176
+ ["supported", "blocked", "timed-out", "failed"].includes(
177
+ observed.status,
178
+ ) &&
179
+ typeof observed.timedOut === "boolean" &&
180
+ Number.isSafeInteger(observed.elapsedMs) &&
181
+ observed.elapsedMs >= 0,
182
+ "journal observation identity or digest changed",
183
+ );
184
+ } else
185
+ requireCondition(
186
+ row.observation === undefined,
187
+ "unexpected journal observation",
188
+ );
189
+ return row;
190
+ });
191
+ if (complete)
192
+ requireCondition(
193
+ lines.length === expected.length && tail === "",
194
+ "target journal incomplete",
195
+ );
196
+ return {
197
+ available: true,
198
+ records,
199
+ lastPhase: records.at(-1)?.id || records.at(-1)?.event || null,
200
+ complete: records.length === expected.length && tail === "",
201
+ trailingPartialBytes: Buffer.byteLength(tail),
202
+ };
203
+ }
204
+
205
+ function sameJournalIdentity(left, right) {
206
+ return (
207
+ left.dev === right.dev &&
208
+ left.ino === right.ino &&
209
+ left.size === right.size &&
210
+ left.mtimeNs === right.mtimeNs &&
211
+ left.ctimeNs === right.ctimeNs &&
212
+ left.nlink === 1n &&
213
+ right.nlink === 1n &&
214
+ left.isFile() &&
215
+ right.isFile()
216
+ );
217
+ }
218
+
219
+ function journalDescriptorIdentity(file) {
220
+ const fd = fs.openSync(file, "r");
221
+ try {
222
+ return fs.fstatSync(fd, { bigint: true });
223
+ } finally {
224
+ fs.closeSync(fd);
225
+ }
226
+ }
227
+
228
+ function readJournalAfterSettlement(report) {
229
+ requireCondition(
230
+ report.settlement?.cleanupConfirmed === true &&
231
+ report.settlement.manifestDigest === report.manifestDigest.slice(7),
232
+ "scratch read requires confirmed native cleanup",
233
+ );
234
+ const scratch = report.stage.scratch;
235
+ const expected = report.manifest.directories.find(
236
+ (entry) => entry.path === scratch,
237
+ );
238
+ const directory = fs.lstatSync(scratch, { bigint: true });
239
+ requireCondition(
240
+ expected &&
241
+ directory.isDirectory() &&
242
+ !directory.isSymbolicLink() &&
243
+ String(directory.dev) === expected.dev &&
244
+ String(directory.ino) === expected.ino &&
245
+ fs.realpathSync.native(scratch).toLowerCase() === scratch.toLowerCase(),
246
+ "scratch identity changed before journal read",
247
+ );
248
+ const file = path.join(scratch, JOURNAL_FILE);
249
+ let before;
250
+ try {
251
+ before = fs.lstatSync(file, { bigint: true });
252
+ } catch (error) {
253
+ if (error.code === "ENOENT") return null;
254
+ throw error;
255
+ }
256
+ requireCondition(
257
+ before.isFile() &&
258
+ !before.isSymbolicLink() &&
259
+ before.nlink === 1n &&
260
+ before.size <= BigInt(JOURNAL_MAX_BYTES) &&
261
+ fs.realpathSync.native(file).toLowerCase() === file.toLowerCase(),
262
+ "journal is linked or exceeds byte bound",
263
+ );
264
+ const fd = fs.openSync(file, "r");
265
+ try {
266
+ const opened = fs.fstatSync(fd, { bigint: true });
267
+ // Windows pathname and descriptor stat can expose different dev/ino
268
+ // projections. Bind the reader to another handle opened by name, and
269
+ // compare each stat domain only with itself before and after the read.
270
+ requireCondition(
271
+ sameJournalIdentity(opened, journalDescriptorIdentity(file)) &&
272
+ opened.size === before.size &&
273
+ opened.size <= BigInt(JOURNAL_MAX_BYTES),
274
+ "journal identity changed while opening",
275
+ );
276
+ const bytes = Buffer.alloc(Number(opened.size));
277
+ let offset = 0;
278
+ while (offset < bytes.length) {
279
+ const read = fs.readSync(
280
+ fd,
281
+ bytes,
282
+ offset,
283
+ bytes.length - offset,
284
+ offset,
285
+ );
286
+ requireCondition(read > 0, "journal truncated while reading");
287
+ offset += read;
288
+ }
289
+ const after = fs.fstatSync(fd, { bigint: true });
290
+ const named = fs.lstatSync(file, { bigint: true });
291
+ requireCondition(
292
+ sameJournalIdentity(after, opened) &&
293
+ sameJournalIdentity(named, before) &&
294
+ sameJournalIdentity(after, journalDescriptorIdentity(file)) &&
295
+ !named.isSymbolicLink() &&
296
+ fs.realpathSync.native(file).toLowerCase() === file.toLowerCase(),
297
+ "journal changed during bounded read",
298
+ );
299
+ const raw = bytes.toString("utf8");
300
+ requireCondition(
301
+ Buffer.from(raw, "utf8").equals(bytes),
302
+ "journal is not valid UTF-8",
303
+ );
304
+ return {
305
+ name: JOURNAL_FILE,
306
+ raw,
307
+ bytes: bytes.length,
308
+ sha256: sha256(bytes),
309
+ };
310
+ } finally {
311
+ fs.closeSync(fd);
312
+ }
313
+ }
314
+
315
+ /** Incomplete captures may be inspected explicitly, but never grant capabilities. */
316
+ export function validateWindowsNativeEvaluatorCapabilitiesReport(
317
+ report,
318
+ { allowPartial = false } = {},
319
+ ) {
320
+ requireCondition(report?.schema === SCHEMA, "unknown report schema");
321
+ requireCondition(
322
+ report.formalSample === false &&
323
+ report.providerAssessed === false &&
324
+ report.fullReviewPackAssessed === false,
325
+ "diagnostic scope changed",
326
+ );
327
+ requireCondition(HASH.test(report.manifestDigest), "manifest digest missing");
328
+ requireCondition(
329
+ sha256(JSON.stringify(report.manifest)) === report.manifestDigest &&
330
+ report.checkSourceSha256 ===
331
+ `sha256:${report.manifest.files.find((file) => file.path === report.manifest.check)?.sha256}`,
332
+ "staged source manifest digest mismatch",
333
+ );
334
+ requireCondition(
335
+ report.settlement?.manifestDigest === report.manifestDigest.slice(7) &&
336
+ report.settlement.cleanupConfirmed === true &&
337
+ report.settlement.capabilityCount === 0 &&
338
+ report.settlement.loopbackExemptionAbsent === true &&
339
+ /^[a-f0-9]{64}$/u.test(report.settlement.supervisorUserSidSha256),
340
+ "native cleanup settlement is not confirmed",
341
+ );
342
+ const execution = report.execution;
343
+ requireCondition(
344
+ execution &&
345
+ typeof execution.stdout === "string" &&
346
+ typeof execution.stderr === "string" &&
347
+ Buffer.byteLength(execution.stdout) <= 8 * 1024 * 1024 &&
348
+ Buffer.byteLength(execution.stderr) <= 8 * 1024 * 1024,
349
+ "target execution incomplete",
350
+ );
351
+ requireCondition(
352
+ sha256(execution.stdout) === execution.stdoutSha256 &&
353
+ sha256(execution.stderr) === execution.stderrSha256,
354
+ "raw output digest mismatch",
355
+ );
356
+ const executionCompleted =
357
+ execution.status === 0 &&
358
+ execution.signal === null &&
359
+ execution.error === null &&
360
+ report.settlement.targetExitCode === 0 &&
361
+ report.settlement.executionFailed === false;
362
+ if (!executionCompleted) {
363
+ const timedOut = /Windows sandbox wall-time limit exceeded/u.test(
364
+ execution.stderr,
365
+ );
366
+ requireCondition(
367
+ allowPartial,
368
+ timedOut
369
+ ? "target execution timed out; native cleanup confirmed"
370
+ : "target execution incomplete; native cleanup confirmed",
371
+ );
372
+ const journal = validateJournal(report, false);
373
+ return {
374
+ diagnosticCompleted: false,
375
+ allCapabilitiesSupported: false,
376
+ capabilities: {},
377
+ failureKind: timedOut ? "execution-timeout" : "execution-failure",
378
+ cleanupConfirmed: true,
379
+ journal,
380
+ observedPrefix: journal.records
381
+ .filter((row) => row.event === "settled")
382
+ .map((row) => row.observation),
383
+ };
384
+ }
385
+ const lines = execution.stdout.trim().split(/\r?\n/u);
386
+ requireCondition(
387
+ lines.length === 1 && lines[0].startsWith(PREFIX),
388
+ "expected exactly one target report",
389
+ );
390
+ const target = JSON.parse(lines[0].slice(PREFIX.length));
391
+ requireCondition(
392
+ target.version === 1 &&
393
+ Number.isSafeInteger(target.pid) &&
394
+ target.pid > 0 &&
395
+ target.pid === report.settlement.targetPid &&
396
+ report.stage.workspace === report.manifest.workspace &&
397
+ report.stage.scratch === report.manifest.scratch &&
398
+ target.workspace === report.stage.workspace &&
399
+ target.scratch === report.stage.scratch &&
400
+ Array.isArray(target.observations) &&
401
+ JSON.stringify(target.observations.map((item) => item.id)) ===
402
+ JSON.stringify(PROBES),
403
+ "target identity or probe sequence mismatch",
404
+ );
405
+ for (const observation of target.observations) {
406
+ requireCondition(
407
+ ["supported", "blocked", "timed-out", "failed"].includes(
408
+ observation.status,
409
+ ) &&
410
+ (observation.code === null || Number.isInteger(observation.code)) &&
411
+ (observation.signal === null ||
412
+ typeof observation.signal === "string") &&
413
+ typeof observation.timedOut === "boolean" &&
414
+ typeof observation.output === "string" &&
415
+ sha256(observation.output) === observation.outputSha256 &&
416
+ Number.isSafeInteger(observation.elapsedMs) &&
417
+ observation.elapsedMs >= 0,
418
+ "malformed probe observation",
419
+ );
420
+ if (observation.status === "supported") {
421
+ requireCondition(
422
+ observation.code === 0 &&
423
+ observation.signal === null &&
424
+ observation.error === null &&
425
+ observation.errorCode === null,
426
+ "failed observation cannot advertise support",
427
+ );
428
+ const payload = JSON.parse(observation.output);
429
+ if (observation.id === "scratch-environment") {
430
+ requireCondition(
431
+ payload.credentialsAbsent === true &&
432
+ payload.nodeOptionsAbsent === true &&
433
+ Array.isArray(payload.credentialKeys) &&
434
+ payload.credentialKeys.length === 0,
435
+ "credential environment was not isolated",
436
+ );
437
+ for (const name of [
438
+ "TMP",
439
+ "TEMP",
440
+ "HOME",
441
+ "USERPROFILE",
442
+ "APPDATA",
443
+ "LOCALAPPDATA",
444
+ ]) {
445
+ const relative = path.win32.relative(
446
+ target.scratch,
447
+ payload.derived[name],
448
+ );
449
+ requireCondition(
450
+ relative &&
451
+ !relative.startsWith("..") &&
452
+ !path.win32.isAbsolute(relative) &&
453
+ payload.proofs.some(
454
+ (proof) =>
455
+ proof.key === name &&
456
+ proof.path === payload.derived[name] &&
457
+ proof.value === name,
458
+ ),
459
+ "environment escaped scratch or omitted a write/read proof",
460
+ );
461
+ }
462
+ requireCondition(
463
+ payload.tmpdir === payload.derived.TEMP &&
464
+ payload.homedir === payload.derived.USERPROFILE,
465
+ "temporary or home directory differs from isolated environment",
466
+ );
467
+ } else {
468
+ const expected =
469
+ observation.id === "esm"
470
+ ? "native-esm-ok"
471
+ : observation.id === "worker-threads"
472
+ ? "native-worker-ok"
473
+ : observation.id === "child-fork-ipc"
474
+ ? "native-fork-ok"
475
+ : "native-child-ok";
476
+ requireCondition(payload.marker === expected, "probe marker mismatch");
477
+ if (observation.id === "worker-threads")
478
+ requireCondition(
479
+ payload.pid === target.pid &&
480
+ Number.isSafeInteger(payload.threadId) &&
481
+ payload.threadId > 0,
482
+ "worker identity mismatch",
483
+ );
484
+ else if (observation.id !== "esm")
485
+ requireCondition(
486
+ Number.isSafeInteger(payload.pid) &&
487
+ payload.pid > 0 &&
488
+ payload.pid !== target.pid,
489
+ "child identity mismatch",
490
+ );
491
+ }
492
+ }
493
+ if (observation.status === "blocked")
494
+ requireCondition(
495
+ ["EPERM", "EACCES"].includes(observation.errorCode),
496
+ "blocked probe lacks its actual access error",
497
+ );
498
+ let payload;
499
+ try {
500
+ payload = JSON.parse(observation.output);
501
+ } catch {
502
+ payload = null;
503
+ }
504
+ const expectedMarker =
505
+ observation.id === "esm"
506
+ ? "native-esm-ok"
507
+ : observation.id === "worker-threads"
508
+ ? "native-worker-ok"
509
+ : observation.id === "child-fork-ipc"
510
+ ? "native-fork-ok"
511
+ : "native-child-ok";
512
+ const successOutput =
513
+ observation.id === "scratch-environment"
514
+ ? payload?.credentialsAbsent === true &&
515
+ payload?.nodeOptionsAbsent === true &&
516
+ payload?.tmpdir === payload?.derived?.TEMP &&
517
+ payload?.homedir === payload?.derived?.USERPROFILE
518
+ : payload?.marker === expectedMarker;
519
+ const actualSuccess =
520
+ observation.code === 0 &&
521
+ observation.signal === null &&
522
+ observation.error === null &&
523
+ observation.errorCode === null &&
524
+ !observation.timedOut &&
525
+ successOutput;
526
+ const actualStatus = actualSuccess
527
+ ? "supported"
528
+ : observation.timedOut
529
+ ? "timed-out"
530
+ : ["EPERM", "EACCES"].includes(observation.errorCode)
531
+ ? "blocked"
532
+ : "failed";
533
+ requireCondition(
534
+ observation.status === actualStatus,
535
+ "probe status contradicts raw result",
536
+ );
537
+ }
538
+ requireCondition(
539
+ JSON.stringify(report.observations) === JSON.stringify(target.observations),
540
+ "report observations differ from raw output",
541
+ );
542
+ requireCondition(
543
+ target.observations[0].status === "supported",
544
+ "scratch environment or credential isolation failed",
545
+ );
546
+ const journal = validateJournal(report, true);
547
+ requireCondition(
548
+ JSON.stringify(
549
+ journal.records
550
+ .filter((row) => row.event === "settled")
551
+ .map((row) => row.observation),
552
+ ) === JSON.stringify(target.observations),
553
+ "journal observations differ from final target report",
554
+ );
555
+ return {
556
+ diagnosticCompleted: true,
557
+ allCapabilitiesSupported: target.observations.every(
558
+ (item) => item.status === "supported",
559
+ ),
560
+ capabilities: Object.fromEntries(
561
+ target.observations.map((item) => [item.id, item.status]),
562
+ ),
563
+ journal,
564
+ };
565
+ }
566
+
567
+ /** Execute only through the existing one-use AppContainer factory.
568
+ * evidenceDirectory, when supplied, must be a new directory. A failed native
569
+ * settlement retains its stage; there is no unsandboxed fallback or provider.
570
+ */
571
+ export async function runWindowsNativeEvaluatorCapabilities({
572
+ wallTimeMs = 15000,
573
+ probeTimeoutMs = 1200,
574
+ evidenceDirectory,
575
+ } = {}) {
576
+ requireCondition(process.platform === "win32", "Windows host required");
577
+ requireCondition(
578
+ Number.isSafeInteger(probeTimeoutMs) &&
579
+ probeTimeoutMs >= 100 &&
580
+ probeTimeoutMs <= 5000 &&
581
+ Number.isSafeInteger(wallTimeMs) &&
582
+ wallTimeMs >= probeTimeoutMs * 5 + 3000 &&
583
+ wallTimeMs <= 60000,
584
+ "invalid bounded diagnostic deadlines",
585
+ );
586
+ if (evidenceDirectory) {
587
+ requireCondition(
588
+ path.isAbsolute(evidenceDirectory),
589
+ "absolute evidence path required",
590
+ );
591
+ fs.mkdirSync(evidenceDirectory, { mode: 0o700 });
592
+ }
593
+ const sourceRoot = fs.mkdtempSync(
594
+ path.join(
595
+ fs.realpathSync.native(os.tmpdir()),
596
+ "cc-native-capability-source-",
597
+ ),
598
+ );
599
+ const sourceIdentity = fs.lstatSync(sourceRoot, { bigint: true });
600
+ let evaluator;
601
+ const report = {
602
+ schema: SCHEMA,
603
+ startedAt: new Date().toISOString(),
604
+ platform: process.platform,
605
+ osRelease: os.release(),
606
+ nodeVersion: process.version,
607
+ architecture: process.arch,
608
+ formalSample: false,
609
+ providerAssessed: false,
610
+ fullReviewPackAssessed: false,
611
+ diagnosticCompleted: false,
612
+ wallTimeMs,
613
+ probeTimeoutMs,
614
+ observations: [],
615
+ stageRetained: false,
616
+ sourceFiles: Object.entries(FIXTURES).map(([name, bytes]) => ({
617
+ name,
618
+ bytes: Buffer.byteLength(bytes),
619
+ sha256: sha256(bytes),
620
+ })),
621
+ brokerFiles: [],
622
+ };
623
+ try {
624
+ report.brokerFiles = [
625
+ "windows-native-evaluator-capabilities.js",
626
+ "windows-native-evaluator.js",
627
+ "index.js",
628
+ "platform-sandbox.js",
629
+ "windows-sandbox.cs",
630
+ "windows-sandbox-helper.exe",
631
+ "windows-sandbox-helper.dll",
632
+ ].map((name) => ({
633
+ name,
634
+ sha256: sha256(fs.readFileSync(new URL(name, import.meta.url))),
635
+ }));
636
+ for (const [name, bytes] of Object.entries(FIXTURES))
637
+ fs.writeFileSync(path.join(sourceRoot, name), bytes, { flag: "wx" });
638
+ const source = checkSource(probeTimeoutMs);
639
+ report.checkSourceSha256 = sha256(source);
640
+ evaluator = createWindowsNativeEvaluator({
641
+ sourceRoot,
642
+ files: Object.keys(FIXTURES),
643
+ checkSource: source,
644
+ wallTimeMs,
645
+ });
646
+ report.manifestDigest = `sha256:${evaluator.manifestDigest}`;
647
+ report.stage = {
648
+ root: evaluator.root,
649
+ workspace: evaluator.manifest.workspace,
650
+ scratch: evaluator.manifest.scratch,
651
+ };
652
+ report.manifest = evaluator.manifest;
653
+ const outcome = await evaluator.execute();
654
+ report.settlement = outcome.receipt;
655
+ const { result } = outcome;
656
+ report.execution = {
657
+ status: result.status ?? null,
658
+ signal: result.signal ?? null,
659
+ error: result.error?.message ?? null,
660
+ errorCode: result.error?.code ?? null,
661
+ stdout: String(result.stdout || ""),
662
+ stderr: String(result.stderr || ""),
663
+ };
664
+ report.execution.stdoutSha256 = sha256(report.execution.stdout);
665
+ report.execution.stderrSha256 = sha256(report.execution.stderr);
666
+ report.journal = readJournalAfterSettlement(report);
667
+ report.journalReadAfterCleanup = true;
668
+ const line = report.execution.stdout
669
+ .trim()
670
+ .split(/\r?\n/u)
671
+ .find((value) => value.startsWith(PREFIX));
672
+ if (line)
673
+ report.observations = JSON.parse(line.slice(PREFIX.length)).observations;
674
+ report.validation = validateWindowsNativeEvaluatorCapabilitiesReport(
675
+ report,
676
+ { allowPartial: true },
677
+ );
678
+ requireCondition(
679
+ report.brokerFiles.every(
680
+ ({ name, sha256: expected }) =>
681
+ sha256(fs.readFileSync(new URL(name, import.meta.url))) === expected,
682
+ ),
683
+ "broker source or binary changed during probe execution",
684
+ );
685
+ report.diagnosticCompleted = report.validation.diagnosticCompleted;
686
+ if (!report.diagnosticCompleted) {
687
+ report.failureKind = report.validation.failureKind;
688
+ report.error =
689
+ report.failureKind === "execution-timeout"
690
+ ? "Target execution timed out; native cleanup confirmed"
691
+ : "Target execution incomplete; native cleanup confirmed";
692
+ }
693
+ } catch (error) {
694
+ report.error = String(error.stack || error);
695
+ report.errorCode = error.code ?? null;
696
+ report.failureKind = evaluator
697
+ ? report.settlement?.cleanupConfirmed === true
698
+ ? "diagnostic-incomplete"
699
+ : "cleanup-unconfirmed"
700
+ : "preparation-failure";
701
+ } finally {
702
+ if (evaluator) {
703
+ if (!report.diagnosticCompleted) {
704
+ report.stageRetained = true;
705
+ report.retentionReason =
706
+ report.settlement?.cleanupConfirmed === true
707
+ ? "diagnostic-incomplete"
708
+ : "cleanup-unconfirmed";
709
+ } else {
710
+ try {
711
+ evaluator.dispose();
712
+ } catch (error) {
713
+ report.stageRetained = true;
714
+ report.retentionReason = "stage-disposal-failed";
715
+ report.cleanupError = String(error.stack || error);
716
+ report.diagnosticCompleted = false;
717
+ }
718
+ }
719
+ }
720
+ try {
721
+ const current = fs.lstatSync(sourceRoot, { bigint: true });
722
+ requireCondition(
723
+ current.dev === sourceIdentity.dev &&
724
+ current.ino === sourceIdentity.ino &&
725
+ !current.isSymbolicLink() &&
726
+ fs.realpathSync.native(sourceRoot) === sourceRoot,
727
+ "private fixture source identity changed; retained",
728
+ );
729
+ fs.rmSync(sourceRoot, { recursive: true });
730
+ } catch (error) {
731
+ report.sourceRetained = true;
732
+ report.sourceCleanupError = String(error.stack || error);
733
+ report.diagnosticCompleted = false;
734
+ }
735
+ report.finishedAt = new Date().toISOString();
736
+ if (evidenceDirectory) {
737
+ for (const stream of ["stdout", "stderr"])
738
+ fs.writeFileSync(
739
+ path.join(evidenceDirectory, `${stream}.txt`),
740
+ report.execution?.[stream] || "",
741
+ { flag: "wx" },
742
+ );
743
+ if (report.journal)
744
+ fs.writeFileSync(
745
+ path.join(evidenceDirectory, JOURNAL_FILE),
746
+ report.journal.raw,
747
+ { flag: "wx" },
748
+ );
749
+ fs.writeFileSync(
750
+ path.join(evidenceDirectory, "report.json"),
751
+ `${JSON.stringify(report, null, 2)}\n`,
752
+ { flag: "wx" },
753
+ );
754
+ }
755
+ }
756
+ return report;
757
+ }