mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,369 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const crypto = require('node:crypto');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const { test } = require('node:test');
|
||||
|
||||
const {
|
||||
buildDirectServiceStopReport,
|
||||
normalizeStopSession,
|
||||
parseArguments,
|
||||
validateDirectServiceStopReport,
|
||||
} = require('../../scripts/ql3-physical-edge-direct-service-stop.cjs');
|
||||
const {
|
||||
normalizeDirectServiceStartManifest,
|
||||
} = require('../../scripts/ql3-physical-edge-direct-service-start.cjs');
|
||||
const {
|
||||
buildEvidenceReport,
|
||||
canonicalDigest,
|
||||
normalizeManifest,
|
||||
parseArguments: parseEvidenceArguments,
|
||||
validateDirectServiceStopEvidenceReport,
|
||||
} = require('../../scripts/ql3-physical-edge-evidence.cjs');
|
||||
|
||||
function manifest() {
|
||||
return normalizeDirectServiceStartManifest({
|
||||
schemaVersion: 1,
|
||||
evidenceClass: 'physical_edge_direct_service_start_candidate',
|
||||
profile: 'edge',
|
||||
deviceId: 'router-a1',
|
||||
serviceManager: 'systemd',
|
||||
expectedArchitecture: 'arm64',
|
||||
expectedFilesystem: 'ext4',
|
||||
expectedArtifactSha256: 'a'.repeat(64),
|
||||
expectedArtifactFiles: 640,
|
||||
expectedArtifactBytes: 6_000_000,
|
||||
expectedNodeSha256: 'b'.repeat(64),
|
||||
maximumBootToActiveMs: 180_000,
|
||||
maximumServiceStartBootAgeMs: 60_000,
|
||||
maximumServiceStartToActiveMs: 30_000,
|
||||
});
|
||||
}
|
||||
|
||||
function directSession() {
|
||||
return {
|
||||
uid: process.getuid?.() ?? 0,
|
||||
sha256: 'c'.repeat(64),
|
||||
paths: { deploymentRoot: '/mnt/ql3/direct' },
|
||||
};
|
||||
}
|
||||
|
||||
function stopSession() {
|
||||
const source = directSession();
|
||||
const sessionId = '123e4567-e89b-42d3-a456-426614174031';
|
||||
const body = {
|
||||
schemaVersion: 1,
|
||||
evidenceClass: 'physical_edge_direct_service_stop_session',
|
||||
sessionId,
|
||||
uid: source.uid,
|
||||
preparedAt: '2026-08-11T12:00:00.000Z',
|
||||
manifestDigest: canonicalDigest(manifest()),
|
||||
directSessionDigest: source.sha256,
|
||||
activeReportDigest: 'd'.repeat(64),
|
||||
activeBootId: '12345678-1234-4abc-8def-123456789abc',
|
||||
startupReceiptDigest: 'e'.repeat(64),
|
||||
processId: 101,
|
||||
processStartTicks: '1200',
|
||||
bridge: {
|
||||
actionId: sessionId,
|
||||
controllerRoot: '/var/lib/qinglong3-service-bridge',
|
||||
intentDigest: 'f'.repeat(64),
|
||||
intentPath: `/mnt/ql3/direct/service/service-manager-intents/${sessionId}.json`,
|
||||
outcomePath: `/mnt/ql3/direct/service/service-manager-outcomes/${sessionId}.json`,
|
||||
},
|
||||
};
|
||||
return normalizeStopSession(
|
||||
{ ...body, sha256: canonicalDigest(body) },
|
||||
source,
|
||||
);
|
||||
}
|
||||
|
||||
function shutdownReceipt() {
|
||||
const body = {
|
||||
schemaVersion: 1,
|
||||
schema: 'qinglong/local-application-shutdown-receipt@v1',
|
||||
instanceId: 'physical-direct-12345678',
|
||||
profile: 'edge',
|
||||
signal: 'SIGTERM',
|
||||
stopResult: 'stopped',
|
||||
startupReceiptDigest: 'e'.repeat(64),
|
||||
bootId: '12345678-1234-4abc-8def-123456789abc',
|
||||
stoppedBootAgeMs: 20_000,
|
||||
processId: 101,
|
||||
processStartTicks: '1200',
|
||||
nodeExecutable: '/usr/bin/node',
|
||||
nodeVersion: 'v24.18.0',
|
||||
};
|
||||
const sha256 = crypto
|
||||
.createHash('sha256')
|
||||
.update('qinglong.local-application-shutdown-receipt.v1\0', 'utf8')
|
||||
.update(JSON.stringify(body), 'utf8')
|
||||
.digest('hex');
|
||||
return { ...body, sha256 };
|
||||
}
|
||||
|
||||
function observed(overrides = {}) {
|
||||
const session = stopSession();
|
||||
return {
|
||||
currentBootId: session.activeBootId,
|
||||
bridge: {
|
||||
actionId: session.bridge.actionId,
|
||||
intentDigest: session.bridge.intentDigest,
|
||||
outcomeDigest: '1'.repeat(64),
|
||||
observationDigest: '2'.repeat(64),
|
||||
state: 'stopped',
|
||||
},
|
||||
shutdownReceipt: shutdownReceipt(),
|
||||
processIdentityGone: true,
|
||||
service: {
|
||||
active: false,
|
||||
enabled: true,
|
||||
fragmentPath: '/etc/systemd/system/qinglong3.service',
|
||||
mainPid: 0,
|
||||
},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function baseManifest() {
|
||||
return normalizeManifest({
|
||||
schemaVersion: 1,
|
||||
evidenceClass: 'physical_edge_candidate',
|
||||
profile: 'edge',
|
||||
deviceId: 'router-a1',
|
||||
deviceModel: 'router-a1-model',
|
||||
soc: 'arm-soc',
|
||||
storageMedium: 'emmc',
|
||||
expectedArchitecture: 'arm64',
|
||||
memoryBytes: { minimum: 128 * 1024 * 1024, maximum: 512 * 1024 * 1024 },
|
||||
expectedFilesystem: 'ext4',
|
||||
});
|
||||
}
|
||||
|
||||
function physicalObserved() {
|
||||
return {
|
||||
platform: 'linux',
|
||||
architecture: 'arm64',
|
||||
node: 'v24.18.0',
|
||||
bootId: stopSession().activeBootId,
|
||||
kernel: '6.6.0',
|
||||
distribution: { id: 'openwrt', versionId: '24.10' },
|
||||
libc: 'musl-ld-musl-aarch64.so.1',
|
||||
cpuModel: 'test-cpu',
|
||||
cpuCount: 1,
|
||||
totalMemoryBytes: 256 * 1024 * 1024,
|
||||
observedModel: 'router-a1-model',
|
||||
dataPath: '/mnt/ql3',
|
||||
dataFilesystem: 'ext4',
|
||||
dataMountOptions: ['rw', 'noatime'],
|
||||
dataBytes: 4 * 1024 * 1024 * 1024,
|
||||
dataAvailableBytes: 2 * 1024 * 1024 * 1024,
|
||||
virtualizationIndicators: [],
|
||||
};
|
||||
}
|
||||
|
||||
test('requires exact phase-specific stop evidence paths', () => {
|
||||
assert.equal(
|
||||
parseArguments([
|
||||
'prepare',
|
||||
'--manifest=/mnt/ql3/manifest.json',
|
||||
'--session=/mnt/ql3/session.json',
|
||||
'--active-report=/mnt/ql3/active.json',
|
||||
'--stop-session=/mnt/ql3/stop-session.json',
|
||||
'--root-command-output=/mnt/ql3/stop-root-command.json',
|
||||
]).phase,
|
||||
'prepare',
|
||||
);
|
||||
assert.equal(
|
||||
parseArguments([
|
||||
'prepare',
|
||||
'--manifest=/mnt/ql3/manifest.json',
|
||||
'--session=/mnt/ql3/session.json',
|
||||
'--active-report=/mnt/ql3/active.json',
|
||||
'--stop-session=/mnt/ql3/stop-session.json',
|
||||
'--root-command-output=/mnt/ql3/stop-root-command.json',
|
||||
]).rootCommandOutputPath,
|
||||
'/mnt/ql3/stop-root-command.json',
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
parseArguments([
|
||||
'resume',
|
||||
'--manifest=/mnt/ql3/manifest.json',
|
||||
'--session=/mnt/ql3/session.json',
|
||||
'--active-report=/mnt/ql3/active.json',
|
||||
'--stop-session=/mnt/ql3/stop-session.json',
|
||||
'--output=/mnt/ql3/stop.json',
|
||||
'--root-command-output=/mnt/ql3/stop-root-command.json',
|
||||
]),
|
||||
/valid only as a normalized prepare path/,
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
parseArguments([
|
||||
'resume',
|
||||
'--manifest=manifest.json',
|
||||
'--session=/mnt/ql3/session.json',
|
||||
'--active-report=/mnt/ql3/active.json',
|
||||
'--stop-session=/mnt/ql3/stop-session.json',
|
||||
'--output=/mnt/ql3/stop.json',
|
||||
]),
|
||||
/manifestPath must be absolute/,
|
||||
);
|
||||
});
|
||||
|
||||
test('binds one stop session to the active report and Owner intent', () => {
|
||||
const session = stopSession();
|
||||
assert.equal(session.bridge.actionId, session.sessionId);
|
||||
assert.equal(session.directSessionDigest, directSession().sha256);
|
||||
assert.throws(
|
||||
() =>
|
||||
normalizeStopSession(
|
||||
{ ...session, activeReportDigest: '0'.repeat(64) },
|
||||
directSession(),
|
||||
),
|
||||
/invalid or drifted/,
|
||||
);
|
||||
});
|
||||
|
||||
test('recomputes a graceful direct service stop report', () => {
|
||||
const report = buildDirectServiceStopReport({
|
||||
manifest: manifest(),
|
||||
stopSession: stopSession(),
|
||||
observed: observed(),
|
||||
generatedAt: '2026-08-11T12:01:00.000Z',
|
||||
});
|
||||
assert.equal(report.qualification.passed, true);
|
||||
assert.deepEqual(validateDirectServiceStopReport(report, manifest()), []);
|
||||
});
|
||||
|
||||
test('rejects a forged shutdown receipt and a still-live process', () => {
|
||||
const valid = shutdownReceipt();
|
||||
const report = buildDirectServiceStopReport({
|
||||
manifest: manifest(),
|
||||
stopSession: stopSession(),
|
||||
observed: observed({
|
||||
processIdentityGone: false,
|
||||
shutdownReceipt: {
|
||||
...valid,
|
||||
stoppedBootAgeMs: valid.stoppedBootAgeMs + 1,
|
||||
},
|
||||
}),
|
||||
generatedAt: '2026-08-11T12:01:00.000Z',
|
||||
});
|
||||
assert.equal(report.qualification.passed, false);
|
||||
assert.match(
|
||||
report.qualification.violations.join('; '),
|
||||
/shutdown receipt binding|stopped state/,
|
||||
);
|
||||
});
|
||||
|
||||
test('aggregates graceful stop only when bound to direct start evidence', () => {
|
||||
const stopReport = buildDirectServiceStopReport({
|
||||
manifest: manifest(),
|
||||
stopSession: stopSession(),
|
||||
observed: observed(),
|
||||
generatedAt: '2026-08-11T12:01:00.000Z',
|
||||
});
|
||||
const startEvidence = {
|
||||
evidenceClass: 'physical_edge_direct_service_start_candidate',
|
||||
sha256: stopReport.session.activeReportDigest,
|
||||
};
|
||||
const aggregate = buildEvidenceReport({
|
||||
manifest: baseManifest(),
|
||||
observed: physicalObserved(),
|
||||
workloads: [],
|
||||
supplementalEvidence: [startEvidence, stopReport],
|
||||
generatedAt: '2026-08-11T12:02:00.000Z',
|
||||
});
|
||||
assert.ok(
|
||||
aggregate.qualification.collectedEvidence.includes(
|
||||
'init_managed_graceful_application_stop',
|
||||
),
|
||||
);
|
||||
assert.equal(
|
||||
aggregate.qualification.remainingRequiredEvidence.includes(
|
||||
'init_managed_graceful_application_stop',
|
||||
),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
parseEvidenceArguments([
|
||||
'--manifest=/mnt/ql3/manifest.json',
|
||||
'--data-path=/mnt/ql3',
|
||||
'--direct-service-start-evidence=/mnt/ql3/start.json',
|
||||
'--direct-service-stop-evidence=/mnt/ql3/stop.json',
|
||||
]).directServiceStopEvidencePath,
|
||||
'/mnt/ql3/stop.json',
|
||||
);
|
||||
const active = {
|
||||
...startEvidence,
|
||||
session: { sessionDigest: stopReport.session.directSessionDigest },
|
||||
observed: {
|
||||
after: { bootId: stopReport.session.activeBootId },
|
||||
receipt: {
|
||||
sha256: stopReport.session.startupReceiptDigest,
|
||||
processId: stopReport.session.processId,
|
||||
processStartTicks: stopReport.session.processStartTicks,
|
||||
instanceId: stopReport.observed.shutdownReceipt.instanceId,
|
||||
nodeExecutable: stopReport.observed.shutdownReceipt.nodeExecutable,
|
||||
},
|
||||
},
|
||||
};
|
||||
assert.deepEqual(
|
||||
validateDirectServiceStopEvidenceReport(
|
||||
stopReport,
|
||||
baseManifest(),
|
||||
physicalObserved(),
|
||||
active,
|
||||
),
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
test('documents the exact direct start and graceful stop bridge sequence', () => {
|
||||
const runbook = fs.readFileSync(
|
||||
path.join(__dirname, '../../docs/operations/ql3-local-deployment.md'),
|
||||
'utf8',
|
||||
);
|
||||
const startPrepare = runbook.indexOf(
|
||||
'evidence:physical-edge-direct-service-start -- prepare',
|
||||
);
|
||||
const startBridge = runbook.indexOf(
|
||||
'ql3-service-bridge run --command-file',
|
||||
startPrepare,
|
||||
);
|
||||
const startResume = runbook.indexOf(
|
||||
'evidence:physical-edge-direct-service-start -- resume',
|
||||
startBridge,
|
||||
);
|
||||
const stopPrepare = runbook.indexOf(
|
||||
'evidence:physical-edge-direct-service-stop -- prepare',
|
||||
startResume,
|
||||
);
|
||||
const stopBridge = runbook.indexOf(
|
||||
'ql3-service-bridge run --command-file',
|
||||
stopPrepare,
|
||||
);
|
||||
const stopResume = runbook.indexOf(
|
||||
'evidence:physical-edge-direct-service-stop -- resume',
|
||||
stopBridge,
|
||||
);
|
||||
assert.ok(
|
||||
startPrepare >= 0 &&
|
||||
startPrepare < startBridge &&
|
||||
startBridge < startResume &&
|
||||
startResume < stopPrepare &&
|
||||
stopPrepare < stopBridge &&
|
||||
stopBridge < stopResume,
|
||||
);
|
||||
for (const fragment of [
|
||||
'--root-command-output=/opt/qinglong/evidence-scratch/direct-service-start-root-command.json',
|
||||
'--active-report=/opt/qinglong/evidence-scratch/direct-service-start-report.json',
|
||||
'--stop-session=/opt/qinglong/evidence-scratch/direct-service-stop-session.json',
|
||||
'--root-command-output=/opt/qinglong/evidence-scratch/direct-service-stop-root-command.json',
|
||||
'--direct-service-stop-evidence=/opt/qinglong/evidence-scratch/direct-service-stop-report.json',
|
||||
]) {
|
||||
assert.ok(runbook.includes(fragment), fragment);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user