Advance M7 workflows and release operations
This commit is contained in:
92
web/tests/e2e/engine-upgrade-safety.spec.ts
Normal file
92
web/tests/e2e/engine-upgrade-safety.spec.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test("refreshes on a release switch and rejects tampered WASM without fallback or open", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await expect(page.locator(".status-bar")).toContainText("Manifest: verified");
|
||||
|
||||
const versionGate = await page.evaluate(async () => {
|
||||
const { bootstrapWebEngineRelease } = await import("/src/engine-client/engine-variant-bootstrap.ts");
|
||||
const manifest = await fetch("/engine-manifest.json", { cache: "no-store" }).then((response) => response.json());
|
||||
let initializationCount = 0;
|
||||
const outcome = await bootstrapWebEngineRelease(
|
||||
"blender-wasm-previous",
|
||||
manifest,
|
||||
"AUTO",
|
||||
{ crossOriginIsolated: true, sharedArrayBuffer: true, worker: true },
|
||||
{
|
||||
initialize: async () => {
|
||||
initializationCount += 1;
|
||||
throw new Error("release mismatch initialized an engine");
|
||||
},
|
||||
},
|
||||
new ArrayBuffer(8),
|
||||
);
|
||||
return { result: outcome.result, hasSession: outcome.session !== null, initializationCount };
|
||||
});
|
||||
|
||||
expect(versionGate).toEqual({
|
||||
result: {
|
||||
status: "REFRESH_REQUIRED",
|
||||
expectedReleaseId: "blender-wasm-previous",
|
||||
actualReleaseId: "blender-wasm-0.1.0-rc.1",
|
||||
manifest: null,
|
||||
},
|
||||
hasSession: false,
|
||||
initializationCount: 0,
|
||||
});
|
||||
|
||||
const variantRequests: string[] = [];
|
||||
page.on("request", (request) => {
|
||||
const pathname = new URL(request.url()).pathname;
|
||||
if (pathname.startsWith("/vendor/blender/single/") || pathname.startsWith("/vendor/blender/pthread/")) {
|
||||
variantRequests.push(pathname);
|
||||
}
|
||||
});
|
||||
await page.route("**/vendor/blender/pthread/web_engine.wasm", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/wasm",
|
||||
body: Buffer.from("tampered-pthread-wasm"),
|
||||
});
|
||||
});
|
||||
|
||||
const integrityGate = await page.evaluate(async () => {
|
||||
const { detectBrowserCapabilities } = await import("/src/platform/capabilities.ts");
|
||||
const { bootstrapWebEngineRelease } = await import("/src/engine-client/engine-variant-bootstrap.ts");
|
||||
const { createBrowserEngineVariantSession } = await import("/src/engine-client/browser-engine-variant-session.ts");
|
||||
const manifest = await fetch("/engine-manifest.json", { cache: "no-store" }).then((response) => response.json());
|
||||
try {
|
||||
await bootstrapWebEngineRelease(
|
||||
manifest.releaseId,
|
||||
manifest,
|
||||
"AUTO",
|
||||
detectBrowserCapabilities(),
|
||||
{ initialize: createBrowserEngineVariantSession },
|
||||
new ArrayBuffer(8),
|
||||
);
|
||||
return { rejected: false };
|
||||
}
|
||||
catch (error) {
|
||||
const failure = error as Error & {
|
||||
code?: string;
|
||||
attempted?: string[];
|
||||
cause?: { code?: string };
|
||||
};
|
||||
return {
|
||||
rejected: true,
|
||||
code: failure.code,
|
||||
causeCode: failure.cause?.code,
|
||||
attempted: failure.attempted,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
expect(integrityGate).toEqual({
|
||||
rejected: true,
|
||||
code: "ENGINE_VARIANT_INTEGRITY_FAILED",
|
||||
causeCode: "ENGINE_VARIANT_RESOURCE_HASH_MISMATCH",
|
||||
attempted: ["pthread"],
|
||||
});
|
||||
expect(variantRequests.filter((url) => url.endsWith("/pthread/web_engine.wasm"))).toHaveLength(1);
|
||||
expect(variantRequests.some((url) => url.includes("/single/"))).toBe(false);
|
||||
});
|
||||
Reference in New Issue
Block a user