@lapxo/bound 0.2.4 → 0.2.5

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 (250) hide show
  1. package/CITATION.cff +1 -1
  2. package/TARGET.bound +44 -39
  3. package/dist/cli/accept.js +72 -590
  4. package/dist/cli/act-result.js +3 -103
  5. package/dist/cli/args.js +3 -44
  6. package/dist/cli/custodian.js +2 -29
  7. package/dist/cli/host.js +4 -32
  8. package/dist/cli/names.js +1 -12
  9. package/dist/cli/native-descendant.js +1 -19
  10. package/dist/cli/native.js +3 -60
  11. package/dist/cli/observe.js +1 -13
  12. package/dist/cli/owner.js +3 -139
  13. package/dist/cli/pass.js +21 -321
  14. package/dist/cli/place.js +6 -282
  15. package/dist/cli/release-result.js +3 -80
  16. package/dist/cli/retained-judgment.js +1 -25
  17. package/dist/cli/standing-result.js +4 -19
  18. package/dist/cli/takes.js +10 -112
  19. package/dist/cli/verb.d.ts +1 -2
  20. package/dist/cli/verb.js +83 -684
  21. package/dist/engine/computation.js +2 -0
  22. package/dist/engine/conformance.js +4 -0
  23. package/dist/engine/encoding.js +1 -2
  24. package/dist/engine/index.d.ts +1 -13
  25. package/dist/engine/index.js +2 -11
  26. package/dist/engine/object.js +1 -38
  27. package/dist/engine/ports.js +2 -117
  28. package/dist/fold/admission-history.js +1 -17
  29. package/dist/fold/bootstrap-anchor.js +1 -28
  30. package/dist/fold/ceilings.js +1 -142
  31. package/dist/fold/claims.js +2 -132
  32. package/dist/fold/closed.js +24 -235
  33. package/dist/fold/configures.js +1 -25
  34. package/dist/fold/digests.js +10 -226
  35. package/dist/fold/evidence.js +1 -22
  36. package/dist/fold/fold-worker.js +1 -13
  37. package/dist/fold/kept.js +12 -173
  38. package/dist/fold/keys.js +3 -91
  39. package/dist/fold/laid.js +3 -90
  40. package/dist/fold/nos.js +1 -48
  41. package/dist/fold/object.js +1 -2
  42. package/dist/fold/observed.js +27 -534
  43. package/dist/fold/opened.js +1 -33
  44. package/dist/fold/own.js +3 -217
  45. package/dist/fold/paid.js +1 -92
  46. package/dist/fold/place-inputs.js +1 -70
  47. package/dist/fold/places.js +3 -100
  48. package/dist/fold/rank.js +1 -9
  49. package/dist/fold/reach.js +1 -83
  50. package/dist/fold/readers.js +6 -142
  51. package/dist/fold/receipts.js +1 -47
  52. package/dist/fold/region-declarations.js +1 -13
  53. package/dist/fold/region.js +8 -286
  54. package/dist/fold/release-policy.js +1 -101
  55. package/dist/fold/resolved.js +6 -145
  56. package/dist/fold/roles.js +2 -59
  57. package/dist/fold/second.js +4 -71
  58. package/dist/fold/shards.js +12 -100
  59. package/dist/fold/signed.js +3 -81
  60. package/dist/fold/signers.js +1 -54
  61. package/dist/fold/stranger.js +6 -24
  62. package/dist/fold/views.js +1 -66
  63. package/dist/fold/wire.js +1 -46
  64. package/dist/fold/zoom.js +3 -81
  65. package/dist/host/act-cost.js +1 -25
  66. package/dist/host/adapters/keys/ed25519.js +1 -30
  67. package/dist/host/adapters/modules/javascript.js +1 -50
  68. package/dist/host/adapters/transport/http.js +1 -28
  69. package/dist/host/admitted-place.js +1 -35
  70. package/dist/host/archive.js +1 -152
  71. package/dist/host/call-context.js +1 -14
  72. package/dist/host/capsule-process.js +2 -62
  73. package/dist/host/capsule.js +9 -171
  74. package/dist/host/cell-receipts.js +12 -128
  75. package/dist/host/commit-result.js +1 -5
  76. package/dist/host/content-needed.js +1 -8
  77. package/dist/host/content-store.js +1 -31
  78. package/dist/host/contextual-place.js +2 -72
  79. package/dist/host/digest.js +2 -15
  80. package/dist/host/hash.js +1 -9
  81. package/dist/host/host-controls.js +1 -19
  82. package/dist/host/in-process-act.js +3 -84
  83. package/dist/host/in-process-context.js +3 -91
  84. package/dist/host/in-process-root.js +6 -84
  85. package/dist/host/in-process.js +4 -55
  86. package/dist/host/index.d.ts +1 -15
  87. package/dist/host/index.js +1 -7
  88. package/dist/host/io.js +1 -11
  89. package/dist/host/lifetime.js +1 -79
  90. package/dist/host/located.js +6 -105
  91. package/dist/host/native/bounded-file.js +1 -32
  92. package/dist/host/native/command.js +1 -91
  93. package/dist/host/native/control-bridge-worker.js +2 -88
  94. package/dist/host/native/control-bridge.js +1 -110
  95. package/dist/host/native/control-selection.js +1 -32
  96. package/dist/host/native/custody.js +1 -91
  97. package/dist/host/native/deadline.js +1 -28
  98. package/dist/host/native/descendants.js +1 -528
  99. package/dist/host/native/generated-custodian.js +5 -267
  100. package/dist/host/native/generated.js +1 -379
  101. package/dist/host/native/image.js +1 -45
  102. package/dist/host/native/jobs.js +2 -148
  103. package/dist/host/native/loader.js +1 -269
  104. package/dist/host/native/materialize.js +1 -175
  105. package/dist/host/native/module-closure.js +1 -130
  106. package/dist/host/native/module-delivery.d.ts +1 -62
  107. package/dist/host/native/module-delivery.js +1 -151
  108. package/dist/host/native/module-syntax.js +1 -69
  109. package/dist/host/native/native-binary.js +1 -115
  110. package/dist/host/native/native-program.js +1 -72
  111. package/dist/host/native/node-jobs.js +3 -187
  112. package/dist/host/native/node-launch.js +1 -159
  113. package/dist/host/native/preload.js +1 -45
  114. package/dist/host/native/reading.js +1 -249
  115. package/dist/host/native/receipt-environment.js +1 -41
  116. package/dist/host/native/references.js +1 -30
  117. package/dist/host/native/root.js +1 -37
  118. package/dist/host/native/route.js +1 -216
  119. package/dist/host/native/runtime.js +1 -9
  120. package/dist/host/native-reader-context.js +1 -8
  121. package/dist/host/native-receiver.js +1 -25
  122. package/dist/host/objects.js +1 -38
  123. package/dist/host/order.js +1 -2
  124. package/dist/host/place-act-transaction.js +4 -78
  125. package/dist/host/place-clock-selection.js +5 -124
  126. package/dist/host/ports/ingress.js +2 -57
  127. package/dist/host/ports/local-act.js +5 -183
  128. package/dist/host/ports/place-act.js +1 -134
  129. package/dist/host/ports/publication.js +1 -56
  130. package/dist/host/ports/signing.js +1 -74
  131. package/dist/host/ports/store.js +1 -18
  132. package/dist/host/ports/transport.js +1 -48
  133. package/dist/host/process-lifetime.js +1 -17
  134. package/dist/host/provide.js +1 -183
  135. package/dist/host/read-only.js +1 -9
  136. package/dist/host/reading-closures.js +7 -227
  137. package/dist/host/reading-context.js +1 -53
  138. package/dist/host/reading-identity-types.js +0 -0
  139. package/dist/host/reading-identity.js +3 -0
  140. package/dist/host/reading-preparation.js +6 -0
  141. package/dist/host/reference-authenticated.d.ts +1 -40
  142. package/dist/host/reference-authenticated.js +3 -100
  143. package/dist/host/reference-contracts.js +1 -6
  144. package/dist/host/reference-export.js +6 -81
  145. package/dist/host/reference-native-api.d.ts +1 -3
  146. package/dist/host/reference-native-api.js +1 -3
  147. package/dist/host/reference-native.js +1 -74
  148. package/dist/host/reference-profile.js +1 -63
  149. package/dist/host/reference-standing.js +2 -18
  150. package/dist/host/reference.js +1 -24
  151. package/dist/host/refusals.js +2 -43
  152. package/dist/host/release.js +4 -256
  153. package/dist/host/root-clock-source.js +1 -307
  154. package/dist/host/selected-capsules.js +1 -50
  155. package/dist/host/selected-topos.js +1 -80
  156. package/dist/host/signature-era.js +1 -12
  157. package/dist/host/signing.js +2 -48
  158. package/dist/host/source-content.js +2 -111
  159. package/dist/host/standing-carrier.js +1 -18
  160. package/dist/host/standing-projection.js +1 -50
  161. package/dist/host/timing.js +1 -7
  162. package/dist/host/walk.js +20 -193
  163. package/dist/judge/late.js +1 -33
  164. package/dist/judge/take.js +2 -75
  165. package/dist/judge/widening.js +1 -25
  166. package/dist/land/act.js +8 -336
  167. package/dist/land/alias.js +1 -41
  168. package/dist/land/held.js +1 -23
  169. package/dist/land/inert.js +1 -33
  170. package/dist/land/leaving.js +1 -55
  171. package/dist/land/ledger.js +7 -188
  172. package/dist/land/owned.js +4 -66
  173. package/dist/land/sign.js +1 -53
  174. package/dist/land/standing-pin.js +1 -49
  175. package/dist/land/vouched.js +1 -112
  176. package/dist/land/withdraw.js +1 -24
  177. package/dist/observe/files.js +1 -88
  178. package/dist/observe/identity.js +1 -61
  179. package/dist/observe/match.js +1 -8
  180. package/dist/observe/regions.js +7 -306
  181. package/dist/observe/run.js +2 -41
  182. package/dist/observe/runner.js +4 -101
  183. package/dist/public-types.d.ts +1114 -0
  184. package/dist/render/capsule.js +1 -30
  185. package/dist/render/field.js +1 -40
  186. package/dist/render/names.js +1 -4
  187. package/dist/render/open.js +1 -61
  188. package/dist/render/page.js +1 -7
  189. package/dist/render/receipts.js +1 -47
  190. package/dist/render/shape.js +1 -74
  191. package/dist/render/target.js +4 -52
  192. package/dist/render/view.js +7 -197
  193. package/dist/vendor/50086958553b9376d600583f7dff354196bfeb41170fc6d1482ca7bea7c493e2.LICENSE +21 -0
  194. package/dist/vendor/b3e938d28f88a1851af303a40c749e12ebd5a686daac4f0b343b5cdd2e040419.LICENSE +21 -0
  195. package/dist/vendor/bundle.json +1 -0
  196. package/dist/vendor/library11.js +1 -0
  197. package/dist/vendor/object-provider.js +42 -0
  198. package/dist/vendor/runtime.js +38 -0
  199. package/dist/vendor/sources.json +1 -0
  200. package/dist/wasm/adapter.d.ts +1 -51
  201. package/dist/wasm/adapter.js +1 -180
  202. package/dist/wasm/node-worker.js +1 -13
  203. package/dist/wasm/object.js +1 -76
  204. package/dist/wasm/worker.js +1 -7
  205. package/docs/contracts/closure-delivery.md +1 -1
  206. package/docs/contracts/closure-delivery.publication.json +1 -1
  207. package/docs/contracts/conformance.json +142 -0
  208. package/docs/contracts/determinism.bound +9 -0
  209. package/docs/contracts/engine-object-projection.publication.json +1 -1
  210. package/docs/contracts/engine.md +21 -1
  211. package/docs/contracts/native-publication.inventory.json +2 -1
  212. package/docs/contracts/optional-wasm-adapter.publication.json +1 -1
  213. package/docs/contracts/reading-identity.md +37 -0
  214. package/docs/contracts/reading-identity.publication.json +25 -0
  215. package/docs/contracts/refusals.bound +51 -0
  216. package/docs/contracts/refusals.md +18 -3
  217. package/docs/contracts/refusals.publication.json +2 -2
  218. package/docs/contracts/views.md +8 -0
  219. package/docs/reference.md +1 -0
  220. package/package.json +23 -34
  221. package/receipts.bound +11627 -10323
  222. package/samples/reading-identity/no.json +20 -0
  223. package/samples/reading-identity/yes.json +46 -0
  224. package/vectors/native/reading-identity.vector.json +101 -0
  225. package/vectors/native/refusals.vector.json +104 -0
  226. package/vendor/syntax/LICENSE.md +7 -0
  227. package/vendor/syntax/parser.js +1 -0
  228. package/.github/workflows/release.yml +0 -67
  229. package/.github/workflows/test.yml +0 -35
  230. package/dist/engine/object.d.ts +0 -17
  231. package/dist/engine/ports.d.ts +0 -37
  232. package/dist/fold/claims.d.ts +0 -29
  233. package/dist/host/call-context.d.ts +0 -20
  234. package/dist/host/commit-result.d.ts +0 -6
  235. package/dist/host/in-process-act.d.ts +0 -82
  236. package/dist/host/in-process-context.d.ts +0 -46
  237. package/dist/host/in-process-root.d.ts +0 -117
  238. package/dist/host/in-process.d.ts +0 -41
  239. package/dist/host/native/module-closure.d.ts +0 -35
  240. package/dist/host/native-receiver.d.ts +0 -19
  241. package/dist/host/place-act-transaction.d.ts +0 -24
  242. package/dist/host/place-clock-selection.d.ts +0 -55
  243. package/dist/host/ports/local-act.d.ts +0 -44
  244. package/dist/host/ports/place-act.d.ts +0 -49
  245. package/dist/host/ports/publication.d.ts +0 -10
  246. package/dist/host/reference-export.d.ts +0 -33
  247. package/dist/host/reference-native.d.ts +0 -30
  248. package/dist/host/reference-profile.d.ts +0 -23
  249. package/dist/host/refusals.d.ts +0 -14
  250. package/dist/host/root-clock-source.d.ts +0 -86
