@amalgm/shell 0.1.164-main.38989777736 → 0.1.164-main.39005514559
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.
|
@@ -10,6 +10,7 @@ import { pipeline } from 'node:stream/promises';
|
|
|
10
10
|
import { Readable } from 'node:stream';
|
|
11
11
|
import { DatabaseSync } from 'node:sqlite';
|
|
12
12
|
import { Metadata, MetadataKind } from '@tufjs/models';
|
|
13
|
+
import { LAYOUT_VERSION } from '@amalgm/core/identity';
|
|
13
14
|
import { admitManagedRuntimeRelease } from '@amalgm/core/supervision';
|
|
14
15
|
import { runtimeRoot } from '../dist/updates/trust.js';
|
|
15
16
|
import { examineArchive, hashFile, runIsolated } from '../dist/updates/artifacts.js';
|
|
@@ -43,6 +44,36 @@ function journal(identity) {
|
|
|
43
44
|
} finally { db.close(); }
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
/** Unpack one exact public archive into `directory/package` and install its production dependencies. */
|
|
48
|
+
async function installArchive(artifact, directory, examination) {
|
|
49
|
+
await fs.mkdir(directory, { recursive: true });
|
|
50
|
+
const archive = path.join(directory, 'archive.tgz');
|
|
51
|
+
const response = await fetch(`https://registry.npmjs.org/amalgm/-/amalgm-${artifact.version}.tgz`, { redirect: 'error', signal: AbortSignal.timeout(180_000) });
|
|
52
|
+
assert.equal(response.status, 200, `The exact public package ${artifact.version} must be available`);
|
|
53
|
+
await pipeline(Readable.fromWeb(response.body), createWriteStream(archive, { flags: 'wx' }));
|
|
54
|
+
assert.equal(await hashFile(archive), artifact.sha512);
|
|
55
|
+
await examineArchive(archive, directory);
|
|
56
|
+
const packageRoot = path.join(directory, 'package');
|
|
57
|
+
const manifest = await readJson(path.join(packageRoot, 'package.json'));
|
|
58
|
+
assert.equal(manifest.name, 'amalgm'); assert.equal(manifest.version, artifact.version);
|
|
59
|
+
for (const name of ['repository', 'branch', 'commit']) assert.equal(manifest.amalgmSource[name], artifact.source[name]);
|
|
60
|
+
assert.equal(await hashFile(path.join(packageRoot, 'npm-shrinkwrap.json')), artifact.lockSha512);
|
|
61
|
+
const shippedRoot = await readJson(path.join(packageRoot, 'config/releases/trust/runtime', `${examination.lane}.root.json`));
|
|
62
|
+
assert.deepEqual(shippedRoot, examination.roots[shippedRoot.signed.version - 1], 'The package must carry the actual reviewed trust root');
|
|
63
|
+
const npm = path.join(path.dirname(createRequire(import.meta.url).resolve('npm/package.json')), 'bin/npm-cli.js');
|
|
64
|
+
await runIsolated(process.execPath, [npm, 'ci', '--omit=dev', '--strict-allow-scripts', '--no-audit', '--no-fund'], packageRoot, new AbortController().signal);
|
|
65
|
+
return packageRoot;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** The on-disk layout version of the Core an installed package carries. */
|
|
69
|
+
async function packageLayout(packageRoot) {
|
|
70
|
+
const core = path.join(packageRoot, 'node_modules', '@amalgm', 'core');
|
|
71
|
+
const entry = (await readJson(path.join(core, 'package.json'))).exports['./identity'].default;
|
|
72
|
+
const { LAYOUT_VERSION: version } = await import(pathToFileURL(path.join(core, entry)).href);
|
|
73
|
+
assert.ok(Number.isSafeInteger(version) && version > 0, 'An installed package must declare its layout version');
|
|
74
|
+
return version;
|
|
75
|
+
}
|
|
76
|
+
|
|
46
77
|
/** Failure evidence observes existing owners without copying credentials or
|
|
47
78
|
* creating another update decision. Each input and output has a byte bound. */
|
|
48
79
|
export async function runtimeFailureEvidence(packageRoot, identity) {
|
|
@@ -186,12 +217,12 @@ test('the real native Shell service replaces its authorized package and survives
|
|
|
186
217
|
bootstrapProof: examination.previous === null, legacyAdoptionCertified: false, passed: false,
|
|
187
218
|
previousArtifact: artifact, candidateArtifact: nextArtifact, checkpoints: [] };
|
|
188
219
|
const temporary = path.resolve(workerTemporary);
|
|
189
|
-
let network; let service; let initializingFixtures = false;
|
|
220
|
+
let network; let service; let serviceRoot; let initializingFixtures = false;
|
|
190
221
|
t.after(async () => {
|
|
191
222
|
const errors = [];
|
|
192
223
|
if (!proof.passed) {
|
|
193
224
|
try {
|
|
194
|
-
const evidence = await runtimeFailureEvidence(service ?
|
|
225
|
+
const evidence = await runtimeFailureEvidence(service ? serviceRoot : null, service?.identity);
|
|
195
226
|
await fs.writeFile(path.join(directory, `runtime-update-${process.platform}.diagnostics.json`),
|
|
196
227
|
JSON.stringify({ schema: 1, platform: process.platform, lane: examination.lane,
|
|
197
228
|
lastCheckpoint: proof.checkpoints.at(-1)?.phase ?? null, ...evidence }, null, 2) + '\n', { mode: 0o600 });
|
|
@@ -205,48 +236,49 @@ test('the real native Shell service replaces its authorized package and survives
|
|
|
205
236
|
await fs.writeFile(path.join(temporary, 'proof.json'), JSON.stringify(proof, null, 2) + '\n');
|
|
206
237
|
if (errors.length) throw new AggregateError(errors, 'Native runtime examination cleanup failed');
|
|
207
238
|
});
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const
|
|
220
|
-
assert.deepEqual(shippedRoot, examination.roots[shippedRoot.signed.version - 1], 'The package must carry the actual reviewed trust root');
|
|
221
|
-
const npm = path.join(path.dirname(createRequire(import.meta.url).resolve('npm/package.json')), 'bin/npm-cli.js');
|
|
222
|
-
await runIsolated(process.execPath, [npm, 'ci', '--omit=dev', '--strict-allow-scripts', '--no-audit', '--no-fund'], packageRoot, new AbortController().signal);
|
|
239
|
+
const packageRoot = await installArchive(artifact, temporary, examination);
|
|
240
|
+
// A new on-disk layout has no migration: a computer on the old layout starts
|
|
241
|
+
// again from a fresh install, so the baseline cannot adopt the candidate.
|
|
242
|
+
// Certify that fresh install of the exact candidate instead.
|
|
243
|
+
const layout = { from: await packageLayout(packageRoot), to: LAYOUT_VERSION };
|
|
244
|
+
const reset = layout.from !== layout.to;
|
|
245
|
+
serviceRoot = reset ? await installArchive(nextArtifact, path.join(temporary, 'candidate'), examination) : packageRoot;
|
|
246
|
+
if (reset) {
|
|
247
|
+
assert.equal(await packageLayout(serviceRoot), LAYOUT_VERSION, 'The candidate archive must carry the examined layout');
|
|
248
|
+
proof.layoutReset = layout;
|
|
249
|
+
}
|
|
250
|
+
const installed = reset ? { release: view.candidate, artifact: nextArtifact } : { release: view.baseline, artifact };
|
|
223
251
|
initializingFixtures = true;
|
|
224
|
-
network = await startNetworkView({ temporary, immutable: view.immutable, previous: view.
|
|
225
|
-
events: view.events, hint: { id: examination.id, sequence: examination.candidate.target.sequence },
|
|
226
|
-
|
|
252
|
+
network = await startNetworkView({ temporary, immutable: view.immutable, previous: reset ? view.candidateView : view.previous,
|
|
253
|
+
candidate: view.candidateView, events: view.events, hint: { id: examination.id, sequence: examination.candidate.target.sequence },
|
|
254
|
+
serviceEnvironment: true });
|
|
255
|
+
service = await nativeInstalledService({ packageRoot: serviceRoot, label: examination.lane });
|
|
227
256
|
initializingFixtures = false;
|
|
228
|
-
const baseline = await until(
|
|
257
|
+
const baseline = await until(`Verified installed ${reset ? 'candidate' : 'baseline'} and native service health`, async () => {
|
|
229
258
|
const state = journal(service.identity); const status = await service.status();
|
|
230
|
-
return state.policy?.active?.digest ===
|
|
231
|
-
&& !state.policy.transaction && status.version === artifact.version ? status : null;
|
|
259
|
+
return state.policy?.active?.digest === installed.release.digest && state.policy.activeHealthy
|
|
260
|
+
&& !state.policy.transaction && status.version === installed.artifact.version ? status : null;
|
|
232
261
|
});
|
|
233
262
|
assert.ok(baseline.bootstrapPid && baseline.bootstrapPid !== baseline.controllerPid, 'The OS must own the stable launcher independently of the controller package');
|
|
234
263
|
const marker = crypto.randomUUID();
|
|
235
264
|
const workspace = service.paths.workspaces; await fs.mkdir(workspace, { recursive: true });
|
|
236
265
|
const markerFile = path.join(workspace, 'native-runtime-upgrade-marker.txt'); await fs.writeFile(markerFile, marker);
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
266
|
+
proof.checkpoints.push({ phase: reset ? 'fresh-candidate' : 'baseline', bootstrapPid: baseline.bootstrapPid, controllerPid: baseline.controllerPid, childPid: baseline.childPid });
|
|
267
|
+
let current = baseline;
|
|
268
|
+
if (!reset) {
|
|
269
|
+
await until('Runtime promotion event subscription', async () => (await network.command({ operation: 'status' })).subscribers > 0);
|
|
270
|
+
await network.command({ operation: 'publish' });
|
|
271
|
+
current = await until('Event-driven staging, controller replacement, and native runtime healthy commit', async () => {
|
|
272
|
+
const state = journal(service.identity); const status = await service.status();
|
|
273
|
+
return state.policy?.active?.digest === view.candidate.digest && state.policy.activeHealthy
|
|
274
|
+
&& !state.policy.transaction && state.launch.pending === null && status.version === nextArtifact.version ? status : null;
|
|
275
|
+
});
|
|
276
|
+
assert.equal(current.bootstrapPid, baseline.bootstrapPid, 'A package handover must preserve the stable OS-owned launcher');
|
|
277
|
+
assert.notEqual(current.controllerPid, baseline.controllerPid); assert.notEqual(current.childPid, baseline.childPid);
|
|
278
|
+
assert.deepEqual(current.binding, baseline.binding);
|
|
279
|
+
assert.deepEqual(current.durable, baseline.durable, 'Native replacement must preserve registration and credentials byte for byte');
|
|
280
|
+
assert.equal(await fs.readFile(markerFile, 'utf8'), marker);
|
|
281
|
+
}
|
|
250
282
|
for (const name of ['repository', 'branch', 'commit']) assert.equal(current.source[name], nextArtifact.source[name]);
|
|
251
283
|
const selected = journal(service.identity).launch.current;
|
|
252
284
|
const actual = await readJson(path.resolve(selected.bin, '../../package.json'));
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amalgm/shell",
|
|
3
|
-
"version": "0.1.164-main.
|
|
3
|
+
"version": "0.1.164-main.39005514559",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@amalgm/shell",
|
|
9
|
-
"version": "0.1.164-main.
|
|
9
|
+
"version": "0.1.164-main.39005514559",
|
|
10
10
|
"license": "UNLICENSED",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@amalgm/agents": "0.2.3-main.38983836120",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amalgm/shell",
|
|
3
|
-
"version": "0.1.164-main.
|
|
3
|
+
"version": "0.1.164-main.39005514559",
|
|
4
4
|
"description": "The Amalgm runtime host assembled from the published @amalgm SDK capabilities.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -174,11 +174,11 @@
|
|
|
174
174
|
}
|
|
175
175
|
]
|
|
176
176
|
},
|
|
177
|
-
"gitHead": "
|
|
177
|
+
"gitHead": "907e591762a12660913b3de1ae7ed21830ccdc26",
|
|
178
178
|
"amalgmSource": {
|
|
179
179
|
"repository": "amalgm-inc/amalgm-shell",
|
|
180
180
|
"branch": "main",
|
|
181
|
-
"commit": "
|
|
182
|
-
"occurrence": "
|
|
181
|
+
"commit": "907e591762a12660913b3de1ae7ed21830ccdc26",
|
|
182
|
+
"occurrence": "39005514559"
|
|
183
183
|
}
|
|
184
184
|
}
|