Files
Web_FreeCAD_Bitbybit/scripts/check-camotics-wasm.mjs

39 lines
3.1 KiB
JavaScript

import { createHash } from 'node:crypto'
import { execFileSync } from 'node:child_process'
import { readFile } from 'node:fs/promises'
import { resolve } from 'node:path'
const root = resolve(new URL('..', import.meta.url).pathname)
const evidence = JSON.parse(await readFile(resolve(root, 'config/camotics-wasm-artifact.json'), 'utf8'))
const sha256 = (bytes) => createHash('sha256').update(bytes).digest('hex')
if (evidence.schemaVersion !== 1 || evidence.status !== 'pass' || evidence.kind !== 'standalone-camotics-sweep-wasm-kernel') throw new Error('CAMotics WASM evidence is not passing.')
const revision = execFileSync('git', ['-C', resolve(root, evidence.upstream.path), 'rev-parse', 'HEAD'], { encoding: 'utf8' }).trim()
if (revision !== evidence.upstream.revision) throw new Error(`CAMotics WASM source revision drift: ${revision}`)
for (const [path, expected] of Object.entries(evidence.build.sourceFiles)) {
const bytes = await readFile(resolve(root, path))
if (sha256(bytes) !== expected) throw new Error(`CAMotics WASM source fingerprint drift: ${path}`)
}
const bytes = await readFile(resolve(root, evidence.artifact.path))
if (bytes.byteLength !== evidence.artifact.bytes || sha256(bytes) !== evidence.artifact.sha256) throw new Error('CAMotics WASM artifact size or digest mismatch.')
const module = new WebAssembly.Module(bytes)
const imports = WebAssembly.Module.imports(module)
if (imports.length !== 0 || evidence.artifact.imports.length !== 0) throw new Error('CAMotics WASM must be standalone with zero imports.')
const exports = new Set(WebAssembly.Module.exports(module).map((entry) => entry.name))
for (const required of evidence.artifact.requiredExports) if (!exports.has(required)) throw new Error(`CAMotics WASM export is missing: ${required}`)
const instance = await WebAssembly.instantiate(module, {})
const api = instance.exports
if (api.camotics_sweep_abi_version() !== evidence.artifact.abiVersion) throw new Error('CAMotics WASM ABI version drift.')
const smoke = {
conicInsideDepth: api.camotics_conic_depth(5, 2, 2, 0, 0, 0, 10, 0, 0, 5, 0, 0),
conicOutsideDepth: api.camotics_conic_depth(5, 2, 2, 0, 0, 0, 10, 0, 0, 5, 4, 0),
spheroidInsideDepth: api.camotics_spheroid_depth(2, 4, 0, 0, 0, 10, 0, 0, 5, 0, 0),
longMoveBoundingBoxes: api.camotics_conic_bbox_count(5, 2, 2, 0, 0, 0, 100, 0, 0, 0.01),
}
if (JSON.stringify(smoke) !== JSON.stringify(evidence.smoke)) throw new Error(`CAMotics WASM smoke drift: ${JSON.stringify(smoke)}`)
if (evidence.scope.actualUpstreamCppCompiled !== true || evidence.scope.browserExecutable !== true || evidence.scope.fullCamoticsProgram !== false || evidence.scope.gcodeParserIncluded !== false || evidence.scope.canonicalGcodeParser !== 'linuxcnc-wasm') throw new Error('CAMotics WASM capability boundary is invalid.')
console.log(JSON.stringify({ status: 'camotics-wasm-pass', sourceRevision: revision, artifact: { bytes: bytes.byteLength, sha256: sha256(bytes), imports: imports.length, exports: [...exports].filter((name) => evidence.artifact.requiredExports.includes(name)) }, abiVersion: evidence.artifact.abiVersion, smoke, scope: evidence.scope }, null, 2))