mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
70cd4cbfb8
Replace fixed Linux Hopper release pins with current vendor feed metadata, complete detached-PGP package verification under the stable publisher primary key, and authenticated package evidence for offline admission. Share parsed publisher facts across approved setup, doctor and the pre-execution guard. Preserve existing ownership, cancellation, private-display and cleanup rules. Fixes #3577 Normalize empty XDG settings, preserve backups during approved cache repair, and retain publisher cleanup through cancellation and shutdown. Exercise cold offline verification without reusing process-local proof state. Serialize approved cache publication across processes, restore old evidence on failure, and share the existing lease owner from process without changing its identities. Validation: 438 focused tests (six platform-related skips), full static/documentation checks, real Ubuntu 24.04 official Hopper 6.6.0 setup/CLI/MCP, offline ordinary-user admission, launcher mutation rejection, and cold/warm verification measurements. Official RPM metadata mismatch is tracked separately in #3578 and fails closed. BREAKING CHANGE: Older Linux Hopper builds admitted by the fixed allowlist now require retained publisher-signed package evidence or an approved update to the current public demo. Update explicit HOPPER_LAUNCHER_PATH values when migrating; the live feed exposes only its current release. Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com> Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
105 lines
3.2 KiB
TypeScript
105 lines
3.2 KiB
TypeScript
import { chmod, copyFile, rm } from "node:fs/promises";
|
|
|
|
import { describe, expect } from "vitest";
|
|
import { z } from "zod";
|
|
|
|
import { workspaceCliTest } from "../../support/cli/workspaceCliFixture.js";
|
|
|
|
import { acquireHopperTargetLease } from "../../../src/process/HopperLease.js";
|
|
|
|
const FAILED_LAUNCHER = `#!/bin/sh
|
|
printf 'Cannot launch Hopper!\\nDocument state is unknown.\\n' >&2
|
|
exit 2
|
|
`;
|
|
|
|
/** The private runtime directory a failed launch reports as retained. */
|
|
const RetainedRuntime = z.object({
|
|
details: z.object({
|
|
diagnostics: z.object({
|
|
cleanup_error: z.object({
|
|
details: z.object({
|
|
diagnostics: z.object({ runtime_root: z.string() }),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
});
|
|
|
|
describe("Hopper launcher failure through the one-shot CLI", () => {
|
|
// Hopper target leases are acquired only for the macOS launcher route.
|
|
workspaceCliTest.skipIf(process.platform !== "darwin")(
|
|
"exits after a retained-cleanup failure and releases the target to a retry",
|
|
{ timeout: 90_000 },
|
|
async ({ cli, workspace }) => {
|
|
const launcherPath = await workspace.write(
|
|
"failure-helper",
|
|
FAILED_LAUNCHER,
|
|
);
|
|
await chmod(launcherPath, 0o700);
|
|
const targetPath = workspace.path("probe");
|
|
await copyFile("/usr/bin/true", targetPath);
|
|
const loaderArgs = ["--probe"];
|
|
try {
|
|
for (const attempt of ["first", "retry"]) {
|
|
const result = await cli.run({
|
|
arguments: [
|
|
"analyze",
|
|
targetPath,
|
|
"--provider",
|
|
"hopper",
|
|
"--json",
|
|
],
|
|
environment: {
|
|
...workspace.environment,
|
|
HOPPER_LAUNCHER_PATH: launcherPath,
|
|
HOPPER_LOADER_ARGS_JSON: JSON.stringify(loaderArgs),
|
|
REA_LOG_LEVEL: "silent",
|
|
},
|
|
timeoutMs: 45_000,
|
|
});
|
|
const retained = RetainedRuntime.safeParse(result.json);
|
|
if (retained.success)
|
|
await rm(
|
|
retained.data.details.diagnostics.cleanup_error.details
|
|
.diagnostics.runtime_root,
|
|
{ recursive: true, force: true },
|
|
);
|
|
|
|
expect(result.exitCode, attempt).toBe(1);
|
|
expect(result.json, attempt).toMatchObject({
|
|
code: "cleanup_incomplete",
|
|
details: {
|
|
cleanup: "incomplete",
|
|
diagnostics: {
|
|
primary_error: {
|
|
code: "provider_unavailable",
|
|
details: {
|
|
stage: "launch",
|
|
launcher: {
|
|
exit_code: 2,
|
|
stderr: {
|
|
text: expect.stringContaining(
|
|
"Document state is unknown",
|
|
),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|
|
} finally {
|
|
const recovered = await acquireHopperTargetLease({
|
|
targetPath,
|
|
targetKind: "executable",
|
|
loaderArgs,
|
|
runId: "failed-cli-test-cleanup",
|
|
});
|
|
expect(recovered.acquired).toBe(true);
|
|
if (recovered.acquired) await recovered.lease.release();
|
|
}
|
|
},
|
|
);
|
|
});
|