import assert from 'node:assert/strict'; import {copyFileSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync} from 'node:fs'; import {spawnSync} from 'node:child_process'; import {createHash} from 'node:crypto'; import {dirname, join, relative, resolve} from 'node:path'; assert.equal(process.argv.length, 3, 'usage: node block-requests-local.mjs '); const root = process.cwd(); const predecessorPath = resolve(process.argv[2]); const predecessor = JSON.parse(readFileSync(predecessorPath, 'utf8')); assert.equal(predecessor.status, 'K1505_BLOCK_GEOMETRY_DEVELOPMENT_MATRIX_VALIDATED'); const dir = mkdtempSync(join(root, 'reports/os-implementation/K1510-block-requests-local-')); const sha = path => createHash('sha256').update(readFileSync(path)).digest('hex'); const artifact = path => ({path: relative(root, path), sha256: sha(path)}); const copy = (source, target) => { mkdirSync(dirname(target), {recursive: true}); copyFileSync(join(root, source), target); return artifact(target); }; const source = join(dir, 'source'); const model = join(source, 'os-block-requests/src/lib.rs'); const fixture = join(source, 'kernel/tests/os/block_io.rs'); const contract = join(source, 'kernel/BLOCK_IO_REQUEST_CONTRACT.md'); const sources = { model: copy('os-block-requests/src/lib.rs', model), fixture: copy('kernel/tests/os/block_io.rs', fixture), contract: copy('kernel/BLOCK_IO_REQUEST_CONTRACT.md', contract), driverReference: copy('kernel/src/virtio_ro_turkfs.rs', join(source, 'kernel/src/virtio_ro_turkfs.rs')), harness: artifact(join(root, 'scripts/os-acceptance/block-requests-local.mjs')), }; const run = (name, program, args, expected) => { const result = spawnSync(program, args, {cwd: root, encoding: 'utf8'}); const log = join(dir, `${name}.log`); writeFileSync(log, `${result.stdout ?? ''}${result.stderr ?? ''}`); assert.equal(result.status, expected, `${name}: expected exit ${expected}, observed ${result.status}; ${artifact(log).path}`); return {exitCode: result.status, log: artifact(log)}; }; const binary = join(dir, 'block-requests-tests'); const tests = { compile: run('host-compile', 'rustc', ['--edition=2024', '--test', fixture, '-o', binary], 0), green: run('host-tests', binary, [], 0), }; const greenText = readFileSync(join(dir, 'host-tests.log'), 'utf8'); assert.match(greenText, /os_block_io_requests_positive \.\.\. ok/); assert.match(greenText, /os_block_io_requests_negative \.\.\. ok/); assert.match(greenText, /2 passed; 0 failed/); const noStdRoot = join(source, 'no-std-root.rs'); writeFileSync(noStdRoot, '#![no_std]\n#[path = "os-block-requests/src/lib.rs"]\npub mod block_io;\n'); sources.noStdRoot = artifact(noStdRoot); tests.target = run('aarch64-no-std-check', 'rustc', ['--edition=2024', '--crate-type=lib', '--target=aarch64-unknown-none', '--emit=metadata', noStdRoot, '-o', join(dir, 'model.rmeta')], 0); const mutantRoot = join(dir, 'mutant'); const mutantModel = join(mutantRoot, 'os-block-requests/src/lib.rs'); const mutantFixture = join(mutantRoot, 'kernel/tests/os/block_io.rs'); copy('kernel/tests/os/block_io.rs', mutantFixture); mkdirSync(dirname(mutantModel), {recursive: true}); const original = readFileSync(model, 'utf8'); const guard = 'if device_generation != self.device_generation { return Err(Error::StaleDevice); }'; assert.equal(original.split(guard).length, 2, 'prepare generation guard must occur once'); writeFileSync(mutantModel, original.replace(guard, 'if false { return Err(Error::StaleDevice); }')); const mutant = artifact(mutantModel); const mutantBinary = join(dir, 'block-requests-mutant-tests'); tests.mutantCompile = run('mutant-compile', 'rustc', ['--edition=2024', '--test', mutantFixture, '-o', mutantBinary], 0); tests.red = run('mutant-tests', mutantBinary, [], 101); assert.match(readFileSync(join(dir, 'mutant-tests.log'), 'utf8'), /os_block_io_requests_negative \.\.\. FAILED/); const report = { schema: 'turkos-k1510-block-requests-local/v1', status: 'K1506_K1509_LOCAL_VALIDATED', guestAccepted: false, productAccepted: false, predecessor: artifact(predecessorPath), sources, mutant, tests: {...tests, greenCount: 2, mutationRejected: true}, scope: 'Bounded read-only request records bind identity, head, buffer, deadline and device generation. Tests cover two concurrent requests, reverse completion, reuse with new ID, stale generation, wrong completion, timeout retention, reset, host and AArch64 no_std builds, and a red stale-generation mutant. Real guest completion matching remains for K1510.' }; const reportPath = join(dir, 'report.json'); writeFileSync(reportPath, JSON.stringify(report, null, 2) + '\n'); console.log(JSON.stringify({status: report.status, report: relative(root, reportPath), tests: report.tests.greenCount, mutationRejected: report.tests.mutationRejected}));