Files
FreeCADWasmDev/tools/run_p6_cloud_python_family_gate.mjs
wangdequan 9a7c4f0335 Save FreeCAD Web workspace sources and user validation evidence
IFC native binding remains incomplete; preserve accurate test results.
2026-09-15 22:01:58 +08:00

52 lines
3.9 KiB
JavaScript

import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
import { createRequire } from "node:module";
import { pathToFileURL } from "node:url";
const root = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..");
const build = path.resolve(process.argv[2] || path.join(root, "freecad-source/build-web/cloud-configure-r2/bin"));
globalThis.__dirname = `${build}${path.sep}`;
globalThis.require = createRequire(import.meta.url);
const loader = await import(pathToFileURL(path.join(build, "FreeCADWebCloudKernelProbe.js")).href);
const kernel = await loader.default({ wasmBinary: fs.readFileSync(path.join(build, "FreeCADWebCloudKernelProbe.wasm")) });
const record = { apiId: "py:Cloud:class:CloudWorkbench", name: "CloudWorkbench", family: "generic-object" };
const request = { cmd: "cloud.pythonFamilyBatch", args: { tier: "tier-1-readonly", records: [record] } };
const invoke = (value) => JSON.parse(String(kernel.ccall("fc_web_dispatch_json", "string", ["string"], [JSON.stringify(value)])));
const success = invoke(request);
const repeated = invoke(request);
const invalid = invoke({ cmd: "cloud.pythonFamilyBatch", args: { tier: "tier-1-readonly", records: [{ ...record, apiId: "py:BIM:class:CloudWorkbench" }] } });
const malformed = invoke({ cmd: "cloud.pythonFamilyBatch", args: { tier: "tier-2-pure", records: [record] } });
if (success.ok !== true || success.module !== "Cloud" || success.count !== 1 || success.resourcesReleased !== true) throw new Error("Cloud family dispatch did not return a complete result");
const result = success.records[0];
if (result.status !== "restricted" || result.code !== "gui_dependency_unavailable" || result.native !== true) throw new Error(`unexpected Cloud family status: ${JSON.stringify(result)}`);
if (JSON.stringify(repeated) !== JSON.stringify(success)) throw new Error("Cloud family replay changed the native result");
if (invalid.ok !== true || invalid.records?.[0]?.status !== "not_implemented" || invalid.records?.[0]?.code !== "unmatched_source_record") throw new Error("module-scoped mismatch was not rejected");
if (malformed.ok !== false || malformed.code !== "invalid_request") throw new Error("invalid tier was not rejected");
const hash = (value) => crypto.createHash("sha256").update(JSON.stringify(value)).digest("hex");
const report = {
schema: "freecad-web-p6-cloud-tier1-readonly-family/v1",
taskId: "FW-P6-FPA-F1-CLOUD",
module: "Cloud",
tier: "tier-1-readonly",
status: "pass_with_restricted",
sourceRevision: "b5a086fda59b0325fe0996147e6e9b344414f9bc",
sourceEntry: "src/Mod/Cloud/InitGui.py:8",
route: { worker: "web/src/cloud.worker.ts", command: "cloud.pythonFamilyBatch", native: "freecad-source/src/WebAssembly/FreeCADCoreProbe/CloudKernelProbe.cpp:644" },
input: request,
inputSha256: hash(request),
result: success,
resultSha256: hash(success),
replay: { equal: true, resultSha256: hash(repeated) },
invalidRecord: { result: invalid, resultSha256: hash(invalid) },
malformedRequest: { result: malformed, resultSha256: hash(malformed) },
resources: { resourcesReleased: true, documentMutation: false },
disposition: { apiId: record.apiId, status: result.status, code: result.code, evidenceSha256: hash(result) },
boundaries: ["CloudWorkbench is declared by the GUI InitGui.py surface and is restricted without FreeCADGui.", "The classification is returned by compiled FreeCAD WebAssembly through fc_web_dispatch_json.", "No JavaScript geometry, API result, or cross-module name match is used."]
};
fs.writeFileSync(path.join(root, "docs/p6/cloud-tier1-readonly-family.json"), `${JSON.stringify(report, null, 2)}\n`);
fs.writeFileSync(path.join(root, "docs/freecad-p6-cloud-tier1-readonly-family.log"), `${JSON.stringify({ status: report.status, apiId: record.apiId, disposition: result.status, resultSha256: report.resultSha256 })}\n`);
console.log(JSON.stringify({ status: report.status, apiId: record.apiId, disposition: result.status, resultSha256: report.resultSha256 }));