@@ -1,72 +1 @@
1
- import { retainedProjection } from "./reading.js";
2
- import { fieldNames } from "./reading.js";
3
- import { sha256 as sha } from "../hash.js";
4
- /** A program alias is a Root selection, never PATH.
5
- * This verifies a finite implementation before entry; it executes nothing.
6
- * The runtime hook must still verify each reached member before loading it. */
7
- import { isAbsolute, resolve, relative } from 'node:path';
8
- import { realpathSync } from 'node:fs';
9
- import { authenticateSignedPort, nativeParentInputBytes, canonicalJson } from "./reading.js";
10
- import { readBounded } from "./generated.js";
11
- const fail = (why) => { throw Error('REFUSE·native program ' + why); };
12
- const keys = fieldNames;
13
- const verified = new WeakMap();
14
- export function verifyNativeProgram(root, coordinate, parent, runtimeBinding) {
15
- const authenticated = authenticateSignedPort(root, coordinate), p = authenticated.profile;
16
- if (!p || keys(p) !== 'alias,condition,coordinate,entry,interpreter,limits,members,profile,root,selector' || p.profile !== 'host-native-program@1' || p.coordinate !== coordinate || typeof p.alias !== 'string' || !p.alias.length || p.alias.includes('\0') || typeof p.condition !== 'string' || !p.condition.length)
17
- fail('selection absent/unknown');
18
- if (keys(p.selector ?? {}) !== 'binding,implementation,port' || canonicalJson(p.selector) !== canonicalJson({ port: parent.port, binding: parent.binding, implementation: parent.implementation }))
19
- fail('selection differs from parent');
20
- if (keys(p.limits ?? {}) !== 'bytes,members' || !Number.isSafeInteger(p.limits.members) || p.limits.members < 1 || !Number.isSafeInteger(p.limits.bytes) || p.limits.bytes < 1 || p.limits.bytes > nativeParentInputBytes(root, parent))
21
- fail('implementation resource absent/exceeds Root');
22
- if ([parent.identity, parent.instrument, parent.policy, parent.authority, parent.implementation].some(d => typeof d !== 'string' || !/^sha256:[0-9a-f]{64}$/.test(d)))
23
- fail('parent identity absent');
24
- if (!Array.isArray(p.members) || p.members.length > p.limits.members || typeof p.root !== 'string' || isAbsolute(p.root) || p.root.split('/').some(s => !s || s === '.' || s === '..') || !p.interpreter || typeof p.interpreter.path !== 'string' || isAbsolute(p.interpreter.path) || p.interpreter.path !== runtimeBinding.coordinate || keys(p.interpreter) !== 'bytes,digest,path' || !Number.isSafeInteger(p.interpreter.bytes) || p.interpreter.bytes < 1)
25
- fail('interpreter/implementation context absent');
26
- // This binding comes from the private prepared host image, not the program's
27
- // declaration. Matching a path alone cannot identify an implementation.
28
- if (!runtimeBinding || runtimeBinding.path !== parent.runtime || runtimeBinding.digest !== p.interpreter.digest || !parent.inputs.some(p => p[1] === runtimeBinding.digest))
29
- fail('interpreter differs from parent image');
30
- let bytes = p.interpreter.bytes;
31
- if (bytes > p.limits.bytes)
32
- fail('interpreter byte resource');
33
- const coordinates = new Set();
34
- for (const m of p.members) {
35
- if (!m || keys(m) !== 'bytes,coordinate,digest' || typeof m.coordinate !== 'string' || !m.coordinate.length || isAbsolute(m.coordinate) || m.coordinate.includes('\\') || m.coordinate.split('/').some(x => !x || x === '.' || x === '..') || coordinates.has(m.coordinate) || !/^sha256:[0-9a-f]{64}$/.test(m.digest) || !Number.isSafeInteger(m.bytes) || m.bytes < 0)
36
- fail('member identity ambiguous');
37
- coordinates.add(m.coordinate);
38
- bytes += m.bytes;
39
- if (bytes > p.limits.bytes)
40
- fail('implementation byte resource');
41
- }
42
- // All declarations and aggregate resources are checked before reading files.
43
- if (!coordinates.has(p.entry) || !/^sha256:[0-9a-f]{64}$/.test(p.interpreter.digest))
44
- fail('entry/interpreter digest absent');
45
- const physical = (path) => { try {
46
- return realpathSync(path);
47
- }
48
- catch {
49
- return fail('selected member absent ' + path);
50
- } };
51
- const entryMount = runtimeBinding.members.find(m => m.coordinate === p.root + '/' + p.entry);
52
- if (!entryMount)
53
- return fail('entry mount absent from host image');
54
- const levels = p.entry.split('/').length;
55
- let physicalRoot = physical(entryMount.path);
56
- for (let i = 0; i < levels; i++)
57
- physicalRoot = resolve(physicalRoot, '..');
58
- const interpreter = physical(runtimeBinding.path);
59
- const interpreterBytes = readBounded(interpreter, p.interpreter.bytes);
60
- if (interpreterBytes.length !== p.interpreter.bytes || sha(interpreterBytes) !== p.interpreter.digest)
61
- fail('interpreter bytes differ');
62
- const members = p.members.map(m => { const mounted = runtimeBinding.members.find(one => one.coordinate === p.root + '/' + m.coordinate); if (!mounted)
63
- return fail('member absent from actual host image ' + m.coordinate); const path = physical(mounted.path), r = relative(physicalRoot, path); if (r === '..' || r.startsWith('../') || isAbsolute(r))
64
- fail('member outside selected implementation'); const b = readBounded(path, m.bytes); if (b.length !== m.bytes || sha(b) !== m.digest)
65
- fail('member bytes differ ' + m.coordinate); return { path, digest: m.digest }; });
66
- const handle = Object.freeze({ identity: sha(canonicalJson([authenticated.line, parent.identity])) });
67
- verified.set(handle, { alias: p.alias, interpreter, interpreterDigest: p.interpreter.digest, entry: physical(resolve(physicalRoot, p.entry)), root: physicalRoot, members, condition: p.condition });
68
- return handle;
69
- }
70
- /** Only the guarded instrument can obtain this from a verified opaque handle.
71
- * Put it in the signed native image; never accept it from a world proposal. */
72
- export const nativeProgramProjection = retainedProjection(verified, fail);
1
+ var x=Object.defineProperty;var l=(s,c)=>x(s,"name",{value:c,configurable:!0});import{retainedProjection as M}from"./reading.js";import{fieldNames as W}from"./reading.js";import{sha256 as h}from"../hash.js";import{isAbsolute as f,resolve as j,relative as z}from"node:path";import{realpathSync as D}from"node:fs";import{authenticateSignedPort as F,nativeParentInputBytes as J,canonicalJson as u}from"./reading.js";import{readBounded as k}from"./generated.js";const r=l(s=>{throw Error("REFUSE\xB7native program "+s)},"fail"),m=W,A=new WeakMap;function Q(s,c,i,o){const v=F(s,c),e=v.profile;(!e||m(e)!=="alias,condition,coordinate,entry,interpreter,limits,members,profile,root,selector"||e.profile!=="host-native-program@1"||e.coordinate!==c||typeof e.alias!="string"||!e.alias.length||e.alias.includes("\0")||typeof e.condition!="string"||!e.condition.length)&&r("selection absent/unknown"),(m(e.selector??{})!=="binding,implementation,port"||u(e.selector)!==u({port:i.port,binding:i.binding,implementation:i.implementation}))&&r("selection differs from parent"),(m(e.limits??{})!=="bytes,members"||!Number.isSafeInteger(e.limits.members)||e.limits.members<1||!Number.isSafeInteger(e.limits.bytes)||e.limits.bytes<1||e.limits.bytes>J(s,i))&&r("implementation resource absent/exceeds Root"),[i.identity,i.instrument,i.policy,i.authority,i.implementation].some(t=>typeof t!="string"||!/^sha256:[0-9a-f]{64}$/.test(t))&&r("parent identity absent"),(!Array.isArray(e.members)||e.members.length>e.limits.members||typeof e.root!="string"||f(e.root)||e.root.split("/").some(t=>!t||t==="."||t==="..")||!e.interpreter||typeof e.interpreter.path!="string"||f(e.interpreter.path)||e.interpreter.path!==o.coordinate||m(e.interpreter)!=="bytes,digest,path"||!Number.isSafeInteger(e.interpreter.bytes)||e.interpreter.bytes<1)&&r("interpreter/implementation context absent"),(!o||o.path!==i.runtime||o.digest!==e.interpreter.digest||!i.inputs.some(t=>t[1]===o.digest))&&r("interpreter differs from parent image");let b=e.interpreter.bytes;b>e.limits.bytes&&r("interpreter byte resource");const d=new Set;for(const t of e.members)(!t||m(t)!=="bytes,coordinate,digest"||typeof t.coordinate!="string"||!t.coordinate.length||f(t.coordinate)||t.coordinate.includes("\\")||t.coordinate.split("/").some(n=>!n||n==="."||n==="..")||d.has(t.coordinate)||!/^sha256:[0-9a-f]{64}$/.test(t.digest)||!Number.isSafeInteger(t.bytes)||t.bytes<0)&&r("member identity ambiguous"),d.add(t.coordinate),b+=t.bytes,b>e.limits.bytes&&r("implementation byte resource");(!d.has(e.entry)||!/^sha256:[0-9a-f]{64}$/.test(e.interpreter.digest))&&r("entry/interpreter digest absent");const p=l(t=>{try{return D(t)}catch{return r("selected member absent "+t)}},"physical"),S=o.members.find(t=>t.coordinate===e.root+"/"+e.entry);if(!S)return r("entry mount absent from host image");const E=e.entry.split("/").length;let a=p(S.path);for(let t=0;t<E;t++)a=j(a,"..");const N=p(o.path),P=k(N,e.interpreter.bytes);(P.length!==e.interpreter.bytes||h(P)!==e.interpreter.digest)&&r("interpreter bytes differ");const R=e.members.map(t=>{const n=o.members.find($=>$.coordinate===e.root+"/"+t.coordinate);if(!n)return r("member absent from actual host image "+t.coordinate);const y=p(n.path),g=z(a,y);(g===".."||g.startsWith("../")||f(g))&&r("member outside selected implementation");const w=k(y,t.bytes);return(w.length!==t.bytes||h(w)!==t.digest)&&r("member bytes differ "+t.coordinate),{path:y,digest:t.digest}}),I=Object.freeze({identity:h(u([v.line,i.identity]))});return A.set(I,{alias:e.alias,interpreter:N,interpreterDigest:e.interpreter.digest,entry:p(j(a,e.entry)),root:a,members:R,condition:e.condition}),I}l(Q,"verifyNativeProgram");const T=M(A,r);export{T as nativeProgramProjection,Q as verifyNativeProgram};
@@ -1,187 +1,3 @@
1
- import { sha256 as digest } from "../hash.js";
2
- /** Host-only controlled Node adapter; pure planning remains in planner.ts. */
3
- import { realpathSync } from 'node:fs';
4
- import { isAbsolute } from 'node:path';
5
- import { readBoundedFile } from "./bounded-file.js";
6
- import { executeLot } from "./command.js";
7
- import { moduleClosure } from "./module-closure.js";
8
- import { planJobs } from "./jobs.js";
9
- const refuse = (why) => { throw Error('REFUSE·job adapter ' + why); };
10
- const fileDigest = (path, limit) => { try {
11
- return digest(readBoundedFile(path, limit, path));
12
- }
13
- catch {
14
- return refuse('image member absent ' + path);
15
- } };
16
- const capturedCommand = (value) => { if (!value || typeof value !== 'object' || Array.isArray(value))
17
- return false; const v = value; return Object.keys(v).sort().join(',') === 'exitStatus,stderr,stdout' && Number.isSafeInteger(v.exitStatus) && v.exitStatus >= 0 && typeof v.stdout === 'string' && typeof v.stderr === 'string'; };
18
- const admittedImages = new WeakMap();
19
- /** Image/runtime condition and locations are instrument-admitted inputs, selected
20
- * before requests. Condition includes trusted Node builtins/platform libraries;
21
- * a binary's file digest alone does not seal every dynamic platform library. */
22
- export function prepareNodeImage(input, inputImage) {
23
- if (!inputImage?.commandPort)
24
- refuse('missing admitted command port');
25
- if (!inputImage || !isAbsolute(inputImage.cwd) || !inputImage.condition)
26
- refuse('missing admitted Node image condition');
27
- const host = { ...input, budget: { ...input.budget }, members: input.members.map(m => ({ ...m, bytes: new Uint8Array(m.bytes) })), loads: input.loads.map(e => ({ ...e, target: typeof e.target === 'string' ? e.target : { ...e.target } })), bindings: input.bindings.map(b => ({ ...b, places: [...b.places], args: [...b.args], inputs: [...b.inputs], environment: b.environment.map(p => [...p]), limits: { ...b.limits } })) };
28
- // Validate all declarations and member bytes without any world proposal/launch.
29
- planJobs(host, new TextEncoder().encode('[]'), digest);
30
- const members = new Map(host.members.map(m => [m.coordinate, m])), locations = new Map();
31
- let actualBytes = 0;
32
- for (const member of host.members) {
33
- actualBytes += member.bytes.length;
34
- if (actualBytes > host.budget.bytes)
35
- refuse('image byte resources');
36
- }
37
- const runtimeLocation = inputImage.locations.find(l => l.member === inputImage.runtime);
38
- if (!runtimeLocation || realpathSync(runtimeLocation.path) !== realpathSync(process.execPath))
39
- refuse('runtime differs from executing interpreter');
40
- for (const location of inputImage.locations) {
41
- if (locations.has(location.member) || !members.has(location.member) || !isAbsolute(location.path) || !['binary', 'module', 'data'].includes(location.kind))
42
- refuse('unknown/duplicate image location ' + location.member);
43
- if (fileDigest(location.path, host.budget.bytes) !== members.get(location.member).digest)
44
- refuse('image bytes differ ' + location.member);
45
- locations.set(location.member, { ...location });
46
- }
47
- if (locations.size !== members.size)
48
- refuse('image omitted handed member');
49
- const texts = new Map([...members].filter(([c]) => locations.get(c).kind === 'module' || c.endsWith('.json')).map(([c, m]) => { let source; try {
50
- source = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(m.bytes);
51
- }
52
- catch {
53
- return refuse('invalid text member ' + c);
54
- } return [c, { source, digest: m.digest }]; }));
55
- const snapshot = { identity: digest(new TextEncoder().encode(JSON.stringify([...members].map(([c, m]) => [c, m.digest]).sort()) + '\n')), entry: '', members: texts };
56
- if (!inputImage.runtime || locations.get(inputImage.runtime)?.kind !== 'binary')
57
- refuse('selected Node runtime absent');
58
- if (inputImage.preload !== undefined && locations.get(inputImage.preload)?.kind !== 'module')
59
- refuse('selected Node preloader absent');
60
- if (!Array.isArray(inputImage.nativePreloadMembers) || (inputImage.preload !== undefined && !inputImage.nativePreloadMembers.includes(inputImage.preload)) || new Set(inputImage.nativePreloadMembers).size !== inputImage.nativePreloadMembers.length || inputImage.nativePreloadMembers.some(c => !members.has(c)))
61
- refuse('native preloader members not handed');
62
- const nativePreloadMembers = [...inputImage.nativePreloadMembers];
63
- const proofs = new Map();
64
- for (const binding of host.bindings) {
65
- if (locations.get(binding.program)?.kind !== 'module' || binding.interpreter !== inputImage.runtime)
66
- refuse('unsupported raw binary profile ' + binding.id);
67
- if (binding.kind === 'process' && binding.entry !== undefined)
68
- refuse('process entry unsupported ' + binding.id);
69
- const roots = [binding.program, ...(binding.entry ? [binding.entry] : [])].filter(c => locations.get(c).kind === 'module');
70
- if (!roots.length && locations.get(binding.program).kind !== 'binary')
71
- refuse('unsupported program member ' + binding.program);
72
- if (binding.interpreter && locations.get(binding.interpreter).kind !== 'binary')
73
- refuse('interpreter is not a selected binary');
74
- if (binding.kind === 'worker' && (!binding.entry || locations.get(binding.entry).kind !== 'module'))
75
- refuse('worker entry is not a selected module');
76
- const reached = roots.flatMap(entry => moduleClosure({ ...snapshot, entry }, () => undefined));
77
- const declaredTargets = new Set([inputImage.preload, binding.program, binding.interpreter, binding.entry, ...binding.inputs, ...host.loads.map(e => typeof e.target === 'string' ? e.target : '')].filter(Boolean));
78
- for (const reading of reached)
79
- if (!declaredTargets.has(reading.coordinate))
80
- refuse('literal module dependency not declared ' + reading.coordinate);
81
- proofs.set(binding.id, JSON.stringify(reached));
82
- }
83
- host.policy = digest(new TextEncoder().encode(JSON.stringify([host.policy, 'captured-command/1', inputImage.condition, inputImage.runtime, inputImage.preload, nativePreloadMembers.map(c => [c, members.get(c).digest]), snapshot.identity, inputImage.commandPort ?? null, [...proofs]]) + '\n'));
84
- const handle = Object.freeze({ identity: digest(new TextEncoder().encode(JSON.stringify([host.place, host.policy, snapshot.identity]))) });
85
- admittedImages.set(handle, { handoff: host, image: { cwd: inputImage.cwd, condition: inputImage.condition, runtime: inputImage.runtime, preload: inputImage.preload, nativePreloadMembers, ...(inputImage.hostLoader ? { hostLoader: inputImage.hostLoader } : {}), ...(inputImage.commandPort ? { commandPort: { ...inputImage.commandPort, closure: [...inputImage.commandPort.closure], environment: [...inputImage.commandPort.environment] } } : {}), locations: [...locations.values()] }, locations, proofs, snapshot });
86
- return handle;
87
- }
88
- /** Exact expectations from the same opaque host image used by execution. */
89
- export function plannedJobs(handle, request) { const ready = admittedImages.get(handle); if (!ready)
90
- return refuse('unknown prepared host image'); return planJobs(ready.handoff, request, digest).map(({ id, identity }) => ({ id, identity })); }
91
- function parentExecution(ready, job) { const port = ready.image.commandPort; if (!port)
92
- return refuse('producer requires declared parent port'); return { identity: job.identity, port: port.coordinate, binding: job.id, implementation: job.program[1], instrument: ready.handoff.instrument, policy: ready.handoff.policy, authority: ready.handoff.authoritySnapshot, inputs: job.edges.map(e => [e.target, e.digest]).filter((p, i, all) => all.findIndex(q => q[0] === p[0]) === i), environment: job.environment, argv: invocation(ready, job).args, cwd: ready.image.cwd, runtime: ready.locations.get(ready.image.runtime).path, timeoutMs: Math.min(port.timeoutMs, job.limits.timeMs), responseBytes: Math.min(port.responseBytes, job.limits.responseBytes) }; }
93
- export function plannedParentExecutions(handle, request) { const ready = admittedImages.get(handle); if (!ready)
94
- return refuse('unknown prepared host image'); return planJobs(ready.handoff, request, digest).map(job => parentExecution(ready, job)); }
95
- const invocation = (ready, job) => {
96
- const program = ready.locations.get(job.program[0]), interpreter = job.interpreter && ready.locations.get(job.interpreter[0]);
97
- if (!interpreter)
98
- return { command: program.path, args: [...job.args], cwd: ready.image.cwd };
99
- const host = ready.image.hostLoader;
100
- if (!host)
101
- return refuse('fixed loader envelope absent');
102
- const url = new URL(host.preload);
103
- url.searchParams.set('bytes', String(ready.handoff.budget.bytes));
104
- const envelope = Buffer.from(JSON.stringify({ format: 'native-image-envelope/1', entries: host.entries, declaration: host.declaration, execution: { runtime: ready.locations.get(ready.image.runtime).path, cwd: ready.image.cwd, mounts: ready.image.locations.map(location => ({ coordinate: location.member, path: location.path, kind: location.kind })) } }));
105
- return { command: interpreter.path, args: ['--import', url.href, ...(ready.image.preload ? ['--import', ready.locations.get(ready.image.preload).path] : []), program.path, ...(job.kind === 'worker' ? [ready.locations.get(job.entry[0]).path] : []), ...job.args], cwd: ready.image.cwd, hostEnvelope: envelope, envelopeBytes: ready.handoff.budget.bytes };
106
- };
107
- /** No partial member escapes a failed batch. Uses the existing bounded async
108
- * child-group executor; worker launcher is itself an exact selected module. */
109
- export async function executeJobs(handle, request, options) {
110
- const ready = admittedImages.get(handle);
111
- if (!ready)
112
- return refuse('unknown prepared host image');
113
- const { phase, signal, trace } = options;
114
- if (phase !== 'act')
115
- refuse('invocation forbidden during ' + phase);
116
- if (signal?.aborted)
117
- refuse('interrupted before batch');
118
- const jobs = planJobs(ready.handoff, request, digest);
119
- // Complete batch and all locations are verified before invoking any program.
120
- for (const member of ready.handoff.members) {
121
- const loc = ready.locations.get(member.coordinate);
122
- if (fileDigest(loc.path, ready.handoff.budget.bytes) !== member.digest)
123
- refuse('image bytes differ ' + member.coordinate);
124
- }
125
- if (!jobs.length)
126
- return [];
127
- const slots = Math.min(...jobs.map(j => j.limits.slots)), controller = new AbortController(), abort = controller.abort.bind(controller, undefined);
128
- signal?.addEventListener('abort', abort, { once: true });
129
- if (signal?.aborted)
130
- abort();
131
- const results = new Array(jobs.length);
132
- let next = 0;
133
- let primary;
134
- const work = async () => {
135
- while (!controller.signal.aborted) {
136
- const index = next++;
137
- if (index >= jobs.length)
138
- return;
139
- const job = jobs[index], fixed = invocation(ready, job), implementation = job.program[1], port = { ...ready.image.commandPort, timeoutMs: Math.min(ready.image.commandPort.timeoutMs, job.limits.timeMs), responseBytes: Math.min(ready.image.commandPort.responseBytes, job.limits.responseBytes) };
140
- const proofFor = () => { for (const edge of job.edges) {
141
- const loc = ready.locations.get(edge.target);
142
- if (!loc || fileDigest(loc.path, ready.handoff.budget.bytes) !== edge.digest)
143
- return 'unmeasured';
144
- } const roots = [job.program[0], ...(job.entry ? [job.entry[0]] : [])].filter(c => ready.locations.get(c).kind === 'module'); const actual = JSON.stringify(roots.flatMap(entry => moduleClosure({ ...ready.snapshot, entry }, () => undefined))); return actual === ready.proofs.get(job.id) ? 'verified' : 'unmeasured'; };
145
- trace?.({ id: job.id, phase: 'start' });
146
- let custody;
147
- try {
148
- if (options.custody)
149
- custody = await options.custody.open(parentExecution(ready, job));
150
- if (!custody)
151
- return refuse('native descendant custody missing ' + job.id);
152
- const envelope = JSON.parse(Buffer.from(fixed.hostEnvelope).toString('utf8'));
153
- envelope.descendant = custody.descendant;
154
- if (!envelope.descendant)
155
- return refuse('fixed descendant envelope absent ' + job.id);
156
- const guarded = { ...fixed, hostEnvelope: Buffer.from(JSON.stringify(envelope)) };
157
- const result = await executeLot({ port, lot: { identity: job.identity, requests: [new TextDecoder().decode(job.payload)] }, phase, signal: controller.signal, environment: Object.fromEntries(job.environment), host: { admitsDeclaration: p => JSON.stringify(p) === JSON.stringify(port), covers: c => c === port.coordinate && ready.handoff.bindings.find(b => b.id === job.id).places.includes(ready.handoff.place), verifies: d => ready.handoff.members.some(m => m.digest === d && fileDigest(ready.locations.get(m.coordinate).path, ready.handoff.budget.bytes) === d), resolve: () => guarded, loaderClosure: (_p, actual) => JSON.stringify(actual) === JSON.stringify(guarded) ? proofFor() : 'unmeasured' }, accepts: (response, index) => index === 0 && capturedCommand(response) });
158
- custody?.assertClosed();
159
- results[index] = { id: job.id, identity: job.identity, responses: result.members };
160
- }
161
- catch (error) {
162
- if (primary === undefined)
163
- primary = error;
164
- controller.abort();
165
- throw error;
166
- }
167
- finally {
168
- await custody?.close();
169
- trace?.({ id: job.id, phase: 'end' });
170
- }
171
- }
172
- };
173
- try {
174
- const settled = await Promise.allSettled(Array.from({ length: Math.min(slots, jobs.length) }, work));
175
- if (primary !== undefined)
176
- throw primary;
177
- const failed = settled.find(x => x.status === 'rejected');
178
- if (failed?.status === 'rejected')
179
- throw failed.reason;
180
- if (controller.signal.aborted || results.some(x => x === undefined) || results.filter(Boolean).length !== jobs.length)
181
- refuse('interrupted/incomplete batch');
182
- return results;
183
- }
184
- finally {
185
- signal?.removeEventListener('abort', abort);
186
- }
187
- }
1
+ var F=Object.defineProperty;var d=(r,t)=>F(r,"name",{value:t,configurable:!0});import{sha256 as w}from"../hash.js";import{realpathSync as A}from"node:fs";import{isAbsolute as L}from"node:path";import{readBoundedFile as U}from"./bounded-file.js";import{executeLot as q}from"./command.js";import{moduleClosure as T}from"./module-closure.js";import{planJobs as N}from"./jobs.js";const s=d(r=>{throw Error("REFUSE\xB7job adapter "+r)},"refuse"),O=d((r,t)=>{try{return w(U(r,t,r))}catch{return s("image member absent "+r)}},"fileDigest"),R=d(r=>{if(!r||typeof r!="object"||Array.isArray(r))return!1;const t=r;return Object.keys(t).sort().join(",")==="exitStatus,stderr,stdout"&&Number.isSafeInteger(t.exitStatus)&&t.exitStatus>=0&&typeof t.stdout=="string"&&typeof t.stderr=="string"},"capturedCommand"),B=new WeakMap;function Z(r,t){t?.commandPort||s("missing admitted command port"),(!t||!L(t.cwd)||!t.condition)&&s("missing admitted Node image condition");const i={...r,budget:{...r.budget},members:r.members.map(e=>({...e,bytes:new Uint8Array(e.bytes)})),loads:r.loads.map(e=>({...e,target:typeof e.target=="string"?e.target:{...e.target}})),bindings:r.bindings.map(e=>({...e,places:[...e.places],args:[...e.args],inputs:[...e.inputs],environment:e.environment.map(c=>[...c]),limits:{...e.limits}}))};N(i,new TextEncoder().encode("[]"),w);const n=new Map(i.members.map(e=>[e.coordinate,e])),a=new Map;let l=0;for(const e of i.members)l+=e.bytes.length,l>i.budget.bytes&&s("image byte resources");const g=t.locations.find(e=>e.member===t.runtime);(!g||A(g.path)!==A(process.execPath))&&s("runtime differs from executing interpreter");for(const e of t.locations)(a.has(e.member)||!n.has(e.member)||!L(e.path)||!["binary","module","data"].includes(e.kind))&&s("unknown/duplicate image location "+e.member),O(e.path,i.budget.bytes)!==n.get(e.member).digest&&s("image bytes differ "+e.member),a.set(e.member,{...e});a.size!==n.size&&s("image omitted handed member");const m=new Map([...n].filter(([e])=>a.get(e).kind==="module"||e.endsWith(".json")).map(([e,c])=>{let M;try{M=new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(c.bytes)}catch{return s("invalid text member "+e)}return[e,{source:M,digest:c.digest}]})),k={identity:w(new TextEncoder().encode(JSON.stringify([...n].map(([e,c])=>[e,c.digest]).sort())+`
2
+ `)),entry:"",members:m};(!t.runtime||a.get(t.runtime)?.kind!=="binary")&&s("selected Node runtime absent"),t.preload!==void 0&&a.get(t.preload)?.kind!=="module"&&s("selected Node preloader absent"),(!Array.isArray(t.nativePreloadMembers)||t.preload!==void 0&&!t.nativePreloadMembers.includes(t.preload)||new Set(t.nativePreloadMembers).size!==t.nativePreloadMembers.length||t.nativePreloadMembers.some(e=>!n.has(e)))&&s("native preloader members not handed");const u=[...t.nativePreloadMembers],v=new Map;for(const e of i.bindings){(a.get(e.program)?.kind!=="module"||e.interpreter!==t.runtime)&&s("unsupported raw binary profile "+e.id),e.kind==="process"&&e.entry!==void 0&&s("process entry unsupported "+e.id);const c=[e.program,...e.entry?[e.entry]:[]].filter(o=>a.get(o).kind==="module");!c.length&&a.get(e.program).kind!=="binary"&&s("unsupported program member "+e.program),e.interpreter&&a.get(e.interpreter).kind!=="binary"&&s("interpreter is not a selected binary"),e.kind==="worker"&&(!e.entry||a.get(e.entry).kind!=="module")&&s("worker entry is not a selected module");const M=c.flatMap(o=>T({...k,entry:o},()=>{})),f=new Set([t.preload,e.program,e.interpreter,e.entry,...e.inputs,...i.loads.map(o=>typeof o.target=="string"?o.target:"")].filter(Boolean));for(const o of M)f.has(o.coordinate)||s("literal module dependency not declared "+o.coordinate);v.set(e.id,JSON.stringify(M))}i.policy=w(new TextEncoder().encode(JSON.stringify([i.policy,"captured-command/1",t.condition,t.runtime,t.preload,u.map(e=>[e,n.get(e).digest]),k.identity,t.commandPort??null,[...v]])+`
3
+ `));const x=Object.freeze({identity:w(new TextEncoder().encode(JSON.stringify([i.place,i.policy,k.identity])))});return B.set(x,{handoff:i,image:{cwd:t.cwd,condition:t.condition,runtime:t.runtime,preload:t.preload,nativePreloadMembers:u,...t.hostLoader?{hostLoader:t.hostLoader}:{},...t.commandPort?{commandPort:{...t.commandPort,closure:[...t.commandPort.closure],environment:[...t.commandPort.environment]}}:{},locations:[...a.values()]},locations:a,proofs:v,snapshot:k}),x}d(Z,"prepareNodeImage");function $(r,t){const i=B.get(r);return i?N(i.handoff,t,w).map(({id:n,identity:a})=>({id:n,identity:a})):s("unknown prepared host image")}d($,"plannedJobs");function C(r,t){const i=r.image.commandPort;return i?{identity:t.identity,port:i.coordinate,binding:t.id,implementation:t.program[1],instrument:r.handoff.instrument,policy:r.handoff.policy,authority:r.handoff.authoritySnapshot,inputs:t.edges.map(n=>[n.target,n.digest]).filter((n,a,l)=>l.findIndex(g=>g[0]===n[0])===a),environment:t.environment,argv:z(r,t).args,cwd:r.image.cwd,runtime:r.locations.get(r.image.runtime).path,timeoutMs:Math.min(i.timeoutMs,t.limits.timeMs),responseBytes:Math.min(i.responseBytes,t.limits.responseBytes)}:s("producer requires declared parent port")}d(C,"parentExecution");function j(r,t){const i=B.get(r);return i?N(i.handoff,t,w).map(n=>C(i,n)):s("unknown prepared host image")}d(j,"plannedParentExecutions");const z=d((r,t)=>{const i=r.locations.get(t.program[0]),n=t.interpreter&&r.locations.get(t.interpreter[0]);if(!n)return{command:i.path,args:[...t.args],cwd:r.image.cwd};const a=r.image.hostLoader;if(!a)return s("fixed loader envelope absent");const l=new URL(a.preload);l.searchParams.set("bytes",String(r.handoff.budget.bytes));const g=Buffer.from(JSON.stringify({format:"native-image-envelope/1",entries:a.entries,declaration:a.declaration,execution:{runtime:r.locations.get(r.image.runtime).path,cwd:r.image.cwd,mounts:r.image.locations.map(m=>({coordinate:m.member,path:m.path,kind:m.kind}))}}));return{command:n.path,args:["--import",l.href,...r.image.preload?["--import",r.locations.get(r.image.preload).path]:[],i.path,...t.kind==="worker"?[r.locations.get(t.entry[0]).path]:[],...t.args],cwd:r.image.cwd,hostEnvelope:g,envelopeBytes:r.handoff.budget.bytes}},"invocation");async function I(r,t,i){const n=B.get(r);if(!n)return s("unknown prepared host image");const{phase:a,signal:l,trace:g}=i;a!=="act"&&s("invocation forbidden during "+a),l?.aborted&&s("interrupted before batch");const m=N(n.handoff,t,w);for(const f of n.handoff.members){const o=n.locations.get(f.coordinate);O(o.path,n.handoff.budget.bytes)!==f.digest&&s("image bytes differ "+f.coordinate)}if(!m.length)return[];const k=Math.min(...m.map(f=>f.limits.slots)),u=new AbortController,v=u.abort.bind(u,void 0);l?.addEventListener("abort",v,{once:!0}),l?.aborted&&v();const x=new Array(m.length);let e=0,c;const M=d(async()=>{for(;!u.signal.aborted;){const f=e++;if(f>=m.length)return;const o=m[f],S=z(n,o),W=o.program[1],E={...n.image.commandPort,timeoutMs:Math.min(n.image.commandPort.timeoutMs,o.limits.timeMs),responseBytes:Math.min(n.image.commandPort.responseBytes,o.limits.responseBytes)},D=d(()=>{for(const b of o.edges){const p=n.locations.get(b.target);if(!p||O(p.path,n.handoff.budget.bytes)!==b.digest)return"unmeasured"}const h=[o.program[0],...o.entry?[o.entry[0]]:[]].filter(b=>n.locations.get(b).kind==="module");return JSON.stringify(h.flatMap(b=>T({...n.snapshot,entry:b},()=>{})))===n.proofs.get(o.id)?"verified":"unmeasured"},"proofFor");g?.({id:o.id,phase:"start"});let P;try{if(i.custody&&(P=await i.custody.open(C(n,o))),!P)return s("native descendant custody missing "+o.id);const h=JSON.parse(Buffer.from(S.hostEnvelope).toString("utf8"));if(h.descendant=P.descendant,!h.descendant)return s("fixed descendant envelope absent "+o.id);const J={...S,hostEnvelope:Buffer.from(JSON.stringify(h))},b=await q({port:E,lot:{identity:o.identity,requests:[new TextDecoder().decode(o.payload)]},phase:a,signal:u.signal,environment:Object.fromEntries(o.environment),host:{admitsDeclaration:d(p=>JSON.stringify(p)===JSON.stringify(E),"admitsDeclaration"),covers:d(p=>p===E.coordinate&&n.handoff.bindings.find(y=>y.id===o.id).places.includes(n.handoff.place),"covers"),verifies:d(p=>n.handoff.members.some(y=>y.digest===p&&O(n.locations.get(y.coordinate).path,n.handoff.budget.bytes)===p),"verifies"),resolve:d(()=>J,"resolve"),loaderClosure:d((p,y)=>JSON.stringify(y)===JSON.stringify(J)?D():"unmeasured","loaderClosure")},accepts:d((p,y)=>y===0&&R(p),"accepts")});P?.assertClosed(),x[f]={id:o.id,identity:o.identity,responses:b.members}}catch(h){throw c===void 0&&(c=h),u.abort(),h}finally{await P?.close(),g?.({id:o.id,phase:"end"})}}},"work");try{const f=await Promise.allSettled(Array.from({length:Math.min(k,m.length)},M));if(c!==void 0)throw c;const o=f.find(S=>S.status==="rejected");if(o?.status==="rejected")throw o.reason;return(u.signal.aborted||x.some(S=>S===void 0)||x.filter(Boolean).length!==m.length)&&s("interrupted/incomplete batch"),x}finally{l?.removeEventListener("abort",v)}}d(I,"executeJobs");export{I as executeJobs,$ as plannedJobs,j as plannedParentExecutions,Z as prepareNodeImage};
@@ -1,159 +1 @@
1
- const refuse = (why) => { throw Error('REFUSE·native descendant ' + why); };
2
- export function nodeLaunch(args) {
3
- if (!Array.isArray(args) || args.some(s => typeof s !== 'string' || s.includes('\0')))
4
- refuse('argv invalid');
5
- let mode = 'commonjs', evalText, entry, test = false;
6
- const imports = [];
7
- for (let i = 0; i < args.length; i++) {
8
- const arg = args[i];
9
- if (arg === '--') {
10
- entry = args[++i];
11
- break;
12
- }
13
- if (arg === '--input-type=module') {
14
- mode = 'module';
15
- continue;
16
- }
17
- if (arg === '--input-type=commonjs') {
18
- mode = 'commonjs';
19
- continue;
20
- }
21
- if (arg === '--input-type') {
22
- const value = args[++i];
23
- if (value !== 'module' && value !== 'commonjs')
24
- refuse('input type unsupported');
25
- mode = value;
26
- continue;
27
- }
28
- if (arg === '-e' || arg === '--eval') {
29
- if (evalText !== undefined)
30
- refuse('eval ambiguous');
31
- evalText = args[++i];
32
- if (evalText === undefined)
33
- refuse('eval absent');
34
- continue;
35
- }
36
- if (arg.startsWith('--eval=')) {
37
- if (evalText !== undefined)
38
- refuse('eval ambiguous');
39
- evalText = arg.slice(7);
40
- continue;
41
- }
42
- if (arg === '--import' || arg === '--require' || arg === '-r') {
43
- const value = args[++i];
44
- if (value === undefined)
45
- refuse('preload absent');
46
- imports.push(value);
47
- continue;
48
- }
49
- if (arg.startsWith('--import=') || arg.startsWith('--require=')) {
50
- imports.push(arg.slice(arg.indexOf('=') + 1));
51
- continue;
52
- }
53
- if (arg === '--test') {
54
- test = true;
55
- continue;
56
- }
57
- if (arg.startsWith('--test-') || arg === '--experimental-strip-types' || arg === '--experimental-transform-types')
58
- continue;
59
- if (arg.startsWith('-'))
60
- refuse('option unsupported ' + arg);
61
- if (evalText !== undefined)
62
- break;
63
- entry = arg;
64
- break;
65
- }
66
- if (evalText !== undefined) {
67
- if (entry !== undefined)
68
- refuse('eval plus executable file');
69
- return { kind: 'eval', mode, text: evalText, args: [...args], imports };
70
- }
71
- if (!entry)
72
- refuse(test ? 'implicit test discovery unsupported' : 'executable target absent');
73
- return { kind: 'file', entry, args: [...args], imports, test };
74
- }
75
- /** Pure host glue. Inputs are projections obtained from verified opaque native
76
- * program handles under Root's guard, never accepted from a world proposal.
77
- * Selection names preserve argv; they confer no independent authority. */
78
- import { isAbsolute, resolve } from 'node:path';
79
- import { isSha256 } from "../hash.js";
80
- const programFail = (why) => { throw Error('REFUSE·native launch ' + why); };
81
- const digest = isSha256;
82
- const exactPath = (value) => typeof value === 'string' && isAbsolute(value) && resolve(value) === value;
83
- function graph(program) {
84
- if (!program || typeof program.alias !== 'string' || !program.alias.length || !exactPath(program.interpreter) || !digest(program.interpreterDigest) || !exactPath(program.entry) || !exactPath(program.root) || !Array.isArray(program.members))
85
- programFail('verified program projection absent');
86
- const paths = new Set();
87
- for (const member of program.members) {
88
- if (!member || !exactPath(member.path) || !digest(member.digest) || paths.has(member.path))
89
- programFail('program graph member ambiguous');
90
- paths.add(member.path);
91
- }
92
- if (!paths.has(program.entry))
93
- programFail('program entry not in selected graph');
94
- }
95
- /** Only an exact, unique declared alias selects a native program. No PATH,
96
- * filename heuristics, option rewriting or consumer-specific names occur here. */
97
- export function projectNativeProgramLaunch(programs, program, args, runtime) {
98
- if (!Array.isArray(programs) || typeof program !== 'string' || !program.length || !Array.isArray(args) || args.some(arg => typeof arg !== 'string' || arg.includes('\0')) || !runtime || !exactPath(runtime.path) || !digest(runtime.digest))
99
- programFail('invocation context absent');
100
- const matches = programs.filter(p => p?.alias === program);
101
- if (matches.length !== 1)
102
- programFail(matches.length ? 'program alias ambiguous ' + program : 'program alias undeclared ' + program);
103
- const selected = matches[0];
104
- graph(selected);
105
- if (selected.interpreter !== runtime.path || selected.interpreterDigest !== runtime.digest)
106
- programFail('selected interpreter differs');
107
- return Object.freeze({ interpreter: selected.interpreter, interpreterDigest: selected.interpreterDigest, entry: selected.entry, args: Object.freeze([...args]) });
108
- }
109
- /** Select a package-resolution context only for the exact reached parent member.
110
- * Root must validate the supplied parent digest against actual bytes first.
111
- * Node still performs actual resolution; Root checks the returned target digest
112
- * before handing it back. Merely sharing a path prefix grants no membership. */
113
- export function selectNativeProgramParent(programs, parent) {
114
- if (!Array.isArray(programs) || !parent || !exactPath(parent.path) || !digest(parent.digest))
115
- programFail('parent content context absent');
116
- const matches = programs.filter(p => Array.isArray(p?.members) && p.members.some((m) => m?.path === parent.path && m.digest === parent.digest));
117
- if (matches.length !== 1)
118
- programFail(matches.length ? 'parent graph ambiguous' : 'parent not in selected graph');
119
- const selected = matches[0];
120
- graph(selected);
121
- return Object.freeze({ parent: parent.path, root: selected.root, members: Object.freeze(selected.members.map((member) => Object.freeze({ ...member }))) });
122
- }
123
- import { createHash } from 'node:crypto';
124
- import { pathToFileURL } from 'node:url';
125
- import { canonicalJson } from "./reading.js";
126
- export function retainedNativeEvalMatches(record, actual) {
127
- if (!record || record.kind !== 'derived-executable/1' || record.target?.kind !== 'eval' || !actual || !Array.isArray(actual.argv) || !Array.isArray(actual.rootPrefix) || !exactPath(actual.cwd) || !exactPath(actual.runtime) || !Array.isArray(actual.environment))
128
- return false;
129
- if (actual.rootPrefix.some((arg, i) => actual.argv[i] !== arg) || canonicalJson(actual.argv) !== canonicalJson(record.target.argv) || actual.cwd !== record.target.cwd || actual.cwd !== record.invocation.cwd || actual.runtime !== record.invocation.runtime || canonicalJson(actual.environment) !== canonicalJson(record.invocation.environment) || canonicalJson(actual.argv.slice(actual.rootPrefix.length)) !== canonicalJson(record.invocation.argv))
130
- return false;
131
- let launch;
132
- try {
133
- launch = nodeLaunch(actual.argv);
134
- }
135
- catch {
136
- return false;
137
- }
138
- if (launch.kind !== 'eval' || launch.text !== record.target.text || launch.mode !== record.mode)
139
- return false;
140
- const bytes = Buffer.from(launch.text, 'utf8');
141
- return bytes.toString('utf8') === launch.text && bytes.length === record.byteLength && 'sha256:' + createHash('sha256').update(bytes).digest('hex') === record.digest;
142
- }
143
- /** Exact Node CLI eval origin, not a file-pattern exception. A different URL
144
- * continues through ordinary physical-parent verification and refuses if absent.
145
- * Node's module and CommonJS CLI forms have distinct observed synthetic names. */
146
- export function nativeEvalParent(record, actual) {
147
- if (!retainedNativeEvalMatches(record, actual))
148
- programFail('actual eval differs from Root-retained context');
149
- return Object.freeze({ url: record.mode === 'module' ? pathToFileURL(actual.cwd + '/').href + '[eval1]' : pathToFileURL(resolve(actual.cwd, '[eval]')).href, context: record.identity, digest: record.digest, mode: record.mode });
150
- }
151
- /** Non-authoritative discovery from Node's actual runtime options only. A false
152
- * result confers no permission: physical-parent/load checks remain unchanged.
153
- * Before-fork argv validation and exact retained-record matching are separate. */
154
- export function actualNodeEvalOptions(execArgv) { try {
155
- return nodeLaunch(execArgv).kind === 'eval';
156
- }
157
- catch {
158
- return false;
159
- } }
1
+ var b=Object.defineProperty;var f=(e,t)=>b(e,"name",{value:t,configurable:!0});const u=f(e=>{throw Error("REFUSE\xB7native descendant "+e)},"refuse");function h(e){(!Array.isArray(e)||e.some(o=>typeof o!="string"||o.includes("\0")))&&u("argv invalid");let t="commonjs",i,r,a=!1;const s=[];for(let o=0;o<e.length;o++){const n=e[o];if(n==="--"){r=e[++o];break}if(n==="--input-type=module"){t="module";continue}if(n==="--input-type=commonjs"){t="commonjs";continue}if(n==="--input-type"){const c=e[++o];c!=="module"&&c!=="commonjs"&&u("input type unsupported"),t=c;continue}if(n==="-e"||n==="--eval"){i!==void 0&&u("eval ambiguous"),i=e[++o],i===void 0&&u("eval absent");continue}if(n.startsWith("--eval=")){i!==void 0&&u("eval ambiguous"),i=n.slice(7);continue}if(n==="--import"||n==="--require"||n==="-r"){const c=e[++o];c===void 0&&u("preload absent"),s.push(c);continue}if(n.startsWith("--import=")||n.startsWith("--require=")){s.push(n.slice(n.indexOf("=")+1));continue}if(n==="--test"){a=!0;continue}if(!(n.startsWith("--test-")||n==="--experimental-strip-types"||n==="--experimental-transform-types")){if(n.startsWith("-")&&u("option unsupported "+n),i!==void 0)break;r=n;break}}return i!==void 0?(r!==void 0&&u("eval plus executable file"),{kind:"eval",mode:t,text:i,args:[...e],imports:s}):(r||u(a?"implicit test discovery unsupported":"executable target absent"),{kind:"file",entry:r,args:[...e],imports:s,test:a})}f(h,"nodeLaunch");import{isAbsolute as x,resolve as v}from"node:path";import{isSha256 as A}from"../hash.js";const d=f(e=>{throw Error("REFUSE\xB7native launch "+e)},"programFail"),m=A,p=f(e=>typeof e=="string"&&x(e)&&v(e)===e,"exactPath");function y(e){(!e||typeof e.alias!="string"||!e.alias.length||!p(e.interpreter)||!m(e.interpreterDigest)||!p(e.entry)||!p(e.root)||!Array.isArray(e.members))&&d("verified program projection absent");const t=new Set;for(const i of e.members)(!i||!p(i.path)||!m(i.digest)||t.has(i.path))&&d("program graph member ambiguous"),t.add(i.path);t.has(e.entry)||d("program entry not in selected graph")}f(y,"graph");function P(e,t,i,r){(!Array.isArray(e)||typeof t!="string"||!t.length||!Array.isArray(i)||i.some(o=>typeof o!="string"||o.includes("\0"))||!r||!p(r.path)||!m(r.digest))&&d("invocation context absent");const a=e.filter(o=>o?.alias===t);a.length!==1&&d(a.length?"program alias ambiguous "+t:"program alias undeclared "+t);const s=a[0];return y(s),(s.interpreter!==r.path||s.interpreterDigest!==r.digest)&&d("selected interpreter differs"),Object.freeze({interpreter:s.interpreter,interpreterDigest:s.interpreterDigest,entry:s.entry,args:Object.freeze([...i])})}f(P,"projectNativeProgramLaunch");function z(e,t){(!Array.isArray(e)||!t||!p(t.path)||!m(t.digest))&&d("parent content context absent");const i=e.filter(a=>Array.isArray(a?.members)&&a.members.some(s=>s?.path===t.path&&s.digest===t.digest));i.length!==1&&d(i.length?"parent graph ambiguous":"parent not in selected graph");const r=i[0];return y(r),Object.freeze({parent:t.path,root:r.root,members:Object.freeze(r.members.map(a=>Object.freeze({...a})))})}f(z,"selectNativeProgramParent");import{createHash as j}from"node:crypto";import{pathToFileURL as g}from"node:url";import{canonicalJson as l}from"./reading.js";function w(e,t){if(!e||e.kind!=="derived-executable/1"||e.target?.kind!=="eval"||!t||!Array.isArray(t.argv)||!Array.isArray(t.rootPrefix)||!p(t.cwd)||!p(t.runtime)||!Array.isArray(t.environment)||t.rootPrefix.some((a,s)=>t.argv[s]!==a)||l(t.argv)!==l(e.target.argv)||t.cwd!==e.target.cwd||t.cwd!==e.invocation.cwd||t.runtime!==e.invocation.runtime||l(t.environment)!==l(e.invocation.environment)||l(t.argv.slice(t.rootPrefix.length))!==l(e.invocation.argv))return!1;let i;try{i=h(t.argv)}catch{return!1}if(i.kind!=="eval"||i.text!==e.target.text||i.mode!==e.mode)return!1;const r=Buffer.from(i.text,"utf8");return r.toString("utf8")===i.text&&r.length===e.byteLength&&"sha256:"+j("sha256").update(r).digest("hex")===e.digest}f(w,"retainedNativeEvalMatches");function F(e,t){return w(e,t)||d("actual eval differs from Root-retained context"),Object.freeze({url:e.mode==="module"?g(t.cwd+"/").href+"[eval1]":g(v(t.cwd,"[eval]")).href,context:e.identity,digest:e.digest,mode:e.mode})}f(F,"nativeEvalParent");function L(e){try{return h(e).kind==="eval"}catch{return!1}}f(L,"actualNodeEvalOptions");export{L as actualNodeEvalOptions,F as nativeEvalParent,h as nodeLaunch,P as projectNativeProgramLaunch,w as retainedNativeEvalMatches,z as selectNativeProgramParent};
@@ -1,45 +1 @@
1
- /** Fixed instrument preload. FD3 is an instrument-created execution envelope,
2
- * never world stdin or workerData. It introduces no key or command grant.
3
- */
4
- import { readSync, closeSync } from 'node:fs';
5
- import { realpathSync } from 'node:fs';
6
- import { installDescendantBoundary } from "./descendants.js";
7
- import { installBoundary, installNativeResolutionReuse } from "./loader.js";
8
- const fail = (why) => { throw Error('REFUSE·native preload ' + why); };
9
- const limit = Number(new URL(import.meta.url).searchParams.get('bytes'));
10
- if (!Number.isSafeInteger(limit) || limit < 1)
11
- fail('missing admitted envelope resources');
12
- const header = Buffer.alloc(8);
13
- let read = 0;
14
- while (read < header.length) {
15
- const n = readSync(3, header, read, header.length - read, null);
16
- if (!n)
17
- fail('truncated host frame');
18
- read += n;
19
- }
20
- const size = header.readBigUInt64BE();
21
- if (size > BigInt(limit))
22
- fail('host envelope bytes exceeded');
23
- const raw = Buffer.alloc(Number(size));
24
- read = 0;
25
- while (read < raw.length) {
26
- const n = readSync(3, raw, read, raw.length - read, null);
27
- if (!n)
28
- fail('truncated host envelope');
29
- read += n;
30
- }
31
- if (readSync(3, Buffer.alloc(1), 0, 1, null) !== 0)
32
- fail('host envelope has trailing bytes');
33
- closeSync(3);
34
- const frame = JSON.parse(raw.toString('utf8'));
35
- if (frame.format !== 'native-image-envelope/1' || !Array.isArray(frame.entries) || !frame.entries.includes(realpathSync(process.argv[1])))
36
- fail('entry outside host image');
37
- if (frame.descendant)
38
- installDescendantBoundary(frame.descendant);
39
- installNativeResolutionReuse(frame.declaration);
40
- if (frame.execution) {
41
- const facade = Object.freeze({ ...frame.execution, preload: frame.descendant?.custodian?.preload, mounts: Object.freeze(frame.execution.mounts.map(mount => Object.freeze({ ...mount }))) });
42
- Object.defineProperty(globalThis, Symbol.for('bound.native.execution@1'), { value: facade, writable: false, configurable: false });
43
- }
44
- const boundary = installBoundary({ ...frame.declaration, entry: realpathSync(process.argv[1]) });
45
- process.once('beforeExit', () => boundary.assertClosed());
1
+ var u=Object.defineProperty;var c=(e,s)=>u(e,"name",{value:s,configurable:!0});import{readSync as i,closeSync as m}from"node:fs";import{realpathSync as f}from"node:fs";import{installDescendantBoundary as p}from"./descendants.js";import{installBoundary as b,installNativeResolutionReuse as g}from"./loader.js";const r=c(e=>{throw Error("REFUSE\xB7native preload "+e)},"fail"),l=Number(new URL(import.meta.url).searchParams.get("bytes"));(!Number.isSafeInteger(l)||l<1)&&r("missing admitted envelope resources");const o=Buffer.alloc(8);let n=0;for(;n<o.length;){const e=i(3,o,n,o.length-n,null);e||r("truncated host frame"),n+=e}const d=o.readBigUInt64BE();d>BigInt(l)&&r("host envelope bytes exceeded");const a=Buffer.alloc(Number(d));for(n=0;n<a.length;){const e=i(3,a,n,a.length-n,null);e||r("truncated host envelope"),n+=e}i(3,Buffer.alloc(1),0,1,null)!==0&&r("host envelope has trailing bytes"),m(3);const t=JSON.parse(a.toString("utf8"));if((t.format!=="native-image-envelope/1"||!Array.isArray(t.entries)||!t.entries.includes(f(process.argv[1])))&&r("entry outside host image"),t.descendant&&p(t.descendant),g(t.declaration),t.execution){const e=Object.freeze({...t.execution,preload:t.descendant?.custodian?.preload,mounts:Object.freeze(t.execution.mounts.map(s=>Object.freeze({...s})))});Object.defineProperty(globalThis,Symbol.for("bound.native.execution@1"),{value:e,writable:!1,configurable:!1})}const h=b({...t.declaration,entry:f(process.argv[1])});process.once("beforeExit",()=>h.assertClosed());