@lapxo/bound 0.2.3 → 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.
- package/CITATION.cff +19 -0
- package/TARGET.bound +95 -39
- package/dist/cli/accept.js +72 -558
- package/dist/cli/act-result.js +3 -103
- package/dist/cli/args.js +3 -44
- package/dist/cli/custodian.js +2 -29
- package/dist/cli/host.js +4 -32
- package/dist/cli/names.js +1 -12
- package/dist/cli/native-descendant.js +1 -19
- package/dist/cli/native.js +3 -60
- package/dist/cli/observe.js +1 -13
- package/dist/cli/owner.js +3 -139
- package/dist/cli/pass.js +21 -321
- package/dist/cli/place.js +6 -281
- package/dist/cli/release-result.js +3 -80
- package/dist/cli/retained-judgment.js +1 -25
- package/dist/cli/standing-result.js +4 -21
- package/dist/cli/takes.js +10 -111
- package/dist/cli/verb.d.ts +1 -2
- package/dist/cli/verb.js +83 -683
- package/dist/engine/computation.js +2 -0
- package/dist/engine/conformance.js +4 -0
- package/dist/engine/encoding.js +1 -2
- package/dist/engine/index.d.ts +1 -13
- package/dist/engine/index.js +2 -11
- package/dist/engine/object.js +1 -38
- package/dist/engine/ports.js +2 -103
- package/dist/fold/admission-history.js +1 -17
- package/dist/fold/bootstrap-anchor.js +1 -28
- package/dist/fold/ceilings.js +1 -142
- package/dist/fold/claims.js +2 -131
- package/dist/fold/closed.js +24 -234
- package/dist/fold/configures.js +1 -25
- package/dist/fold/digests.js +10 -226
- package/dist/fold/evidence.js +1 -22
- package/dist/fold/fold-worker.js +1 -13
- package/dist/fold/kept.js +12 -173
- package/dist/fold/keys.js +3 -91
- package/dist/fold/laid.js +3 -90
- package/dist/fold/nos.js +1 -48
- package/dist/fold/object.js +1 -2
- package/dist/fold/observed.js +27 -534
- package/dist/fold/opened.js +1 -33
- package/dist/fold/own.js +3 -217
- package/dist/fold/paid.js +1 -92
- package/dist/fold/place-inputs.js +1 -70
- package/dist/fold/places.js +3 -100
- package/dist/fold/rank.js +1 -9
- package/dist/fold/reach.js +1 -83
- package/dist/fold/readers.js +6 -142
- package/dist/fold/receipts.js +1 -47
- package/dist/fold/region-declarations.js +1 -13
- package/dist/fold/region.js +8 -286
- package/dist/fold/release-policy.js +1 -101
- package/dist/fold/resolved.js +6 -145
- package/dist/fold/roles.js +2 -59
- package/dist/fold/second.js +4 -71
- package/dist/fold/shards.js +12 -100
- package/dist/fold/signed.js +3 -81
- package/dist/fold/signers.js +1 -54
- package/dist/fold/stranger.js +6 -24
- package/dist/fold/views.js +1 -66
- package/dist/fold/wire.js +1 -46
- package/dist/fold/zoom.js +3 -81
- package/dist/host/act-cost.js +1 -25
- package/dist/host/adapters/keys/ed25519.js +1 -30
- package/dist/host/adapters/modules/javascript.js +1 -50
- package/dist/host/adapters/transport/http.js +1 -28
- package/dist/host/admitted-place.js +1 -63
- package/dist/host/archive.js +1 -152
- package/dist/host/call-context.js +1 -0
- package/dist/host/capsule-process.js +2 -61
- package/dist/host/capsule.js +9 -168
- package/dist/host/cell-receipts.js +12 -128
- package/dist/host/commit-result.js +1 -0
- package/dist/host/content-needed.js +1 -8
- package/dist/host/content-store.js +1 -31
- package/dist/host/contextual-place.js +2 -77
- package/dist/host/digest.js +2 -15
- package/dist/host/hash.js +1 -9
- package/dist/host/host-controls.js +1 -0
- package/dist/host/in-process-act.js +3 -0
- package/dist/host/in-process-context.js +3 -0
- package/dist/host/in-process-root.js +6 -0
- package/dist/host/in-process.js +4 -0
- package/dist/host/index.d.ts +1 -0
- package/dist/host/index.js +1 -0
- package/dist/host/io.js +1 -11
- package/dist/host/lifetime.js +1 -79
- package/dist/host/located.js +6 -105
- package/dist/host/native/bounded-file.js +1 -32
- package/dist/host/native/command.js +1 -91
- package/dist/host/native/control-bridge-worker.js +2 -88
- package/dist/host/native/control-bridge.js +1 -110
- package/dist/host/native/control-selection.js +1 -32
- package/dist/host/native/custody.js +1 -91
- package/dist/host/native/deadline.js +1 -28
- package/dist/host/native/descendants.js +1 -528
- package/dist/host/native/generated-custodian.js +5 -267
- package/dist/host/native/generated.js +1 -379
- package/dist/host/native/image.js +1 -45
- package/dist/host/native/jobs.js +2 -148
- package/dist/host/native/loader.js +1 -269
- package/dist/host/native/materialize.js +1 -175
- package/dist/host/native/module-closure.js +1 -130
- package/dist/host/native/module-delivery.d.ts +1 -62
- package/dist/host/native/module-delivery.js +1 -151
- package/dist/host/native/module-syntax.js +1 -69
- package/dist/host/native/native-binary.js +1 -115
- package/dist/host/native/native-program.js +1 -72
- package/dist/host/native/node-jobs.js +3 -187
- package/dist/host/native/node-launch.js +1 -159
- package/dist/host/native/preload.js +1 -45
- package/dist/host/native/reading.js +1 -249
- package/dist/host/native/receipt-environment.js +1 -41
- package/dist/host/native/references.js +1 -30
- package/dist/host/native/root.js +1 -37
- package/dist/host/native/route.js +1 -216
- package/dist/host/native/runtime.js +1 -9
- package/dist/host/native-reader-context.js +1 -8
- package/dist/host/native-receiver.js +1 -0
- package/dist/host/objects.js +1 -38
- package/dist/host/order.js +1 -2
- package/dist/host/place-act-transaction.js +4 -0
- package/dist/host/place-clock-selection.js +5 -124
- package/dist/host/ports/ingress.js +2 -57
- package/dist/host/ports/local-act.js +5 -172
- package/dist/host/ports/place-act.js +1 -169
- package/dist/host/ports/publication.js +1 -56
- package/dist/host/ports/signing.js +1 -74
- package/dist/host/ports/store.js +1 -18
- package/dist/host/ports/transport.js +1 -48
- package/dist/host/process-lifetime.js +1 -17
- package/dist/host/provide.js +1 -183
- package/dist/host/read-only.js +1 -9
- package/dist/host/reading-closures.js +7 -227
- package/dist/host/reading-context.js +1 -53
- package/dist/host/reading-identity-types.js +0 -0
- package/dist/host/reading-identity.js +3 -0
- package/dist/host/reading-preparation.js +6 -0
- package/dist/host/reference-authenticated.d.ts +1 -40
- package/dist/host/reference-authenticated.js +3 -100
- package/dist/host/reference-contracts.js +1 -6
- package/dist/host/reference-export.js +6 -81
- package/dist/host/reference-native-api.d.ts +1 -3
- package/dist/host/reference-native-api.js +1 -3
- package/dist/host/reference-native.js +1 -74
- package/dist/host/reference-profile.js +1 -63
- package/dist/host/reference-standing.js +2 -18
- package/dist/host/reference.js +1 -24
- package/dist/host/refusals.js +2 -43
- package/dist/host/release.js +4 -256
- package/dist/host/root-clock-source.js +1 -305
- package/dist/host/selected-capsules.js +1 -50
- package/dist/host/selected-topos.js +1 -80
- package/dist/host/signature-era.js +1 -0
- package/dist/host/signing.js +2 -48
- package/dist/host/source-content.js +2 -110
- package/dist/host/standing-carrier.js +1 -0
- package/dist/host/standing-projection.js +1 -0
- package/dist/host/timing.js +1 -7
- package/dist/host/walk.js +20 -193
- package/dist/judge/late.js +1 -33
- package/dist/judge/take.js +2 -75
- package/dist/judge/widening.js +1 -25
- package/dist/land/act.js +8 -302
- package/dist/land/alias.js +1 -41
- package/dist/land/held.js +1 -23
- package/dist/land/inert.js +1 -33
- package/dist/land/leaving.js +1 -55
- package/dist/land/ledger.js +7 -188
- package/dist/land/owned.js +4 -66
- package/dist/land/sign.js +1 -53
- package/dist/land/standing-pin.js +1 -49
- package/dist/land/vouched.js +1 -112
- package/dist/land/withdraw.js +1 -24
- package/dist/observe/files.js +1 -88
- package/dist/observe/identity.js +1 -61
- package/dist/observe/match.js +1 -8
- package/dist/observe/regions.js +7 -306
- package/dist/observe/run.js +2 -40
- package/dist/observe/runner.js +4 -93
- package/dist/public-types.d.ts +1114 -0
- package/dist/render/capsule.js +1 -30
- package/dist/render/field.js +1 -40
- package/dist/render/names.js +1 -4
- package/dist/render/open.js +1 -61
- package/dist/render/page.js +1 -7
- package/dist/render/receipts.js +1 -47
- package/dist/render/shape.js +1 -74
- package/dist/render/target.js +4 -52
- package/dist/render/view.js +7 -197
- package/dist/vendor/50086958553b9376d600583f7dff354196bfeb41170fc6d1482ca7bea7c493e2.LICENSE +21 -0
- package/dist/vendor/b3e938d28f88a1851af303a40c749e12ebd5a686daac4f0b343b5cdd2e040419.LICENSE +21 -0
- package/dist/vendor/bundle.json +1 -0
- package/dist/vendor/library11.js +1 -0
- package/dist/vendor/object-provider.js +42 -0
- package/dist/vendor/runtime.js +38 -0
- package/dist/vendor/sources.json +1 -0
- package/dist/wasm/adapter.d.ts +1 -51
- package/dist/wasm/adapter.js +1 -180
- package/dist/wasm/node-worker.js +1 -13
- package/dist/wasm/object.js +1 -76
- package/dist/wasm/worker.js +1 -7
- package/docs/contracts/closure-delivery.md +1 -1
- package/docs/contracts/closure-delivery.publication.json +1 -1
- package/docs/contracts/conformance.json +142 -0
- package/docs/contracts/determinism.bound +9 -0
- package/docs/contracts/engine-object-projection.publication.json +1 -1
- package/docs/contracts/engine.md +21 -1
- package/docs/contracts/native-host.md +21 -0
- package/docs/contracts/native-host.publication.json +25 -0
- package/docs/contracts/native-publication.inventory.json +3 -1
- package/docs/contracts/optional-wasm-adapter.publication.json +1 -1
- package/docs/contracts/publication.inventory.json +29 -0
- package/docs/contracts/reading-identity.md +37 -0
- package/docs/contracts/reading-identity.publication.json +25 -0
- package/docs/contracts/refusals.bound +51 -0
- package/docs/contracts/refusals.md +18 -3
- package/docs/contracts/refusals.publication.json +2 -2
- package/docs/contracts/views.md +8 -0
- package/docs/guide.md +10 -0
- package/docs/reference.md +40 -0
- package/docs/why.md +109 -0
- package/package.json +37 -18
- package/receipts.bound +11675 -9725
- package/samples/native-host/no.json +10 -0
- package/samples/native-host/yes.json +20 -0
- package/samples/reading-identity/no.json +20 -0
- package/samples/reading-identity/yes.json +46 -0
- package/vectors/native/native-host.vector.json +62 -0
- package/vectors/native/reading-identity.vector.json +101 -0
- package/vectors/native/refusals.vector.json +104 -0
- package/vendor/syntax/LICENSE.md +7 -0
- package/vendor/syntax/parser.js +1 -0
- package/dist/engine/object.d.ts +0 -17
- package/dist/engine/ports.d.ts +0 -32
- package/dist/host/native/module-closure.d.ts +0 -35
- package/dist/host/reference-export.d.ts +0 -33
- package/dist/host/reference-native.d.ts +0 -30
- package/dist/host/reference-profile.d.ts +0 -23
- package/dist/host/refusals.d.ts +0 -14
|
@@ -1,249 +1 @@
|
|
|
1
|
-
import { sha256 as hash } from "../hash.js";
|
|
2
|
-
/** Host profile authentication and bounded executable input handoff. */
|
|
3
|
-
import { extname } from 'node:path';
|
|
4
|
-
import { gunzipSync } from 'node:zlib';
|
|
5
|
-
import { readBoundedFile } from "./bounded-file.js";
|
|
6
|
-
import { members as archiveMembers } from "../archive.js";
|
|
7
|
-
import { installBoundary } from "./loader.js";
|
|
8
|
-
import { nativeRootJobCustody } from "./custody.js";
|
|
9
|
-
import { mountNativeImage } from "./image.js";
|
|
10
|
-
import { createHash } from 'node:crypto';
|
|
11
|
-
import { canonical } from '@lapxo/topos/wire';
|
|
12
|
-
import { parsedLine as parse } from "../../fold/claims.js";
|
|
13
|
-
import { answer } from '@lapxo/topos/contract';
|
|
14
|
-
import { authorityFor } from "../../fold/signers.js";
|
|
15
|
-
// Public SDK eligibility implementation; no private SDK module import.
|
|
16
|
-
import { authorityAtEpoch } from '@lapxo/topos/wire';
|
|
17
|
-
import { scheduleDeadline } from "./deadline.js";
|
|
18
|
-
import { prepareNodeImage, plannedJobs, executeJobs } from "./node-jobs.js";
|
|
19
|
-
const fail = (why) => { throw Error('REFUSE·native reading ' + why); };
|
|
20
|
-
export const canonicalJson = (value) => JSON.stringify(order(value));
|
|
21
|
-
const order = (value) => Array.isArray(value) ? value.map(order) : value !== null && typeof value === 'object' ? Object.fromEntries(Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([k, v]) => [k, order(v)])) : value;
|
|
22
|
-
const prepared = new WeakMap();
|
|
23
|
-
export function authenticateSignedPort(root, coordinate) {
|
|
24
|
-
if (!root || !Number.isSafeInteger(root.epoch) || root.epoch < 0 || !Number.isSafeInteger(root.budget?.lines) || root.budget.lines < 1 || !Number.isSafeInteger(root.budget.bytes) || root.budget.bytes < 1)
|
|
25
|
-
fail('missing authority/budget');
|
|
26
|
-
const retained = [...new Set([...root.history, ...root.live])];
|
|
27
|
-
if (retained.length > root.budget.lines)
|
|
28
|
-
fail('authority line budget');
|
|
29
|
-
let bytes = 0;
|
|
30
|
-
for (const line of retained) {
|
|
31
|
-
if (typeof line !== 'string' || (bytes += Buffer.byteLength(line)) > root.budget.bytes)
|
|
32
|
-
fail('authority byte budget');
|
|
33
|
-
}
|
|
34
|
-
if (!/^port\/[^\s]+$/.test(coordinate))
|
|
35
|
-
fail('selection is not a command port');
|
|
36
|
-
const rows = root.live.filter(line => { const got = parse(line); return got.kind === 'fact' && got.value.fields.scope === coordinate; });
|
|
37
|
-
if (rows.length !== 1)
|
|
38
|
-
fail('missing/ambiguous signed declaration ' + coordinate);
|
|
39
|
-
const line = rows[0];
|
|
40
|
-
if (!root.history.includes(line))
|
|
41
|
-
fail('port absent from authenticated admission history');
|
|
42
|
-
const got = parse(line);
|
|
43
|
-
if (got.kind !== 'fact')
|
|
44
|
-
return fail('port not a wire record');
|
|
45
|
-
const f = got.value.fields;
|
|
46
|
-
if (f.role !== 'writes' || f.form !== 'alphabet' || f.measure !== 'text' || f.value !== 'lock' || typeof f.about !== 'string')
|
|
47
|
-
fail('unknown port projection ' + coordinate);
|
|
48
|
-
const auth = authorityFor(root.history, root.signer, root.eras), verdict = auth.of(line);
|
|
49
|
-
if (verdict.kind !== 'admitted')
|
|
50
|
-
fail('port signature/coverage ' + verdict.why);
|
|
51
|
-
const signerId = verdict.kind === 'admitted' ? verdict.signer : fail('signature not admitted');
|
|
52
|
-
const signers = auth.admitted.filter(s => s.id === signerId);
|
|
53
|
-
if (signers.length !== 1)
|
|
54
|
-
fail('ambiguous port signer');
|
|
55
|
-
if (root.history.some(line => { const p = parse(line); return p.kind === 'fact' && p.value.fields.epoch !== undefined && (!Number.isSafeInteger(Number(p.value.fields.epoch)) || Number(p.value.fields.epoch) > root.epoch); }))
|
|
56
|
-
fail('authority prefix exceeds current epoch');
|
|
57
|
-
const current = authorityAtEpoch(f, signers[0], root.epoch, coordinate, 'authority');
|
|
58
|
-
if (current.kind !== 'admitted')
|
|
59
|
-
fail('current port authority ' + current.why);
|
|
60
|
-
let value;
|
|
61
|
-
try {
|
|
62
|
-
value = JSON.parse(f.about);
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
return fail('port JSON invalid');
|
|
66
|
-
}
|
|
67
|
-
if (!value || typeof value !== 'object' || Array.isArray(value) || canonicalJson(value) !== f.about)
|
|
68
|
-
fail('port profile invalid/noncanonical');
|
|
69
|
-
return { line, profile: value };
|
|
70
|
-
}
|
|
71
|
-
function selected(root, coordinate) {
|
|
72
|
-
const got = authenticateSignedPort(root, coordinate), profile = got.profile;
|
|
73
|
-
const line = got.line;
|
|
74
|
-
if (!profile.port || !profile.selection || typeof profile.selection !== 'object' || Array.isArray(profile.selection))
|
|
75
|
-
fail('missing native selection');
|
|
76
|
-
if (Object.keys(profile.selection).sort().join(',') !== 'archive,bindings,budget,condition,entry,loaderConfig,loads,members,nativePreloadMembers,preload,reader,runtime')
|
|
77
|
-
fail('unknown native selection field');
|
|
78
|
-
if (Object.keys(profile).sort().join(',') !== 'port,profile,selection' || profile.profile !== 'host-native-reading@1' || profile.port?.coordinate !== coordinate)
|
|
79
|
-
fail('unknown/noncanonical native profile');
|
|
80
|
-
return { line, profile };
|
|
81
|
-
}
|
|
82
|
-
const selections = new WeakMap();
|
|
83
|
-
/** This is the BEFORE-LOAD boundary. It authenticates the actual signed profile
|
|
84
|
-
* and checks current authority; a packet cannot mint the opaque result. */
|
|
85
|
-
function freezeProfile(value) { if (value !== null && typeof value === 'object') {
|
|
86
|
-
for (const child of Object.values(value))
|
|
87
|
-
freezeProfile(child);
|
|
88
|
-
Object.freeze(value);
|
|
89
|
-
} return value; }
|
|
90
|
-
function holdSelection(root, coordinate, selection) { const handle = Object.freeze({ identity: hash(canonicalJson([selection.line, root.epoch])) }); selections.set(handle, { root: { ...root, history: [...root.history], live: [...root.live], eras: [...root.eras], budget: { ...root.budget } }, coordinate, profile: freezeProfile(selection.profile) }); return handle; }
|
|
91
|
-
/** One synchronous authentication supplies both the opaque boundary and its
|
|
92
|
-
* immutable signed profile. Fresh Root checks still run at load and answer. */
|
|
93
|
-
export function authenticateNativeProfile(root, coordinate) { const got = selected(root, coordinate), selection = holdSelection(root, coordinate, got); return Object.freeze({ selection, line: got.line, profile: got.profile }); }
|
|
94
|
-
export function validateSignedNativeProfile(root, coordinate, expected) { const got = selected(root, coordinate); if (canonicalJson(got.profile) !== canonicalJson(expected))
|
|
95
|
-
fail('expected profile differs from signature'); return holdSelection(root, coordinate, got); }
|
|
96
|
-
/** Root supplies an authenticated current standing and its selected exact image.
|
|
97
|
-
* The signature authenticates the ENTIRE profile JSON including its selection;
|
|
98
|
-
* matching resolved selection is checked byte-for-byte, never from world data.
|
|
99
|
-
* The real Root guard constructor remains a host-integration prerequisite. */
|
|
100
|
-
function prepareSignedNativeReading(root, coordinate, resolved) {
|
|
101
|
-
const selection = selected(root, coordinate);
|
|
102
|
-
if (canonicalJson(selection.profile) !== canonicalJson(resolved.profile))
|
|
103
|
-
fail('resolved image/profile differs from signed selection');
|
|
104
|
-
if (!(resolved.archive instanceof Uint8Array) || resolved.archive.byteLength > resolved.handoff.budget.bytes)
|
|
105
|
-
fail('archive exceeds declared input budget');
|
|
106
|
-
let entries;
|
|
107
|
-
try {
|
|
108
|
-
gunzipSync(resolved.archive, { maxOutputLength: resolved.handoff.budget.bytes });
|
|
109
|
-
entries = archiveMembers(resolved.archive);
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
return fail('native implementation archive invalid');
|
|
113
|
-
}
|
|
114
|
-
const entriesAt = entries.filter(e => e.name === resolved.profile.selection.entry);
|
|
115
|
-
if (entriesAt.length !== 1 || 'sha256:' + createHash('sha256').update(entriesAt[0].bytes).digest('hex') !== resolved.profile.port.implementation)
|
|
116
|
-
fail('archive native entry differs from implementation');
|
|
117
|
-
const computedSelection = { archive: 'sha256:' + createHash('sha256').update(resolved.archive).digest('hex'), entry: resolved.profile.selection.entry, reader: resolved.profile.selection.reader, loaderConfig: resolved.profile.selection.loaderConfig, runtime: resolved.image.runtime, preload: resolved.image.preload ?? null, nativePreloadMembers: resolved.image.nativePreloadMembers, condition: resolved.image.condition, budget: resolved.handoff.budget, members: resolved.handoff.members.map(({ coordinate, digest }) => ({ coordinate, digest })), bindings: resolved.handoff.bindings, loads: resolved.handoff.loads };
|
|
118
|
-
if (canonicalJson(computedSelection) !== canonicalJson(resolved.profile.selection))
|
|
119
|
-
fail('resolved host bindings differ from signed selection');
|
|
120
|
-
if (resolved.profile.port.implementation !== resolved.handoff.members.find(m => m.coordinate === resolved.profile.selection.entry)?.digest)
|
|
121
|
-
fail('native implementation differs from handed member');
|
|
122
|
-
if (resolved.handoff.bindings.some(b => b.limits.slots !== resolved.handoff.bindings[0].limits.slots))
|
|
123
|
-
fail('native bindings need one declared parent slots resource');
|
|
124
|
-
if (!Number.isSafeInteger(resolved.profile.port.timeoutMs) || resolved.profile.port.timeoutMs < 1 || !Number.isSafeInteger(resolved.profile.port.responseBytes) || resolved.profile.port.responseBytes < 1)
|
|
125
|
-
fail('missing parent time/bytes');
|
|
126
|
-
const declared = resolved.profile.port;
|
|
127
|
-
if (Object.keys(declared).sort().join(',') !== 'closure,coordinate,environment,implementation,responseBytes,stderr,timeoutMs' || declared.stderr !== 'reject' || new Set(declared.closure).size !== declared.closure.length || canonicalJson([...declared.closure].sort()) !== canonicalJson([...new Set(resolved.handoff.members.map(m => m.digest))].sort()) || resolved.handoff.bindings.some(b => canonicalJson(b.environment.map(([name]) => name).sort()) !== canonicalJson([...declared.environment].sort())))
|
|
128
|
-
fail('command resource/environment/closure projection differs');
|
|
129
|
-
const authorityIdentity = hash(canonicalJson([root.signer.id, root.signer.publicKey, root.eras, root.epoch, root.history, root.live]));
|
|
130
|
-
const contextualHandoff = { ...resolved.handoff, authoritySnapshot: authorityIdentity, policy: hash(canonicalJson([resolved.handoff.policy, selection.line, authorityIdentity])) };
|
|
131
|
-
const image = prepareNodeImage(contextualHandoff, { ...resolved.image, commandPort: declared }), handle = Object.freeze({ identity: hash(canonicalJson([selection.line, root.epoch, image.identity])) });
|
|
132
|
-
prepared.set(handle, { root: { ...root, history: [...root.history], live: [...root.live], eras: [...root.eras], budget: { ...root.budget } }, coordinate, profile: selection.profile, image, module: Object.freeze({ ...resolved.module }) });
|
|
133
|
-
return handle;
|
|
134
|
-
}
|
|
135
|
-
/** Fixed instrument loader, never a callback supplied by module/request/profile.
|
|
136
|
-
* Root's REAL await-safe lease must cover verification, load and completion.
|
|
137
|
-
* The handoff image is verified before the fixed loader receives an entry. */
|
|
138
|
-
export async function loadSignedNativeReading(selection, resolved, guard) {
|
|
139
|
-
const held = selections.get(selection);
|
|
140
|
-
if (!held)
|
|
141
|
-
return fail('unknown pre-load selection');
|
|
142
|
-
return guard.withCurrent(async (current) => {
|
|
143
|
-
const fresh = selected(current, held.coordinate);
|
|
144
|
-
if (current.epoch !== held.root.epoch || canonicalJson(fresh.profile) !== canonicalJson(held.profile) || canonicalJson(current.history) !== canonicalJson(held.root.history))
|
|
145
|
-
fail('authority changed before load');
|
|
146
|
-
// Validate the exact entire image/profile FIRST, without importing reader code.
|
|
147
|
-
prepareSignedNativeReading(current, held.coordinate, { ...resolved, module: {} });
|
|
148
|
-
const reader = resolved.image.locations.find(l => l.member === held.profile.selection.reader), config = resolved.handoff.members.find(m => m.coordinate === held.profile.selection.loaderConfig), location = resolved.image.locations.find(l => l.member === held.profile.selection.loaderConfig);
|
|
149
|
-
if (!reader || reader.kind !== 'module' || !config || !location || !held.profile.selection.nativePreloadMembers.includes(config.coordinate))
|
|
150
|
-
return fail('reader/config not selected');
|
|
151
|
-
const raw = readBoundedFile(location.path, resolved.handoff.budget.bytes, held.profile.selection.loaderConfig);
|
|
152
|
-
if (hash(raw.toString('utf8')) !== config.digest)
|
|
153
|
-
fail('loader configuration changed');
|
|
154
|
-
let declared;
|
|
155
|
-
try {
|
|
156
|
-
declared = JSON.parse(raw.toString('utf8'));
|
|
157
|
-
}
|
|
158
|
-
catch {
|
|
159
|
-
return fail('loader configuration invalid');
|
|
160
|
-
}
|
|
161
|
-
const logical = declared;
|
|
162
|
-
if (logical.platform !== resolved.image.condition)
|
|
163
|
-
fail('selected runtime condition differs from logical platform');
|
|
164
|
-
if (!Array.isArray(logical.members) || logical.members.some(m => resolved.handoff.members.find(member => member.coordinate === m.coordinate)?.digest !== m.digest))
|
|
165
|
-
fail('loader target not covered by exact signed image');
|
|
166
|
-
const mounted = mountNativeImage(logical, resolved.image.locations.filter(location => logical.members.some(member => member.coordinate === location.member)).map(location => ({ coordinate: location.member, path: location.path })), held.profile.selection.reader, resolved.handoff.budget);
|
|
167
|
-
const boundary = installBoundary(mounted.declaration);
|
|
168
|
-
try {
|
|
169
|
-
const module = await boundary.loadEntry();
|
|
170
|
-
boundary.assertClosed();
|
|
171
|
-
const ready = prepareSignedNativeReading(current, held.coordinate, { ...resolved, image: { ...resolved.image, hostLoader: { ...mounted, preload: new URL('./preload' + extname(new URL(import.meta.url).pathname), import.meta.url).href } }, module });
|
|
172
|
-
prepared.get(ready).loader = mounted.declaration;
|
|
173
|
-
prepared.get(ready).custody = resolved.custody ?? nativeRootJobCustody(current, resolved.profile, resolved.handoff, resolved.image, logical);
|
|
174
|
-
return ready;
|
|
175
|
-
}
|
|
176
|
-
finally {
|
|
177
|
-
boundary.close();
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
export async function answerNativeReading(handle, requests, self, options) {
|
|
182
|
-
const held = prepared.get(handle);
|
|
183
|
-
if (!held)
|
|
184
|
-
return fail('unknown instrument selection');
|
|
185
|
-
if (options.phase !== 'act')
|
|
186
|
-
fail('effects forbidden during ' + options.phase);
|
|
187
|
-
if (options.signal?.aborted)
|
|
188
|
-
fail('interrupted before wrapper');
|
|
189
|
-
const deadline = process.hrtime.bigint() + BigInt(held.profile.port.timeoutMs) * 1000000n, controller = new AbortController(), abort = controller.abort.bind(controller, undefined), cancel = scheduleDeadline(deadline, abort);
|
|
190
|
-
options.signal?.addEventListener('abort', abort, { once: true });
|
|
191
|
-
try {
|
|
192
|
-
return await options.guard.withCurrent(async (current) => {
|
|
193
|
-
const fresh = selected(current, held.coordinate);
|
|
194
|
-
if (canonicalJson(fresh.profile) !== canonicalJson(held.profile) || current.epoch !== held.root.epoch || hash(canonicalJson(current.history)) !== hash(canonicalJson(held.root.history)))
|
|
195
|
-
fail('authority changed since preparation');
|
|
196
|
-
if (!held.loader)
|
|
197
|
-
return fail('reader not loaded by fixed host boundary');
|
|
198
|
-
const boundary = installBoundary(held.loader);
|
|
199
|
-
try {
|
|
200
|
-
const frames = requests.map(request => { let asked; if (request.verb === 'read' && held.module.commands) {
|
|
201
|
-
const extraction = answer({ receipt: a => { asked = a; return []; } }, request, self);
|
|
202
|
-
if (extraction.kind !== 'fact' || !asked)
|
|
203
|
-
fail('Asked extraction refused');
|
|
204
|
-
} const jobs = asked ? held.module.commands(asked) : []; return { request, asked, jobs }; });
|
|
205
|
-
const jobs = frames.flatMap(f => f.jobs), frame = new TextEncoder().encode(JSON.stringify(jobs)), wanted = plannedJobs(held.image, frame), observations = jobs.length ? await executeJobs(held.image, frame, { phase: 'act', signal: controller.signal, custody: held.custody }) : [];
|
|
206
|
-
if (observations.length !== wanted.length || observations.some((got, i) => got.id !== wanted[i].id || got.identity !== wanted[i].identity || got.responses.length !== 1))
|
|
207
|
-
fail('capture identity/count differs');
|
|
208
|
-
const rows = new Map(observations.map(got => [got.id, got]));
|
|
209
|
-
if (rows.size !== observations.length)
|
|
210
|
-
fail('duplicate capture');
|
|
211
|
-
// Capture text is witness provenance, not a new conceptual origin. Actual
|
|
212
|
-
// Topos answer performs its normal handed(reads,lines) projection both times.
|
|
213
|
-
const results = frames.map(({ request, jobs }) => { const captures = jobs.map(job => { const got = rows.get(job.id); if (!got)
|
|
214
|
-
return fail('missing capture ' + job.id); return canonical({ scope: 'command/capture/' + job.id, shape: 'same', role: 'reads', form: 'alphabet', measure: 'text', value: 'lock', by: 'host', at: 'witness:' + got.identity, about: JSON.stringify({ identity: got.identity, responses: got.responses }) }); }); return answer(held.module, { ...request, lines: [...(request.lines ?? []), ...captures] }, self); });
|
|
215
|
-
if (results.length !== requests.length)
|
|
216
|
-
return fail('incomplete pure response');
|
|
217
|
-
if (controller.signal.aborted || process.hrtime.bigint() >= deadline)
|
|
218
|
-
fail('interrupted/timeout wrapper');
|
|
219
|
-
if (Buffer.byteLength(JSON.stringify(results)) > held.profile.port.responseBytes)
|
|
220
|
-
fail('parent response bytes exceeded');
|
|
221
|
-
boundary.assertClosed();
|
|
222
|
-
return results;
|
|
223
|
-
}
|
|
224
|
-
finally {
|
|
225
|
-
boundary.close();
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
finally {
|
|
230
|
-
cancel();
|
|
231
|
-
options.signal?.removeEventListener('abort', abort);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
/** Executable resources belong to the currently authenticated parent command
|
|
235
|
-
* declaration, not to the separate authority-history/clock parsing budget. */
|
|
236
|
-
export function nativeParentInputBytes(root, parent) {
|
|
237
|
-
const selected = authenticateSignedPort(root, parent.port).profile;
|
|
238
|
-
const bytes = selected?.selection?.budget?.bytes;
|
|
239
|
-
if (selected?.profile !== 'host-native-reading@1' || !Number.isSafeInteger(bytes) || bytes < 1)
|
|
240
|
-
fail('parent executable input resource absent');
|
|
241
|
-
return bytes;
|
|
242
|
-
}
|
|
243
|
-
/** Exact schema field names, shared by the host's selected native formats. */
|
|
244
|
-
export function fieldNames(value) { return Object.keys(value).sort().join(','); }
|
|
245
|
-
/** Retain each verifier's private map and return a fresh canonical projection. */
|
|
246
|
-
export function retainedProjection(verified, fail) {
|
|
247
|
-
return handle => { const p = verified.get(handle); if (!p)
|
|
248
|
-
return fail('unknown verified selection'); return JSON.parse(canonicalJson(p)); };
|
|
249
|
-
}
|
|
1
|
+
var _=Object.defineProperty;var p=(e,n)=>_(e,"name",{value:n,configurable:!0});import{sha256 as S}from"../hash.js";import{extname as H}from"node:path";import{gunzipSync as W}from"node:zlib";import{readBoundedFile as D}from"./bounded-file.js";import{members as K}from"../archive.js";import{installBoundary as B}from"./loader.js";import{nativeRootJobCustody as T}from"./custody.js";import{mountNativeImage as $}from"./image.js";import{createHash as E}from"node:crypto";import{library11_canonical as G}from"../../vendor/runtime.js";import{parsedLine as C}from"../../fold/claims.js";import{library2_answer as L}from"../../vendor/runtime.js";import{authorityFor as Q}from"../../fold/signers.js";import{library11_authorityAtEpoch as V}from"../../vendor/runtime.js";import{scheduleDeadline as X}from"./deadline.js";import{prepareNodeImage as Y,plannedJobs as Z,executeJobs as q}from"./node-jobs.js";const r=p(e=>{throw Error("REFUSE\xB7native reading "+e)},"fail"),f=p(e=>JSON.stringify(J(e)),"canonicalJson"),J=p(e=>Array.isArray(e)?e.map(J):e!==null&&typeof e=="object"?Object.fromEntries(Object.entries(e).sort(([n],[t])=>n<t?-1:n>t?1:0).map(([n,t])=>[n,J(t)])):e,"order"),A=new WeakMap;function v(e,n){(!e||!Number.isSafeInteger(e.epoch)||e.epoch<0||!Number.isSafeInteger(e.budget?.lines)||e.budget.lines<1||!Number.isSafeInteger(e.budget.bytes)||e.budget.bytes<1)&&r("missing authority/budget");const t=[...new Set([...e.history,...e.live])];t.length>e.budget.lines&&r("authority line budget");let i=0;for(const a of t)(typeof a!="string"||(i+=Buffer.byteLength(a))>e.budget.bytes)&&r("authority byte budget");/^port\/[^\s]+$/.test(n)||r("selection is not a command port");const o=e.live.filter(a=>{const d=C(a);return d.kind==="fact"&&d.value.fields.scope===n});o.length!==1&&r("missing/ambiguous signed declaration "+n);const h=o[0];e.history.includes(h)||r("port absent from authenticated admission history");const b=C(h);if(b.kind!=="fact")return r("port not a wire record");const s=b.value.fields;(s.role!=="writes"||s.form!=="alphabet"||s.measure!=="text"||s.value!=="lock"||typeof s.about!="string")&&r("unknown port projection "+n);const y=Q(e.history,e.signer,e.eras),g=y.of(h);g.kind!=="admitted"&&r("port signature/coverage "+g.why);const x=g.kind==="admitted"?g.signer:r("signature not admitted"),m=y.admitted.filter(a=>a.id===x);m.length!==1&&r("ambiguous port signer"),e.history.some(a=>{const d=C(a);return d.kind==="fact"&&d.value.fields.epoch!==void 0&&(!Number.isSafeInteger(Number(d.value.fields.epoch))||Number(d.value.fields.epoch)>e.epoch)})&&r("authority prefix exceeds current epoch");const c=V(s,m[0],e.epoch,n,"authority");c.kind!=="admitted"&&r("current port authority "+c.why);let l;try{l=JSON.parse(s.about)}catch{return r("port JSON invalid")}return(!l||typeof l!="object"||Array.isArray(l)||f(l)!==s.about)&&r("port profile invalid/noncanonical"),{line:h,profile:l}}p(v,"authenticateSignedPort");function N(e,n){const t=v(e,n),i=t.profile,o=t.line;return(!i.port||!i.selection||typeof i.selection!="object"||Array.isArray(i.selection))&&r("missing native selection"),Object.keys(i.selection).sort().join(",")!=="archive,bindings,budget,condition,entry,loaderConfig,loads,members,nativePreloadMembers,preload,reader,runtime"&&r("unknown native selection field"),(Object.keys(i).sort().join(",")!=="port,profile,selection"||i.profile!=="host-native-reading@1"||i.port?.coordinate!==n)&&r("unknown/noncanonical native profile"),{line:o,profile:i}}p(N,"selected");const z=new WeakMap;function R(e){if(e!==null&&typeof e=="object"){for(const n of Object.values(e))R(n);Object.freeze(e)}return e}p(R,"freezeProfile");function U(e,n,t){const i=Object.freeze({identity:S(f([t.line,e.epoch]))});return z.set(i,{root:{...e,history:[...e.history],live:[...e.live],eras:[...e.eras],budget:{...e.budget}},coordinate:n,profile:R(t.profile)}),i}p(U,"holdSelection");function be(e,n){const t=N(e,n),i=U(e,n,t);return Object.freeze({selection:i,line:t.line,profile:t.profile})}p(be,"authenticateNativeProfile");function ye(e,n,t){const i=N(e,n);return f(i.profile)!==f(t)&&r("expected profile differs from signature"),U(e,n,i)}p(ye,"validateSignedNativeProfile");function F(e,n,t){const i=N(e,n);f(i.profile)!==f(t.profile)&&r("resolved image/profile differs from signed selection"),(!(t.archive instanceof Uint8Array)||t.archive.byteLength>t.handoff.budget.bytes)&&r("archive exceeds declared input budget");let o;try{W(t.archive,{maxOutputLength:t.handoff.budget.bytes}),o=K(t.archive)}catch{return r("native implementation archive invalid")}const h=o.filter(c=>c.name===t.profile.selection.entry);(h.length!==1||"sha256:"+E("sha256").update(h[0].bytes).digest("hex")!==t.profile.port.implementation)&&r("archive native entry differs from implementation");const b={archive:"sha256:"+E("sha256").update(t.archive).digest("hex"),entry:t.profile.selection.entry,reader:t.profile.selection.reader,loaderConfig:t.profile.selection.loaderConfig,runtime:t.image.runtime,preload:t.image.preload??null,nativePreloadMembers:t.image.nativePreloadMembers,condition:t.image.condition,budget:t.handoff.budget,members:t.handoff.members.map(({coordinate:c,digest:l})=>({coordinate:c,digest:l})),bindings:t.handoff.bindings,loads:t.handoff.loads};f(b)!==f(t.profile.selection)&&r("resolved host bindings differ from signed selection"),t.profile.port.implementation!==t.handoff.members.find(c=>c.coordinate===t.profile.selection.entry)?.digest&&r("native implementation differs from handed member"),t.handoff.bindings.some(c=>c.limits.slots!==t.handoff.bindings[0].limits.slots)&&r("native bindings need one declared parent slots resource"),(!Number.isSafeInteger(t.profile.port.timeoutMs)||t.profile.port.timeoutMs<1||!Number.isSafeInteger(t.profile.port.responseBytes)||t.profile.port.responseBytes<1)&&r("missing parent time/bytes");const s=t.profile.port;(Object.keys(s).sort().join(",")!=="closure,coordinate,environment,implementation,responseBytes,stderr,timeoutMs"||s.stderr!=="reject"||new Set(s.closure).size!==s.closure.length||f([...s.closure].sort())!==f([...new Set(t.handoff.members.map(c=>c.digest))].sort())||t.handoff.bindings.some(c=>f(c.environment.map(([l])=>l).sort())!==f([...s.environment].sort())))&&r("command resource/environment/closure projection differs");const y=S(f([e.signer.id,e.signer.publicKey,e.eras,e.epoch,e.history,e.live])),g={...t.handoff,authoritySnapshot:y,policy:S(f([t.handoff.policy,i.line,y]))},x=Y(g,{...t.image,commandPort:s}),m=Object.freeze({identity:S(f([i.line,e.epoch,x.identity]))});return A.set(m,{root:{...e,history:[...e.history],live:[...e.live],eras:[...e.eras],budget:{...e.budget}},coordinate:n,profile:i.profile,image:x,module:Object.freeze({...t.module})}),m}p(F,"prepareSignedNativeReading");async function we(e,n,t){const i=z.get(e);return i?t.withCurrent(async o=>{const h=N(o,i.coordinate);(o.epoch!==i.root.epoch||f(h.profile)!==f(i.profile)||f(o.history)!==f(i.root.history))&&r("authority changed before load"),F(o,i.coordinate,{...n,module:{}});const b=n.image.locations.find(a=>a.member===i.profile.selection.reader),s=n.handoff.members.find(a=>a.coordinate===i.profile.selection.loaderConfig),y=n.image.locations.find(a=>a.member===i.profile.selection.loaderConfig);if(!b||b.kind!=="module"||!s||!y||!i.profile.selection.nativePreloadMembers.includes(s.coordinate))return r("reader/config not selected");const g=D(y.path,n.handoff.budget.bytes,i.profile.selection.loaderConfig);S(g.toString("utf8"))!==s.digest&&r("loader configuration changed");let x;try{x=JSON.parse(g.toString("utf8"))}catch{return r("loader configuration invalid")}const m=x;m.platform!==n.image.condition&&r("selected runtime condition differs from logical platform"),(!Array.isArray(m.members)||m.members.some(a=>n.handoff.members.find(d=>d.coordinate===a.coordinate)?.digest!==a.digest))&&r("loader target not covered by exact signed image");const c=$(m,n.image.locations.filter(a=>m.members.some(d=>d.coordinate===a.member)).map(a=>({coordinate:a.member,path:a.path})),i.profile.selection.reader,n.handoff.budget),l=B(c.declaration);try{const a=await l.loadEntry();l.assertClosed();const d=F(o,i.coordinate,{...n,image:{...n.image,hostLoader:{...c,preload:new URL("./preload"+H(new URL(import.meta.url).pathname),import.meta.url).href}},module:a});return A.get(d).loader=c.declaration,A.get(d).custody=n.custody??T(o,n.profile,n.handoff,n.image,m),d}finally{l.close()}}):r("unknown pre-load selection")}p(we,"loadSignedNativeReading");async function xe(e,n,t,i){const o=A.get(e);if(!o)return r("unknown instrument selection");i.phase!=="act"&&r("effects forbidden during "+i.phase),i.signal?.aborted&&r("interrupted before wrapper");const h=process.hrtime.bigint()+BigInt(o.profile.port.timeoutMs)*1000000n,b=new AbortController,s=b.abort.bind(b,void 0),y=X(h,s);i.signal?.addEventListener("abort",s,{once:!0});try{return await i.guard.withCurrent(async g=>{const x=N(g,o.coordinate);if((f(x.profile)!==f(o.profile)||g.epoch!==o.root.epoch||S(f(g.history))!==S(f(o.root.history)))&&r("authority changed since preparation"),!o.loader)return r("reader not loaded by fixed host boundary");const m=B(o.loader);try{const c=n.map(u=>{let w;u.verb==="read"&&o.module.commands&&(L({receipt:p(j=>(w=j,[]),"receipt")},u,t).kind!=="fact"||!w)&&r("Asked extraction refused");const M=w?o.module.commands(w):[];return{request:u,asked:w,jobs:M}}),l=c.flatMap(u=>u.jobs),a=new TextEncoder().encode(JSON.stringify(l)),d=Z(o.image,a),k=l.length?await q(o.image,a,{phase:"act",signal:b.signal,custody:o.custody}):[];(k.length!==d.length||k.some((u,w)=>u.id!==d[w].id||u.identity!==d[w].identity||u.responses.length!==1))&&r("capture identity/count differs");const P=new Map(k.map(u=>[u.id,u]));P.size!==k.length&&r("duplicate capture");const I=c.map(({request:u,jobs:w})=>{const M=w.map(O=>{const j=P.get(O.id);return j?G({scope:"command/capture/"+O.id,shape:"same",role:"reads",form:"alphabet",measure:"text",value:"lock",by:"host",at:"witness:"+j.identity,about:JSON.stringify({identity:j.identity,responses:j.responses})}):r("missing capture "+O.id)});return L(o.module,{...u,lines:[...u.lines??[],...M]},t)});return I.length!==n.length?r("incomplete pure response"):((b.signal.aborted||process.hrtime.bigint()>=h)&&r("interrupted/timeout wrapper"),Buffer.byteLength(JSON.stringify(I))>o.profile.port.responseBytes&&r("parent response bytes exceeded"),m.assertClosed(),I)}finally{m.close()}})}finally{y(),i.signal?.removeEventListener("abort",s)}}p(xe,"answerNativeReading");function Se(e,n){const t=v(e,n.port).profile,i=t?.selection?.budget?.bytes;return(t?.profile!=="host-native-reading@1"||!Number.isSafeInteger(i)||i<1)&&r("parent executable input resource absent"),i}p(Se,"nativeParentInputBytes");function je(e){return Object.keys(e).sort().join(",")}p(je,"fieldNames");function Ne(e,n){return t=>{const i=e.get(t);return i?JSON.parse(f(i)):n("unknown verified selection")}}p(Ne,"retainedProjection");export{xe as answerNativeReading,be as authenticateNativeProfile,v as authenticateSignedPort,f as canonicalJson,je as fieldNames,we as loadSignedNativeReading,Se as nativeParentInputBytes,Ne as retainedProjection,ye as validateSignedNativeProfile};
|
|
@@ -1,41 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* A retained receipt never selects its own cwd or execution flags. Historical
|
|
3
|
-
* inspection does not call this resolver and does not authorize a current act.
|
|
4
|
-
*/
|
|
5
|
-
import { join } from 'node:path';
|
|
6
|
-
import { readingEnvironment } from "../reading-context.js";
|
|
7
|
-
import { currentNativeReaderSelections, nativeMountIdentity } from "./route.js";
|
|
8
|
-
export function currentReadingEnvironment(store, root, hash, flags) {
|
|
9
|
-
const selections = currentNativeReaderSelections(store);
|
|
10
|
-
const ordinary = readingEnvironment(hash, process.env, root, flags);
|
|
11
|
-
return context => {
|
|
12
|
-
const mounts = [];
|
|
13
|
-
for (const [encoded, digest] of context.inputs) {
|
|
14
|
-
let name = encoded;
|
|
15
|
-
for (;;) {
|
|
16
|
-
let value;
|
|
17
|
-
try {
|
|
18
|
-
value = JSON.parse(name);
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
break;
|
|
22
|
-
}
|
|
23
|
-
if (!Array.isArray(value) || value.length !== 2 || value[0] !== 'context' || typeof value[1] !== 'string')
|
|
24
|
-
break;
|
|
25
|
-
name = value[1];
|
|
26
|
-
}
|
|
27
|
-
if (name === 'native/mount')
|
|
28
|
-
mounts.push(digest);
|
|
29
|
-
}
|
|
30
|
-
if (!mounts.length)
|
|
31
|
-
return selections.some(one => one.profile.selection.archive === context.implementation) ? undefined : ordinary;
|
|
32
|
-
if (mounts.length !== 1)
|
|
33
|
-
return undefined;
|
|
34
|
-
const selected = selections.filter(one => one.profile.selection.archive === context.implementation && nativeMountIdentity(one.profile, one.binaries, one.control) === mounts[0]);
|
|
35
|
-
if (!selected.length)
|
|
36
|
-
return undefined;
|
|
37
|
-
// Several readers may share this exact image. They have the same execution
|
|
38
|
-
// boundary; their policy and transitive inputs remain separate in the receipt.
|
|
39
|
-
return readingEnvironment(hash, process.env, join(store, 'cas', 'laid', mounts[0].slice(7)), []);
|
|
40
|
-
};
|
|
41
|
-
}
|
|
1
|
+
var p=Object.defineProperty;var a=(r,i)=>p(r,"name",{value:i,configurable:!0});import{join as v}from"node:path";import{readingEnvironment as f}from"../reading-context.js";import{currentNativeReaderSelections as g,nativeMountIdentity as h}from"./route.js";function N(r,i,c,d){const l=g(r),u=f(c,process.env,i,d);return o=>{const t=[];for(const[e,m]of o.inputs){let s=e;for(;;){let n;try{n=JSON.parse(s)}catch{break}if(!Array.isArray(n)||n.length!==2||n[0]!=="context"||typeof n[1]!="string")break;s=n[1]}s==="native/mount"&&t.push(m)}if(!t.length)return l.some(e=>e.profile.selection.archive===o.implementation)?void 0:u;if(!(t.length!==1||!l.filter(e=>e.profile.selection.archive===o.implementation&&h(e.profile,e.binaries,e.control)===t[0]).length))return f(c,process.env,v(r,"cas","laid",t[0].slice(7)),[])}}a(N,"currentReadingEnvironment");export{N as currentReadingEnvironment};
|
|
@@ -1,30 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* namespace without dropping any inherited identity, and never pick a duplicate.
|
|
3
|
-
*/
|
|
4
|
-
export function nativeReferenceInputs(inputs, required) {
|
|
5
|
-
const names = new Map(required);
|
|
6
|
-
const found = new Map();
|
|
7
|
-
for (const [encoded, digest] of inputs) {
|
|
8
|
-
let name = encoded;
|
|
9
|
-
for (;;) {
|
|
10
|
-
let value;
|
|
11
|
-
try {
|
|
12
|
-
value = JSON.parse(name);
|
|
13
|
-
}
|
|
14
|
-
catch {
|
|
15
|
-
break;
|
|
16
|
-
}
|
|
17
|
-
if (!Array.isArray(value) || value.length !== 2 || value[0] !== 'context' || typeof value[1] !== 'string')
|
|
18
|
-
break;
|
|
19
|
-
name = value[1];
|
|
20
|
-
}
|
|
21
|
-
if (!names.has(name))
|
|
22
|
-
continue;
|
|
23
|
-
if (found.has(name))
|
|
24
|
-
throw Error('REFUSE·native reading duplicate context input ' + name);
|
|
25
|
-
found.set(name, digest);
|
|
26
|
-
}
|
|
27
|
-
for (const [name, digest] of required)
|
|
28
|
-
if (found.get(name) !== digest)
|
|
29
|
-
throw Error('REFUSE·native reading context omits or changes ' + name);
|
|
30
|
-
}
|
|
1
|
+
var f=Object.defineProperty;var s=(r,n)=>f(r,"name",{value:n,configurable:!0});function p(r,n){const c=new Map(n),a=new Map;for(const[o,i]of r){let e=o;for(;;){let t;try{t=JSON.parse(e)}catch{break}if(!Array.isArray(t)||t.length!==2||t[0]!=="context"||typeof t[1]!="string")break;e=t[1]}if(c.has(e)){if(a.has(e))throw Error("REFUSE\xB7native reading duplicate context input "+e);a.set(e,i)}}for(const[o,i]of n)if(a.get(o)!==i)throw Error("REFUSE\xB7native reading context omits or changes "+o)}s(p,"nativeReferenceInputs");export{p as nativeReferenceInputs};
|
package/dist/host/native/root.js
CHANGED
|
@@ -1,37 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createHash } from 'node:crypto';
|
|
3
|
-
import { declaredRootClockSource } from "../root-clock-source.js";
|
|
4
|
-
import { foldClaims, fieldOf } from "../../fold/claims.js";
|
|
5
|
-
import { assertRootAuthorityProtection } from "../../land/act.js";
|
|
6
|
-
import { withCommittedLocalActObservation } from "../ports/local-act.js";
|
|
7
|
-
const fail = (why) => { throw Error('REFUSE·native Root ' + why); };
|
|
8
|
-
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
9
|
-
export function currentNativeRoot(store, parent, proof) {
|
|
10
|
-
assertRootAuthorityProtection(proof, store, parent);
|
|
11
|
-
return withCommittedLocalActObservation(store, () => {
|
|
12
|
-
// The constructor has just authenticated this cursor and its receiver heads.
|
|
13
|
-
// Reuse that result only within this protected synchronous invocation. Calling
|
|
14
|
-
// trust.current() here would repeat the same full construction immediately;
|
|
15
|
-
// subsequent gates still construct their own fresh source under the lease.
|
|
16
|
-
const root = dirname(store), source = declaredRootClockSource(root), current = source.trust.contract.root;
|
|
17
|
-
const { history, anchor: signer, algorithms: eras } = source.observation;
|
|
18
|
-
const live = foldClaims(history).standing.filter(line => fieldOf(line, 'value') !== 'withdraw');
|
|
19
|
-
// The source constructor authenticates the complete history at each original
|
|
20
|
-
// admission snapshot. Current port eligibility stays a separate SDK check.
|
|
21
|
-
const limits = source.resources;
|
|
22
|
-
if (history.length > limits.lines || history.reduce((bytes, line) => bytes + Buffer.byteLength(line), 0) > limits.bytes)
|
|
23
|
-
fail('Root declared history resources exceeded');
|
|
24
|
-
assertRootAuthorityProtection(proof, store, parent);
|
|
25
|
-
return { context: current, root: { history, live, signer, eras, epoch: Number(current.epoch), budget: { lines: limits.lines, bytes: limits.bytes } } };
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
export function inheritedNativeRoot(inherited, proof) {
|
|
29
|
-
const current = currentNativeRoot(inherited.store, inherited.parent, proof);
|
|
30
|
-
if (!same(current.context, inherited.expected))
|
|
31
|
-
fail('actual authority cursor or dependencies changed');
|
|
32
|
-
return current.root;
|
|
33
|
-
}
|
|
34
|
-
export function inheritedNativeGuard(inherited, proof) {
|
|
35
|
-
return { async withCurrent(body) { const before = inheritedNativeRoot(inherited, proof), result = await body(before), after = inheritedNativeRoot(inherited, proof); if (createHash('sha256').update(JSON.stringify(before)).digest('hex') !== createHash('sha256').update(JSON.stringify(after)).digest('hex'))
|
|
36
|
-
fail('Root changed during native execution'); return result; } };
|
|
37
|
-
}
|
|
1
|
+
var x=Object.defineProperty;var o=(t,e)=>x(t,"name",{value:e,configurable:!0});import{dirname as b}from"node:path";import{createHash as f}from"node:crypto";import{declaredRootClockSource as v}from"../root-clock-source.js";import{foldClaims as N,fieldOf as R}from"../../fold/claims.js";import{assertRootAuthorityProtection as h}from"../../land/act.js";import{withCommittedLocalActObservation as w}from"../ports/local-act.js";const d=o(t=>{throw Error("REFUSE\xB7native Root "+t)},"fail"),O=o((t,e)=>JSON.stringify(t)===JSON.stringify(e),"same");function S(t,e,r){return h(r,t,e),w(t,()=>{const n=b(t),i=v(n),s=i.trust.contract.root,{history:c,anchor:l,algorithms:g}=i.observation,p=N(c).standing.filter(u=>R(u,"value")!=="withdraw"),a=i.resources;return(c.length>a.lines||c.reduce((u,y)=>u+Buffer.byteLength(y),0)>a.bytes)&&d("Root declared history resources exceeded"),h(r,t,e),{context:s,root:{history:c,live:p,signer:l,eras:g,epoch:Number(s.epoch),budget:{lines:a.lines,bytes:a.bytes}}}})}o(S,"currentNativeRoot");function m(t,e){const r=S(t.store,t.parent,e);return O(r.context,t.expected)||d("actual authority cursor or dependencies changed"),r.root}o(m,"inheritedNativeRoot");function F(t,e){return{async withCurrent(r){const n=m(t,e),i=await r(n),s=m(t,e);return f("sha256").update(JSON.stringify(n)).digest("hex")!==f("sha256").update(JSON.stringify(s)).digest("hex")&&d("Root changed during native execution"),i}}}o(F,"inheritedNativeGuard");export{S as currentNativeRoot,F as inheritedNativeGuard,m as inheritedNativeRoot};
|