67 lines
4.5 KiB
JavaScript
67 lines
4.5 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
import ts from "typescript";
|
|
|
|
const root = path.resolve(import.meta.dirname, "../../..");
|
|
const sourcePath = path.join(root, "web/protocol/server-render-job.ts");
|
|
const source = fs.readFileSync(sourcePath, "utf8").replace('import type { ErrorCode } from "./error";\n', "");
|
|
const transpiled = ts.transpileModule(source, {
|
|
compilerOptions: { module: ts.ModuleKind.ES2022, target: ts.ScriptTarget.ES2022 },
|
|
fileName: sourcePath,
|
|
reportDiagnostics: true,
|
|
});
|
|
assert.deepEqual(transpiled.diagnostics, []);
|
|
const jobs = await import("data:text/javascript;base64," + Buffer.from(transpiled.outputText).toString("base64"));
|
|
|
|
const sourceBytes = new TextEncoder().encode("server-render-source-v1").buffer;
|
|
const build = { version: "5.2.0", buildSha256: "a".repeat(64) };
|
|
const settings = {
|
|
renderEngine: "BLENDER_CYCLES",
|
|
frameStart: 1,
|
|
frameEnd: 1,
|
|
resolutionX: 32,
|
|
resolutionY: 32,
|
|
resolutionPercentage: 100,
|
|
samples: 4,
|
|
outputMime: "image/png",
|
|
transparent: false,
|
|
};
|
|
|
|
test("M11-06 binds source bytes, Blender build and canonical render settings", async () => {
|
|
const request = await jobs.createServerRenderJobRequest(sourceBytes, build, settings, { jobId: "render:test", sourceRevision: 7 });
|
|
assert.equal(request.sourceBlendByteLength, sourceBytes.byteLength);
|
|
assert.match(request.sourceBlendSha256, /^[a-f0-9]{64}$/);
|
|
assert.match(request.settingsSha256, /^[a-f0-9]{64}$/);
|
|
assert.match(request.requestSha256, /^[a-f0-9]{64}$/);
|
|
assert.deepEqual(await jobs.verifyServerRenderJobRequest(request, sourceBytes), request);
|
|
const reordered = await jobs.createServerRenderJobRequest(sourceBytes, build, { transparent: settings.transparent, ...settings }, { jobId: "render:test", sourceRevision: 7 });
|
|
assert.equal(reordered.settingsSha256, request.settingsSha256);
|
|
assert.equal(await jobs.createServerRenderJobKey(request), await jobs.createServerRenderJobKey(reordered));
|
|
});
|
|
|
|
test("M11-06 verifies output hash and rejects every provenance drift", async () => {
|
|
const request = await jobs.createServerRenderJobRequest(sourceBytes, build, settings, { jobId: "render:verify", sourceRevision: 2 });
|
|
const output = Uint8Array.from([0x89, 0x50, 0x4e, 0x47, 0x00, 0x01]).buffer;
|
|
const result = await jobs.createServerRenderJobResult(request, output);
|
|
assert.equal(result.status, "SUCCEEDED");
|
|
assert.deepEqual(await jobs.verifyServerRenderJobResult(result, request, output), result);
|
|
await assert.rejects(jobs.verifyServerRenderJobRequest(request, Uint8Array.from([1, 2, 3]).buffer), { code: "SERVER_RENDER_SOURCE_HASH_MISMATCH" });
|
|
await assert.rejects(jobs.verifyServerRenderJobResult(result, request, Uint8Array.from([9, 9]).buffer), { code: "SERVER_RENDER_OUTPUT_HASH_MISMATCH" });
|
|
await assert.rejects(jobs.verifyServerRenderJobResult({ ...result, sourceBlendSha256: "b".repeat(64) }, request, output), { code: "SERVER_RENDER_BINDING_MISMATCH" });
|
|
await assert.rejects(jobs.verifyServerRenderJobRequest({ ...request, blenderBuild: { ...build, buildSha256: "b".repeat(64) } }), { code: "SERVER_RENDER_REQUEST_HASH_MISMATCH" });
|
|
await assert.rejects(jobs.createServerRenderJobRequest(sourceBytes, { ...build, version: "5.3.0" }, settings), { code: "SERVER_RENDER_BUILD_INVALID" });
|
|
await assert.rejects(jobs.createServerRenderJobRequest(sourceBytes, build, { ...settings, samples: 0 }), { code: "SERVER_RENDER_SETTINGS_INVALID" });
|
|
});
|
|
|
|
test("M11-06 rejects malformed result metadata and settings budget abuse", async () => {
|
|
await assert.rejects(jobs.createServerRenderJobRequest(sourceBytes, build, { ...settings, payload: "x".repeat(300_000) }), { code: "SERVER_RENDER_SETTINGS_INVALID" });
|
|
const request = await jobs.createServerRenderJobRequest(sourceBytes, build, settings);
|
|
const result = await jobs.createServerRenderJobResult(request, Uint8Array.from([1]).buffer);
|
|
await assert.rejects(jobs.verifyServerRenderJobResult({ ...result, outputByteLength: result.outputByteLength + 1 }, request), { code: "SERVER_RENDER_RESULT_HASH_MISMATCH" });
|
|
await assert.rejects(jobs.verifyServerRenderJobResult({ ...result, outputMime: "image/openexr" }, request), { code: "SERVER_RENDER_OUTPUT_INVALID" });
|
|
await assert.rejects(jobs.verifyServerRenderJobResult({ ...result, errorCode: "SERVER_RENDER_FAILED" }, request), { code: "SERVER_RENDER_OUTPUT_INVALID" });
|
|
await assert.rejects(jobs.verifyServerRenderJobRequest({ ...request, unexpected: true }), { code: "SERVER_RENDER_REQUEST_INVALID" });
|
|
});
|