import assert from 'node:assert/strict'; import {spawnSync} from 'node:child_process'; import {cpSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync} from 'node:fs'; import {join, relative, resolve} from 'node:path'; import {hashAt} from './boot-contract-report.mjs'; assert.equal(process.argv.length, 3, 'usage: node service-registry-versions-local.mjs '); const root = process.cwd(); const predecessorPath = relative(root, resolve(process.argv[2])); assert.match(predecessorPath, /^reports\/os-implementation\/K1385-registry-el0-matrix-check-[A-Za-z0-9_-]+\/report\.json$/); const predecessor = JSON.parse(readFileSync(join(root, predecessorPath), 'utf8')); assert.equal(predecessor.status, 'K1385_REGISTRY_EL0_DEVELOPMENT_MATRIX_VALIDATED'); assert.equal(predecessor.guestAccepted, true); const directory = mkdtempSync(join(root, 'reports/os-implementation/K1390-service-registry-versions-local-preflight-')); const workspace = join(directory, 'workspace'); mkdirSync(join(workspace, 'userspace/src'), {recursive: true}); mkdirSync(join(workspace, 'userspace/tests'), {recursive: true}); const source = 'userspace/src/service_registry.rs'; const fixture = 'userspace/tests/service_registry.rs'; const original = readFileSync(join(root, source), 'utf8'); cpSync(join(root, source), join(workspace, source)); const originalFixture = readFileSync(join(root, fixture), 'utf8'); const importLine = 'use turkos_userspace::service_registry::{'; assert.equal(originalFixture.split(importLine).length, 2); const standalone = originalFixture.replace(importLine, '#[path = "../src/service_registry.rs"] mod service_registry;\n' + 'use service_registry::{'); writeFileSync(join(workspace, fixture), standalone); const artifact = path => ({path: relative(root, path), sha256: hashAt(root, relative(root, path))}); const run = (name, command, args) => { const answer = spawnSync(command, args, {cwd: root, encoding: 'utf8', timeout: 120000, maxBuffer: 32 * 1024 * 1024}); const log = join(directory, name + '.log'); writeFileSync(log, (answer.stdout ?? '') + (answer.stderr ?? '')); return {exitCode: answer.status, error: answer.error?.message ?? null, log: artifact(log)}; }; const binary = join(directory, 'service-registry-test'); const compile = run('host-compile', 'rustc', ['--edition=2024', '--test', join(workspace, fixture), '-o', binary]); assert.equal(compile.exitCode, 0, readFileSync(join(root, compile.log.path), 'utf8')); const green = run('host-tests', binary, ['--nocapture']); const greenText = readFileSync(join(root, green.log.path), 'utf8'); assert.equal(green.exitCode, 0, greenText); for (const name of ['os_service_registry_versions_positive', 'os_service_registry_versions_negative']) assert.match(greenText, new RegExp(`test ${name} \\.\\.\\. ok`)); assert.match(greenText, /5 passed; 0 failed/); const wrapper = join(workspace, 'userspace/src/no_std_check.rs'); writeFileSync(wrapper, '#![no_std]\n#[path = "service_registry.rs"] pub mod service_registry;\n'); const target = run('aarch64-no-std-check', 'rustc', ['--edition=2024', '--crate-type=lib', '--target=aarch64-unknown-none', '--emit=metadata', wrapper, '-o', join(directory, 'service-registry-aarch64.rmeta')]); assert.equal(target.exitCode, 0, readFileSync(join(root, target.log.path), 'utf8')); const guard = 'if bytes[2] != WIRE_VERSION { return Err(WireError::Version); }'; assert.equal(original.split(guard).length, 2); writeFileSync(join(workspace, source), original.replace(guard, 'if false { return Err(WireError::Version); }')); const mutant = join(directory, 'service-registry-mutant-test'); const mutantCompile = run('version-guard-mutant-compile', 'rustc', ['--edition=2024', '--test', join(workspace, fixture), '-o', mutant]); assert.equal(mutantCompile.exitCode, 0, readFileSync(join(root, mutantCompile.log.path), 'utf8')); const red = run('version-guard-mutant', mutant, ['os_service_registry_versions_negative', '--exact', '--nocapture']); const redText = readFileSync(join(root, red.log.path), 'utf8'); assert.notEqual(red.exitCode, 0); assert.match(redText, /os_service_registry_versions_negative \.\.\. FAILED/); writeFileSync(join(workspace, source), original); const report = {schema: 'turkos-k1390-service-registry-versions-local-preflight/v1', status: 'K1386_K1389_LOCAL_VALIDATED', guestAccepted: false, productAccepted: false, predecessor: artifact(join(root, predecessorPath)), sources: {contract: artifact(join(root, 'userspace/SERVICE_REGISTRY_PROTOCOL_V1.md')), model: artifact(join(root, source)), fixture: artifact(join(root, fixture)), module: artifact(join(root, 'userspace/src/lib.rs')), harness: artifact(join(root, 'scripts/os-acceptance/service-registry-versions-local.mjs'))}, tests: {compile, green, target, mutantCompile, red, greenCount: 5, mutationRejected: true}, scope: 'Fixed eight-byte V1 frame with bounded payload and trusted caller identity. V1 publish and unpublish request/response succeed; V255, every truncated header prefix, truncated and oversized payload, wrong flags and kind, insufficient response buffer, and foreign caller reject without registry or response mutation. Five host tests, AArch64 no_std compilation, and a disabled-version-guard mutant are local evidence. Native EL0 six-profile integration remains K1390.'}; const reportPath = join(directory, 'report.json'); writeFileSync(reportPath, JSON.stringify(report, null, 2) + '\n'); console.log(JSON.stringify({status: report.status, report: relative(root, reportPath), green: report.tests.greenCount}));