@dharma-ai-labs/agent-fabric 0.2.210 → 0.2.212
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codexSetupSessionHandoff.test.js +46 -5
- package/dist/codexSetupSessionHandoff.test.js.map +1 -1
- package/dist/containerRelayLifecycle.d.ts +16 -0
- package/dist/containerRelayLifecycle.d.ts.map +1 -1
- package/dist/containerRelayLifecycle.js +55 -5
- package/dist/containerRelayLifecycle.js.map +1 -1
- package/dist/containerRelayLifecycle.test.js +38 -6
- package/dist/containerRelayLifecycle.test.js.map +1 -1
- package/dist/containerRelayPublicCommand.test.js +17 -0
- package/dist/containerRelayPublicCommand.test.js.map +1 -1
- package/dist/containerRelayRuntimeTrust.test.js +10 -0
- package/dist/containerRelayRuntimeTrust.test.js.map +1 -1
- package/dist/containerRelaySchema.test.js +13 -0
- package/dist/containerRelaySchema.test.js.map +1 -1
- package/dist/containerStartupInspection.test.d.ts +2 -0
- package/dist/containerStartupInspection.test.d.ts.map +1 -0
- package/dist/containerStartupInspection.test.js +175 -0
- package/dist/containerStartupInspection.test.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +124 -9
- package/dist/index.js.map +1 -1
- package/dist/maintenanceControlCaller.test.d.ts +2 -0
- package/dist/maintenanceControlCaller.test.d.ts.map +1 -0
- package/dist/maintenanceControlCaller.test.js +119 -0
- package/dist/maintenanceControlCaller.test.js.map +1 -0
- package/dist/namedSessionStoppedLock.d.ts +34 -0
- package/dist/namedSessionStoppedLock.d.ts.map +1 -0
- package/dist/namedSessionStoppedLock.js +108 -0
- package/dist/namedSessionStoppedLock.js.map +1 -0
- package/dist/namedSessionStoppedLock.test.d.ts +2 -0
- package/dist/namedSessionStoppedLock.test.d.ts.map +1 -0
- package/dist/namedSessionStoppedLock.test.js +104 -0
- package/dist/namedSessionStoppedLock.test.js.map +1 -0
- package/dist/relayAutostart.d.ts +3 -0
- package/dist/relayAutostart.d.ts.map +1 -1
- package/dist/relayAutostart.js +45 -6
- package/dist/relayAutostart.js.map +1 -1
- package/dist/relayAutostart.test.js +49 -1
- package/dist/relayAutostart.test.js.map +1 -1
- package/dist/relayRuntimeUpgrade.d.ts +1 -0
- package/dist/relayRuntimeUpgrade.d.ts.map +1 -1
- package/dist/relayRuntimeUpgrade.js +3 -3
- package/dist/relayRuntimeUpgrade.js.map +1 -1
- package/dist/relayRuntimeUpgradeCaller.test.js +76 -0
- package/dist/relayRuntimeUpgradeCaller.test.js.map +1 -1
- package/dist/relaySigningMaintenanceUpgrade.d.ts +44 -0
- package/dist/relaySigningMaintenanceUpgrade.d.ts.map +1 -0
- package/dist/relaySigningMaintenanceUpgrade.js +249 -0
- package/dist/relaySigningMaintenanceUpgrade.js.map +1 -0
- package/dist/relaySigningMaintenanceUpgrade.test.d.ts +2 -0
- package/dist/relaySigningMaintenanceUpgrade.test.d.ts.map +1 -0
- package/dist/relaySigningMaintenanceUpgrade.test.js +230 -0
- package/dist/relaySigningMaintenanceUpgrade.test.js.map +1 -0
- package/dist/schemas/container-startup-inspection.v1.schema.json +27 -0
- package/dist/schemas/local-signing-maintenance-upgrade-journal.schema.json +34 -0
- package/dist/schemas/local-signing-maintenance-upgrade.schema.json +33 -0
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +3 -2
- package/dist/usage.js.map +1 -1
- package/dist/wslRelayHost.d.ts +2 -0
- package/dist/wslRelayHost.d.ts.map +1 -1
- package/dist/wslRelayHost.js +35 -0
- package/dist/wslRelayHost.js.map +1 -1
- package/dist/wslRelayHost.test.js +81 -4
- package/dist/wslRelayHost.test.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maintenanceControlCaller.test.d.ts","sourceRoot":"","sources":["../src/maintenanceControlCaller.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { runInNewContext } from 'node:vm';
|
|
6
|
+
import test from 'node:test';
|
|
7
|
+
import ts from 'typescript';
|
|
8
|
+
async function source() { return ts.createSourceFile('index.ts', await readFile(fileURLToPath(new URL('../src/index.ts', import.meta.url)), 'utf8'), ts.ScriptTarget.Latest, true); }
|
|
9
|
+
function compile(text) {
|
|
10
|
+
return ts.transpileModule(text.replaceAll('import.meta.url', JSON.stringify(import.meta.url)), { compilerOptions: { target: ts.ScriptTarget.ES2023, module: ts.ModuleKind.None } }).outputText;
|
|
11
|
+
}
|
|
12
|
+
async function namedFixture() {
|
|
13
|
+
const ast = await source(), node = ast.statements.find(n => ts.isFunctionDeclaration(n) && n.name?.text === 'namedSessionCommand');
|
|
14
|
+
assert(node);
|
|
15
|
+
const events = [], workspaceId = '33333333-3333-4333-8333-333333333333';
|
|
16
|
+
const registration = { name: 'codex-fixture', enabled: false, bindingId: 'binding', identity: { workspaceId, organizationId: 'org_fixture', deviceId: 'device',
|
|
17
|
+
endpointId: 'endpoint', repositoryBindingId: 'repository' } };
|
|
18
|
+
class TransportFailure extends Error {
|
|
19
|
+
diagnostic = { phase: 'connect', osCode: 'ENOENT' };
|
|
20
|
+
}
|
|
21
|
+
const globals = {
|
|
22
|
+
namedSessionReadinessDiagnosticRequested: () => false, currentBootstrapHostScope: () => undefined, currentAcceptedSetupSessionScope: () => undefined,
|
|
23
|
+
currentNamedSessionChildOwner: () => undefined, process: { platform: 'linux', kill: () => { throw Object.assign(Error('absent'), { code: 'ESRCH' }); } },
|
|
24
|
+
namedSessionPaths: () => ({ root: '/owned/sessions/codex-fixture' }), dharmaHome: () => '/owned',
|
|
25
|
+
required: (flags, key) => { if (!flags.has(key))
|
|
26
|
+
throw Error('required'); return String(flags.get(key)); },
|
|
27
|
+
acquireNamedSessionStartupAdmission: async () => { events.push('admitted'); return async () => { events.push('released'); }; },
|
|
28
|
+
registry: async () => [{ workspaceId, organizationId: 'org_fixture', path: '/checkout' }], readDeviceConfig: async () => ({ organizationId: 'org_fixture', deviceId: 'device' }),
|
|
29
|
+
assertBootstrapHostSource: async () => { }, repositoryRoleScope: () => ({ endpointId: 'endpoint', repositoryBindingId: 'repository' }),
|
|
30
|
+
readNamedSession: async () => registration, assertRelayAutostartPaused: async () => { events.push('paused-proof'); },
|
|
31
|
+
relayProcessState: async () => 'stopped', relaySupervisorProcessState: async () => 'stopped',
|
|
32
|
+
NamedSessionTransportFailure: TransportFailure, namedSessionRequest: async () => { throw new TransportFailure(); },
|
|
33
|
+
reconcileStoppedNamedSessionLock: async () => ({ ok: true }), resolve,
|
|
34
|
+
};
|
|
35
|
+
const run = runInNewContext(compile(node.getText(ast)) + '\nnamedSessionCommand', globals);
|
|
36
|
+
const flags = new Map([['name', registration.name], ['workspace-id', workspaceId], ['registration-sha256', 'a'.repeat(64)], ['lock-sha256', 'b'.repeat(64)], ['apply', true]]);
|
|
37
|
+
return { run, flags, events, globals };
|
|
38
|
+
}
|
|
39
|
+
test('actual stopped-lock caller holds home-wide startup admission until reconciliation settles', { timeout: 5000 }, async () => {
|
|
40
|
+
const f = await namedFixture();
|
|
41
|
+
let complete;
|
|
42
|
+
f.globals.reconcileStoppedNamedSessionLock = async (_input, deps) => {
|
|
43
|
+
await deps.assertTopology();
|
|
44
|
+
assert.equal(await deps.processState(987654), 'stopped');
|
|
45
|
+
await new Promise(r => { complete = r; });
|
|
46
|
+
return { ok: true };
|
|
47
|
+
};
|
|
48
|
+
const result = f.run('reconcile-stopped-lock', f.flags);
|
|
49
|
+
let failure;
|
|
50
|
+
void result.catch(error => { failure = error; });
|
|
51
|
+
for (let n = 0; n < 1000 && !complete && !failure; n++)
|
|
52
|
+
await new Promise(r => setTimeout(r, 1));
|
|
53
|
+
if (failure)
|
|
54
|
+
throw failure;
|
|
55
|
+
assert(complete, 'bounded fixture admission did not settle');
|
|
56
|
+
assert.deepEqual(f.events, ['admitted', 'paused-proof']);
|
|
57
|
+
complete();
|
|
58
|
+
await result;
|
|
59
|
+
assert.deepEqual(f.events, ['admitted', 'paused-proof', 'released']);
|
|
60
|
+
});
|
|
61
|
+
test('actual stopped-lock caller refuses setup/peer contexts and malformed mutation options before admission', async () => {
|
|
62
|
+
for (const kind of ['host', 'peer', 'accepted', 'false-apply', 'unknown', 'conflict']) {
|
|
63
|
+
const f = await namedFixture();
|
|
64
|
+
if (kind === 'host')
|
|
65
|
+
f.globals.currentBootstrapHostScope = () => ({});
|
|
66
|
+
if (kind === 'peer')
|
|
67
|
+
f.globals.currentNamedSessionChildOwner = () => ({});
|
|
68
|
+
if (kind === 'accepted')
|
|
69
|
+
f.globals.currentAcceptedSetupSessionScope = () => ({});
|
|
70
|
+
if (kind === 'false-apply')
|
|
71
|
+
f.flags.set('apply', 'false');
|
|
72
|
+
if (kind === 'unknown')
|
|
73
|
+
f.flags.set('force', true);
|
|
74
|
+
if (kind === 'conflict')
|
|
75
|
+
f.flags.set('dry-run', true);
|
|
76
|
+
await assert.rejects(f.run('reconcile-stopped-lock', f.flags), /named_session_stopped_lock_options_invalid/);
|
|
77
|
+
assert.deepEqual(f.events, []);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
test('actual stopped-lock caller rejects a listening owner and unknown or denied socket failures', async () => {
|
|
81
|
+
for (const kind of ['live', 'denied', 'unknown']) {
|
|
82
|
+
const f = await namedFixture();
|
|
83
|
+
f.globals.namedSessionRequest = kind === 'live' ? async () => ({ ok: true }) : async () => { throw Object.assign(Error('unconfirmed'), { code: kind === 'denied' ? 'EACCES' : 'ECONNRESET' }); };
|
|
84
|
+
f.globals.reconcileStoppedNamedSessionLock = async (_input, deps) => { await deps.assertTopology(); throw Error('must not mutate'); };
|
|
85
|
+
await assert.rejects(f.run('reconcile-stopped-lock', f.flags), /named_session_stopped_lock_unconfirmed/);
|
|
86
|
+
assert.deepEqual(f.events, ['admitted', 'paused-proof', 'released']);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
test('actual autostart pause is plan-first, container-only and preserves the owning mutation admission', async () => {
|
|
90
|
+
const ast = await source(), nodes = [];
|
|
91
|
+
const visit = (n) => { if (ts.isIfStatement(n) && n.expression.getText(ast) === "command === 'relay' && subcommand === 'autostart'")
|
|
92
|
+
nodes.push(n); ts.forEachChild(n, visit); };
|
|
93
|
+
visit(ast);
|
|
94
|
+
assert.equal(nodes.length, 1);
|
|
95
|
+
for (const mode of ['plan', 'apply', 'foreign', 'false-apply']) {
|
|
96
|
+
const events = [], flags = new Map();
|
|
97
|
+
if (mode !== 'plan')
|
|
98
|
+
flags.set('apply', mode === 'false-apply' ? 'false' : true);
|
|
99
|
+
const globals = { command: 'relay', subcommand: 'autostart', positional: ['relay', 'autostart', 'pause'], flags, dharmaHome: () => '/owned',
|
|
100
|
+
withRelayStartupMutation: async (f) => { events.push('lock'); try {
|
|
101
|
+
return await f();
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
events.push('unlock');
|
|
105
|
+
} },
|
|
106
|
+
inspectOwnedRelayAutostart: async () => ({ backend: mode === 'foreign' ? 'systemd-user' : 'container-entrypoint' }),
|
|
107
|
+
stopRelayAutostart: async () => { events.push('pause'); }, assertRelayAutostartPaused: async () => { events.push('proof'); } };
|
|
108
|
+
const run = runInNewContext(compile('async function run(){' + nodes[0].getText(ast) + '}') + '\nrun', globals);
|
|
109
|
+
if (mode === 'foreign' || mode === 'false-apply') {
|
|
110
|
+
await assert.rejects(run());
|
|
111
|
+
assert(!events.includes('pause'));
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
await run();
|
|
115
|
+
assert.deepEqual(events, mode === 'plan' ? ['lock', 'unlock'] : ['lock', 'pause', 'proof', 'unlock']);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=maintenanceControlCaller.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maintenanceControlCaller.test.js","sourceRoot":"","sources":["../src/maintenanceControlCaller.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { NamedSessionRegistration } from './namedSessionService.js';
|
|
2
|
+
interface Input {
|
|
3
|
+
home: string;
|
|
4
|
+
name: string;
|
|
5
|
+
registration: NamedSessionRegistration;
|
|
6
|
+
registrationSha256: string;
|
|
7
|
+
lockSha256: string;
|
|
8
|
+
apply: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface Dependencies {
|
|
11
|
+
assertTopology(): Promise<void>;
|
|
12
|
+
processState(pid: number): Promise<'stopped' | 'running' | 'unknown'>;
|
|
13
|
+
}
|
|
14
|
+
/** Called only under the owning CLI's home-wide startup mutation admission. */
|
|
15
|
+
export declare function reconcileStoppedNamedSessionLock(input: Input, deps: Dependencies): Promise<{
|
|
16
|
+
state: string;
|
|
17
|
+
ok: boolean;
|
|
18
|
+
planned: boolean;
|
|
19
|
+
name: string;
|
|
20
|
+
workspaceId: string;
|
|
21
|
+
bindingId: string;
|
|
22
|
+
registrationSha256: string;
|
|
23
|
+
lockSha256: string;
|
|
24
|
+
archive: string;
|
|
25
|
+
previousPid: number;
|
|
26
|
+
registrationChanged: boolean;
|
|
27
|
+
budgetChanged: boolean;
|
|
28
|
+
providerStarted: boolean;
|
|
29
|
+
protectedStoreRead: boolean;
|
|
30
|
+
ready: boolean;
|
|
31
|
+
nativeContinuationAuthorized: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=namedSessionStoppedLock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namedSessionStoppedLock.d.ts","sourceRoot":"","sources":["../src/namedSessionStoppedLock.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,0BAA0B,CAAC;AAIvE,UAAU,KAAK;IACb,IAAI,EAAC,MAAM,CAAC;IAAC,IAAI,EAAC,MAAM,CAAC;IAAC,YAAY,EAAC,wBAAwB,CAAC;IAChE,kBAAkB,EAAC,MAAM,CAAC;IAAC,UAAU,EAAC,MAAM,CAAC;IAAC,KAAK,EAAC,OAAO,CAAC;CAC7D;AACD,UAAU,YAAY;IACpB,cAAc,IAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,YAAY,CAAC,GAAG,EAAC,MAAM,GAAE,OAAO,CAAC,SAAS,GAAC,SAAS,GAAC,SAAS,CAAC,CAAC;CACjE;AAYD,+EAA+E;AAC/E,wBAAsB,gCAAgC,CAAC,KAAK,EAAC,KAAK,EAAC,IAAI,EAAC,YAAY;;;;;;;;;;;;;;;;;GA+CnF"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { constants } from 'node:fs';
|
|
3
|
+
import { link, lstat, open, realpath, unlink } from 'node:fs/promises';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
const digest = (bytes) => createHash('sha256').update(bytes).digest('hex');
|
|
6
|
+
const unavailable = () => new Error('named_session_stopped_lock_unconfirmed');
|
|
7
|
+
async function privateFile(path, uid, limit) {
|
|
8
|
+
const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
9
|
+
try {
|
|
10
|
+
const stat = await file.stat({ bigint: true });
|
|
11
|
+
if (!stat.isFile() || Number(stat.uid) !== uid || (Number(stat.mode) & 0o077) !== 0 || stat.size > BigInt(limit))
|
|
12
|
+
throw unavailable();
|
|
13
|
+
const bytes = await file.readFile();
|
|
14
|
+
if (bytes.length > limit)
|
|
15
|
+
throw unavailable();
|
|
16
|
+
return { bytes, dev: stat.dev, ino: stat.ino };
|
|
17
|
+
}
|
|
18
|
+
finally {
|
|
19
|
+
await file.close();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Called only under the owning CLI's home-wide startup mutation admission. */
|
|
23
|
+
export async function reconcileStoppedNamedSessionLock(input, deps) {
|
|
24
|
+
const uid = process.getuid?.() ?? -1;
|
|
25
|
+
if (process.platform !== 'linux' || uid <= 0 || resolve(input.home) !== input.home
|
|
26
|
+
|| !/^[a-z][a-z0-9-]{0,47}$/.test(input.name) || input.registration.name !== input.name
|
|
27
|
+
|| input.registration.enabled || input.registration.maintenanceFence
|
|
28
|
+
|| ![input.registrationSha256, input.lockSha256].every(v => /^[a-f0-9]{64}$/.test(v)))
|
|
29
|
+
throw unavailable();
|
|
30
|
+
const root = join(input.home, 'sessions', input.name), registrationPath = join(root, 'registration.json'), lockPath = join(root, 'service.lock');
|
|
31
|
+
for (const path of [input.home, join(input.home, 'sessions'), root]) {
|
|
32
|
+
const stat = await lstat(path);
|
|
33
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== uid || (stat.mode & 0o077) !== 0 || await realpath(path) !== path)
|
|
34
|
+
throw unavailable();
|
|
35
|
+
}
|
|
36
|
+
const verify = async () => {
|
|
37
|
+
await deps.assertTopology();
|
|
38
|
+
const registration = await privateFile(registrationPath, uid, 4096);
|
|
39
|
+
if (digest(registration.bytes) !== input.registrationSha256
|
|
40
|
+
|| JSON.stringify(JSON.parse(registration.bytes.toString('utf8'))) !== JSON.stringify(input.registration))
|
|
41
|
+
throw unavailable();
|
|
42
|
+
const lock = await privateFile(lockPath, uid, 64), text = lock.bytes.toString('utf8');
|
|
43
|
+
if (digest(lock.bytes) !== input.lockSha256 || !/^([1-9][0-9]*)\n?$/.test(text))
|
|
44
|
+
throw unavailable();
|
|
45
|
+
const pid = Number(text.trim());
|
|
46
|
+
if (!Number.isSafeInteger(pid) || pid <= 1 || await deps.processState(pid) !== 'stopped')
|
|
47
|
+
throw unavailable();
|
|
48
|
+
return { ...lock, pid };
|
|
49
|
+
};
|
|
50
|
+
const before = await verify(), archiveName = 'service.lock.stopped.' + input.lockSha256;
|
|
51
|
+
const receipt = { ok: true, planned: !input.apply, name: input.name, workspaceId: input.registration.identity.workspaceId,
|
|
52
|
+
bindingId: input.registration.bindingId, registrationSha256: input.registrationSha256, lockSha256: input.lockSha256,
|
|
53
|
+
archive: archiveName, previousPid: before.pid, registrationChanged: false, budgetChanged: false, providerStarted: false, protectedStoreRead: false,
|
|
54
|
+
ready: false, nativeContinuationAuthorized: false };
|
|
55
|
+
if (!input.apply)
|
|
56
|
+
return { ...receipt, state: 'stopped_lock_reconciliation_planned' };
|
|
57
|
+
const current = await verify();
|
|
58
|
+
if (current.dev !== before.dev || current.ino !== before.ino)
|
|
59
|
+
throw unavailable();
|
|
60
|
+
const archive = join(root, archiveName);
|
|
61
|
+
try {
|
|
62
|
+
await link(lockPath, archive);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error.code !== 'EEXIST')
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
const retained = await privateFile(archive, uid, 64);
|
|
69
|
+
if (retained.dev !== before.dev || retained.ino !== before.ino || digest(retained.bytes) !== input.lockSha256)
|
|
70
|
+
throw unavailable();
|
|
71
|
+
const archiveFile = await open(archive, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
72
|
+
try {
|
|
73
|
+
await archiveFile.sync();
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
await archiveFile.close();
|
|
77
|
+
}
|
|
78
|
+
const directory = await open(root, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
79
|
+
try {
|
|
80
|
+
await directory.sync();
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
await directory.close();
|
|
84
|
+
}
|
|
85
|
+
const final = await verify();
|
|
86
|
+
if (final.dev !== before.dev || final.ino !== before.ino)
|
|
87
|
+
throw unavailable();
|
|
88
|
+
await unlink(lockPath);
|
|
89
|
+
const completedDirectory = await open(root, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
90
|
+
try {
|
|
91
|
+
await completedDirectory.sync();
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
await completedDirectory.close();
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
await lstat(lockPath);
|
|
98
|
+
throw unavailable();
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
if (error.code !== 'ENOENT')
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
if (digest((await privateFile(registrationPath, uid, 4096)).bytes) !== input.registrationSha256)
|
|
105
|
+
throw unavailable();
|
|
106
|
+
return { ...receipt, state: 'stopped_lock_reconciled', planned: false };
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=namedSessionStoppedLock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namedSessionStoppedLock.js","sourceRoot":"","sources":["../src/namedSessionStoppedLock.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namedSessionStoppedLock.test.d.ts","sourceRoot":"","sources":["../src/namedSessionStoppedLock.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { chmod, lstat, mkdir, mkdtemp, readFile, realpath, rename, symlink, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import test from 'node:test';
|
|
7
|
+
import { reconcileStoppedNamedSessionLock } from './namedSessionStoppedLock.js';
|
|
8
|
+
const linux = { skip: process.platform !== 'linux' }, sha = (v) => createHash('sha256').update(v).digest('hex');
|
|
9
|
+
async function fixture() {
|
|
10
|
+
const home = await realpath(await mkdtemp(join(tmpdir(), 'dharma-stopped-lock-')));
|
|
11
|
+
await chmod(home, 0o700);
|
|
12
|
+
const name = 'codex-fixture', root = join(home, 'sessions', name);
|
|
13
|
+
await mkdir(root, { recursive: true, mode: 0o700 });
|
|
14
|
+
await chmod(join(home, 'sessions'), 0o700);
|
|
15
|
+
const registration = { schema: 'dharma.named-session/v1', name, bindingId: '11111111-1111-4111-8111-111111111111', enabled: false,
|
|
16
|
+
maximumCostCents: 1000, maximumTurnCostCents: 25, identity: { organizationId: 'org_fixture', provider: 'codex',
|
|
17
|
+
repositoryBindingId: '22222222-2222-4222-8222-222222222222', workspaceId: '33333333-3333-4333-8333-333333333333',
|
|
18
|
+
endpointId: '44444444-4444-4444-8444-444444444444', membershipId: '55555555-5555-4555-8555-555555555555', deviceId: '66666666-6666-4666-8666-666666666666' } };
|
|
19
|
+
await writeFile(join(root, 'registration.json'), JSON.stringify(registration) + '\n', { mode: 0o600 });
|
|
20
|
+
const lock = join(root, 'service.lock');
|
|
21
|
+
await writeFile(lock, '987654\n', { mode: 0o600 });
|
|
22
|
+
const input = { home, name, registration, registrationSha256: sha(await readFile(join(root, 'registration.json'))), lockSha256: sha(await readFile(lock)), apply: false };
|
|
23
|
+
const deps = { assertTopology: async () => { }, processState: async () => 'stopped' };
|
|
24
|
+
return { home, root, lock, input, deps };
|
|
25
|
+
}
|
|
26
|
+
test('stopped-lock plan is inert and apply retains the exact original lock inode and registration', linux, async () => {
|
|
27
|
+
const f = await fixture(), before = await lstat(f.lock);
|
|
28
|
+
const plan = await reconcileStoppedNamedSessionLock(f.input, f.deps);
|
|
29
|
+
assert.equal(plan.state, 'stopped_lock_reconciliation_planned');
|
|
30
|
+
assert.equal((await lstat(f.lock)).ino, before.ino);
|
|
31
|
+
await assert.rejects(lstat(join(f.root, plan.archive)), { code: 'ENOENT' });
|
|
32
|
+
const result = await reconcileStoppedNamedSessionLock({ ...f.input, apply: true }, f.deps);
|
|
33
|
+
assert.equal(result.state, 'stopped_lock_reconciled');
|
|
34
|
+
assert.equal((await lstat(join(f.root, result.archive))).ino, before.ino);
|
|
35
|
+
assert.equal(result.registrationChanged, false);
|
|
36
|
+
assert.equal(result.budgetChanged, false);
|
|
37
|
+
assert.equal(result.protectedStoreRead, false);
|
|
38
|
+
await assert.rejects(lstat(f.lock), { code: 'ENOENT' });
|
|
39
|
+
});
|
|
40
|
+
for (const cause of ['enabled', 'wrong-registration', 'wrong-lock', 'running', 'unknown', 'unsafe-parent', 'foreign-topology', 'symlink', 'malformed']) {
|
|
41
|
+
test('stopped-lock reconciliation refuses ' + cause + ' without removing the lock', linux, async () => {
|
|
42
|
+
const f = await fixture();
|
|
43
|
+
if (cause === 'enabled')
|
|
44
|
+
f.input.registration.enabled = true;
|
|
45
|
+
if (cause === 'wrong-registration')
|
|
46
|
+
f.input.registrationSha256 = '0'.repeat(64);
|
|
47
|
+
if (cause === 'wrong-lock')
|
|
48
|
+
f.input.lockSha256 = '0'.repeat(64);
|
|
49
|
+
if (cause === 'running' || cause === 'unknown')
|
|
50
|
+
f.deps.processState = async () => cause;
|
|
51
|
+
if (cause === 'unsafe-parent')
|
|
52
|
+
await chmod(f.root, 0o755);
|
|
53
|
+
if (cause === 'foreign-topology')
|
|
54
|
+
f.deps.assertTopology = async () => { throw Error('foreign controller'); };
|
|
55
|
+
if (cause === 'symlink') {
|
|
56
|
+
await writeFile(join(f.root, 'foreign'), '987654\n', { mode: 0o600 });
|
|
57
|
+
f.input.name = 'linked';
|
|
58
|
+
f.input.registration = { ...f.input.registration, name: 'linked' };
|
|
59
|
+
await symlink(f.root, join(f.home, 'sessions', 'linked'));
|
|
60
|
+
}
|
|
61
|
+
if (cause === 'malformed') {
|
|
62
|
+
await writeFile(f.lock, 'not-a-pid\n');
|
|
63
|
+
f.input.lockSha256 = sha(await readFile(f.lock));
|
|
64
|
+
}
|
|
65
|
+
await assert.rejects(reconcileStoppedNamedSessionLock({ ...f.input, apply: true }, f.deps));
|
|
66
|
+
assert.equal((await lstat(f.lock)).isFile(), true);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
test('a topology change after archive creation leaves the active lock intact', linux, async () => {
|
|
70
|
+
const f = await fixture();
|
|
71
|
+
let checks = 0;
|
|
72
|
+
f.deps.assertTopology = async () => { if (++checks === 3)
|
|
73
|
+
throw Error('topology changed'); };
|
|
74
|
+
await assert.rejects(reconcileStoppedNamedSessionLock({ ...f.input, apply: true }, f.deps));
|
|
75
|
+
assert.equal((await lstat(f.lock)).isFile(), true);
|
|
76
|
+
assert.equal(sha(await readFile(join(f.root, 'service.lock.stopped.' + f.input.lockSha256))), f.input.lockSha256);
|
|
77
|
+
});
|
|
78
|
+
test('a symbolic service lock and an existing foreign archive never admit reconciliation', linux, async () => {
|
|
79
|
+
for (const cause of ['symlink', 'archive']) {
|
|
80
|
+
const f = await fixture();
|
|
81
|
+
if (cause === 'symlink') {
|
|
82
|
+
await rename(f.lock, join(f.root, 'original'));
|
|
83
|
+
await symlink(join(f.root, 'original'), f.lock);
|
|
84
|
+
}
|
|
85
|
+
else
|
|
86
|
+
await writeFile(join(f.root, 'service.lock.stopped.' + f.input.lockSha256), 'foreign\n', { mode: 0o600 });
|
|
87
|
+
await assert.rejects(reconcileStoppedNamedSessionLock({ ...f.input, apply: true }, f.deps));
|
|
88
|
+
assert.equal(Boolean(await lstat(f.lock)), true);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
test('registration replacement or a newly live PID after planning cannot remove the active lock', linux, async () => {
|
|
92
|
+
for (const cause of ['registration', 'pid']) {
|
|
93
|
+
const f = await fixture();
|
|
94
|
+
let n = 0;
|
|
95
|
+
f.deps.assertTopology = async () => { if (++n === 2 && cause === 'registration')
|
|
96
|
+
await writeFile(join(f.root, 'registration.json'), '{}\n'); };
|
|
97
|
+
let pidChecks = 0;
|
|
98
|
+
if (cause === 'pid')
|
|
99
|
+
f.deps.processState = async () => ++pidChecks === 1 ? 'stopped' : 'running';
|
|
100
|
+
await assert.rejects(reconcileStoppedNamedSessionLock({ ...f.input, apply: true }, f.deps));
|
|
101
|
+
assert.equal((await lstat(f.lock)).isFile(), true);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
//# sourceMappingURL=namedSessionStoppedLock.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namedSessionStoppedLock.test.js","sourceRoot":"","sources":["../src/namedSessionStoppedLock.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AACvC,OAAO,EAAC,KAAK,EAAC,KAAK,EAAC,KAAK,EAAC,OAAO,EAAC,QAAQ,EAAC,QAAQ,EAAC,MAAM,EAAC,OAAO,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAC;AACtG,OAAO,EAAC,MAAM,EAAC,MAAM,SAAS,CAAC;AAC/B,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAC/B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAC,gCAAgC,EAAC,MAAM,8BAA8B,CAAC;AAG9E,MAAM,KAAK,GAAC,EAAC,IAAI,EAAC,OAAO,CAAC,QAAQ,KAAG,OAAO,EAAC,EAAC,GAAG,GAAC,CAAC,CAAY,EAAC,EAAE,CAAA,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC/G,KAAK,UAAU,OAAO;IACpB,MAAM,IAAI,GAAC,MAAM,QAAQ,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAAA,MAAM,KAAK,CAAC,IAAI,EAAC,KAAK,CAAC,CAAC;IACxG,MAAM,IAAI,GAAC,eAAe,EAAC,IAAI,GAAC,IAAI,CAAC,IAAI,EAAC,UAAU,EAAC,IAAI,CAAC,CAAC;IAAA,MAAM,KAAK,CAAC,IAAI,EAAC,EAAC,SAAS,EAAC,IAAI,EAAC,IAAI,EAAC,KAAK,EAAC,CAAC,CAAC;IAAA,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,EAAC,UAAU,CAAC,EAAC,KAAK,CAAC,CAAC;IAClJ,MAAM,YAAY,GAA0B,EAAC,MAAM,EAAC,yBAAyB,EAAC,IAAI,EAAC,SAAS,EAAC,sCAAsC,EAAC,OAAO,EAAC,KAAK;QAC/I,gBAAgB,EAAC,IAAI,EAAC,oBAAoB,EAAC,EAAE,EAAC,QAAQ,EAAC,EAAC,cAAc,EAAC,aAAa,EAAC,QAAQ,EAAC,OAAO;YACnG,mBAAmB,EAAC,sCAAsC,EAAC,WAAW,EAAC,sCAAsC;YAC7G,UAAU,EAAC,sCAAsC,EAAC,YAAY,EAAC,sCAAsC,EAAC,QAAQ,EAAC,sCAAsC,EAAC,EAAC,CAAC;IAC5J,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,EAAC,mBAAmB,CAAC,EAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAC,IAAI,EAAC,EAAC,IAAI,EAAC,KAAK,EAAC,CAAC,CAAC;IAC/F,MAAM,IAAI,GAAC,IAAI,CAAC,IAAI,EAAC,cAAc,CAAC,CAAC;IAAA,MAAM,SAAS,CAAC,IAAI,EAAC,UAAU,EAAC,EAAC,IAAI,EAAC,KAAK,EAAC,CAAC,CAAC;IACnF,MAAM,KAAK,GAAC,EAAC,IAAI,EAAC,IAAI,EAAC,YAAY,EAAC,kBAAkB,EAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAC,mBAAmB,CAAC,CAAC,CAAC,EAAC,UAAU,EAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAC,KAAK,EAAC,KAAK,EAAC,CAAC;IAC7J,MAAM,IAAI,GAAC,EAAC,cAAc,EAAC,KAAK,IAAE,EAAE,GAAC,CAAC,EAAC,YAAY,EAAC,KAAK,IAAE,EAAE,CAAC,SAA0C,EAAC,CAAC;IAC1G,OAAM,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,KAAK,EAAC,IAAI,EAAC,CAAC;AACpC,CAAC;AAED,IAAI,CAAC,6FAA6F,EAAC,KAAK,EAAC,KAAK,IAAE,EAAE;IAChH,MAAM,CAAC,GAAC,MAAM,OAAO,EAAE,EAAC,MAAM,GAAC,MAAM,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAAA,MAAM,IAAI,GAAC,MAAM,gCAAgC,CAAC,CAAC,CAAC,KAAK,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACrH,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAC,qCAAqC,CAAC,CAAC;IAAA,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAClH,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAC,EAAC,IAAI,EAAC,QAAQ,EAAC,CAAC,CAAC;IACvE,MAAM,MAAM,GAAC,MAAM,gCAAgC,CAAC,EAAC,GAAG,CAAC,CAAC,KAAK,EAAC,KAAK,EAAC,IAAI,EAAC,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACpF,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAC,yBAAyB,CAAC,CAAC;IAAA,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,EAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7H,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,mBAAmB,EAAC,KAAK,CAAC,CAAC;IAAA,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,EAAC,KAAK,CAAC,CAAC;IAAA,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,kBAAkB,EAAC,KAAK,CAAC,CAAC;IACtI,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAC,EAAC,IAAI,EAAC,QAAQ,EAAC,CAAC,CAAC;AACtD,CAAC,CAAC,CAAC;AAEH,KAAI,MAAM,KAAK,IAAI,CAAC,SAAS,EAAC,oBAAoB,EAAC,YAAY,EAAC,SAAS,EAAC,SAAS,EAAC,eAAe,EAAC,kBAAkB,EAAC,SAAS,EAAC,WAAW,CAAC,EAAC,CAAC;IAC7I,IAAI,CAAC,sCAAsC,GAAC,KAAK,GAAC,4BAA4B,EAAC,KAAK,EAAC,KAAK,IAAE,EAAE;QAC5F,MAAM,CAAC,GAAC,MAAM,OAAO,EAAE,CAAC;QACxB,IAAG,KAAK,KAAG,SAAS;YAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,GAAC,IAAI,CAAC;QACvD,IAAG,KAAK,KAAG,oBAAoB;YAAC,CAAC,CAAC,KAAK,CAAC,kBAAkB,GAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1E,IAAG,KAAK,KAAG,YAAY;YAAC,CAAC,CAAC,KAAK,CAAC,UAAU,GAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1D,IAAG,KAAK,KAAG,SAAS,IAAE,KAAK,KAAG,SAAS;YAAC,CAAC,CAAC,IAAI,CAAC,YAAY,GAAC,KAAK,IAAE,EAAE,CAAA,KAAK,CAAC;QAC3E,IAAG,KAAK,KAAG,eAAe;YAAC,MAAM,KAAK,CAAC,CAAC,CAAC,IAAI,EAAC,KAAK,CAAC,CAAC;QACrD,IAAG,KAAK,KAAG,kBAAkB;YAAC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAC,KAAK,IAAE,EAAE,GAAC,MAAM,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAA,CAAC,CAAC;QAClG,IAAG,KAAK,KAAG,SAAS,EAAC,CAAC;YAAA,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAC,SAAS,CAAC,EAAC,UAAU,EAAC,EAAC,IAAI,EAAC,KAAK,EAAC,CAAC,CAAC;YACpF,CAAC,CAAC,KAAK,CAAC,IAAI,GAAC,QAAQ,CAAC;YAAA,CAAC,CAAC,KAAK,CAAC,YAAY,GAAC,EAAC,GAAG,CAAC,CAAC,KAAK,CAAC,YAAY,EAAC,IAAI,EAAC,QAAQ,EAAC,CAAC;YAAA,MAAM,OAAO,CAAC,CAAC,CAAC,IAAI,EAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAC,UAAU,EAAC,QAAQ,CAAC,CAAC,CAAC;QAAA,CAAC;QAC7I,IAAG,KAAK,KAAG,WAAW,EAAC,CAAC;YAAA,MAAM,SAAS,CAAC,CAAC,CAAC,IAAI,EAAC,aAAa,CAAC,CAAC;YAAA,CAAC,CAAC,KAAK,CAAC,UAAU,GAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAAA,CAAC;QAC9G,MAAM,MAAM,CAAC,OAAO,CAAC,gCAAgC,CAAC,EAAC,GAAG,CAAC,CAAC,KAAK,EAAC,KAAK,EAAC,IAAI,EAAC,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAAA,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,EAAC,IAAI,CAAC,CAAC;IAC3I,CAAC,CAAC,CAAC;AACL,CAAC;AAED,IAAI,CAAC,wEAAwE,EAAC,KAAK,EAAC,KAAK,IAAE,EAAE;IAC3F,MAAM,CAAC,GAAC,MAAM,OAAO,EAAE,CAAC;IAAA,IAAI,MAAM,GAAC,CAAC,CAAC;IAAA,CAAC,CAAC,IAAI,CAAC,cAAc,GAAC,KAAK,IAAE,EAAE,GAAC,IAAG,EAAE,MAAM,KAAG,CAAC;QAAC,MAAM,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAA,CAAC,CAAC;IACvH,MAAM,MAAM,CAAC,OAAO,CAAC,gCAAgC,CAAC,EAAC,GAAG,CAAC,CAAC,KAAK,EAAC,KAAK,EAAC,IAAI,EAAC,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACvF,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,EAAC,IAAI,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAC,uBAAuB,GAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;AAChH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,oFAAoF,EAAC,KAAK,EAAC,KAAK,IAAE,EAAE;IACvG,KAAI,MAAM,KAAK,IAAI,CAAC,SAAS,EAAC,SAAS,CAAC,EAAC,CAAC;QACxC,MAAM,CAAC,GAAC,MAAM,OAAO,EAAE,CAAC;QACxB,IAAG,KAAK,KAAG,SAAS,EAAC,CAAC;YAAA,MAAM,MAAM,CAAC,CAAC,CAAC,IAAI,EAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAC,UAAU,CAAC,CAAC,CAAC;YAAA,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAC,UAAU,CAAC,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAAA,CAAC;;YAC7G,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAC,uBAAuB,GAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAC,WAAW,EAAC,EAAC,IAAI,EAAC,KAAK,EAAC,CAAC,CAAC;QACvG,MAAM,MAAM,CAAC,OAAO,CAAC,gCAAgC,CAAC,EAAC,GAAG,CAAC,CAAC,KAAK,EAAC,KAAK,EAAC,IAAI,EAAC,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACvF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAC,IAAI,CAAC,CAAC;IAClD,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2FAA2F,EAAC,KAAK,EAAC,KAAK,IAAE,EAAE;IAC9G,KAAI,MAAM,KAAK,IAAI,CAAC,cAAc,EAAC,KAAK,CAAC,EAAC,CAAC;QACzC,MAAM,CAAC,GAAC,MAAM,OAAO,EAAE,CAAC;QAAA,IAAI,CAAC,GAAC,CAAC,CAAC;QAChC,CAAC,CAAC,IAAI,CAAC,cAAc,GAAC,KAAK,IAAE,EAAE,GAAC,IAAG,EAAE,CAAC,KAAG,CAAC,IAAE,KAAK,KAAG,cAAc;YAAC,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAC,mBAAmB,CAAC,EAAC,MAAM,CAAC,CAAC,CAAA,CAAC,CAAC;QAC9H,IAAI,SAAS,GAAC,CAAC,CAAC;QAAA,IAAG,KAAK,KAAG,KAAK;YAAC,CAAC,CAAC,IAAI,CAAC,YAAY,GAAC,KAAK,IAAE,EAAE,CAAA,EAAE,SAAS,KAAG,CAAC,CAAA,CAAC,CAAA,SAAS,CAAA,CAAC,CAAA,SAAS,CAAC;QAClG,MAAM,MAAM,CAAC,OAAO,CAAC,gCAAgC,CAAC,EAAC,GAAG,CAAC,CAAC,KAAK,EAAC,KAAK,EAAC,IAAI,EAAC,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAAA,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,EAAC,IAAI,CAAC,CAAC;IAC3I,CAAC;AACH,CAAC,CAAC,CAAC"}
|
package/dist/relayAutostart.d.ts
CHANGED
|
@@ -62,6 +62,8 @@ export declare function enableRelayAutostart(options: RelayAutostartOptions & {
|
|
|
62
62
|
policy: string | null;
|
|
63
63
|
version: string;
|
|
64
64
|
preserveStandardAnchor?: boolean;
|
|
65
|
+
/** Existing Linux registration only; keep its controller paused during a signing-maintenance upgrade. */
|
|
66
|
+
pauseForSigningMaintenance?: boolean;
|
|
65
67
|
}): Promise<RelayAutostartState>;
|
|
66
68
|
export declare function disableRelayAutostart(options: RelayAutostartOptions): Promise<RelayAutostartState>;
|
|
67
69
|
export declare function startRelayAutostart(options: RelayAutostartOptions): Promise<{
|
|
@@ -72,6 +74,7 @@ export declare function startRelayAutostart(options: RelayAutostartOptions): Pro
|
|
|
72
74
|
export declare function inspectOwnedRelayAutostart(options: RelayAutostartOptions, inspection?: {
|
|
73
75
|
allowLegacy?: boolean;
|
|
74
76
|
}): Promise<RelayAutostartRegistration>;
|
|
77
|
+
export declare function assertRelayAutostartPaused(options: RelayAutostartOptions): Promise<void>;
|
|
75
78
|
export declare function stopRelayAutostart(options: RelayAutostartOptions): Promise<{
|
|
76
79
|
state: "stop_requested";
|
|
77
80
|
backend: "container-entrypoint" | "systemd-user" | "windows-task" | "launchd-user";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relayAutostart.d.ts","sourceRoot":"","sources":["../src/relayAutostart.ts"],"names":[],"mappings":"AAMA,OAAO,
|
|
1
|
+
{"version":3,"file":"relayAutostart.d.ts","sourceRoot":"","sources":["../src/relayAutostart.ts"],"names":[],"mappings":"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"}
|
package/dist/relayAutostart.js
CHANGED
|
@@ -4,9 +4,9 @@ import { lstat, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { dirname, isAbsolute, join, posix } from 'node:path';
|
|
6
6
|
import { promisify } from 'node:util';
|
|
7
|
-
import { assertContainerStartupOwnership, containerEntrypointAvailable, containerStartupControl, containerStartupState, ownsContainerStartup, writeContainerRegistration, readContainerRegistration } from './containerRelayLifecycle.js';
|
|
7
|
+
import { assertContainerStartupOwnership, containerEntrypointAvailable, containerStartupControl, containerStartupState, ownsContainerStartup, containerStartupPaused, writeContainerRegistration, readContainerRegistration } from './containerRelayLifecycle.js';
|
|
8
8
|
import { currentBootstrapHostScope } from './bootstrapHostScope.js';
|
|
9
|
-
import { assertWslHostPreflight, disableWslRelayHost, enableWslRelayHost, startWslRelayHost, wslRelayHostStatus } from './wslRelayHost.js';
|
|
9
|
+
import { assertWslHostPreflight, assertWslRelayHostPaused, pauseWslRelayHost, disableWslRelayHost, enableWslRelayHost, startWslRelayHost, wslRelayHostStatus } from './wslRelayHost.js';
|
|
10
10
|
const execFileAsync = promisify(execFile);
|
|
11
11
|
const UNIT_NAME = 'dharma-agent-fabric.service';
|
|
12
12
|
const MAC_LABEL = 'io.dharma.agent-fabric.relay';
|
|
@@ -341,6 +341,9 @@ export async function relayAutostartStatus(options) {
|
|
|
341
341
|
}
|
|
342
342
|
export async function enableRelayAutostart(options) {
|
|
343
343
|
const platform = options.platform || process.platform;
|
|
344
|
+
if (options.pauseForSigningMaintenance && (platform !== 'linux' || options.preserveStandardAnchor)) {
|
|
345
|
+
throw new Error('relay_signing_maintenance_startup_scope_invalid');
|
|
346
|
+
}
|
|
344
347
|
if (platform !== 'linux' && platform !== 'win32' && platform !== 'darwin') {
|
|
345
348
|
throw new Error(`Relay autostart is unsupported on ${platform}.`);
|
|
346
349
|
}
|
|
@@ -349,6 +352,8 @@ export async function enableRelayAutostart(options) {
|
|
|
349
352
|
const userHome = options.userHome || homedir();
|
|
350
353
|
const run = options.run || defaultRunner;
|
|
351
354
|
const previous = await readRegistration(options);
|
|
355
|
+
if (options.pauseForSigningMaintenance && !previous)
|
|
356
|
+
throw new Error('relay_signing_maintenance_startup_scope_invalid');
|
|
352
357
|
const backend = platform === 'linux'
|
|
353
358
|
? await containerEntrypointAvailable(options) ? 'container-entrypoint' : 'systemd-user'
|
|
354
359
|
: platform === 'darwin' ? 'launchd-user' : 'windows-task';
|
|
@@ -393,7 +398,7 @@ export async function enableRelayAutostart(options) {
|
|
|
393
398
|
if (previous && !await ownsStartupFile(options, previous))
|
|
394
399
|
throw new Error('autostart_conflict: container startup is not owned.');
|
|
395
400
|
await writeContainerRegistration(options, registration);
|
|
396
|
-
await containerStartupControl(options, registration,
|
|
401
|
+
await containerStartupControl(options, registration, !options.pauseForSigningMaintenance);
|
|
397
402
|
return containerStartupState(options, registration);
|
|
398
403
|
}
|
|
399
404
|
if (platform === 'win32' && !previous) {
|
|
@@ -451,8 +456,11 @@ export async function enableRelayAutostart(options) {
|
|
|
451
456
|
await writeFile(registrationPath(options.home), `${JSON.stringify(registration, null, 2)}\n`, { mode: 0o600 });
|
|
452
457
|
if (platform === 'linux') {
|
|
453
458
|
await run('systemctl', ['--user', 'daemon-reload']);
|
|
454
|
-
await run('systemctl', ['--user', 'enable', UNIT_NAME]);
|
|
455
|
-
|
|
459
|
+
await run('systemctl', ['--user', options.pauseForSigningMaintenance ? 'disable' : 'enable', UNIT_NAME]);
|
|
460
|
+
if (options.pauseForSigningMaintenance)
|
|
461
|
+
await pauseWslRelayHost(options);
|
|
462
|
+
else
|
|
463
|
+
await enableWslRelayHost(options);
|
|
456
464
|
}
|
|
457
465
|
else if (platform === 'darwin') {
|
|
458
466
|
await run('/usr/bin/plutil', ['-lint', destination]);
|
|
@@ -474,7 +482,7 @@ export async function enableRelayAutostart(options) {
|
|
|
474
482
|
await run('powershell.exe', encodedPowerShell(command));
|
|
475
483
|
}
|
|
476
484
|
const status = await relayAutostartStatus(options);
|
|
477
|
-
if (status.state !== 'enabled')
|
|
485
|
+
if (status.state !== (options.pauseForSigningMaintenance ? 'disabled' : 'enabled'))
|
|
478
486
|
throw new Error(`Relay autostart registration was not verified (${status.state}).`);
|
|
479
487
|
return status;
|
|
480
488
|
}
|
|
@@ -561,6 +569,37 @@ export async function inspectOwnedRelayAutostart(options, inspection = {}) {
|
|
|
561
569
|
await macLoaded(options, registration);
|
|
562
570
|
return registration;
|
|
563
571
|
}
|
|
572
|
+
export async function assertRelayAutostartPaused(options) {
|
|
573
|
+
const registration = await inspectOwnedRelayAutostart(options);
|
|
574
|
+
if (registration.backend === 'container-entrypoint') {
|
|
575
|
+
// Only a valid paused control awaiting its new matching heartbeat is polled.
|
|
576
|
+
// Identity, permission, malformed metadata and other failures stop immediately.
|
|
577
|
+
for (let attempt = 0; attempt < 50; attempt++) {
|
|
578
|
+
if (await containerStartupPaused(options, registration))
|
|
579
|
+
return;
|
|
580
|
+
if (attempt < 49)
|
|
581
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
582
|
+
}
|
|
583
|
+
throw Error('relay_startup_pause_unconfirmed');
|
|
584
|
+
}
|
|
585
|
+
if (registration.backend !== 'systemd-user' || (await relayAutostartStatus(options)).state !== 'disabled') {
|
|
586
|
+
throw Error('relay_startup_pause_unconfirmed');
|
|
587
|
+
}
|
|
588
|
+
const run = options.run || defaultRunner;
|
|
589
|
+
let active;
|
|
590
|
+
try {
|
|
591
|
+
active = (await run('systemctl', ['--user', 'is-active', UNIT_NAME])).stdout.trim();
|
|
592
|
+
}
|
|
593
|
+
catch (error) {
|
|
594
|
+
const e = error;
|
|
595
|
+
if (e.code !== 3 || typeof e.stdout !== 'string' || e.stdout.trim() !== 'inactive')
|
|
596
|
+
throw error;
|
|
597
|
+
active = 'inactive';
|
|
598
|
+
}
|
|
599
|
+
if (active !== 'inactive')
|
|
600
|
+
throw Error('relay_startup_pause_unconfirmed');
|
|
601
|
+
await assertWslRelayHostPaused(options);
|
|
602
|
+
}
|
|
564
603
|
export async function stopRelayAutostart(options) {
|
|
565
604
|
const registration = await inspectOwnedRelayAutostart(options);
|
|
566
605
|
const run = options.run || defaultRunner;
|