import { spawn } from "node:child_process"; import { createHash } from "node:crypto"; import { access, constants as fsConstants, copyFile, lstat, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, writeFile, } from "node:fs/promises"; import path from "node:path"; export const GO_LOCK = Object.freeze({ bridgeAbi: 1, engineVersion: "1.26.5", runtimeVersion: "go1.26.5", sourceDateEpoch: 1_783_452_544, source: Object.freeze({ repository: "https://go.googlesource.com/go", tag: "go1.26.5", commit: "c19862e5f8415b4f24b189d065ed739517c548ba", tree: "0bb2fb1cc06c334c36a2a92d2f0b07fea7236d74", license: "BSD-3-Clause", }), toolchain: Object.freeze({ archive: "https://go.dev/dl/go1.26.5.linux-amd64.tar.gz", archiveSha256: "5c2c3b16caefa1d968a94c1daca04a7ca301a496d9b086e17ad77bb81393f053", licenseSha256: "911f8f5782931320f5b8d1160a76365b83aea6447ee6c04fa6d5591467db9dad", wasmExecSha256: "0c949f4996f9a89698e4b5c586de32249c3b69b7baadb64d220073cc04acba14", }), limits: Object.freeze({ maximumPatternBytes: 262_144, maximumSubjectBytes: 16_777_216, maximumReplacementBytes: 262_144, maximumMatches: 10_000, maximumCaptureRows: 100_000, maximumCaptureGroups: 1_000, maximumOutputBytes: 67_108_864, maximumRequestJSONBytes: 103_874_560, }), }); const PACK_FILES = Object.freeze([ "LICENSE-Go.txt", "SHA256SUMS", "engine-metadata.json", "go-regex.wasm", "wasm_exec.mjs", ]); const CHECKSUM_FILES = Object.freeze([ "LICENSE-Go.txt", "engine-metadata.json", "go-regex.wasm", "wasm_exec.mjs", ]); const SOURCE_FILES = Object.freeze([ "engines/go/README.md", "engines/go/go.mod", "engines/go/main.go", ]); function sha256(value) { return createHash("sha256").update(value).digest("hex"); } async function sha256File(file) { return sha256(await readFile(file)); } async function assertRealDirectory(candidate, label) { const details = await lstat(candidate).catch(() => null); if (!details?.isDirectory() || details.isSymbolicLink()) { throw new Error(`${label} must be a real directory: ${candidate}`); } return realpath(candidate); } async function assertRegularFile(candidate, label) { const details = await lstat(candidate).catch(() => null); if (!details?.isFile() || details.isSymbolicLink()) { throw new Error(`${label} must be a regular file: ${candidate}`); } return realpath(candidate); } function commandLabel(command, arguments_) { return [command, ...arguments_] .map((part) => /^[A-Za-z0-9_./:=,+-]+$/u.test(part) ? part : JSON.stringify(part), ) .join(" "); } async function run(command, arguments_, options = {}) { const child = spawn(command, arguments_, { cwd: options.cwd, env: options.env, stdio: ["ignore", "pipe", "pipe"], }); const stdout = []; const stderr = []; child.stdout.on("data", (chunk) => stdout.push(chunk)); child.stderr.on("data", (chunk) => stderr.push(chunk)); const result = await new Promise((resolve, reject) => { child.once("error", reject); child.once("close", (code, signal) => resolve({ code, signal })); }); const output = Buffer.concat(stdout).toString("utf8"); const errorOutput = Buffer.concat(stderr).toString("utf8"); if (result.code !== 0) { const detail = [output, errorOutput].filter(Boolean).join("\n").trim(); throw new Error( `${commandLabel(command, arguments_)} failed with ${ result.signal ? `signal ${result.signal}` : `exit code ${result.code}` }${detail ? `:\n${detail}` : "."}`, ); } return { stdout: output, stderr: errorOutput }; } async function verifyToolchain(goRootDirectory) { const goRoot = await assertRealDirectory( goRootDirectory, "Go 1.26.5 toolchain", ); const go = await assertRegularFile(path.join(goRoot, "bin", "go"), "go"); await access(go, fsConstants.X_OK); const version = await run(go, ["version"]); if (version.stdout.trim() !== "go version go1.26.5 linux/amd64") { throw new Error("The Go pack requires official go1.26.5 linux/amd64."); } const license = await assertRegularFile( path.join(goRoot, "LICENSE"), "Go licence", ); const wasmExec = await assertRegularFile( path.join(goRoot, "lib", "wasm", "wasm_exec.js"), "Go wasm_exec.js", ); if ((await sha256File(license)) !== GO_LOCK.toolchain.licenseSha256) { throw new Error("The Go toolchain licence SHA-256 is not pinned go1.26.5."); } if ((await sha256File(wasmExec)) !== GO_LOCK.toolchain.wasmExecSha256) { throw new Error("wasm_exec.js does not match official go1.26.5."); } return { goRoot, go, license, wasmExec }; } function buildEnvironment(goRoot) { const environment = { ...process.env }; for (const variable of [ "GOFLAGS", "GOENV", "GOEXPERIMENT", "GOMOD", "GOTOOLDIR", "GOVERSION", ]) { delete environment[variable]; } environment.CGO_ENABLED = "0"; environment.GOARCH = "wasm"; environment.GOENV = "off"; environment.GOOS = "js"; environment.GOROOT = goRoot; environment.GOTOOLCHAIN = "local"; environment.GOWORK = "off"; environment.LANG = "C"; environment.LC_ALL = "C"; environment.SOURCE_DATE_EPOCH = String(GO_LOCK.sourceDateEpoch); environment.TZ = "UTC"; return environment; } async function sourceMetadata(root) { return Promise.all( SOURCE_FILES.map(async (relativePath) => { const contents = await readFile(path.join(root, relativePath)); return { path: relativePath, sha256: sha256(contents), bytes: contents.byteLength, }; }), ); } async function fileMetadata(pack, name) { const contents = await readFile(path.join(pack, name)); return { path: name, sha256: sha256(contents), bytes: contents.byteLength }; } async function expectedMetadata(root, pack) { return { schemaVersion: 1, engine: "go", engineName: "Go standard-library regexp", engineVersion: GO_LOCK.engineVersion, semanticIdentity: "Go 1.26.5 standard-library regexp (RE2 syntax), official js/wasm runtime", status: "production-native-runtime", bridge: { abiVersion: GO_LOCK.bridgeAbi, offsetUnit: "utf8-byte", requestEncoding: "Exact UTF-8-bounded JSON values with worst-case escape allowance; fixed callbacks; base64 UTF-8 replacement output; no source evaluation", supportedApplicationFlags: ["g", "i", "m", "s", "U"], replacement: "Bounded streaming expansion with regexp.ExpandString grammar, parity-checked against the native API.", limits: { ...GO_LOCK.limits }, sourceFiles: await sourceMetadata(root), }, source: { repository: GO_LOCK.source.repository, tag: GO_LOCK.source.tag, commitSha1: GO_LOCK.source.commit, treeSha1: GO_LOCK.source.tree, license: GO_LOCK.source.license, }, toolchain: { version: GO_LOCK.runtimeVersion, host: "linux/amd64", target: "js/wasm", archive: GO_LOCK.toolchain.archive, archiveSha256: GO_LOCK.toolchain.archiveSha256, wasmExecSha256: GO_LOCK.toolchain.wasmExecSha256, build: "CGO_ENABLED=0 GOOS=js GOARCH=wasm go build -trimpath -buildvcs=false -ldflags=-s,-w,-buildid=", }, sourceDateEpoch: GO_LOCK.sourceDateEpoch, files: await Promise.all( ["LICENSE-Go.txt", "go-regex.wasm", "wasm_exec.mjs"].map((name) => fileMetadata(pack, name), ), ), }; } async function checksumText(pack) { const lines = await Promise.all( CHECKSUM_FILES.map( async (name) => `${await sha256File(path.join(pack, name))} ${name}`, ), ); return `${lines.join("\n")}\n`; } function equalJson(left, right) { return JSON.stringify(left) === JSON.stringify(right); } async function smokePack(pack) { const runtimeUrl = new URL(`file://${path.join(pack, "wasm_exec.mjs")}`).href; const wasmPath = path.join(pack, "go-regex.wasm"); const smoke = ` import { readFile } from "node:fs/promises"; await import(process.argv[1]); let install; const ready = new Promise((resolve) => { install = resolve; }); globalThis.__regexToolsInstallGoBridge = (identity, run) => install({ identity, run }); const runtime = new globalThis.Go(); const module = await WebAssembly.instantiate( await readFile(process.argv[2]), runtime.importObject, ); void runtime.run(module.instance); const bridge = await ready; const identity = JSON.parse(bridge.identity()); if ( identity.abi !== 1 || identity.ok !== true || identity.identity.goVersion !== "go1.26.5" || identity.identity.selfTest !== true ) throw new Error("Go identity self-test failed."); const result = JSON.parse(bridge.run(JSON.stringify({ abi: 1, operation: "replace", pattern: "(?P😀+)", flags: "g", options: {}, subject: "x😀😀", scanAll: false, maximumMatches: 10, maximumCaptureRows: 10, replacement: "\${word}-$$", maximumOutputBytes: 100, }))); if ( result.ok !== true || result.matches[0].span[0] !== 1 || result.matches[0].span[1] !== 9 || Buffer.from(result.outputBase64, "base64").toString("utf8") !== "x😀😀-$" ) throw new Error("Go execution self-test failed."); process.exit(0); `; await run(process.execPath, [ "--input-type=module", "--eval", smoke, runtimeUrl, wasmPath, ]); } export async function verifyGoPack(packDirectory, root) { const repositoryRoot = await assertRealDirectory( root, "Regex Tools repository", ); const pack = await assertRealDirectory(packDirectory, "Go engine pack"); const entries = (await readdir(pack, { withFileTypes: true })).sort( (left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0, ); if ( entries.length !== PACK_FILES.length || entries.some( (entry, index) => entry.name !== PACK_FILES[index] || !entry.isFile() || entry.isSymbolicLink(), ) ) { throw new Error(`The Go pack must contain only: ${PACK_FILES.join(", ")}.`); } if ( (await sha256File(path.join(pack, "LICENSE-Go.txt"))) !== GO_LOCK.toolchain.licenseSha256 ) { throw new Error("The staged Go licence does not match go1.26.5."); } if ( (await sha256File(path.join(pack, "wasm_exec.mjs"))) !== GO_LOCK.toolchain.wasmExecSha256 ) { throw new Error("The staged wasm_exec runtime does not match go1.26.5."); } const wasm = await readFile(path.join(pack, "go-regex.wasm")); if ( wasm.byteLength < 100_000 || wasm.subarray(0, 4).toString("hex") !== "0061736d" ) { throw new Error("The staged Go WebAssembly module is invalid."); } let metadata; try { metadata = JSON.parse( await readFile(path.join(pack, "engine-metadata.json"), "utf8"), ); } catch (error) { throw new Error("Go engine-metadata.json is invalid JSON.", { cause: error, }); } if (!equalJson(metadata, await expectedMetadata(repositoryRoot, pack))) { throw new Error( "The Go metadata does not match the pinned build contract.", ); } if ( (await readFile(path.join(pack, "SHA256SUMS"), "utf8")) !== (await checksumText(pack)) ) { throw new Error("The Go SHA256SUMS file is incorrect."); } await smokePack(pack); return metadata; } async function replaceDirectory(stage, target, label) { const details = await lstat(target).catch(() => null); if (details && (!details.isDirectory() || details.isSymbolicLink())) { throw new Error(`${label} must be a real directory.`); } if (!details) { await rename(stage, target); return; } const backup = `${target}.replaced-${process.pid}`; await rename(target, backup); try { await rename(stage, target); } catch (error) { await rename(backup, target); throw error; } await rm(backup, { recursive: true }); } export async function buildGoPack(root, goRootDirectory, outputDirectory) { const repositoryRoot = await assertRealDirectory( root, "Regex Tools repository", ); const engine = await assertRealDirectory( path.join(repositoryRoot, "engines", "go"), "Go engine source", ); const toolchain = await verifyToolchain(goRootDirectory); const environment = buildEnvironment(toolchain.goRoot); const buildParent = path.join(repositoryRoot, ".engine-build"); await mkdir(buildParent, { recursive: true }); const temporary = await mkdtemp(path.join(buildParent, "go-build-")); const first = path.join(temporary, "first.wasm"); const second = path.join(temporary, "second.wasm"); const buildArguments = [ "build", "-trimpath", "-buildvcs=false", "-ldflags=-s -w -buildid=", ]; try { await run(toolchain.go, [...buildArguments, "-o", first, "."], { cwd: engine, env: environment, }); await run(toolchain.go, [...buildArguments, "-o", second, "."], { cwd: engine, env: environment, }); if ((await sha256File(first)) !== (await sha256File(second))) { throw new Error("Two pinned Go builds produced different module hashes."); } const target = path.resolve( repositoryRoot, outputDirectory ?? path.join(".engine-build", "go"), ); const stage = await mkdtemp(path.join(buildParent, "go-pack-")); await copyFile(toolchain.license, path.join(stage, "LICENSE-Go.txt")); await copyFile(first, path.join(stage, "go-regex.wasm")); await copyFile(toolchain.wasmExec, path.join(stage, "wasm_exec.mjs")); const metadata = await expectedMetadata(repositoryRoot, stage); await writeFile( path.join(stage, "engine-metadata.json"), `${JSON.stringify(metadata, null, 2)}\n`, "utf8", ); await writeFile(path.join(stage, "SHA256SUMS"), await checksumText(stage)); await verifyGoPack(stage, repositoryRoot); await mkdir(path.dirname(target), { recursive: true }); await replaceDirectory(stage, target, "Go staged pack"); return { metadata, output: target }; } finally { await rm(temporary, { recursive: true }); } } export async function installGoPack(sourceDirectory, root) { const repositoryRoot = await assertRealDirectory( root, "Regex Tools repository", ); const source = await assertRealDirectory(sourceDirectory, "Go staged pack"); const metadata = await verifyGoPack(source, repositoryRoot); const engineParent = path.join(repositoryRoot, "public", "engines"); await mkdir(engineParent, { recursive: true }); const stage = await mkdtemp(path.join(engineParent, "go-install-")); for (const name of PACK_FILES) { await copyFile(path.join(source, name), path.join(stage, name)); } await verifyGoPack(stage, repositoryRoot); const output = path.join(engineParent, "go"); await replaceDirectory(stage, output, "Installed Go engine pack"); return { metadata, output }; }