const assert = require('node:assert/strict'); const fs = require('node:fs'); const os = require('node:os'); const path = require('node:path'); const { afterEach, test } = require('node:test'); const { runLocalServiceBridge, } = require('../dist/deployment/service-manager/serviceBridge.js'); const { prepareLocalServiceManagerIntent, consumeLocalServiceManagerOutcome, } = require('../dist/deployment/service-manager/serviceManagerIntent.js'); const roots = []; const destinations = [ '/etc/systemd/system/qinglong3.service', '/etc/init.d/qinglong3', ]; afterEach(() => { for (const root of roots.splice(0)) { fs.rmSync(root, { force: true, recursive: true }); } if (process.getuid?.() === 0) { for (const destination of destinations) { fs.rmSync(destination, { force: true }); fs.rmSync( path.join( path.dirname(destination), `.${path.basename(destination)}.ql3-service-bridge-stage`, ), { force: true }, ); } } }); function fixture(kind) { const root = fs.realpathSync( fs.mkdtempSync(path.join(os.tmpdir(), `ql3-service-bridge-${kind}-`)), ); roots.push(root); fs.chmodSync(root, 0o700); const service = path.join(root, 'service'); fs.mkdirSync(service, { mode: 0o700 }); fs.writeFileSync( path.join(root, 'local-application.json'), `${JSON.stringify({ schema: 'qinglong/local-application-process@v2', instanceId: `${kind}-edge-1`, profile: 'edge', storage: { mode: 'fresh' }, })}\n`, { mode: 0o600 }, ); fs.writeFileSync( path.join( service, kind === 'systemd' ? 'qinglong3.service' : 'qinglong3.openrc', ), kind === 'systemd' ? '[Service]\nExecStart=/usr/bin/node /opt/qinglong3/app.js\n' : '#!/sbin/openrc-run\ncommand=/usr/bin/node\n', { mode: kind === 'systemd' ? 0o600 : 0o700 }, ); const controllerRoot = path.join(root, 'root-controller'); return { root, controllerRoot }; } function prepare(root, kind, actionId, action) { return prepareLocalServiceManagerIntent({ schemaVersion: 1, operation: 'local.deployment.service-manager.intent.prepare', options: { deploymentRoot: root, allowRootService: true }, request: { actionId, action, serviceKind: kind, lineage: { mode: 'fresh' }, requestedAtMs: 1786416100000, }, }); } function bridgeCommand(prepared, controllerRoot, kind) { return { schemaVersion: 1, operation: 'local.deployment.service-manager.execute', options: { controllerRoot, allowRootController: true, manager: kind === 'systemd' ? { kind, executable: '/usr/bin/true' } : { kind, serviceExecutable: '/usr/bin/true', updateExecutable: '/usr/bin/true', }, }, request: { intentPath: prepared.intentPath, expectedIntentDigest: prepared.intentDigest, }, }; } function result(status, stdout = '', responseLost = false) { return { status, signal: null, stdout, stderr: '', responseLost }; } test( 'root systemd bridge installs, starts, survives response loss and replays without mutation', { skip: process.getuid?.() !== 0 }, () => { const { root, controllerRoot } = fixture('systemd'); const state = { active: false, enabled: false, pid: 0, loseRestart: false }; const calls = []; const runner = ({ args }) => { calls.push([...args]); if (args[0] === 'show') { return result( 0, [ 'LoadState=loaded', `ActiveState=${state.active ? 'active' : 'inactive'}`, `SubState=${state.active ? 'running' : 'dead'}`, 'FragmentPath=/etc/systemd/system/qinglong3.service', `MainPID=${state.pid}`, `UnitFileState=${state.enabled ? 'enabled' : 'disabled'}`, '', ].join('\n'), ); } if (args[0] === 'enable') state.enabled = true; if (args[0] === 'start') { state.active = true; state.pid = 4101; } if (args[0] === 'restart') { state.active = true; state.pid += 1; if (state.loseRestart) return result(null, '', true); } if (args[0] === 'stop') { state.active = false; state.pid = 0; } return result(0); }; let now = 1786416100100; const dependencies = { runManager: runner, now: () => now++ }; const first = prepare( root, 'systemd', '123e4567-e89b-42d3-a456-426614174021', 'install-enable-start', ); const firstResult = runLocalServiceBridge( bridgeCommand(first, controllerRoot, 'systemd'), dependencies, ); assert.equal(firstResult.state, 'active'); assert.equal(fs.statSync('/etc/systemd/system/qinglong3.service').uid, 0); assert.equal( fs.statSync('/etc/systemd/system/qinglong3.service').mode & 0o777, 0o644, ); const callCount = calls.length; assert.equal( runLocalServiceBridge( bridgeCommand(first, controllerRoot, 'systemd'), dependencies, ).status, 'existing', ); assert.equal(calls.length, callCount); state.loseRestart = true; const restart = prepare( root, 'systemd', '123e4567-e89b-42d3-a456-426614174022', 'restart', ); const restarted = runLocalServiceBridge( bridgeCommand(restart, controllerRoot, 'systemd'), dependencies, ); assert.equal(restarted.state, 'active'); const outcome = JSON.parse(fs.readFileSync(restart.outcomePath, 'utf8')); assert.equal(outcome.mutationDisposition, 'response-loss-inspected'); assert.equal(outcome.observation.mainPid, 4102); assert.equal( consumeLocalServiceManagerOutcome({ schemaVersion: 1, operation: 'local.deployment.service-manager.outcome.consume', options: { deploymentRoot: root, allowRootService: true }, request: { actionId: restart.actionId, expectedIntentDigest: restart.intentDigest, }, }).state, 'active', ); }, ); test( 'root bridge rejects Owner descriptor drift before publishing a barrier', { skip: process.getuid?.() !== 0 }, () => { const { root, controllerRoot } = fixture('systemd'); const prepared = prepare( root, 'systemd', '123e4567-e89b-42d3-a456-426614174041', 'install-enable-start', ); fs.writeFileSync( path.join(root, 'service', 'qinglong3.service'), '[Service]\nExecStart=/usr/bin/false\n', { mode: 0o600 }, ); assert.throws( () => runLocalServiceBridge( bridgeCommand(prepared, controllerRoot, 'systemd'), { runManager: () => result(0) }, ), /service manager source material drifted/, ); assert.equal(fs.existsSync(controllerRoot), false); }, ); test( 'barrier replay never repeats mutation after a crash and replaced installed unit', { skip: process.getuid?.() !== 0 }, () => { const { root, controllerRoot } = fixture('systemd'); const prepared = prepare( root, 'systemd', '123e4567-e89b-42d3-a456-426614174042', 'install-enable-start', ); let crash = true; const calls = []; const runner = ({ args }) => { calls.push([...args]); if (args[0] === 'show') { return result( 0, [ 'LoadState=loaded', 'ActiveState=inactive', 'SubState=dead', 'FragmentPath=/etc/systemd/system/qinglong3.service', 'MainPID=0', 'UnitFileState=disabled', '', ].join('\n'), ); } if (args[0] === 'enable' && crash) throw new Error('injected crash'); return result(0); }; assert.throws( () => runLocalServiceBridge( bridgeCommand(prepared, controllerRoot, 'systemd'), { runManager: runner, now: () => 1786416300000 }, ), /injected crash/, ); assert.equal( fs.existsSync( path.join(controllerRoot, prepared.actionId, 'barrier.json'), ), true, ); assert.equal( fs.existsSync( path.join(controllerRoot, prepared.actionId, 'outcome.json'), ), false, ); fs.writeFileSync( '/etc/systemd/system/qinglong3.service', '[Service]\nExecStart=/usr/bin/false\n', { mode: 0o644 }, ); crash = false; const mutationsBeforeReplay = calls.filter( (args) => args[0] !== 'show', ).length; const replay = runLocalServiceBridge( bridgeCommand(prepared, controllerRoot, 'systemd'), { runManager: runner, now: () => 1786416300100 }, ); assert.equal(replay.state, 'manual_required'); const outcome = JSON.parse(fs.readFileSync(prepared.outcomePath, 'utf8')); assert.equal(outcome.manualReason, 'descriptor_install_unproved'); assert.equal(outcome.mutationDisposition, 'replay-inspected'); assert.equal( calls.filter((args) => args[0] !== 'show').length, mutationsBeforeReplay, ); }, ); test( 'root outcome survives Owner outcome preoccupation without overwriting it', { skip: process.getuid?.() !== 0 }, () => { const { root, controllerRoot } = fixture('systemd'); const prepared = prepare( root, 'systemd', '123e4567-e89b-42d3-a456-426614174043', 'install-enable-start', ); fs.writeFileSync(prepared.outcomePath, '{}\n', { mode: 0o600 }); const state = { active: false, enabled: false, pid: 0 }; let mutations = 0; const runner = ({ args }) => { if (args[0] === 'show') { return result( 0, [ 'LoadState=loaded', `ActiveState=${state.active ? 'active' : 'inactive'}`, `SubState=${state.active ? 'running' : 'dead'}`, 'FragmentPath=/etc/systemd/system/qinglong3.service', `MainPID=${state.pid}`, `UnitFileState=${state.enabled ? 'enabled' : 'disabled'}`, '', ].join('\n'), ); } mutations += 1; if (args[0] === 'enable') state.enabled = true; if (args[0] === 'start') { state.active = true; state.pid = 6101; } return result(0); }; assert.throws( () => runLocalServiceBridge( bridgeCommand(prepared, controllerRoot, 'systemd'), { runManager: runner, now: () => 1786416400000 }, ), /service bridge Owner outcome drifted/, ); assert.equal(fs.readFileSync(prepared.outcomePath, 'utf8'), '{}\n'); assert.equal( fs.existsSync( path.join(controllerRoot, prepared.actionId, 'outcome.json'), ), true, ); const mutationsAfterFirst = mutations; assert.throws( () => runLocalServiceBridge( bridgeCommand(prepared, controllerRoot, 'systemd'), { runManager: runner, now: () => 1786416400100 }, ), /service bridge Owner outcome drifted/, ); assert.equal(mutations, mutationsAfterFirst); assert.equal(fs.readFileSync(prepared.outcomePath, 'utf8'), '{}\n'); }, ); test( 'root OpenRC bridge uses fixed update/service argv for install and stop', { skip: process.getuid?.() !== 0 }, () => { fs.mkdirSync('/etc/init.d', { mode: 0o755, recursive: true }); const { root, controllerRoot } = fixture('openrc'); const state = { active: false, enabled: false, loseStart: true }; const calls = []; const runner = ({ args }) => { calls.push([...args]); if (args[0] === 'show') { return result(0, state.enabled ? ' qinglong3 | default\n' : ''); } if (args[1] === 'status') { return state.active ? result(0, 'status: started\n') : result(3, 'status: stopped\n'); } if (args[0] === 'add') state.enabled = true; if (args[1] === 'start') { state.active = true; if (state.loseStart) return result(null, '', true); } if (args[1] === 'stop') state.active = false; return result(0); }; let now = 1786416200000; const dependencies = { runManager: runner, now: () => now++ }; const install = prepare( root, 'openrc', '123e4567-e89b-42d3-a456-426614174031', 'install-enable-start', ); const installed = runLocalServiceBridge( bridgeCommand(install, controllerRoot, 'openrc'), dependencies, ); assert.equal(installed.state, 'active'); const installedOutcome = JSON.parse( fs.readFileSync(install.outcomePath, 'utf8'), ); assert.equal( installedOutcome.mutationDisposition, 'response-loss-inspected', ); const callCount = calls.length; assert.equal( runLocalServiceBridge( bridgeCommand(install, controllerRoot, 'openrc'), dependencies, ).status, 'existing', ); assert.equal(calls.length, callCount); state.loseStart = false; const stop = prepare( root, 'openrc', '123e4567-e89b-42d3-a456-426614174032', 'stop', ); assert.equal( runLocalServiceBridge( bridgeCommand(stop, controllerRoot, 'openrc'), dependencies, ).state, 'stopped', ); assert.ok(calls.some((args) => args.join(' ') === 'add qinglong3 default')); assert.ok(calls.some((args) => args.join(' ') === 'qinglong3 start')); assert.ok(calls.some((args) => args.join(' ') === 'qinglong3 stop')); }, );