#!/usr/bin/env node 'use strict'; const crypto = require('node:crypto'); const fs = require('node:fs'); const path = require('node:path'); const { QingLong3PhysicalEvidenceError, buildEvidenceReport, canonicalDigest, normalizeManifest, validateAdoptionScaleEvidenceReport, validateApplicationStartEvidenceReport, validateComposeStorageEvidenceReport, validateDirectServiceStartEvidenceReport, validateDirectServiceStopEvidenceReport, validateEvidenceWorkloads, validateFaultEvidenceReport, validateIdleEvidenceReport, validateObservedPlatform, validateServiceStartEvidenceReport, validateTaskScaleEvidenceReport, writeNoReplace, } = require('./ql3-physical-edge-evidence.cjs'); const MAX_PHYSICAL_REPORT_BYTES = 4 * 1024 * 1024; const MAX_RELEASE_ARCHIVE_BYTES = 64 * 1024 * 1024; const MAX_PAYLOAD_BYTES = 16 * 1024; const MAX_PUBLIC_KEY_BYTES = 8 * 1024; const ED25519_SIGNATURE_BYTES = 64; const SHA256_PATTERN = /^[a-f0-9]{64}$/; const REVISION_PATTERN = /^[a-f0-9]{40}$/; const RELEASE_SCOPE = 'operator_attests_archive_source_and_runtime_artifact_identity'; const PHYSICAL_REPORT_KEYS = Object.freeze([ 'evidenceClass', 'generatedAt', 'manifest', 'observed', 'qualification', 'schemaVersion', 'sha256', 'supplementalEvidence', 'supported', 'workloads', ]); const QUALIFICATION_KEYS = Object.freeze([ 'collectedEvidence', 'physicalCandidate', 'remainingRequiredEvidence', 'violations', ]); const OBSERVED_KEYS = Object.freeze([ 'architecture', 'bootId', 'cpuCount', 'cpuModel', 'dataAvailableBytes', 'dataBytes', 'dataFilesystem', 'dataMountOptions', 'dataPath', 'distribution', 'kernel', 'libc', 'node', 'observedModel', 'platform', 'totalMemoryBytes', 'virtualizationIndicators', ]); const EDGE_REPORT_KEYS = Object.freeze([ 'cancellation', 'cases', 'gates', 'generatedAt', 'host', 'moduleLoad', 'profile', 'schemaVersion', ]); const EDGE_CASE_KEYS = Object.freeze([ 'baselineRssBytes', 'durationMs', 'exitCode', 'name', 'outcome', 'peakRssBytes', 'peakRssDeltaBytes', ]); const SQLITE_REPORT_KEYS = Object.freeze([ 'arch', 'batchSize', 'databaseBytes', 'integrityCheck', 'iterations', 'journalMode', 'maxBatchStallMs', 'node', 'platform', 'rssDeltaMb', 'synchronous', 'transactionMs', ]); const SUPPLEMENTAL_CLASSES = Object.freeze([ 'physical_edge_idle_candidate', 'physical_edge_fault_candidate', 'physical_edge_task_scale_candidate', 'physical_edge_adoption_scale_candidate', 'physical_edge_compose_storage_candidate', 'physical_edge_application_start_candidate', 'physical_edge_service_start_candidate', 'physical_edge_direct_service_start_candidate', 'physical_edge_direct_service_stop_candidate', ]); const LIMITATIONS = Object.freeze([ 'the trusted operator attests the archive, source revision and runtime artifact relationship; this verifier does not unpack or independently reproduce the archive', 'public-key distribution, rotation, revocation and transparency remain release-operator responsibilities', 'the signature does not prove firmware or bootloader time, whole-device flash behavior, physical power loss, migration capacity or cluster capacity', 'the final report remains a physical Edge candidate and never changes supported status', ]); class QingLong3PhysicalEdgeReleaseEvidenceError extends Error { constructor(message) { super(`QingLong 3.0 physical Edge release evidence failed: ${message}`); this.name = 'QingLong3PhysicalEdgeReleaseEvidenceError'; } } function hasExactKeys(value, expected) { return ( value !== null && typeof value === 'object' && !Array.isArray(value) && JSON.stringify(Object.keys(value).sort()) === JSON.stringify(expected) ); } function parseArguments(argv) { const options = { json: false }; for (const argument of argv) { if (argument === '--') continue; if (argument === '--json') { options.json = true; continue; } if (!options.phase && ['prepare', 'finalize'].includes(argument)) { options.phase = argument; continue; } const separator = argument.indexOf('='); if (separator < 1) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `unsupported argument ${argument}`, ); } const name = argument.slice(0, separator); const value = argument.slice(separator + 1); if (name === '--physical-report') options.physicalReportPath = value; else if (name === '--release-archive') options.releaseArchivePath = value; else if (name === '--repository') options.repository = value; else if (name === '--revision') options.revision = value; else if (name === '--payload') options.payloadPath = value; else if (name === '--signature') options.signaturePath = value; else if (name === '--trusted-public-key') options.publicKeyPath = value; else if (name === '--expected-repository') options.expectedRepository = value; else if (name === '--expected-revision') options.expectedRevision = value; else if (name === '--output') options.outputPath = value; else { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `unsupported argument ${name}`, ); } } if (!['prepare', 'finalize'].includes(options.phase)) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( 'phase must be prepare or finalize', ); } const commonPaths = [ ['physicalReportPath', options.physicalReportPath], ['releaseArchivePath', options.releaseArchivePath], ['payloadPath', options.payloadPath], ]; const phasePaths = options.phase === 'finalize' ? [ ['signaturePath', options.signaturePath], ['publicKeyPath', options.publicKeyPath], ['outputPath', options.outputPath], ] : []; for (const [label, value] of [...commonPaths, ...phasePaths]) { if (!path.isAbsolute(value ?? '')) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `${label} must be absolute`, ); } } if (options.phase === 'prepare') { validateRepository(options.repository, 'repository'); validateRevision(options.revision, 'revision'); const invalid = [ options.signaturePath, options.publicKeyPath, options.expectedRepository, options.expectedRevision, options.outputPath, ].some((value) => value !== undefined); if (invalid) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( 'prepare received a finalize-only option', ); } } else { validateRepository(options.expectedRepository, 'expectedRepository'); validateRevision(options.expectedRevision, 'expectedRevision'); if (options.repository !== undefined || options.revision !== undefined) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( 'finalize received a prepare-only option', ); } } return Object.freeze(options); } function validateRepository(value, label) { if ( typeof value !== 'string' || value.length < 3 || value.length > 512 || !/^[A-Za-z0-9][A-Za-z0-9._:/@+~-]+$/.test(value) ) { throw new QingLong3PhysicalEdgeReleaseEvidenceError(`${label} is invalid`); } return value; } function validateRevision(value, label) { if (!REVISION_PATTERN.test(value ?? '')) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `${label} must be a 40-character lowercase Git revision`, ); } return value; } function stableStatIdentity(stat) { return [stat.dev, stat.ino, stat.size, stat.mtimeNs, stat.ctimeNs].join(':'); } function openStableInput(filePath, label, maximumBytes, privateInput) { if (!path.isAbsolute(filePath) || fs.realpathSync(filePath) !== filePath) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `${label} must use a canonical absolute path`, ); } const before = fs.lstatSync(filePath, { bigint: true }); if (!before.isFile() || before.isSymbolicLink()) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `${label} must be a regular file without symlinks`, ); } const mode = Number(before.mode & 0o777n); const effectiveUserId = process.geteuid?.(); if ( privateInput && (!Number.isSafeInteger(effectiveUserId) || before.uid !== BigInt(effectiveUserId) || mode !== 0o600) ) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `${label} must be a current-user-owned 0600 file`, ); } if (!privateInput && (mode & 0o022) !== 0) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `${label} must not be group- or other-writable`, ); } if (before.size < 1n || before.size > BigInt(maximumBytes)) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `${label} exceeds its bounded size`, ); } const descriptor = fs.openSync( filePath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0), ); const opened = fs.fstatSync(descriptor, { bigint: true }); if (stableStatIdentity(before) !== stableStatIdentity(opened)) { fs.closeSync(descriptor); throw new QingLong3PhysicalEdgeReleaseEvidenceError( `${label} changed while it was opened`, ); } return Object.freeze({ descriptor, before }); } function finishStableInput(filePath, label, descriptor, before) { const afterDescriptor = fs.fstatSync(descriptor, { bigint: true }); const afterPath = fs.lstatSync(filePath, { bigint: true }); if ( stableStatIdentity(before) !== stableStatIdentity(afterDescriptor) || stableStatIdentity(before) !== stableStatIdentity(afterPath) ) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `${label} changed while it was read`, ); } } function readStableBuffer(filePath, label, maximumBytes, privateInput) { const { descriptor, before } = openStableInput( filePath, label, maximumBytes, privateInput, ); try { const contents = Buffer.alloc(Number(before.size)); let offset = 0; while (offset < contents.length) { const count = fs.readSync( descriptor, contents, offset, contents.length - offset, offset, ); if (count === 0) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `${label} ended before its declared size`, ); } offset += count; } finishStableInput(filePath, label, descriptor, before); return contents; } finally { fs.closeSync(descriptor); } } function hashStableFile(filePath, label, maximumBytes) { const { descriptor, before } = openStableInput( filePath, label, maximumBytes, false, ); try { const digest = crypto.createHash('sha256'); const buffer = Buffer.alloc(64 * 1024); let offset = 0; while (offset < Number(before.size)) { const count = fs.readSync( descriptor, buffer, 0, Math.min(buffer.length, Number(before.size) - offset), offset, ); if (count === 0) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `${label} ended before its declared size`, ); } digest.update(buffer.subarray(0, count)); offset += count; } finishStableInput(filePath, label, descriptor, before); return Object.freeze({ sha256: digest.digest('hex'), bytes: Number(before.size), }); } finally { fs.closeSync(descriptor); } } function parsePrivateJson(filePath, label, maximumBytes) { const contents = readStableBuffer(filePath, label, maximumBytes, true); try { return JSON.parse(contents.toString('utf8')); } catch (error) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `${label} is not valid JSON: ${error.message}`, ); } } function validateExactObserved(observed) { if ( !hasExactKeys(observed, OBSERVED_KEYS) || !hasExactKeys(observed?.distribution, ['id', 'versionId']) || observed.platform !== 'linux' || !['arm64', 'x64', 'arm'].includes(observed.architecture) || !/^v24\.[0-9]+\.[0-9]+$/.test(observed.node ?? '') || !/^[a-f0-9-]{36}$/.test(observed.bootId ?? '') || !path.isAbsolute(observed.dataPath ?? '') || !Number.isSafeInteger(observed.cpuCount) || observed.cpuCount < 1 || !Number.isSafeInteger(observed.totalMemoryBytes) || observed.totalMemoryBytes < 1 || !Number.isSafeInteger(observed.dataBytes) || observed.dataBytes < 1 || !Number.isSafeInteger(observed.dataAvailableBytes) || observed.dataAvailableBytes < 0 || observed.dataAvailableBytes > observed.dataBytes || !Array.isArray(observed.dataMountOptions) || observed.dataMountOptions.length < 1 || observed.dataMountOptions.some( (option) => typeof option !== 'string' || option.length > 128, ) || !Array.isArray(observed.virtualizationIndicators) || ![ observed.cpuModel, observed.observedModel, observed.kernel, observed.libc, observed.dataFilesystem, observed.distribution.id, observed.distribution.versionId, ].every( (value) => typeof value === 'string' && value.length >= 1 && value.length <= 384, ) ) { return Object.freeze(['physical observed platform shape is invalid']); } return Object.freeze([]); } function validRssMeasurement(value) { return ( hasExactKeys(value, ['rssAfterBytes', 'rssBeforeBytes', 'rssDeltaBytes']) && Number.isSafeInteger(value.rssBeforeBytes) && value.rssBeforeBytes > 0 && Number.isSafeInteger(value.rssAfterBytes) && value.rssAfterBytes > 0 && Number.isSafeInteger(value.rssDeltaBytes) && value.rssDeltaBytes === Math.max(0, value.rssAfterBytes - value.rssBeforeBytes) ); } function validEdgeCase(value, expectedName, outputRequired) { const expectedKeys = outputRequired ? [...EDGE_CASE_KEYS, 'output'].sort() : EDGE_CASE_KEYS; if ( !hasExactKeys(value, expectedKeys) || value.name !== expectedName || value.outcome !== 'succeeded' || value.exitCode !== 0 || !Number.isFinite(value.durationMs) || value.durationMs < 0 || !Number.isSafeInteger(value.baselineRssBytes) || value.baselineRssBytes < 1 || !Number.isSafeInteger(value.peakRssBytes) || value.peakRssBytes < value.baselineRssBytes || value.peakRssDeltaBytes !== Math.max(0, value.peakRssBytes - value.baselineRssBytes) ) { return false; } return ( !outputRequired || (hasExactKeys(value.output, ['bytes', 'lines', 'writes']) && Number.isSafeInteger(value.output.bytes) && value.output.bytes > 0 && value.output.lines === 10_000 && Number.isSafeInteger(value.output.writes) && value.output.writes > 0) ); } function validateExactBaseWorkloads(workloads, observed) { const violations = []; if (!Array.isArray(workloads) || workloads.length !== 3) { return Object.freeze(['physical evidence workloads are incomplete']); } const edge = workloads[0]?.report; if ( !hasExactKeys(edge, EDGE_REPORT_KEYS) || !hasExactKeys(edge?.host, [ 'architecture', 'cpuCount', 'node', 'platform', 'totalMemoryBytes', ]) || edge.host.platform !== observed.platform || edge.host.architecture !== observed.architecture || edge.host.node !== observed.node || !Number.isSafeInteger(edge.host.cpuCount) || edge.host.cpuCount < 1 || !Number.isSafeInteger(edge.host.totalMemoryBytes) || edge.host.totalMemoryBytes < 1 || !Number.isFinite(Date.parse(edge.generatedAt ?? '')) || !validRssMeasurement(edge.moduleLoad) || !Array.isArray(edge.cases) || edge.cases.length !== 2 || !validEdgeCase(edge.cases[0], 'single_noop', false) || !validEdgeCase(edge.cases[1], 'stdout_10000_lines', true) || !hasExactKeys(edge.cancellation, [ 'durationMs', 'killSignalSent', 'outcome', 'termSignalSent', ]) || !Number.isFinite(edge.cancellation.durationMs) || edge.cancellation.durationMs < 0 || edge.cancellation.outcome !== 'cancelled' || typeof edge.cancellation.termSignalSent !== 'boolean' || typeof edge.cancellation.killSignalSent !== 'boolean' || !hasExactKeys(edge.gates, [ 'maxCancelMs', 'maxRssDeltaMb', 'passed', 'violations', ]) || edge.gates.maxCancelMs !== 5000 || edge.gates.maxRssDeltaMb !== 96 || edge.gates.passed !== true || !Array.isArray(edge.gates.violations) || edge.gates.violations.length !== 0 ) { violations.push('Edge executor report is not an exact recorder result'); } const sqlite = workloads[1]?.report; if ( !hasExactKeys(sqlite, SQLITE_REPORT_KEYS) || sqlite.platform !== observed.platform || sqlite.arch !== observed.architecture || sqlite.node !== observed.node || sqlite.iterations !== 250 || sqlite.batchSize !== 10 || sqlite.journalMode !== 'delete' || sqlite.synchronous !== 'full' || sqlite.integrityCheck !== 'ok' || !Number.isSafeInteger(sqlite.databaseBytes) || sqlite.databaseBytes < 1 || !Number.isFinite(sqlite.maxBatchStallMs) || sqlite.maxBatchStallMs < 0 || !Number.isFinite(sqlite.rssDeltaMb) || sqlite.rssDeltaMb < 0 || !hasExactKeys(sqlite.transactionMs, ['max', 'p50', 'p95', 'p99']) || ![ sqlite.transactionMs.p50, sqlite.transactionMs.p95, sqlite.transactionMs.p99, sqlite.transactionMs.max, ].every((value) => Number.isFinite(value) && value >= 0) || sqlite.transactionMs.p50 > sqlite.transactionMs.p95 || sqlite.transactionMs.p95 > sqlite.transactionMs.p99 || sqlite.transactionMs.p99 > sqlite.transactionMs.max ) { violations.push('Node SQLite report is not an exact recorder result'); } if (workloads[2]?.report?.identity?.node !== observed.node) { violations.push('Plugin Package recovery Node identity did not match'); } return Object.freeze(violations); } function validateSupplementalEvidence(report, manifest, observed) { const violations = []; const counts = new Map(); const directStart = report.supplementalEvidence.find( ({ evidenceClass }) => evidenceClass === 'physical_edge_direct_service_start_candidate', ); for (const evidence of report.supplementalEvidence) { const evidenceClass = evidence?.evidenceClass; if (!SUPPLEMENTAL_CLASSES.includes(evidenceClass)) { violations.push(`unknown supplemental evidence class ${evidenceClass}`); continue; } const discriminator = evidenceClass === 'physical_edge_fault_candidate' ? `${evidenceClass}:${evidence.manifest?.fault}` : evidenceClass; counts.set(discriminator, (counts.get(discriminator) ?? 0) + 1); if (counts.get(discriminator) > 1) { violations.push(`duplicate supplemental evidence ${discriminator}`); continue; } let evidenceViolations; if (evidenceClass === 'physical_edge_idle_candidate') { evidenceViolations = validateIdleEvidenceReport( evidence, manifest, observed, ); } else if (evidenceClass === 'physical_edge_fault_candidate') { evidenceViolations = validateFaultEvidenceReport( evidence, manifest, observed, ); } else if (evidenceClass === 'physical_edge_task_scale_candidate') { evidenceViolations = validateTaskScaleEvidenceReport( evidence, manifest, observed, ); } else if (evidenceClass === 'physical_edge_adoption_scale_candidate') { evidenceViolations = validateAdoptionScaleEvidenceReport( evidence, manifest, observed, ); } else if (evidenceClass === 'physical_edge_compose_storage_candidate') { evidenceViolations = validateComposeStorageEvidenceReport( evidence, manifest, observed, ); } else if (evidenceClass === 'physical_edge_application_start_candidate') { evidenceViolations = validateApplicationStartEvidenceReport( evidence, manifest, observed, ); } else if (evidenceClass === 'physical_edge_service_start_candidate') { evidenceViolations = validateServiceStartEvidenceReport( evidence, manifest, observed, ); } else if ( evidenceClass === 'physical_edge_direct_service_start_candidate' ) { evidenceViolations = validateDirectServiceStartEvidenceReport( evidence, manifest, observed, ); } else { evidenceViolations = validateDirectServiceStopEvidenceReport( evidence, manifest, observed, directStart, ); } violations.push( ...evidenceViolations.map( (violation) => `${evidenceClass}: ${violation}`, ), ); } return Object.freeze(violations); } function validatePhysicalEvidenceReport(report) { const violations = []; if (!hasExactKeys(report, PHYSICAL_REPORT_KEYS)) { return Object.freeze(['physical evidence report shape is invalid']); } if (!hasExactKeys(report.qualification, QUALIFICATION_KEYS)) { return Object.freeze(['physical evidence qualification shape is invalid']); } let manifest; try { manifest = normalizeManifest(report.manifest); } catch (error) { return Object.freeze([ `physical evidence manifest is invalid: ${error.message}`, ]); } if ( report.schemaVersion !== 1 || report.evidenceClass !== 'physical_edge_candidate' || report.supported !== false || !Number.isFinite(Date.parse(report.generatedAt ?? '')) || !Array.isArray(report.workloads) || !Array.isArray(report.supplementalEvidence) ) { violations.push('physical evidence identity is invalid'); } violations.push( ...validateExactObserved(report.observed), ...validateObservedPlatform(manifest, report.observed), ...validateEvidenceWorkloads(report.workloads, report.observed), ...validateExactBaseWorkloads(report.workloads, report.observed), ); if (Array.isArray(report.supplementalEvidence)) { violations.push( ...validateSupplementalEvidence(report, manifest, report.observed), ); } let rebuilt; try { rebuilt = buildEvidenceReport({ manifest, observed: report.observed, workloads: report.workloads, supplementalEvidence: report.supplementalEvidence, generatedAt: report.generatedAt, }); } catch (error) { violations.push(`physical evidence could not be rebuilt: ${error.message}`); } if (rebuilt && JSON.stringify(rebuilt) !== JSON.stringify(report)) { violations.push('physical evidence report was not an exact reconstruction'); } if ( report.qualification.physicalCandidate !== true || report.qualification.violations.length !== 0 ) { violations.push('physical evidence candidate did not pass'); } const directStart = report.supplementalEvidence.find?.( ({ evidenceClass }) => evidenceClass === 'physical_edge_direct_service_start_candidate', ); if (!directStart) { violations.push('direct release service start evidence is required'); } const releaseRequirementCount = report.qualification.remainingRequiredEvidence.filter?.( (item) => item === 'release_archive_signature', ).length ?? 0; if (releaseRequirementCount !== 1) { violations.push('release archive signature requirement is not exact'); } return Object.freeze(violations); } function requirePhysicalEvidenceReport(report) { const violations = validatePhysicalEvidenceReport(report); if (violations.length > 0) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `physical evidence rejected: ${violations.join('; ')}`, ); } return Object.freeze(report); } function buildSigningPayload({ physicalReport, releaseArchive, repository, revision, signedAt, }) { validateRepository(repository, 'repository'); validateRevision(revision, 'revision'); if (!Number.isFinite(Date.parse(signedAt ?? ''))) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( 'signedAt must be an ISO timestamp', ); } if ( !SHA256_PATTERN.test(releaseArchive?.sha256 ?? '') || !Number.isSafeInteger(releaseArchive?.bytes) || releaseArchive.bytes < 1 || releaseArchive.bytes > MAX_RELEASE_ARCHIVE_BYTES ) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( 'release archive identity is invalid', ); } const directStart = physicalReport.supplementalEvidence.find( ({ evidenceClass }) => evidenceClass === 'physical_edge_direct_service_start_candidate', ); const artifact = directStart.observed.artifact; const after = directStart.observed.after; return Object.freeze({ schemaVersion: 1, attestationClass: 'physical_edge_release_archive_binding', algorithm: 'Ed25519', repository, revision, signedAt, scope: RELEASE_SCOPE, device: Object.freeze({ deviceId: physicalReport.manifest.deviceId, deviceModel: physicalReport.manifest.deviceModel, soc: physicalReport.manifest.soc, architecture: physicalReport.observed.architecture, filesystem: physicalReport.observed.dataFilesystem, storageMedium: physicalReport.manifest.storageMedium, bootId: physicalReport.observed.bootId, }), physicalEvidence: Object.freeze({ sha256: physicalReport.sha256, generatedAt: physicalReport.generatedAt, }), release: Object.freeze({ archiveSha256: releaseArchive.sha256, archiveBytes: releaseArchive.bytes, profile: 'edge', artifactSha256: artifact.artifactSha256, artifactMetadataSha256: artifact.artifactMetadataSha256, artifactFiles: artifact.artifactFiles, artifactBytes: artifact.artifactBytes, entrypointSha256: artifact.entrypointSha256, nodeSha256: after.nodeSha256, nodeVersion: after.nodeVersion, }), }); } function readExactPayload(filePath) { const contents = readStableBuffer( filePath, 'signing payload', MAX_PAYLOAD_BYTES, true, ); let payload; try { payload = JSON.parse(contents.toString('utf8')); } catch (error) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `signing payload is not valid JSON: ${error.message}`, ); } const canonical = Buffer.from(JSON.stringify(payload), 'utf8'); if ( contents.length !== canonical.length || !crypto.timingSafeEqual(contents, canonical) ) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( 'signing payload must contain exact canonical JSON without a newline', ); } return Object.freeze({ payload, contents }); } function readTrustedPublicKey(filePath) { const pem = readStableBuffer( filePath, 'trusted public key', MAX_PUBLIC_KEY_BYTES, false, ); let key; try { key = crypto.createPublicKey(pem); } catch (error) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( `trusted public key is invalid: ${error.message}`, ); } if (key.asymmetricKeyType !== 'ed25519') { throw new QingLong3PhysicalEdgeReleaseEvidenceError( 'trusted public key must be Ed25519', ); } const der = key.export({ type: 'spki', format: 'der' }); return Object.freeze({ key, fingerprintSha256: crypto.createHash('sha256').update(der).digest('hex'), }); } function buildFinalReport({ physicalReport, payload, signature, fingerprint }) { const remainingRequiredEvidence = physicalReport.qualification.remainingRequiredEvidence.filter( (item) => item !== 'release_archive_signature', ); const collectedEvidence = [ ...physicalReport.qualification.collectedEvidence, 'release_archive_signature_or_attestation', ]; const body = { schemaVersion: 1, evidenceClass: 'physical_edge_release_candidate', supported: false, generatedAt: new Date().toISOString(), payload, trust: { algorithm: 'Ed25519', publicKeyFingerprintSha256: fingerprint, }, signature: { encoding: 'base64', value: signature.toString('base64'), }, qualification: { passed: true, violations: [], collectedEvidence, remainingRequiredEvidence, }, limitations: LIMITATIONS, }; return Object.freeze({ ...body, sha256: canonicalDigest(body) }); } function preparePhase(options) { const physicalReport = requirePhysicalEvidenceReport( parsePrivateJson( options.physicalReportPath, 'physical evidence report', MAX_PHYSICAL_REPORT_BYTES, ), ); const releaseArchive = hashStableFile( options.releaseArchivePath, 'release archive', MAX_RELEASE_ARCHIVE_BYTES, ); const payload = buildSigningPayload({ physicalReport, releaseArchive, repository: options.repository, revision: options.revision, signedAt: new Date().toISOString(), }); const serialized = JSON.stringify(payload); writeNoReplace(options.payloadPath, serialized); process.stdout.write( `${JSON.stringify(payload, null, options.json ? 0 : 2)}\n`, ); } function finalizePhase(options) { const physicalReport = requirePhysicalEvidenceReport( parsePrivateJson( options.physicalReportPath, 'physical evidence report', MAX_PHYSICAL_REPORT_BYTES, ), ); const releaseArchive = hashStableFile( options.releaseArchivePath, 'release archive', MAX_RELEASE_ARCHIVE_BYTES, ); const { payload, contents } = readExactPayload(options.payloadPath); const expectedPayload = buildSigningPayload({ physicalReport, releaseArchive, repository: options.expectedRepository, revision: options.expectedRevision, signedAt: payload.signedAt, }); if (JSON.stringify(payload) !== JSON.stringify(expectedPayload)) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( 'signing payload did not match the expected source, archive and evidence', ); } const signature = readStableBuffer( options.signaturePath, 'detached signature', ED25519_SIGNATURE_BYTES, true, ); if (signature.length !== ED25519_SIGNATURE_BYTES) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( 'detached Ed25519 signature must be exactly 64 bytes', ); } const trustedKey = readTrustedPublicKey(options.publicKeyPath); if (!crypto.verify(null, contents, trustedKey.key, signature)) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( 'detached signature verification failed', ); } const report = buildFinalReport({ physicalReport, payload, signature, fingerprint: trustedKey.fingerprintSha256, }); const serialized = `${JSON.stringify(report, null, options.json ? 0 : 2)}\n`; writeNoReplace(options.outputPath, serialized); process.stdout.write(serialized); } function main() { if (Number(process.versions.node.split('.')[0]) < 24) { throw new QingLong3PhysicalEdgeReleaseEvidenceError( 'Node.js 24 or newer is required', ); } const options = parseArguments(process.argv.slice(2)); if (options.phase === 'prepare') preparePhase(options); else finalizePhase(options); } module.exports = { ED25519_SIGNATURE_BYTES, LIMITATIONS, MAX_RELEASE_ARCHIVE_BYTES, QingLong3PhysicalEdgeReleaseEvidenceError, buildFinalReport, buildSigningPayload, hashStableFile, parseArguments, readExactPayload, readTrustedPublicKey, validatePhysicalEvidenceReport, validateExactBaseWorkloads, validateExactObserved, }; if (require.main === module) { try { main(); } catch (error) { const message = error instanceof QingLong3PhysicalEvidenceError || error instanceof Error ? error.message : String(error); process.stderr.write(`${message}\n`); process.exitCode = 1; } }