mirror of
https://github.com/nexu-io/open-design.git
synced 2026-09-20 06:15:06 +08:00
8ab7c3d5f1
* feat(standalone): add shell-neutral exact lifecycle * feat(terminal): add native exact cold-start carrier * test(terminal): exercise mutable exact channel heads * feat(standalone): model synced blobs and Shell updates * feat(terminal): exercise the complete Shell lifecycle * feat(release): add the independent exact Terminal line * test(exact): run the full local Terminal release line * feat(terminal): harden exact Sidecar lifecycle * feat(standalone): prove exact update transactions * refactor(standalone): separate shell lifecycle dimensions * refactor(e2e): decouple terminal exact drivers * refactor(terminal): isolate exact sidecar fixture host * feat(terminal): gate handoff on physical retirement * refactor(release): gate exact activation on public acceptance * test(terminal): formalize guarded lifecycle algebra * fix(terminal): guard shell installer handoff * feat(terminal): add exact bootloader handoff * feat(terminal): integrate exact sidecar lifecycle * refactor(exact): rename validation channels * test(terminal): harden exact release acceptance * fix(postinstall): build standalone dependencies first Generated-By: looper 0.11.2 (runner=fixer, agent=codex) * fix(ci): build the native Terminal scene Generated-By: looper 0.11.2 (runner=fixer, agent=codex) * test(ci): cover exact convergence handoff routing Generated-By: looper 0.11.2 (runner=fixer, agent=codex) * fix(exact): isolate terminal validation from main CI * fix(terminal): complete shell update confirmation Generated-By: looper 0.11.2 (runner=fixer, agent=codex) * fix(exact): bind acceptance to installed manifest Generated-By: looper 0.11.2 (runner=fixer, agent=codex) * fix(standalone): block occupied shell installs Generated-By: looper 0.11.2 (runner=fixer, agent=codex) --------- Co-authored-by: Looper <looper@noreply.github.com>
61 lines
5.4 KiB
TypeScript
61 lines
5.4 KiB
TypeScript
import { readFileSync, writeFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
|
|
import { cleanupFixtures, expectedShellBuildHash, prepareExactFixture, run, terminalRoot, verifyExactLifecycle, writeDistributionRequest, writeSceneRequest, type TerminalOptions } from "./helpers.js";
|
|
|
|
afterEach(cleanupFixtures);
|
|
|
|
describe("Terminal macOS carrier", () => {
|
|
it.skipIf(process.platform !== "darwin" || !new Set(["arm64", "x64"]).has(process.arch))(
|
|
"runs sh scene, tar distribution, lifecycle, update, install, and tamper rejection",
|
|
() => {
|
|
const target = `darwin-${process.arch}`;
|
|
const fixture = prepareExactFixture(target);
|
|
if (fixture == null) {
|
|
throw new Error(`locked Node archive for ${target} is required to run the native macOS E2E test`);
|
|
}
|
|
const { archive, closureFile, directories, lock, locked, releases, standaloneDirectory, sidecarDirectory, platformDirectory, work } = fixture;
|
|
const scene = join(work, "scene");
|
|
const sceneRequest = join(work, "scene-request.json");
|
|
const sceneReceipt = join(work, "scene-receipt.json");
|
|
writeSceneRequest(sceneRequest, { target, shellVersion: readFileSync(join(terminalRoot, "version"), "utf8").trim(), nodeVersion: lock.version, nodeArchive: archive, nodeArchiveSha256: locked.sha256, closureFile, standaloneDirectory, sidecarDirectory, platformDirectory, sceneDirectory: scene });
|
|
run("sh", [join(terminalRoot, "sh/scene.sh"), "--request", sceneRequest, "--receipt", sceneReceipt]);
|
|
const sceneSha = JSON.parse(readFileSync(sceneReceipt, "utf8")).sceneManifestSha256 as string;
|
|
expect(JSON.parse(readFileSync(join(scene, "scene.json"), "utf8"))).toMatchObject({ shellBuildHash: expectedShellBuildHash(scene, target, locked.sha256) });
|
|
const distributionRequest = join(work, "distribution-request.json");
|
|
writeDistributionRequest(distributionRequest, { target, sceneDirectory: scene, sceneManifestSha256: sceneSha, releaseDocumentsDirectory: directories.documents, trustFile: releases.trustFile, release: { ...releases.beta1.release, releaseVersion: "0.1.0-somechan.2" }, outputDirectory: directories.output });
|
|
const mismatched = run("sh", [join(terminalRoot, "sh/distribution.sh"), "--request", distributionRequest, "--receipt", join(work, "mismatched-distribution-receipt.json")], { allowFailure: true });
|
|
expect(mismatched.status).not.toBe(0);
|
|
writeDistributionRequest(distributionRequest, { target, sceneDirectory: scene, sceneManifestSha256: sceneSha, releaseDocumentsDirectory: directories.documents, trustFile: releases.trustFile, release: releases.beta1.release, outputDirectory: directories.output });
|
|
const distributionReceipt = join(work, "distribution-receipt.json");
|
|
run("sh", [join(terminalRoot, "sh/distribution.sh"), "--request", distributionRequest, "--receipt", distributionReceipt]);
|
|
const distribution = join(directories.output, `nexu-terminal-${target}-0.1.0-somechan.1.tar.gz`);
|
|
expect(JSON.parse(readFileSync(distributionReceipt, "utf8"))).toMatchObject({ operation: "terminal.distribution.build", target, archive: { file: distribution } });
|
|
run("tar", ["-xzf", distribution, "-C", directories.unpacked]);
|
|
const root = join(directories.unpacked, "nexu-terminal");
|
|
const terminal = (installRoot: string, storeRoot: string, channel: string, namespace: string, operation: string, options: TerminalOptions = {}) => {
|
|
const result = run("sh", [join(installRoot, "sh/terminal.sh"), "--root", installRoot, "--store-root", storeRoot, "--channel", channel, "--namespace", namespace, "--operation", operation,
|
|
...(options.attachmentId == null ? [] : ["--attachment-id", options.attachmentId]),
|
|
...(options.attachmentCapability == null ? [] : ["--attachment-capability", options.attachmentCapability]),
|
|
...(options.channelHeadUrl == null ? [] : ["--channel-head-url", options.channelHeadUrl]),
|
|
...(options.activationPolicy == null ? [] : ["--activation-policy", options.activationPolicy]),
|
|
...(options.feedbackFile == null ? [] : ["--feedback", options.feedbackFile])]);
|
|
return JSON.parse(result.stdout) as Record<string, any>;
|
|
};
|
|
const rejected = run("sh", [join(root, "sh/terminal.sh"), "--root", root, "--store-root", directories.store, "--channel", "somechan", "--namespace", "shared", "--operation", "heartbeat", "--attachment-id", "missing"], { allowFailure: true });
|
|
expect(rejected.status).not.toBe(0);
|
|
expect(JSON.parse(rejected.stdout)).toMatchObject({ outcome: "rejected", operation: "heartbeat", error: { code: "operation-failed" } });
|
|
verifyExactLifecycle(root, directories.store, terminal, releases);
|
|
|
|
const installed = join(work, "installed");
|
|
run("sh", [join(root, "sh/install.sh"), "--root", installed, "--channel", "somechan", "--namespace", "installed"]);
|
|
const before = terminal(installed, join(work, "installed-store"), "somechan", "installed", "probe");
|
|
writeFileSync(join(installed, "runtime/fossil.mjs"), `${readFileSync(join(installed, "runtime/fossil.mjs"), "utf8")}\n`);
|
|
const tampered = run("sh", [join(installed, "sh/terminal.sh"), "--root", installed, "--channel", "somechan", "--namespace", "installed", "--operation", "probe"], { allowFailure: true });
|
|
expect(tampered.status).not.toBe(0);
|
|
expect(before.shell.digest).toMatch(/^[a-f0-9]{64}$/);
|
|
},
|
|
);
|
|
});
|