Files
qinglong/test/back/ql3PhysicalEdgeApplicationStart.test.cjs
T

400 lines
11 KiB
JavaScript

const assert = require('node:assert/strict');
const crypto = require('node:crypto');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { test } = require('node:test');
const {
buildApplicationStartReport,
collectArtifactIdentity,
normalizeApplicationStartManifest,
normalizeSession,
parseArguments,
parseEventLines,
preflightArtifactMetadata,
validateApplicationStartReport,
validateArtifactAgainstManifest,
validateBootObservation,
} = require('../../scripts/ql3-physical-edge-application-start.cjs');
const {
canonicalDigest,
} = require('../../scripts/ql3-physical-edge-evidence.cjs');
const packages = [
'@qinglong/local-admin',
'@qinglong/local-application',
'@qinglong/local-command-file',
'@qinglong/local-execution',
'@qinglong/local-process',
'@qinglong/local-secret',
'@qinglong/local-sqlite',
'@qinglong/runtime-core',
'croner',
'semver',
];
function writePrivate(filePath, contents) {
fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });
fs.writeFileSync(filePath, contents, { mode: 0o600 });
}
function artifactFixture(t) {
const root = fs.realpathSync(
fs.mkdtempSync(path.join(os.tmpdir(), 'ql3-application-artifact-')),
);
fs.chmodSync(root, 0o700);
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
for (const packageName of packages) {
const packageRoot = path.join(
root,
'node_modules',
...packageName.split('/'),
);
const manifest =
packageName === '@qinglong/local-application'
? {
name: packageName,
version: '3.0.0-alpha.0',
engines: { node: '>=24.18.0 <25' },
bin: { 'ql3-local-application': 'dist/cli.js' },
}
: { name: packageName, version: '1.0.0' };
writePrivate(
path.join(packageRoot, 'package.json'),
`${JSON.stringify(manifest)}\n`,
);
writePrivate(path.join(packageRoot, 'dist', 'index.js'), `'use strict';\n`);
}
writePrivate(
path.join(
root,
'node_modules',
'@qinglong',
'local-application',
'dist',
'cli.js',
),
`#!/usr/bin/env node\n'use strict';\n`,
);
return { root, identity: collectArtifactIdentity(root) };
}
function manifest(artifact, overrides = {}) {
return normalizeApplicationStartManifest({
schemaVersion: 1,
evidenceClass: 'physical_edge_application_start_candidate',
profile: 'edge',
deviceId: 'router-a1',
expectedArchitecture: 'arm64',
expectedFilesystem: 'ext4',
expectedArtifactSha256: artifact.artifactSha256,
expectedArtifactFiles: artifact.artifactFiles,
expectedArtifactBytes: artifact.artifactBytes,
expectedNodeSha256: 'b'.repeat(64),
maximumBootAgeMs: 180_000,
maximumFirstActiveMs: 30_000,
maximumSampledRssBytes: 256 * 1024 * 1024,
sampleIntervalMs: 10,
...overrides,
});
}
function boot(bootId, bootAgeMs = 1000, overrides = {}) {
return {
platform: 'linux',
architecture: 'arm64',
bootId,
dataFilesystem: 'ext4',
nodeExecutable: '/usr/bin/node',
nodeSha256: 'b'.repeat(64),
nodeVersion: 'v24.18.0',
bootAgeMs,
...overrides,
};
}
function sessionFixture(artifact) {
const sessionId = '019f0000-0000-4000-8000-000000000010';
const dataPath = '/mnt/ql3-evidence';
const deploymentRoot = path.join(
dataPath,
`.ql3-application-start-${sessionId}`,
);
const artifactRoot = '/opt/qinglong3-release';
const body = {
schemaVersion: 1,
evidenceClass: 'physical_edge_application_start_session',
sessionId,
manifestDigest: canonicalDigest(manifest(artifact)),
uid: 1000,
preparedAt: '2026-07-29T00:00:00.000Z',
artifact,
environment: boot('019f0000-0000-4000-8000-000000000001', 50_000),
paths: {
dataPath,
deploymentRoot,
artifactRoot,
applicationEntrypoint: path.join(
artifactRoot,
'node_modules',
'@qinglong',
'local-application',
'dist',
'cli.js',
),
applicationConfig: path.join(deploymentRoot, 'local-application.json'),
},
};
return { ...body, sha256: canonicalDigest(body) };
}
function reportFixture(artifact, overrides = {}) {
const session = normalizeSession(sessionFixture(artifact));
return buildApplicationStartReport({
manifest: manifest(artifact),
session,
observed: {
before: session.environment,
after: boot('019f0000-0000-4000-8000-000000000002'),
artifact,
},
measurements: {
firstActiveMs: 1200,
maximumSampledRssBytes: 80 * 1024 * 1024,
processReadBytes: 4096,
processWriteBytes: 8192,
sampleCount: 20,
eventCount: 5,
},
outcomes: {
activeEventCount: 1,
aiStatus: 'deployment_excluded',
gracefulStop: true,
exitCode: 0,
exitSignal: null,
stderrBytes: 0,
sqliteContractVersion: 41,
},
generatedAt: '2026-07-29T00:01:00.000Z',
...overrides,
});
}
test('normalizes exact Edge application start budgets', () => {
const artifact = {
artifactSha256: 'a'.repeat(64),
artifactMetadataSha256: 'd'.repeat(64),
artifactFiles: 100,
artifactBytes: 2 * 1024 * 1024,
};
assert.equal(manifest(artifact).maximumBootAgeMs, 180_000);
assert.throws(
() => manifest(artifact, { maximumBootAgeMs: 601_000 }),
/measurement budget/,
);
assert.throws(
() => manifest(artifact, { maximumSampledRssBytes: 1 }),
/measurement budget/,
);
});
test('requires phase-specific absolute paths', () => {
assert.deepEqual(
parseArguments([
'inspect',
'--artifact-root=/opt/qinglong3-release',
'--json',
]),
{
phase: 'inspect',
artifactRoot: '/opt/qinglong3-release',
json: true,
},
);
assert.equal(
parseArguments([
'prepare',
'--manifest=/mnt/data/manifest.json',
'--data-path=/mnt/data',
'--artifact-root=/opt/qinglong3-release',
'--session=/mnt/data/session.json',
]).phase,
'prepare',
);
assert.throws(
() =>
parseArguments([
'resume',
'--manifest=manifest.json',
'--session=/data/session.json',
'--output=/data/report.json',
]),
/manifestPath must be absolute/,
);
});
test('hashes one exact AI-excluded native release closure', (t) => {
const fixture = artifactFixture(t);
assert.deepEqual(fixture.identity.artifact.packages, packages);
assert.match(fixture.identity.artifact.artifactSha256, /^[a-f0-9]{64}$/);
assert.equal(
fixture.identity.applicationEntrypoint.endsWith('/dist/cli.js'),
true,
);
assert.deepEqual(
validateArtifactAgainstManifest(
manifest(fixture.identity.artifact),
fixture.identity.artifact,
{ nodeSha256: 'b'.repeat(64) },
),
[],
);
writePrivate(
path.join(fixture.root, 'node_modules', 'unexpected', 'package.json'),
'{}\n',
);
assert.throws(
() => collectArtifactIdentity(fixture.root),
/package closure is invalid/,
);
});
test('detects cross-boot artifact metadata drift without reading file content', (t) => {
const fixture = artifactFixture(t);
const entrypoint = fixture.identity.applicationEntrypoint;
const before = preflightArtifactMetadata(fixture.root, entrypoint);
assert.equal(
before.artifactMetadataSha256,
fixture.identity.artifact.artifactMetadataSha256,
);
fs.chmodSync(entrypoint, 0o400);
const after = preflightArtifactMetadata(fixture.root, entrypoint);
assert.notEqual(
after.artifactMetadataSha256,
fixture.identity.artifact.artifactMetadataSha256,
);
});
test('binds the pre-reboot session to deterministic deployment paths', () => {
const artifact = {
artifactSha256: 'a'.repeat(64),
artifactMetadataSha256: 'd'.repeat(64),
artifactFiles: 100,
artifactBytes: 2 * 1024 * 1024,
entrypointSha256: 'c'.repeat(64),
packages,
};
const session = normalizeSession(sessionFixture(artifact));
assert.equal(session.environment.bootAgeMs, 50_000);
const escaped = sessionFixture(artifact);
escaped.paths.deploymentRoot = '/opt/qinglong3';
const { sha256: ignored, ...body } = escaped;
assert.throws(
() => normalizeSession({ ...body, sha256: canonicalDigest(body) }),
/session is invalid or drifted/,
);
});
test('parses bounded production active events', () => {
const events = [];
const remaining = parseEventLines(
`${JSON.stringify({
schemaVersion: 1,
component: 'qinglong3-local-application',
level: 'info',
event: 'active',
instanceId: 'edge-a',
profile: 'edge',
aiStatus: 'deployment_excluded',
})}\npartial`,
events,
);
assert.equal(remaining, 'partial');
assert.equal(events[0].event, 'active');
assert.throws(
() => parseEventLines(`${'x'.repeat(4097)}\n`, []),
/event line exceeded/,
);
});
test('accepts only different-boot bounded native application activation', () => {
const artifact = {
artifactSha256: 'a'.repeat(64),
artifactMetadataSha256: 'd'.repeat(64),
artifactFiles: 100,
artifactBytes: 2 * 1024 * 1024,
entrypointSha256: 'c'.repeat(64),
packages,
};
const report = reportFixture(artifact);
assert.equal(report.supported, false);
assert.equal(report.qualification.passed, true);
assert.ok(
report.qualification.doesNotProve.includes(
'cold_node_runtime_or_dynamic_linker_cache',
),
);
assert.deepEqual(
validateApplicationStartReport(report, manifest(artifact), {
bootId: report.observed.after.bootId,
architecture: 'arm64',
dataFilesystem: 'ext4',
dataPath: '/mnt/ql3-evidence',
}),
[],
);
assert.deepEqual(
validateBootObservation(
manifest(artifact),
report.observed.after,
'/mnt/ql3-evidence',
),
[],
);
});
test('fails same boot, latency, sampled RSS and lifecycle drift', () => {
const artifact = {
artifactSha256: 'a'.repeat(64),
artifactMetadataSha256: 'd'.repeat(64),
artifactFiles: 100,
artifactBytes: 2 * 1024 * 1024,
entrypointSha256: 'c'.repeat(64),
packages,
};
const session = normalizeSession(sessionFixture(artifact));
const report = buildApplicationStartReport({
manifest: manifest(artifact),
session,
observed: {
before: session.environment,
after: session.environment,
artifact,
},
measurements: {
firstActiveMs: 31_000,
maximumSampledRssBytes: 300 * 1024 * 1024,
processReadBytes: 0,
processWriteBytes: 0,
sampleCount: 1,
eventCount: 1,
},
outcomes: {
activeEventCount: 0,
aiStatus: 'active',
gracefulStop: false,
exitCode: 1,
exitSignal: null,
stderrBytes: 1,
sqliteContractVersion: 34,
},
generatedAt: '2026-07-29T00:01:00.000Z',
});
assert.equal(report.qualification.passed, false);
assert.match(
report.qualification.violations.join('; '),
/reboot boundary.*measurement budget.*lifecycle outcome/,
);
});