@tiangong-lca/cli 0.1.8 → 0.1.10
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/README.md +18 -5
- package/assets/runtime/cli-runtime-descriptor.schema.json +138 -0
- package/assets/runtime/cli-runtime-expectation.schema.json +38 -0
- package/assets/runtime/runtime-bootstrap-lock.schema.json +254 -0
- package/assets/runtime/runtime-command-result.schema.json +95 -0
- package/assets/runtime/runtime-manifest.schema.json +380 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +48 -2
- package/dist/src/cli.js.map +1 -1
- package/dist/src/lib/dataset-import-lca.js +2 -2
- package/dist/src/lib/dataset-import-lca.js.map +1 -1
- package/dist/src/lib/dataset-support-cache.d.ts +48 -0
- package/dist/src/lib/dataset-support-cache.js +265 -0
- package/dist/src/lib/dataset-support-cache.js.map +1 -0
- package/dist/src/lib/runtime/archive-writer.d.ts +7 -0
- package/dist/src/lib/runtime/archive-writer.js +89 -0
- package/dist/src/lib/runtime/archive-writer.js.map +1 -0
- package/dist/src/lib/runtime/archive.d.ts +2 -0
- package/dist/src/lib/runtime/archive.js +122 -0
- package/dist/src/lib/runtime/archive.js.map +1 -0
- package/dist/src/lib/runtime/command.d.ts +8 -0
- package/dist/src/lib/runtime/command.js +57 -0
- package/dist/src/lib/runtime/command.js.map +1 -0
- package/dist/src/lib/runtime/descriptor.d.ts +11 -0
- package/dist/src/lib/runtime/descriptor.js +126 -0
- package/dist/src/lib/runtime/descriptor.js.map +1 -0
- package/dist/src/lib/runtime/download.d.ts +9 -0
- package/dist/src/lib/runtime/download.js +118 -0
- package/dist/src/lib/runtime/download.js.map +1 -0
- package/dist/src/lib/runtime/exec-command.d.ts +7 -0
- package/dist/src/lib/runtime/exec-command.js +83 -0
- package/dist/src/lib/runtime/exec-command.js.map +1 -0
- package/dist/src/lib/runtime/execute.d.ts +11 -0
- package/dist/src/lib/runtime/execute.js +125 -0
- package/dist/src/lib/runtime/execute.js.map +1 -0
- package/dist/src/lib/runtime/files.d.ts +7 -0
- package/dist/src/lib/runtime/files.js +91 -0
- package/dist/src/lib/runtime/files.js.map +1 -0
- package/dist/src/lib/runtime/host.d.ts +8 -0
- package/dist/src/lib/runtime/host.js +37 -0
- package/dist/src/lib/runtime/host.js.map +1 -0
- package/dist/src/lib/runtime/leases.d.ts +12 -0
- package/dist/src/lib/runtime/leases.js +72 -0
- package/dist/src/lib/runtime/leases.js.map +1 -0
- package/dist/src/lib/runtime/managed-command.d.ts +6 -0
- package/dist/src/lib/runtime/managed-command.js +99 -0
- package/dist/src/lib/runtime/managed-command.js.map +1 -0
- package/dist/src/lib/runtime/manager.d.ts +33 -0
- package/dist/src/lib/runtime/manager.js +196 -0
- package/dist/src/lib/runtime/manager.js.map +1 -0
- package/dist/src/lib/runtime/manifest-types.d.ts +73 -0
- package/dist/src/lib/runtime/manifest-types.js +4 -0
- package/dist/src/lib/runtime/manifest-types.js.map +1 -0
- package/dist/src/lib/runtime/manifest-values.d.ts +15 -0
- package/dist/src/lib/runtime/manifest-values.js +124 -0
- package/dist/src/lib/runtime/manifest-values.js.map +1 -0
- package/dist/src/lib/runtime/manifest.d.ts +7 -0
- package/dist/src/lib/runtime/manifest.js +220 -0
- package/dist/src/lib/runtime/manifest.js.map +1 -0
- package/dist/src/lib/runtime/process.d.ts +3 -0
- package/dist/src/lib/runtime/process.js +55 -0
- package/dist/src/lib/runtime/process.js.map +1 -0
- package/dist/src/lib/runtime/storage.d.ts +8 -0
- package/dist/src/lib/runtime/storage.js +142 -0
- package/dist/src/lib/runtime/storage.js.map +1 -0
- package/dist/src/lib/runtime/types.d.ts +45 -0
- package/dist/src/lib/runtime/types.js +9 -0
- package/dist/src/lib/runtime/types.js.map +1 -0
- package/dist/src/lib/supabase-data-api-contract.d.ts +4 -4
- package/dist/src/lib/supabase-data-api-contract.js +2 -0
- package/dist/src/lib/supabase-data-api-contract.js.map +1 -1
- package/dist/src/main.js +13 -1
- package/dist/src/main.js.map +1 -1
- package/dist/src/runtime.d.ts +15 -0
- package/dist/src/runtime.js +22 -0
- package/dist/src/runtime.js.map +1 -0
- package/package.json +8 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-values.js","sourceRoot":"","sources":["../../../../src/lib/runtime/manifest-values.ts"],"names":[],"mappings":"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","sourcesContent":["import { runtimeError } from './files.js';\nimport { RUNTIME_PLATFORMS, type RuntimePlatform } from './types.js';\n\nexport function record(value: unknown, label: string): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) invalid(label);\n return value as Record<string, unknown>;\n}\nexport function invalid(label: string): never {\n return runtimeError('RUNTIME_MANIFEST_INVALID', `Runtime manifest has invalid ${label}.`);\n}\nexport function exact(\n value: Record<string, unknown>,\n keys: readonly string[],\n label: string,\n): void {\n if (Object.keys(value).length !== keys.length || keys.some((key) => !Object.hasOwn(value, key)))\n invalid(label);\n}\nexport function text(value: unknown, label: string, max = 256): string {\n if (\n typeof value !== 'string' ||\n !value ||\n value.length > max ||\n value.split('').some((char) => char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127)\n )\n invalid(label);\n return value;\n}\nexport function id(value: unknown): string {\n const result = text(value, 'identifier', 64);\n if (!/^[a-z0-9][a-z0-9._-]*$/u.test(result) || result === '.' || result === '..')\n invalid('identifier');\n return result;\n}\nexport function version(value: unknown): string {\n const result = text(value, 'version', 40);\n if (!/^(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*)$/u.test(result))\n invalid('exact stable version');\n return result;\n}\nexport function sha(value: unknown): string {\n const result = text(value, 'SHA-256', 64);\n if (!/^[0-9a-f]{64}$/u.test(result)) invalid('SHA-256');\n return result;\n}\nexport function integer(value: unknown, max: number, minimum = 0): number {\n if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < minimum || value > max)\n invalid('bounded integer');\n return value;\n}\nexport function array(value: unknown, max: number, minimum = 0): unknown[] {\n if (!Array.isArray(value) || value.length > max || value.length < minimum)\n invalid('bounded array');\n return value;\n}\nexport function platform(value: unknown): RuntimePlatform {\n if (!RUNTIME_PLATFORMS.includes(value as RuntimePlatform)) invalid('platform');\n return value as RuntimePlatform;\n}\nexport function relativeFile(value: unknown): string {\n const result = text(value, 'portable file path', 255);\n if (\n Buffer.byteLength(result) > 255 ||\n result.includes('\\\\') ||\n result.includes(':') ||\n result.startsWith('/') ||\n result\n .split('/')\n .some(\n (part) =>\n !part ||\n part === '.' ||\n part === '..' ||\n /^(?:\\.env(?:\\..*)?|\\.git|\\.npmrc|\\.ssh)$/iu.test(part) ||\n /[. ]$/u.test(part) ||\n /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\\.|$)/iu.test(part),\n )\n )\n invalid('portable file path');\n const segments = result.split('/');\n if (\n segments.length > 32 ||\n Buffer.byteLength(segments.at(-1)!) > 100 ||\n (Buffer.byteLength(result) > 100 &&\n !segments\n .slice(0, -1)\n .some(\n (_, i) =>\n Buffer.byteLength(segments.slice(0, i + 1).join('/')) <= 155 &&\n Buffer.byteLength(segments.slice(i + 1).join('/')) <= 100,\n ))\n )\n invalid('USTAR path');\n return result;\n}\nexport function unique(values: readonly string[], label: string): void {\n if (new Set(values).size !== values.length) invalid(`duplicate ${label}`);\n}\nexport function distributionUrl(value: unknown, redirected = false): string {\n const input = text(value, 'distribution URL', 4096);\n let url: URL;\n try {\n url = new URL(input);\n } catch {\n invalid('distribution URL');\n }\n if (url.protocol !== 'https:' || url.username || url.password || url.hash || url.port)\n invalid('distribution URL');\n const primary = ['github.com', 'nodejs.org', 'registry.npmjs.org'];\n const redirects = ['release-assets.githubusercontent.com', 'objects.githubusercontent.com'];\n if (!primary.includes(url.hostname) && !(redirected && redirects.includes(url.hostname)))\n invalid('distribution origin');\n if (!redirected) {\n if (url.search || /\\/(?:latest|heads)(?:\\/|$)/u.test(url.pathname))\n invalid('immutable distribution URL');\n if (\n url.hostname === 'github.com' &&\n !/^\\/[^/]+\\/[^/]+\\/releases\\/download\\/[^/]+\\/[^/]+$/u.test(url.pathname)\n )\n invalid('release asset URL');\n if (\n url.hostname === 'nodejs.org' &&\n !/^\\/dist\\/v[0-9]+\\.[0-9]+\\.[0-9]+\\/[^/]+$/u.test(url.pathname)\n )\n invalid('Node release URL');\n if (\n url.hostname === 'registry.npmjs.org' &&\n !/\\/-\\/[^/]+-[0-9]+\\.[0-9]+\\.[0-9]+\\.tgz$/u.test(url.pathname)\n )\n invalid('registry tarball URL');\n }\n return url.href;\n}\nexport function deepFreeze<T>(value: T): T {\n if (value && typeof value === 'object' && !Object.isFrozen(value)) {\n for (const item of Object.values(value)) deepFreeze(item);\n Object.freeze(value);\n }\n return value;\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RuntimeComponent, RuntimeManifest, TrustedRuntimeManifest, WorkspaceCompatibility } from './manifest-types.js';
|
|
2
|
+
export declare function parseRuntimeManifest(value: unknown): RuntimeManifest;
|
|
3
|
+
export declare function trustRuntimeManifest(bytes: Uint8Array, expectedSha256: string): TrustedRuntimeManifest;
|
|
4
|
+
export declare function loadTrustedRuntimeManifest(file: string, expectedSha256: string): TrustedRuntimeManifest;
|
|
5
|
+
export declare function assertTrustedManifest(value: TrustedRuntimeManifest): void;
|
|
6
|
+
export declare function componentKey(value: RuntimeComponent): string;
|
|
7
|
+
export declare function assertWorkspaceCompatibility(value: TrustedRuntimeManifest, request: WorkspaceCompatibility, access: 'read' | 'write'): void;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { contentHash, runtimeError } from './files.js';
|
|
4
|
+
import { array, deepFreeze, distributionUrl, exact, id, integer, invalid, platform, record, relativeFile, sha, text, unique, version, } from './manifest-values.js';
|
|
5
|
+
import { RUNTIME_ARCHIVE_FORMAT, RUNTIME_BOOTSTRAP_PROTOCOL, RUNTIME_MANIFEST_SCHEMA, } from './manifest-types.js';
|
|
6
|
+
const trusted = new WeakSet();
|
|
7
|
+
function compatibility(value) {
|
|
8
|
+
const result = array(value, 32).map((item) => {
|
|
9
|
+
const entry = record(item, 'workspace compatibility');
|
|
10
|
+
exact(entry, ['schema', 'features'], 'workspace compatibility');
|
|
11
|
+
const features = array(entry.features, 64).map((value) => text(value, 'workspace feature', 128));
|
|
12
|
+
unique(features, 'workspace feature');
|
|
13
|
+
return { schema: text(entry.schema, 'workspace schema', 128), features };
|
|
14
|
+
});
|
|
15
|
+
unique(result.map((entry) => entry.schema), 'workspace schema');
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
function component(value) {
|
|
19
|
+
const item = record(value, 'component');
|
|
20
|
+
exact(item, [
|
|
21
|
+
'id',
|
|
22
|
+
'version',
|
|
23
|
+
'platform',
|
|
24
|
+
'archive',
|
|
25
|
+
'files',
|
|
26
|
+
'content_sha256',
|
|
27
|
+
'production_lock',
|
|
28
|
+
'sbom',
|
|
29
|
+
'licenses',
|
|
30
|
+
'provenance',
|
|
31
|
+
'protocols',
|
|
32
|
+
'asset_fingerprints',
|
|
33
|
+
], 'component');
|
|
34
|
+
const archive = record(item.archive, 'archive');
|
|
35
|
+
exact(archive, ['format', 'url', 'bytes', 'sha256'], 'archive');
|
|
36
|
+
if (archive.format !== RUNTIME_ARCHIVE_FORMAT)
|
|
37
|
+
invalid('archive format');
|
|
38
|
+
let total = 0;
|
|
39
|
+
const files = array(item.files, 50_000, 1).map((value) => {
|
|
40
|
+
const file = record(value, 'component file');
|
|
41
|
+
exact(file, ['path', 'bytes', 'sha256', 'mode'], 'component file');
|
|
42
|
+
if (file.mode !== 420 && file.mode !== 493)
|
|
43
|
+
invalid('file mode');
|
|
44
|
+
const bytes = integer(file.bytes, 512 * 1024 * 1024);
|
|
45
|
+
total += bytes;
|
|
46
|
+
return { path: relativeFile(file.path), bytes, sha256: sha(file.sha256), mode: file.mode };
|
|
47
|
+
});
|
|
48
|
+
if (total > 2 * 1024 * 1024 * 1024)
|
|
49
|
+
invalid('unpacked size');
|
|
50
|
+
const paths = files.map((file) => file.path);
|
|
51
|
+
unique(paths.map((path) => path.toLowerCase()), 'case-folded file path');
|
|
52
|
+
if (JSON.stringify(paths) !== JSON.stringify([...paths].sort()))
|
|
53
|
+
invalid('file order');
|
|
54
|
+
const pathSet = new Set(paths.map((path) => path.toLowerCase()));
|
|
55
|
+
for (const file of paths) {
|
|
56
|
+
const parts = file.split('/');
|
|
57
|
+
for (let i = 1; i < parts.length; i++)
|
|
58
|
+
if (pathSet.has(parts.slice(0, i).join('/').toLowerCase()))
|
|
59
|
+
invalid('file/directory collision');
|
|
60
|
+
}
|
|
61
|
+
const content = sha(item.content_sha256);
|
|
62
|
+
if (content !== contentHash(files))
|
|
63
|
+
invalid('component content SHA-256');
|
|
64
|
+
const requiredFile = (value) => {
|
|
65
|
+
const file = relativeFile(value);
|
|
66
|
+
if (!paths.includes(file))
|
|
67
|
+
invalid('metadata file reference');
|
|
68
|
+
return file;
|
|
69
|
+
};
|
|
70
|
+
const licenses = array(item.licenses, 64, 1).map(requiredFile), provenance = array(item.provenance, 64, 1).map(requiredFile);
|
|
71
|
+
unique(licenses, 'license');
|
|
72
|
+
unique(provenance, 'provenance');
|
|
73
|
+
const protocols = array(item.protocols, 32, 1).map((value) => text(value, 'component protocol', 128));
|
|
74
|
+
unique(protocols, 'protocol');
|
|
75
|
+
const fingerprints = record(item.asset_fingerprints, 'asset fingerprints');
|
|
76
|
+
if (Object.keys(fingerprints).length > 64)
|
|
77
|
+
invalid('fingerprint count');
|
|
78
|
+
const asset_fingerprints = Object.fromEntries(Object.entries(fingerprints).map(([key, value]) => [id(key), sha(value)]));
|
|
79
|
+
return {
|
|
80
|
+
id: id(item.id),
|
|
81
|
+
version: version(item.version),
|
|
82
|
+
platform: platform(item.platform),
|
|
83
|
+
archive: {
|
|
84
|
+
format: RUNTIME_ARCHIVE_FORMAT,
|
|
85
|
+
url: distributionUrl(archive.url),
|
|
86
|
+
bytes: integer(archive.bytes, 512 * 1024 * 1024, 1),
|
|
87
|
+
sha256: sha(archive.sha256),
|
|
88
|
+
},
|
|
89
|
+
files,
|
|
90
|
+
content_sha256: content,
|
|
91
|
+
production_lock: requiredFile(item.production_lock),
|
|
92
|
+
sbom: requiredFile(item.sbom),
|
|
93
|
+
licenses,
|
|
94
|
+
provenance,
|
|
95
|
+
protocols,
|
|
96
|
+
asset_fingerprints,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function componentPath(value, components, target, executable = false) {
|
|
100
|
+
const entry = record(value, 'component path');
|
|
101
|
+
exact(entry, ['component', 'path'], 'component path');
|
|
102
|
+
const componentId = id(entry.component), file = relativeFile(entry.path);
|
|
103
|
+
const owner = components.find((item) => item.platform === target && item.id === componentId);
|
|
104
|
+
const fact = owner?.files.find((item) => item.path === file);
|
|
105
|
+
if (!fact || (executable && fact.mode !== 493))
|
|
106
|
+
invalid('launch file reference');
|
|
107
|
+
return { component: componentId, path: file };
|
|
108
|
+
}
|
|
109
|
+
export function parseRuntimeManifest(value) {
|
|
110
|
+
const item = record(value, 'manifest');
|
|
111
|
+
exact(item, [
|
|
112
|
+
'schema',
|
|
113
|
+
'bootstrap_protocol',
|
|
114
|
+
'product',
|
|
115
|
+
'minimum_hosts',
|
|
116
|
+
'workspace',
|
|
117
|
+
'components',
|
|
118
|
+
'launches',
|
|
119
|
+
], 'manifest');
|
|
120
|
+
if (item.schema !== RUNTIME_MANIFEST_SCHEMA ||
|
|
121
|
+
item.bootstrap_protocol !== RUNTIME_BOOTSTRAP_PROTOCOL)
|
|
122
|
+
invalid('manifest protocol version');
|
|
123
|
+
const product = record(item.product, 'product');
|
|
124
|
+
exact(product, ['id', 'version'], 'product');
|
|
125
|
+
const workspace = record(item.workspace, 'workspace');
|
|
126
|
+
exact(workspace, ['read', 'write'], 'workspace');
|
|
127
|
+
const read = compatibility(workspace.read), write = compatibility(workspace.write);
|
|
128
|
+
for (const entry of write)
|
|
129
|
+
if (!read.some((candidate) => candidate.schema === entry.schema &&
|
|
130
|
+
entry.features.every((feature) => candidate.features.includes(feature))))
|
|
131
|
+
invalid('write compatibility outside read support');
|
|
132
|
+
const components = array(item.components, 128, 1).map(component);
|
|
133
|
+
unique(components.map((item) => `${item.platform}:${item.id}`), 'platform component');
|
|
134
|
+
const minimum = record(item.minimum_hosts, 'minimum hosts');
|
|
135
|
+
const minimum_hosts = Object.fromEntries(Object.entries(minimum).map(([key, value]) => {
|
|
136
|
+
const target = platform(key), host = record(value, 'minimum host');
|
|
137
|
+
exact(host, ['os_release', 'glibc'], 'minimum host');
|
|
138
|
+
if ((target.startsWith('linux-') && typeof host.glibc !== 'string') ||
|
|
139
|
+
(!target.startsWith('linux-') && host.glibc !== null))
|
|
140
|
+
invalid('host ABI');
|
|
141
|
+
const glibc = host.glibc === null ? null : text(host.glibc, 'glibc version', 40);
|
|
142
|
+
if (glibc !== null && !/^[0-9]+\.[0-9]+$/u.test(glibc))
|
|
143
|
+
invalid('glibc version');
|
|
144
|
+
return [target, { os_release: version(host.os_release), glibc }];
|
|
145
|
+
}));
|
|
146
|
+
const supported = [...new Set(components.map((item) => item.platform))].sort();
|
|
147
|
+
if (JSON.stringify(Object.keys(minimum_hosts).sort()) !== JSON.stringify(supported))
|
|
148
|
+
invalid('host/component platform coverage');
|
|
149
|
+
const launches = array(item.launches, 64, 1).map((value) => {
|
|
150
|
+
const launch = record(value, 'launch');
|
|
151
|
+
exact(launch, ['id', 'platform', 'executable', 'environment', 'argv'], 'launch');
|
|
152
|
+
if (launch.environment !== 'isolated' && launch.environment !== 'cli-auth')
|
|
153
|
+
invalid('launch environment');
|
|
154
|
+
const target = platform(launch.platform);
|
|
155
|
+
const argv = array(launch.argv, 32).map((value) => {
|
|
156
|
+
const arg = record(value, 'launch argument');
|
|
157
|
+
if (Object.hasOwn(arg, 'literal')) {
|
|
158
|
+
exact(arg, ['literal'], 'literal argument');
|
|
159
|
+
return { literal: text(arg.literal, 'literal argument', 4096) };
|
|
160
|
+
}
|
|
161
|
+
return componentPath(arg, components, target);
|
|
162
|
+
});
|
|
163
|
+
return {
|
|
164
|
+
id: id(launch.id),
|
|
165
|
+
platform: target,
|
|
166
|
+
executable: componentPath(launch.executable, components, target, true),
|
|
167
|
+
environment: launch.environment,
|
|
168
|
+
argv,
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
unique(launches.map((item) => `${item.platform}:${item.id}`), 'platform launch');
|
|
172
|
+
for (const target of supported)
|
|
173
|
+
if (!launches.some((launch) => launch.platform === target))
|
|
174
|
+
invalid('platform launch coverage');
|
|
175
|
+
return deepFreeze({
|
|
176
|
+
schema: RUNTIME_MANIFEST_SCHEMA,
|
|
177
|
+
bootstrap_protocol: RUNTIME_BOOTSTRAP_PROTOCOL,
|
|
178
|
+
product: { id: id(product.id), version: version(product.version) },
|
|
179
|
+
minimum_hosts,
|
|
180
|
+
workspace: { read, write },
|
|
181
|
+
components,
|
|
182
|
+
launches,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
export function trustRuntimeManifest(bytes, expectedSha256) {
|
|
186
|
+
sha(expectedSha256);
|
|
187
|
+
if (bytes.byteLength > 32 * 1024 * 1024 ||
|
|
188
|
+
createHash('sha256').update(bytes).digest('hex') !== expectedSha256)
|
|
189
|
+
runtimeError('RUNTIME_MANIFEST_INTEGRITY', 'Runtime manifest bytes do not match the independent trust anchor.');
|
|
190
|
+
let value;
|
|
191
|
+
try {
|
|
192
|
+
value = JSON.parse(Buffer.from(bytes).toString('utf8'));
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
invalid('JSON');
|
|
196
|
+
}
|
|
197
|
+
const result = Object.freeze({ sha256: expectedSha256, manifest: parseRuntimeManifest(value) });
|
|
198
|
+
trusted.add(result);
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
export function loadTrustedRuntimeManifest(file, expectedSha256) {
|
|
202
|
+
const stat = fs.lstatSync(file);
|
|
203
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 32 * 1024 * 1024)
|
|
204
|
+
runtimeError('RUNTIME_MANIFEST_FILE', 'Runtime manifest must be a bounded regular file.');
|
|
205
|
+
return trustRuntimeManifest(fs.readFileSync(file), expectedSha256);
|
|
206
|
+
}
|
|
207
|
+
export function assertTrustedManifest(value) {
|
|
208
|
+
if (!value || !trusted.has(value))
|
|
209
|
+
runtimeError('RUNTIME_MANIFEST_UNTRUSTED', 'Supply a manifest verified against an independent trusted digest.');
|
|
210
|
+
}
|
|
211
|
+
export function componentKey(value) {
|
|
212
|
+
return contentHash(value);
|
|
213
|
+
}
|
|
214
|
+
export function assertWorkspaceCompatibility(value, request, access) {
|
|
215
|
+
assertTrustedManifest(value);
|
|
216
|
+
const support = value.manifest.workspace[access]?.find((entry) => entry.schema === request.schema);
|
|
217
|
+
if (!support || !request.features.every((feature) => support.features.includes(feature)))
|
|
218
|
+
runtimeError('RUNTIME_WORKSPACE_INCOMPATIBLE', 'The selected runtime does not support the requested workspace access/schema/features.');
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../../src/lib/runtime/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { contentHash, runtimeError } from './files.js';\nimport {\n array,\n deepFreeze,\n distributionUrl,\n exact,\n id,\n integer,\n invalid,\n platform,\n record,\n relativeFile,\n sha,\n text,\n unique,\n version,\n} from './manifest-values.js';\nimport {\n RUNTIME_ARCHIVE_FORMAT,\n RUNTIME_BOOTSTRAP_PROTOCOL,\n RUNTIME_MANIFEST_SCHEMA,\n} from './manifest-types.js';\nimport type {\n ComponentFile,\n ComponentPath,\n RuntimeComponent,\n RuntimeLaunch,\n RuntimeManifest,\n TrustedRuntimeManifest,\n WorkspaceCompatibility,\n} from './manifest-types.js';\nconst trusted = new WeakSet<object>();\n\nfunction compatibility(value: unknown): WorkspaceCompatibility[] {\n const result = array(value, 32).map((item) => {\n const entry = record(item, 'workspace compatibility');\n exact(entry, ['schema', 'features'], 'workspace compatibility');\n const features = array(entry.features, 64).map((value) =>\n text(value, 'workspace feature', 128),\n );\n unique(features, 'workspace feature');\n return { schema: text(entry.schema, 'workspace schema', 128), features };\n });\n unique(\n result.map((entry) => entry.schema),\n 'workspace schema',\n );\n return result;\n}\nfunction component(value: unknown): RuntimeComponent {\n const item = record(value, 'component');\n exact(\n item,\n [\n 'id',\n 'version',\n 'platform',\n 'archive',\n 'files',\n 'content_sha256',\n 'production_lock',\n 'sbom',\n 'licenses',\n 'provenance',\n 'protocols',\n 'asset_fingerprints',\n ],\n 'component',\n );\n const archive = record(item.archive, 'archive');\n exact(archive, ['format', 'url', 'bytes', 'sha256'], 'archive');\n if (archive.format !== RUNTIME_ARCHIVE_FORMAT) invalid('archive format');\n let total = 0;\n const files: ComponentFile[] = array(item.files, 50_000, 1).map((value) => {\n const file = record(value, 'component file');\n exact(file, ['path', 'bytes', 'sha256', 'mode'], 'component file');\n if (file.mode !== 420 && file.mode !== 493) invalid('file mode');\n const bytes = integer(file.bytes, 512 * 1024 * 1024);\n total += bytes;\n return { path: relativeFile(file.path), bytes, sha256: sha(file.sha256), mode: file.mode };\n });\n if (total > 2 * 1024 * 1024 * 1024) invalid('unpacked size');\n const paths = files.map((file) => file.path);\n unique(\n paths.map((path) => path.toLowerCase()),\n 'case-folded file path',\n );\n if (JSON.stringify(paths) !== JSON.stringify([...paths].sort())) invalid('file order');\n const pathSet = new Set(paths.map((path) => path.toLowerCase()));\n for (const file of paths) {\n const parts = file.split('/');\n for (let i = 1; i < parts.length; i++)\n if (pathSet.has(parts.slice(0, i).join('/').toLowerCase()))\n invalid('file/directory collision');\n }\n const content = sha(item.content_sha256);\n if (content !== contentHash(files)) invalid('component content SHA-256');\n const requiredFile = (value: unknown) => {\n const file = relativeFile(value);\n if (!paths.includes(file)) invalid('metadata file reference');\n return file;\n };\n const licenses = array(item.licenses, 64, 1).map(requiredFile),\n provenance = array(item.provenance, 64, 1).map(requiredFile);\n unique(licenses, 'license');\n unique(provenance, 'provenance');\n const protocols = array(item.protocols, 32, 1).map((value) =>\n text(value, 'component protocol', 128),\n );\n unique(protocols, 'protocol');\n const fingerprints = record(item.asset_fingerprints, 'asset fingerprints');\n if (Object.keys(fingerprints).length > 64) invalid('fingerprint count');\n const asset_fingerprints = Object.fromEntries(\n Object.entries(fingerprints).map(([key, value]) => [id(key), sha(value)]),\n );\n return {\n id: id(item.id),\n version: version(item.version),\n platform: platform(item.platform),\n archive: {\n format: RUNTIME_ARCHIVE_FORMAT,\n url: distributionUrl(archive.url),\n bytes: integer(archive.bytes, 512 * 1024 * 1024, 1),\n sha256: sha(archive.sha256),\n },\n files,\n content_sha256: content,\n production_lock: requiredFile(item.production_lock),\n sbom: requiredFile(item.sbom),\n licenses,\n provenance,\n protocols,\n asset_fingerprints,\n };\n}\nfunction componentPath(\n value: unknown,\n components: readonly RuntimeComponent[],\n target: string,\n executable = false,\n): ComponentPath {\n const entry = record(value, 'component path');\n exact(entry, ['component', 'path'], 'component path');\n const componentId = id(entry.component),\n file = relativeFile(entry.path);\n const owner = components.find((item) => item.platform === target && item.id === componentId);\n const fact = owner?.files.find((item) => item.path === file);\n if (!fact || (executable && fact.mode !== 493)) invalid('launch file reference');\n return { component: componentId, path: file };\n}\nexport function parseRuntimeManifest(value: unknown): RuntimeManifest {\n const item = record(value, 'manifest');\n exact(\n item,\n [\n 'schema',\n 'bootstrap_protocol',\n 'product',\n 'minimum_hosts',\n 'workspace',\n 'components',\n 'launches',\n ],\n 'manifest',\n );\n if (\n item.schema !== RUNTIME_MANIFEST_SCHEMA ||\n item.bootstrap_protocol !== RUNTIME_BOOTSTRAP_PROTOCOL\n )\n invalid('manifest protocol version');\n const product = record(item.product, 'product');\n exact(product, ['id', 'version'], 'product');\n const workspace = record(item.workspace, 'workspace');\n exact(workspace, ['read', 'write'], 'workspace');\n const read = compatibility(workspace.read),\n write = compatibility(workspace.write);\n for (const entry of write)\n if (\n !read.some(\n (candidate) =>\n candidate.schema === entry.schema &&\n entry.features.every((feature) => candidate.features.includes(feature)),\n )\n )\n invalid('write compatibility outside read support');\n const components = array(item.components, 128, 1).map(component);\n unique(\n components.map((item) => `${item.platform}:${item.id}`),\n 'platform component',\n );\n const minimum = record(item.minimum_hosts, 'minimum hosts');\n const minimum_hosts = Object.fromEntries(\n Object.entries(minimum).map(([key, value]) => {\n const target = platform(key),\n host = record(value, 'minimum host');\n exact(host, ['os_release', 'glibc'], 'minimum host');\n if (\n (target.startsWith('linux-') && typeof host.glibc !== 'string') ||\n (!target.startsWith('linux-') && host.glibc !== null)\n )\n invalid('host ABI');\n const glibc = host.glibc === null ? null : text(host.glibc, 'glibc version', 40);\n if (glibc !== null && !/^[0-9]+\\.[0-9]+$/u.test(glibc)) invalid('glibc version');\n return [target, { os_release: version(host.os_release), glibc }];\n }),\n );\n const supported = [...new Set(components.map((item) => item.platform))].sort();\n if (JSON.stringify(Object.keys(minimum_hosts).sort()) !== JSON.stringify(supported))\n invalid('host/component platform coverage');\n const launches: RuntimeLaunch[] = array(item.launches, 64, 1).map((value) => {\n const launch = record(value, 'launch');\n exact(launch, ['id', 'platform', 'executable', 'environment', 'argv'], 'launch');\n if (launch.environment !== 'isolated' && launch.environment !== 'cli-auth')\n invalid('launch environment');\n const target = platform(launch.platform);\n const argv = array(launch.argv, 32).map((value) => {\n const arg = record(value, 'launch argument');\n if (Object.hasOwn(arg, 'literal')) {\n exact(arg, ['literal'], 'literal argument');\n return { literal: text(arg.literal, 'literal argument', 4096) };\n }\n return componentPath(arg, components, target);\n });\n return {\n id: id(launch.id),\n platform: target,\n executable: componentPath(launch.executable, components, target, true),\n environment: launch.environment,\n argv,\n };\n });\n unique(\n launches.map((item) => `${item.platform}:${item.id}`),\n 'platform launch',\n );\n for (const target of supported)\n if (!launches.some((launch) => launch.platform === target)) invalid('platform launch coverage');\n return deepFreeze({\n schema: RUNTIME_MANIFEST_SCHEMA,\n bootstrap_protocol: RUNTIME_BOOTSTRAP_PROTOCOL,\n product: { id: id(product.id), version: version(product.version) },\n minimum_hosts,\n workspace: { read, write },\n components,\n launches,\n });\n}\nexport function trustRuntimeManifest(\n bytes: Uint8Array,\n expectedSha256: string,\n): TrustedRuntimeManifest {\n sha(expectedSha256);\n if (\n bytes.byteLength > 32 * 1024 * 1024 ||\n createHash('sha256').update(bytes).digest('hex') !== expectedSha256\n )\n runtimeError(\n 'RUNTIME_MANIFEST_INTEGRITY',\n 'Runtime manifest bytes do not match the independent trust anchor.',\n );\n let value: unknown;\n try {\n value = JSON.parse(Buffer.from(bytes).toString('utf8'));\n } catch {\n invalid('JSON');\n }\n const result = Object.freeze({ sha256: expectedSha256, manifest: parseRuntimeManifest(value) });\n trusted.add(result);\n return result;\n}\nexport function loadTrustedRuntimeManifest(\n file: string,\n expectedSha256: string,\n): TrustedRuntimeManifest {\n const stat = fs.lstatSync(file);\n if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 32 * 1024 * 1024)\n runtimeError('RUNTIME_MANIFEST_FILE', 'Runtime manifest must be a bounded regular file.');\n return trustRuntimeManifest(fs.readFileSync(file), expectedSha256);\n}\nexport function assertTrustedManifest(value: TrustedRuntimeManifest): void {\n if (!value || !trusted.has(value))\n runtimeError(\n 'RUNTIME_MANIFEST_UNTRUSTED',\n 'Supply a manifest verified against an independent trusted digest.',\n );\n}\nexport function componentKey(value: RuntimeComponent): string {\n return contentHash(value);\n}\nexport function assertWorkspaceCompatibility(\n value: TrustedRuntimeManifest,\n request: WorkspaceCompatibility,\n access: 'read' | 'write',\n): void {\n assertTrustedManifest(value);\n const support = value.manifest.workspace[access]?.find(\n (entry) => entry.schema === request.schema,\n );\n if (!support || !request.features.every((feature) => support.features.includes(feature)))\n runtimeError(\n 'RUNTIME_WORKSPACE_INCOMPATIBLE',\n 'The selected runtime does not support the requested workspace access/schema/features.',\n );\n}\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { FoundryCommandSpecAsyncSpawnOptions, FoundryCommandSpecSpawnResult } from '../../command-spec.js';
|
|
2
|
+
/** Resolve only after close, including cancellation and output overflow, so callers retain component leases. */
|
|
3
|
+
export declare function spawnRuntimeProcess(executable: string, argv: readonly string[], options: FoundryCommandSpecAsyncSpawnOptions): Promise<FoundryCommandSpecSpawnResult>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
/** Resolve only after close, including cancellation and output overflow, so callers retain component leases. */
|
|
3
|
+
export function spawnRuntimeProcess(executable, argv, options) {
|
|
4
|
+
return new Promise((resolve) => {
|
|
5
|
+
const child = spawn(executable, [...argv], {
|
|
6
|
+
cwd: options.cwd,
|
|
7
|
+
env: options.env,
|
|
8
|
+
shell: false,
|
|
9
|
+
windowsHide: true,
|
|
10
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
11
|
+
});
|
|
12
|
+
const stdout = [], stderr = [];
|
|
13
|
+
let bytes = 0;
|
|
14
|
+
let error;
|
|
15
|
+
let force;
|
|
16
|
+
const stop = () => {
|
|
17
|
+
child.kill('SIGTERM');
|
|
18
|
+
force ??= setTimeout(() => child.kill('SIGKILL'), 3000);
|
|
19
|
+
};
|
|
20
|
+
const abort = () => {
|
|
21
|
+
error = new Error('Runtime execution was interrupted.');
|
|
22
|
+
stop();
|
|
23
|
+
};
|
|
24
|
+
options.signal.addEventListener('abort', abort, { once: true });
|
|
25
|
+
if (options.signal.aborted)
|
|
26
|
+
abort();
|
|
27
|
+
const capture = (target, chunk) => {
|
|
28
|
+
bytes += chunk.length;
|
|
29
|
+
if (bytes > (options.maxBuffer ?? 16 * 1024 * 1024)) {
|
|
30
|
+
error = new Error('Runtime output exceeded its bound.');
|
|
31
|
+
stop();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
target.push(chunk);
|
|
35
|
+
};
|
|
36
|
+
child.stdout.on('data', (chunk) => capture(stdout, chunk));
|
|
37
|
+
child.stderr.on('data', (chunk) => capture(stderr, chunk));
|
|
38
|
+
child.once('error', (value) => {
|
|
39
|
+
error = value;
|
|
40
|
+
});
|
|
41
|
+
child.once('close', (status, signal) => {
|
|
42
|
+
if (force)
|
|
43
|
+
clearTimeout(force);
|
|
44
|
+
options.signal.removeEventListener('abort', abort);
|
|
45
|
+
resolve({
|
|
46
|
+
stdout: Buffer.concat(stdout).toString('utf8'),
|
|
47
|
+
stderr: Buffer.concat(stderr).toString('utf8'),
|
|
48
|
+
status,
|
|
49
|
+
signal,
|
|
50
|
+
...(error ? { error } : {}),
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.js","sourceRoot":"","sources":["../../../../src/lib/runtime/process.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'node:child_process';\nimport type {\n FoundryCommandSpecAsyncSpawnOptions,\n FoundryCommandSpecSpawnResult,\n} from '../../command-spec.js';\n\n/** Resolve only after close, including cancellation and output overflow, so callers retain component leases. */\nexport function spawnRuntimeProcess(\n executable: string,\n argv: readonly string[],\n options: FoundryCommandSpecAsyncSpawnOptions,\n): Promise<FoundryCommandSpecSpawnResult> {\n return new Promise((resolve) => {\n const child = spawn(executable, [...argv], {\n cwd: options.cwd,\n env: options.env,\n shell: false,\n windowsHide: true,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n const stdout: Buffer[] = [],\n stderr: Buffer[] = [];\n let bytes = 0;\n let error: Error | undefined;\n let force: NodeJS.Timeout | undefined;\n const stop = () => {\n child.kill('SIGTERM');\n force ??= setTimeout(() => child.kill('SIGKILL'), 3000);\n };\n const abort = () => {\n error = new Error('Runtime execution was interrupted.');\n stop();\n };\n options.signal.addEventListener('abort', abort, { once: true });\n if (options.signal.aborted) abort();\n const capture = (target: Buffer[], chunk: Buffer) => {\n bytes += chunk.length;\n if (bytes > (options.maxBuffer ?? 16 * 1024 * 1024)) {\n error = new Error('Runtime output exceeded its bound.');\n stop();\n return;\n }\n target.push(chunk);\n };\n child.stdout.on('data', (chunk: Buffer) => capture(stdout, chunk));\n child.stderr.on('data', (chunk: Buffer) => capture(stderr, chunk));\n child.once('error', (value) => {\n error = value;\n });\n child.once('close', (status, signal) => {\n if (force) clearTimeout(force);\n options.signal.removeEventListener('abort', abort);\n resolve({\n stdout: Buffer.concat(stdout).toString('utf8'),\n stderr: Buffer.concat(stderr).toString('utf8'),\n status,\n signal,\n ...(error ? { error } : {}),\n });\n });\n });\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function defaultRuntimeCache(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): string;
|
|
2
|
+
export declare function canonicalCacheRoot(value: string): string;
|
|
3
|
+
export declare function cachePath(root: string, relative: string): string;
|
|
4
|
+
export declare function writeAll(fd: number, bytes: Uint8Array): void;
|
|
5
|
+
export declare function writeOnce(root: string, relative: string, bytes: Uint8Array): void;
|
|
6
|
+
export declare function openRuntimeCache(value: string, create: boolean): string;
|
|
7
|
+
export declare function readCacheJson(root: string, relative: string, limit?: number): unknown;
|
|
8
|
+
export declare function ensureRuntimeCache(value: string): Promise<string>;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { withBatchRunLock } from '../../batch.js';
|
|
6
|
+
import { runtimeError } from './files.js';
|
|
7
|
+
const marker = Buffer.from('{"schema":"tiangong-lca.runtime-cache.v1"}\n');
|
|
8
|
+
export function defaultRuntimeCache(env = process.env, platform = process.platform) {
|
|
9
|
+
const home = env.HOME || env.USERPROFILE || os.homedir();
|
|
10
|
+
const base = platform === 'darwin'
|
|
11
|
+
? path.join(home, 'Library', 'Caches')
|
|
12
|
+
: platform === 'win32'
|
|
13
|
+
? env.LOCALAPPDATA || path.join(home, 'AppData', 'Local')
|
|
14
|
+
: env.XDG_CACHE_HOME || path.join(home, '.cache');
|
|
15
|
+
return path.join(base, 'tiangong-lca', 'runtimes', 'v1');
|
|
16
|
+
}
|
|
17
|
+
export function canonicalCacheRoot(value) {
|
|
18
|
+
if (!path.isAbsolute(value))
|
|
19
|
+
runtimeError('RUNTIME_CACHE_PATH', 'Runtime cache must be an absolute directory.');
|
|
20
|
+
const missing = [];
|
|
21
|
+
let current = path.resolve(value);
|
|
22
|
+
while (!fs.existsSync(current)) {
|
|
23
|
+
missing.unshift(path.basename(current));
|
|
24
|
+
const parent = path.dirname(current);
|
|
25
|
+
if (parent === current)
|
|
26
|
+
runtimeError('RUNTIME_CACHE_PATH', 'Runtime cache has no existing parent.');
|
|
27
|
+
current = parent;
|
|
28
|
+
}
|
|
29
|
+
if (missing.length && !fs.statSync(current).isDirectory())
|
|
30
|
+
runtimeError('RUNTIME_CACHE_PATH', 'Runtime cache parent must be a directory.');
|
|
31
|
+
const root = path.join(fs.realpathSync(current), ...missing);
|
|
32
|
+
if (root === path.parse(root).root || root === os.homedir())
|
|
33
|
+
runtimeError('RUNTIME_CACHE_PATH', 'A filesystem or home root cannot be a runtime cache.');
|
|
34
|
+
return root;
|
|
35
|
+
}
|
|
36
|
+
export function cachePath(root, relative) {
|
|
37
|
+
if (!relative ||
|
|
38
|
+
relative.includes('\\') ||
|
|
39
|
+
path.isAbsolute(relative) ||
|
|
40
|
+
relative.split(/[\\/]/u).some((part) => !part || part === '.' || part === '..'))
|
|
41
|
+
runtimeError('RUNTIME_CACHE_PATH', 'Cache paths must remain within the owned root.');
|
|
42
|
+
let current = root;
|
|
43
|
+
for (const segment of ['', ...relative.split('/')]) {
|
|
44
|
+
if (segment)
|
|
45
|
+
current = path.join(current, segment);
|
|
46
|
+
try {
|
|
47
|
+
const stat = fs.lstatSync(current);
|
|
48
|
+
if (stat.isSymbolicLink() || (current !== path.join(root, relative) && !stat.isDirectory()))
|
|
49
|
+
runtimeError('RUNTIME_CACHE_PATH', 'Cache paths cannot traverse links or non-directories.');
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (error.code !== 'ENOENT')
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return current;
|
|
57
|
+
}
|
|
58
|
+
export function writeAll(fd, bytes) {
|
|
59
|
+
let offset = 0;
|
|
60
|
+
while (offset < bytes.byteLength) {
|
|
61
|
+
const wrote = fs.writeSync(fd, bytes, offset, bytes.byteLength - offset);
|
|
62
|
+
if (wrote <= 0)
|
|
63
|
+
runtimeError('RUNTIME_WRITE_FAILED', 'Runtime artifact could not be written completely.');
|
|
64
|
+
offset += wrote;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function writeOnce(root, relative, bytes) {
|
|
68
|
+
const target = cachePath(root, relative);
|
|
69
|
+
fs.mkdirSync(path.dirname(target), { recursive: true, mode: 0o700 });
|
|
70
|
+
cachePath(root, relative);
|
|
71
|
+
if (fs.existsSync(target)) {
|
|
72
|
+
if (!fs.lstatSync(target).isFile() || !fs.readFileSync(target).equals(Buffer.from(bytes)))
|
|
73
|
+
runtimeError('RUNTIME_CACHE_CONFLICT', 'An immutable cache record cannot be replaced.');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const temp = cachePath(root, `${relative}.${randomUUID()}.tmp`);
|
|
77
|
+
const fd = fs.openSync(temp, 'wx', 0o600);
|
|
78
|
+
try {
|
|
79
|
+
writeAll(fd, bytes);
|
|
80
|
+
fs.fsyncSync(fd);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
fs.closeSync(fd);
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
try {
|
|
87
|
+
fs.linkSync(temp, target);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (error.code !== 'EEXIST')
|
|
91
|
+
throw error;
|
|
92
|
+
if (!fs.readFileSync(target).equals(Buffer.from(bytes)))
|
|
93
|
+
runtimeError('RUNTIME_CACHE_CONFLICT', 'Concurrent cache records disagree.');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
fs.unlinkSync(temp);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export function openRuntimeCache(value, create) {
|
|
101
|
+
const root = canonicalCacheRoot(value);
|
|
102
|
+
const file = cachePath(root, '.runtime-cache.json');
|
|
103
|
+
if (!fs.existsSync(file)) {
|
|
104
|
+
if (fs.existsSync(root) &&
|
|
105
|
+
(!fs.lstatSync(root).isDirectory() || fs.readdirSync(root).length > 0))
|
|
106
|
+
runtimeError('RUNTIME_CACHE_UNOWNED', 'Existing data is not a runtime-manager cache.');
|
|
107
|
+
if (!create)
|
|
108
|
+
return root;
|
|
109
|
+
fs.mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
110
|
+
writeOnce(root, '.runtime-cache.json', marker);
|
|
111
|
+
}
|
|
112
|
+
if (!fs.lstatSync(file).isFile() ||
|
|
113
|
+
fs.lstatSync(file).size !== marker.length ||
|
|
114
|
+
!fs.readFileSync(file).equals(marker))
|
|
115
|
+
runtimeError('RUNTIME_CACHE_UNOWNED', 'Runtime cache ownership marker is invalid.');
|
|
116
|
+
return root;
|
|
117
|
+
}
|
|
118
|
+
export function readCacheJson(root, relative, limit = 1024 * 1024) {
|
|
119
|
+
const file = cachePath(root, relative);
|
|
120
|
+
const stat = fs.lstatSync(file);
|
|
121
|
+
if (!stat.isFile() || stat.size > limit)
|
|
122
|
+
runtimeError('RUNTIME_CACHE_RECORD', 'Runtime cache record must be a bounded regular file.');
|
|
123
|
+
const bytes = fs.readFileSync(file);
|
|
124
|
+
if (bytes.length > limit)
|
|
125
|
+
runtimeError('RUNTIME_CACHE_RECORD', 'Runtime cache record grew while reading.');
|
|
126
|
+
try {
|
|
127
|
+
return JSON.parse(bytes.toString('utf8'));
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
runtimeError('RUNTIME_CACHE_RECORD', 'Runtime cache record is not complete JSON.');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export async function ensureRuntimeCache(value) {
|
|
134
|
+
const root = canonicalCacheRoot(value);
|
|
135
|
+
fs.mkdirSync(path.dirname(root), { recursive: true, mode: 0o700 });
|
|
136
|
+
return withBatchRunLock({
|
|
137
|
+
runPath: `${root}.initialize.json`,
|
|
138
|
+
identity: { schema: 'runtime-cache-initialize.v1', root },
|
|
139
|
+
reason: 'Runtime cache initialization',
|
|
140
|
+
}, () => openRuntimeCache(root, true));
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../../src/lib/runtime/storage.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { randomUUID } from 'node:crypto';\nimport { withBatchRunLock } from '../../batch.js';\nimport { runtimeError } from './files.js';\nconst marker = Buffer.from('{\"schema\":\"tiangong-lca.runtime-cache.v1\"}\\n');\n\nexport function defaultRuntimeCache(\n env: NodeJS.ProcessEnv = process.env,\n platform: NodeJS.Platform = process.platform,\n): string {\n const home = env.HOME || env.USERPROFILE || os.homedir();\n const base =\n platform === 'darwin'\n ? path.join(home, 'Library', 'Caches')\n : platform === 'win32'\n ? env.LOCALAPPDATA || path.join(home, 'AppData', 'Local')\n : env.XDG_CACHE_HOME || path.join(home, '.cache');\n return path.join(base, 'tiangong-lca', 'runtimes', 'v1');\n}\nexport function canonicalCacheRoot(value: string): string {\n if (!path.isAbsolute(value))\n runtimeError('RUNTIME_CACHE_PATH', 'Runtime cache must be an absolute directory.');\n const missing: string[] = [];\n let current = path.resolve(value);\n while (!fs.existsSync(current)) {\n missing.unshift(path.basename(current));\n const parent = path.dirname(current);\n if (parent === current)\n runtimeError('RUNTIME_CACHE_PATH', 'Runtime cache has no existing parent.');\n current = parent;\n }\n if (missing.length && !fs.statSync(current).isDirectory())\n runtimeError('RUNTIME_CACHE_PATH', 'Runtime cache parent must be a directory.');\n const root = path.join(fs.realpathSync(current), ...missing);\n if (root === path.parse(root).root || root === os.homedir())\n runtimeError('RUNTIME_CACHE_PATH', 'A filesystem or home root cannot be a runtime cache.');\n return root;\n}\nexport function cachePath(root: string, relative: string): string {\n if (\n !relative ||\n relative.includes('\\\\') ||\n path.isAbsolute(relative) ||\n relative.split(/[\\\\/]/u).some((part) => !part || part === '.' || part === '..')\n )\n runtimeError('RUNTIME_CACHE_PATH', 'Cache paths must remain within the owned root.');\n let current = root;\n for (const segment of ['', ...relative.split('/')]) {\n if (segment) current = path.join(current, segment);\n try {\n const stat = fs.lstatSync(current);\n if (stat.isSymbolicLink() || (current !== path.join(root, relative) && !stat.isDirectory()))\n runtimeError('RUNTIME_CACHE_PATH', 'Cache paths cannot traverse links or non-directories.');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n }\n }\n return current;\n}\nexport function writeAll(fd: number, bytes: Uint8Array): void {\n let offset = 0;\n while (offset < bytes.byteLength) {\n const wrote = fs.writeSync(fd, bytes, offset, bytes.byteLength - offset);\n if (wrote <= 0)\n runtimeError('RUNTIME_WRITE_FAILED', 'Runtime artifact could not be written completely.');\n offset += wrote;\n }\n}\nexport function writeOnce(root: string, relative: string, bytes: Uint8Array): void {\n const target = cachePath(root, relative);\n fs.mkdirSync(path.dirname(target), { recursive: true, mode: 0o700 });\n cachePath(root, relative);\n if (fs.existsSync(target)) {\n if (!fs.lstatSync(target).isFile() || !fs.readFileSync(target).equals(Buffer.from(bytes)))\n runtimeError('RUNTIME_CACHE_CONFLICT', 'An immutable cache record cannot be replaced.');\n return;\n }\n const temp = cachePath(root, `${relative}.${randomUUID()}.tmp`);\n const fd = fs.openSync(temp, 'wx', 0o600);\n try {\n writeAll(fd, bytes);\n fs.fsyncSync(fd);\n } finally {\n fs.closeSync(fd);\n }\n try {\n try {\n fs.linkSync(temp, target);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;\n if (!fs.readFileSync(target).equals(Buffer.from(bytes)))\n runtimeError('RUNTIME_CACHE_CONFLICT', 'Concurrent cache records disagree.');\n }\n } finally {\n fs.unlinkSync(temp);\n }\n}\nexport function openRuntimeCache(value: string, create: boolean): string {\n const root = canonicalCacheRoot(value);\n const file = cachePath(root, '.runtime-cache.json');\n if (!fs.existsSync(file)) {\n if (\n fs.existsSync(root) &&\n (!fs.lstatSync(root).isDirectory() || fs.readdirSync(root).length > 0)\n )\n runtimeError('RUNTIME_CACHE_UNOWNED', 'Existing data is not a runtime-manager cache.');\n if (!create) return root;\n fs.mkdirSync(root, { recursive: true, mode: 0o700 });\n writeOnce(root, '.runtime-cache.json', marker);\n }\n if (\n !fs.lstatSync(file).isFile() ||\n fs.lstatSync(file).size !== marker.length ||\n !fs.readFileSync(file).equals(marker)\n )\n runtimeError('RUNTIME_CACHE_UNOWNED', 'Runtime cache ownership marker is invalid.');\n return root;\n}\nexport function readCacheJson(root: string, relative: string, limit = 1024 * 1024): unknown {\n const file = cachePath(root, relative);\n const stat = fs.lstatSync(file);\n if (!stat.isFile() || stat.size > limit)\n runtimeError('RUNTIME_CACHE_RECORD', 'Runtime cache record must be a bounded regular file.');\n const bytes = fs.readFileSync(file);\n if (bytes.length > limit)\n runtimeError('RUNTIME_CACHE_RECORD', 'Runtime cache record grew while reading.');\n try {\n return JSON.parse(bytes.toString('utf8'));\n } catch {\n runtimeError('RUNTIME_CACHE_RECORD', 'Runtime cache record is not complete JSON.');\n }\n}\n\nexport async function ensureRuntimeCache(value: string): Promise<string> {\n const root = canonicalCacheRoot(value);\n fs.mkdirSync(path.dirname(root), { recursive: true, mode: 0o700 });\n return withBatchRunLock(\n {\n runPath: `${root}.initialize.json`,\n identity: { schema: 'runtime-cache-initialize.v1', root },\n reason: 'Runtime cache initialization',\n },\n () => openRuntimeCache(root, true),\n );\n}\n"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export declare const CLI_RUNTIME_DESCRIPTOR_SCHEMA: 'tiangong-lca.cli-runtime-descriptor.v1';
|
|
2
|
+
export declare const CLI_RUNTIME_EXPECTATION_SCHEMA: 'tiangong-lca.cli-runtime-expectation.v1';
|
|
3
|
+
export declare const RUNTIME_PLATFORMS: readonly ["darwin-arm64", "linux-x64", "linux-arm64", "win32-x64"];
|
|
4
|
+
export type RuntimePlatform = (typeof RUNTIME_PLATFORMS)[number];
|
|
5
|
+
export type RuntimeFileFact = Readonly<{
|
|
6
|
+
path: string;
|
|
7
|
+
bytes: number;
|
|
8
|
+
sha256: string;
|
|
9
|
+
}>;
|
|
10
|
+
export type CliRuntimeDescriptor = Readonly<{
|
|
11
|
+
schema: typeof CLI_RUNTIME_DESCRIPTOR_SCHEMA;
|
|
12
|
+
scope: 'cli-package';
|
|
13
|
+
package: Readonly<{
|
|
14
|
+
name: '@tiangong-lca/cli';
|
|
15
|
+
version: string;
|
|
16
|
+
root: string;
|
|
17
|
+
manifest_sha256: string;
|
|
18
|
+
}>;
|
|
19
|
+
platform: RuntimePlatform;
|
|
20
|
+
node: Readonly<{
|
|
21
|
+
version: string;
|
|
22
|
+
executable: string;
|
|
23
|
+
bytes: number;
|
|
24
|
+
sha256: string;
|
|
25
|
+
}>;
|
|
26
|
+
command: Readonly<{
|
|
27
|
+
executable: string;
|
|
28
|
+
argv: readonly string[];
|
|
29
|
+
}>;
|
|
30
|
+
assets: Readonly<{
|
|
31
|
+
tidas_schema_root: string;
|
|
32
|
+
sha256: string;
|
|
33
|
+
}>;
|
|
34
|
+
files: readonly RuntimeFileFact[];
|
|
35
|
+
content_sha256: string;
|
|
36
|
+
}>;
|
|
37
|
+
/** Supplied by an independent trusted release/component manifest, never copied from the observation being checked. */
|
|
38
|
+
export type CliRuntimeExpectation = Readonly<{
|
|
39
|
+
schema: typeof CLI_RUNTIME_EXPECTATION_SCHEMA;
|
|
40
|
+
package_version: string;
|
|
41
|
+
platform: RuntimePlatform;
|
|
42
|
+
content_sha256: string;
|
|
43
|
+
node_version: string;
|
|
44
|
+
node_sha256: string;
|
|
45
|
+
}>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const CLI_RUNTIME_DESCRIPTOR_SCHEMA = 'tiangong-lca.cli-runtime-descriptor.v1';
|
|
2
|
+
export const CLI_RUNTIME_EXPECTATION_SCHEMA = 'tiangong-lca.cli-runtime-expectation.v1';
|
|
3
|
+
export const RUNTIME_PLATFORMS = Object.freeze([
|
|
4
|
+
'darwin-arm64',
|
|
5
|
+
'linux-x64',
|
|
6
|
+
'linux-arm64',
|
|
7
|
+
'win32-x64',
|
|
8
|
+
]);
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/lib/runtime/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,6BAA6B,GAAG,wCAAiD,CAAC;AAC/F,MAAM,CAAC,MAAM,8BAA8B,GAAG,yCAAkD,CAAC;AACjG,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7C,cAAc;IACd,WAAW;IACX,aAAa;IACb,WAAW;CACH,CAAC,CAAC","sourcesContent":["export const CLI_RUNTIME_DESCRIPTOR_SCHEMA = 'tiangong-lca.cli-runtime-descriptor.v1' as const;\nexport const CLI_RUNTIME_EXPECTATION_SCHEMA = 'tiangong-lca.cli-runtime-expectation.v1' as const;\nexport const RUNTIME_PLATFORMS = Object.freeze([\n 'darwin-arm64',\n 'linux-x64',\n 'linux-arm64',\n 'win32-x64',\n] as const);\nexport type RuntimePlatform = (typeof RUNTIME_PLATFORMS)[number];\n\nexport type RuntimeFileFact = Readonly<{ path: string; bytes: number; sha256: string }>;\nexport type CliRuntimeDescriptor = Readonly<{\n schema: typeof CLI_RUNTIME_DESCRIPTOR_SCHEMA;\n scope: 'cli-package';\n package: Readonly<{\n name: '@tiangong-lca/cli';\n version: string;\n root: string;\n manifest_sha256: string;\n }>;\n platform: RuntimePlatform;\n node: Readonly<{ version: string; executable: string; bytes: number; sha256: string }>;\n command: Readonly<{ executable: string; argv: readonly string[] }>;\n assets: Readonly<{ tidas_schema_root: string; sha256: string }>;\n files: readonly RuntimeFileFact[];\n content_sha256: string;\n}>;\n\n/** Supplied by an independent trusted release/component manifest, never copied from the observation being checked. */\nexport type CliRuntimeExpectation = Readonly<{\n schema: typeof CLI_RUNTIME_EXPECTATION_SCHEMA;\n package_version: string;\n platform: RuntimePlatform;\n content_sha256: string;\n node_version: string;\n node_sha256: string;\n}>;\n"]}
|