@dharma-ai-labs/agent-fabric 0.2.197 → 0.2.199

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.
Files changed (34) hide show
  1. package/AGENT_FABRIC_ONBOARDING.md +2 -0
  2. package/dist/bootstrapRelayOrdering.test.js +28 -2
  3. package/dist/bootstrapRelayOrdering.test.js.map +1 -1
  4. package/dist/bootstrapStartupPreflight.test.js +10 -0
  5. package/dist/bootstrapStartupPreflight.test.js.map +1 -1
  6. package/dist/codexBootstrapCompletion.test.js +13 -0
  7. package/dist/codexBootstrapCompletion.test.js.map +1 -1
  8. package/dist/codexSetupPortalIngress.test.js +2 -0
  9. package/dist/codexSetupPortalIngress.test.js.map +1 -1
  10. package/dist/codexSetupSessionHandoff.test.js +4 -2
  11. package/dist/codexSetupSessionHandoff.test.js.map +1 -1
  12. package/dist/codexSetupSourceRequalification.test.d.ts +2 -0
  13. package/dist/codexSetupSourceRequalification.test.d.ts.map +1 -0
  14. package/dist/codexSetupSourceRequalification.test.js +109 -0
  15. package/dist/codexSetupSourceRequalification.test.js.map +1 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +32 -10
  18. package/dist/index.js.map +1 -1
  19. package/dist/relayAutostart.d.ts +4 -2
  20. package/dist/relayAutostart.d.ts.map +1 -1
  21. package/dist/relayAutostart.js +20 -3
  22. package/dist/relayAutostart.js.map +1 -1
  23. package/dist/schemas/wsl-relay-host.v1.schema.json +18 -0
  24. package/dist/startupCommitScope.test.js +6 -0
  25. package/dist/startupCommitScope.test.js.map +1 -1
  26. package/dist/wslRelayHost.d.ts +30 -0
  27. package/dist/wslRelayHost.d.ts.map +1 -0
  28. package/dist/wslRelayHost.js +269 -0
  29. package/dist/wslRelayHost.js.map +1 -0
  30. package/dist/wslRelayHost.test.d.ts +2 -0
  31. package/dist/wslRelayHost.test.d.ts.map +1 -0
  32. package/dist/wslRelayHost.test.js +308 -0
  33. package/dist/wslRelayHost.test.js.map +1 -0
  34. package/package.json +1 -1
@@ -0,0 +1,269 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
3
+ import { lstat, readFile, realpath, rm, writeFile } from 'node:fs/promises';
4
+ import { userInfo } from 'node:os';
5
+ import { join, resolve } from 'node:path';
6
+ import { captureBootstrapHostChild, currentBootstrapHostScope } from './bootstrapHostScope.js';
7
+ const fail = (conflict = false) => {
8
+ throw new Error(conflict
9
+ ? 'autostart_conflict: the WSL host task is not owned by this installation.' : 'wsl_host_startup_unavailable');
10
+ };
11
+ const receiptPath = (home) => join(home, 'relay', 'wsl-host.json');
12
+ const literal = (value) => `'${value.replace(/'/g, "''")}'`;
13
+ const object = (value) => Boolean(value && typeof value === 'object' && !Array.isArray(value));
14
+ const digest = (home, context) => createHash('sha256').update(JSON.stringify([home, context.distribution, context.linuxUser])).digest('hex');
15
+ const windowsArgs = (script) => ['/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe',
16
+ '-NoLogo', '-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(script, 'utf16le').toString('base64')];
17
+ export function resolveWslRelayContext(distribution, linuxUser, installed = null) {
18
+ if (!distribution) {
19
+ if (!object(installed) || installed.schema !== 'dharma.wsl-relay-host/v1'
20
+ || installed.linuxUser !== linuxUser || typeof installed.distribution !== 'string')
21
+ return fail();
22
+ distribution = installed.distribution;
23
+ }
24
+ if (!/^[A-Za-z0-9][A-Za-z0-9 ._-]{0,63}$/.test(distribution) || distribution.trim() !== distribution
25
+ || !/^[a-z_][a-z0-9_-]{0,31}$/.test(linuxUser))
26
+ return fail();
27
+ return { distribution, linuxUser };
28
+ }
29
+ async function privateParent(options) {
30
+ for (const path of [options.home, join(options.home, 'relay')]) {
31
+ const stat = await lstat(path);
32
+ if (!stat.isDirectory() || stat.isSymbolicLink() || await realpath(path) !== resolve(path)
33
+ || process.platform !== 'win32' && ((stat.mode & 0o077) !== 0 || stat.uid !== process.getuid()))
34
+ return fail(true);
35
+ }
36
+ }
37
+ async function windows(script) {
38
+ const scope = currentBootstrapHostScope();
39
+ const operation = () => new Promise((accept, reject) => {
40
+ const child = execFile('/init', windowsArgs(script), { cwd: '/mnt/c/Windows/System32', timeout: 15000, maxBuffer: 16384, signal: scope?.signal }, (error, stdout) => error ? reject(error) : accept({ stdout }));
41
+ if (scope)
42
+ captureBootstrapHostChild(scope, child);
43
+ });
44
+ return operation();
45
+ }
46
+ async function context(options) {
47
+ let value;
48
+ if (options.wslHost)
49
+ value = await options.wslHost.context();
50
+ else {
51
+ if (process.platform !== 'linux')
52
+ return null;
53
+ for (const marker of ['/.dockerenv', '/run/.containerenv']) {
54
+ try {
55
+ await lstat(marker);
56
+ return null;
57
+ }
58
+ catch (error) {
59
+ if (error.code !== 'ENOENT')
60
+ return fail();
61
+ }
62
+ }
63
+ const kernel = await readFile('/proc/sys/kernel/osrelease', 'utf8');
64
+ if (!/microsoft/i.test(kernel))
65
+ return null;
66
+ if (!process.getuid?.())
67
+ return fail();
68
+ value = resolveWslRelayContext(process.env.WSL_DISTRO_NAME, userInfo().username, process.env.WSL_DISTRO_NAME ? null : await saved(options));
69
+ }
70
+ if (value === null)
71
+ return null;
72
+ if (!object(value) || Object.keys(value).sort().join(',') !== 'distribution,linuxUser'
73
+ || typeof value.distribution !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9 ._-]{0,63}$/.test(value.distribution)
74
+ || value.distribution.trim() !== value.distribution || typeof value.linuxUser !== 'string'
75
+ || !/^[a-z_][a-z0-9_-]{0,31}$/.test(value.linuxUser))
76
+ return fail();
77
+ return value;
78
+ }
79
+ async function invoke(options, script) {
80
+ const scope = currentBootstrapHostScope();
81
+ try {
82
+ if (windowsArgs(script).at(-1).length > 28000)
83
+ return fail();
84
+ const run = options.wslHost?.run || (options.run
85
+ ? value => options.run('/init', windowsArgs(value)) : windows);
86
+ const result = await (scope ? scope.step(() => run(script)) : run(script));
87
+ if (Buffer.byteLength(result.stdout) > 16384)
88
+ return fail();
89
+ return JSON.parse(result.stdout.replace(/^\uFEFF/, '').trim());
90
+ }
91
+ catch {
92
+ await scope?.assert();
93
+ return fail();
94
+ }
95
+ }
96
+ async function expected(options, current) {
97
+ const identity = await invoke(options, '# dharma-wsl-host:identity\n$ErrorActionPreference="Stop"; '
98
+ + '$sid=[System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value; '
99
+ + '$exe=Join-Path $env:SystemRoot "System32\\wsl.exe"; '
100
+ + '@{sid=$sid;executable=$exe}|ConvertTo-Json -Compress');
101
+ if (!object(identity) || Object.keys(identity).sort().join(',') !== 'executable,sid'
102
+ || typeof identity.sid !== 'string' || !/^S-1-5-21-(?:\d{1,10}-){2}\d{1,10}-\d{1,10}$/.test(identity.sid)
103
+ || typeof identity.executable !== 'string' || !/^[A-Za-z]:\\Windows\\System32\\wsl\.exe$/i.test(identity.executable))
104
+ return fail();
105
+ const hash = digest(options.home, current);
106
+ return { ...current, schema: 'dharma.wsl-relay-host/v1', windowsSid: identity.sid,
107
+ executable: identity.executable, taskName: `DharmaAgentFabric-WSL-${hash.slice(0, 24)}`,
108
+ arguments: `--distribution "${current.distribution}" --user "${current.linuxUser}" --cd / --exec /usr/bin/systemctl --user start --wait dharma-agent-fabric.service`,
109
+ description: `Dharma Agent Fabric owned WSL host ${hash}` };
110
+ }
111
+ async function saved(options) {
112
+ try {
113
+ const path = receiptPath(options.home), stat = await lstat(path);
114
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 8192
115
+ || process.platform !== 'win32' && ((stat.mode & 0o077) !== 0 || stat.uid !== process.getuid()))
116
+ return fail(true);
117
+ await privateParent(options);
118
+ const value = JSON.parse(await readFile(path, 'utf8'));
119
+ if (!object(value))
120
+ return fail(true);
121
+ return value;
122
+ }
123
+ catch (error) {
124
+ if (error.code === 'ENOENT')
125
+ return null;
126
+ return fail(true);
127
+ }
128
+ }
129
+ function sameReceipt(value, target) {
130
+ const keys = Object.keys(target);
131
+ return Object.keys(value).length === keys.length && keys.every(key => Reflect.get(value, key) === Reflect.get(target, key));
132
+ }
133
+ function lookup(receipt, required = false) {
134
+ const query = `$task=Get-ScheduledTask -TaskPath '\\' -TaskName ${literal(receipt.taskName)} -ErrorAction Stop; `;
135
+ return required ? query : `$task=$null; try { ${query} } catch { `
136
+ + `if ($_.FullyQualifiedErrorId -cne 'CmdletizationQuery_NotFound,Get-ScheduledTask' `
137
+ + `-or [string]$_.CategoryInfo.Category -ne 'ObjectNotFound') {throw} }; `;
138
+ }
139
+ function taskAction(receipt) {
140
+ // Direct WSL scheduled actions can exit before Linux starts. Preserve the
141
+ // same limited identity while hosting the fixed native command in PowerShell.
142
+ const script = `$ErrorActionPreference='Stop'; & ${literal(receipt.executable)} `
143
+ + `--distribution ${literal(receipt.distribution)} --user ${literal(receipt.linuxUser)} `
144
+ + `--cd / --exec /usr/bin/systemctl --user start --wait dharma-agent-fabric.service; exit $LASTEXITCODE`;
145
+ return { executable: receipt.executable.replace(/wsl\.exe$/i, 'WindowsPowerShell\\v1.0\\powershell.exe'),
146
+ arguments: `-NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -EncodedCommand ${Buffer.from(script, 'utf16le').toString('base64')}` };
147
+ }
148
+ function taskPreamble(receipt, operation) {
149
+ const action = taskAction(receipt);
150
+ return `# dharma-wsl-host:${operation}\n$ErrorActionPreference="Stop"; `
151
+ + `$current=[System.Security.Principal.WindowsIdentity]::GetCurrent(); `
152
+ + `if ($current.User.Value -cne ${literal(receipt.windowsSid)}) {throw 'wsl_host_identity_conflict'}; `
153
+ + lookup(receipt)
154
+ + `function Assert-OwnedTask($value) { $actions=@($value.Actions); $triggers=@($value.Triggers); `
155
+ + `$definition=[xml](Export-ScheduledTask -TaskPath '\\' -TaskName ${literal(receipt.taskName)} -ErrorAction Stop); `
156
+ + `$principals=@($definition.Task.Principals.Principal); `
157
+ + `if ($value.Description -cne ${literal(receipt.description)} -or $actions.Count -ne 1 `
158
+ + `-or $actions[0].Execute -cne ${literal(action.executable)} -or $actions[0].Arguments -cne ${literal(action.arguments)} `
159
+ + `-or $principals.Count -ne 1 -or $principals[0].UserId -cne $current.User.Value `
160
+ + `-or [string]$value.Principal.LogonType -ne 'Interactive' -or [string]$value.Principal.RunLevel -ne 'Limited' `
161
+ + `-or $triggers.Count -ne 1 -or $triggers[0].CimClass.CimClassName -ne 'MSFT_TaskLogonTrigger' -or !$triggers[0].Enabled `
162
+ + `-or ($triggers[0].UserId -cne $current.User.Value -and $triggers[0].UserId -cne $current.Name) `
163
+ + `-or [string]$value.Settings.MultipleInstances -ne 'IgnoreNew' `
164
+ + `-or $value.Settings.ExecutionTimeLimit -ne 'PT0S' -or $value.Settings.RestartCount -ne 0 `
165
+ + `-or $value.Settings.DisallowStartIfOnBatteries -or $value.Settings.StopIfGoingOnBatteries) {throw 'wsl_host_task_conflict'} }; `;
166
+ }
167
+ const renderState = `if ($null -eq $task) { @{exists=$false;enabled=$false;running=$false}|ConvertTo-Json -Compress } `
168
+ + `else { Assert-OwnedTask $task; @{exists=$true;enabled=($task.State -ne 'Disabled');running=($task.State -eq 'Running')}|ConvertTo-Json -Compress }`;
169
+ async function query(options, receipt) {
170
+ const value = await invoke(options, taskPreamble(receipt, 'status') + renderState);
171
+ if (!object(value) || Object.keys(value).sort().join(',') !== 'enabled,exists,running'
172
+ || Object.values(value).some(field => typeof field !== 'boolean'))
173
+ return fail();
174
+ if (!value.exists && (value.enabled || value.running) || value.running && !value.enabled)
175
+ return fail();
176
+ return value;
177
+ }
178
+ export async function assertWslHostPreflight(options) {
179
+ const current = await context(options);
180
+ if (!current)
181
+ return;
182
+ const target = await expected(options, current), previous = await saved(options);
183
+ if (previous && !sameReceipt(previous, target))
184
+ return fail(true);
185
+ const state = await query(options, target);
186
+ if (state.exists && !previous)
187
+ return fail(true);
188
+ }
189
+ export async function enableWslRelayHost(options) {
190
+ const current = await context(options);
191
+ if (!current)
192
+ return;
193
+ const target = await expected(options, current), previous = await saved(options);
194
+ if (previous && !sameReceipt(previous, target))
195
+ return fail(true);
196
+ const before = await query(options, target);
197
+ if (before.exists && !previous)
198
+ return fail(true);
199
+ await privateParent(options);
200
+ if (!previous)
201
+ await writeFile(receiptPath(options.home), `${JSON.stringify(target, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
202
+ if (before.exists && before.enabled)
203
+ return;
204
+ // Preserve ownership before external mutation. Lost responses require readback,
205
+ // not replacement of a possibly foreign task.
206
+ const action = taskAction(target);
207
+ await invoke(options, taskPreamble(target, 'register')
208
+ + `if ($null -ne $task) { Assert-OwnedTask $task; Enable-ScheduledTask -TaskPath '\\' -TaskName ${literal(target.taskName)}|Out-Null } else { `
209
+ + `$action=New-ScheduledTaskAction -Execute ${literal(action.executable)} -Argument ${literal(action.arguments)}; `
210
+ + `$trigger=New-ScheduledTaskTrigger -AtLogOn -User $current.Name; `
211
+ + `$principal=New-ScheduledTaskPrincipal -UserId $current.Name -LogonType Interactive -RunLevel Limited; `
212
+ + `$settings=New-ScheduledTaskSettingsSet -MultipleInstances IgnoreNew -ExecutionTimeLimit ([TimeSpan]::Zero) -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries; `
213
+ + `Register-ScheduledTask -TaskPath '\\' -TaskName ${literal(target.taskName)} -Description ${literal(target.description)} `
214
+ + `-Action $action -Trigger $trigger -Principal $principal -Settings $settings|Out-Null }; `
215
+ + lookup(target, true) + renderState);
216
+ const after = await query(options, target);
217
+ if (!after.exists || !after.enabled)
218
+ return fail();
219
+ }
220
+ export async function wslRelayHostStatus(options) {
221
+ const current = await context(options);
222
+ if (!current)
223
+ return null;
224
+ const previous = await saved(options);
225
+ if (!previous)
226
+ return fail();
227
+ const target = await expected(options, current);
228
+ if (!sameReceipt(previous, target))
229
+ return fail(true);
230
+ return query(options, target);
231
+ }
232
+ export async function startWslRelayHost(options) {
233
+ const current = await context(options);
234
+ if (!current)
235
+ return;
236
+ const target = await expected(options, current), previous = await saved(options);
237
+ if (!previous || !sameReceipt(previous, target))
238
+ return fail(true);
239
+ const before = await query(options, target);
240
+ if (!before.exists || !before.enabled)
241
+ return fail();
242
+ if (before.running)
243
+ return;
244
+ await invoke(options, taskPreamble(target, 'start') + `if ($null -eq $task) {throw 'wsl_host_missing'}; Assert-OwnedTask $task; `
245
+ + `Start-ScheduledTask -TaskPath '\\' -TaskName ${literal(target.taskName)}; `
246
+ + `for ($attempt=0; $attempt -lt 40; $attempt++) { ` + lookup(target, true)
247
+ + `Assert-OwnedTask $task; if ($task.State -eq 'Running') {break}; Start-Sleep -Milliseconds 100 }; ` + renderState);
248
+ if (!(await query(options, target)).running)
249
+ return fail();
250
+ }
251
+ export async function disableWslRelayHost(options) {
252
+ const previous = await saved(options);
253
+ if (!previous)
254
+ return;
255
+ const current = await context(options);
256
+ if (!current)
257
+ return fail(true);
258
+ const target = await expected(options, current);
259
+ if (!sameReceipt(previous, target))
260
+ return fail(true);
261
+ await query(options, target);
262
+ await invoke(options, taskPreamble(target, 'disable') + `if ($null -ne $task) { Assert-OwnedTask $task; `
263
+ + `Unregister-ScheduledTask -TaskPath '\\' -TaskName ${literal(target.taskName)} -Confirm:$false }; `
264
+ + lookup(target) + renderState);
265
+ if ((await query(options, target)).exists)
266
+ return fail();
267
+ await rm(receiptPath(options.home));
268
+ }
269
+ //# sourceMappingURL=wslRelayHost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wslRelayHost.js","sourceRoot":"","sources":["../src/wslRelayHost.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=wslRelayHost.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wslRelayHost.test.d.ts","sourceRoot":"","sources":["../src/wslRelayHost.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,308 @@
1
+ import assert from 'node:assert/strict';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { mkdtemp, readFile, realpath, rm, writeFile } from 'node:fs/promises';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { compileFunction } from 'node:vm';
7
+ import test from 'node:test';
8
+ import ts from 'typescript';
9
+ import { enableRelayAutostart, relayAutostartStatus, disableRelayAutostart, startRelayAutostart, assertRelayStartupOwnership } from './relayAutostart.js';
10
+ import { resolveWslRelayContext } from './wslRelayHost.js';
11
+ import { validateContract } from '@dharma-ai-labs/agent-fabric-contracts';
12
+ import { prepareCodexBootstrapHost, runCodexBootstrapHostScope } from './bootstrapHostScope.js';
13
+ test('real WSL Windows launch uses a fixed Windows cwd rather than the Linux caller directory', async () => {
14
+ const source = await readFile(new URL('../src/wslRelayHost.ts', import.meta.url), 'utf8');
15
+ const ast = ts.createSourceFile('wslRelayHost.ts', source, ts.ScriptTarget.Latest, true);
16
+ const declaration = ast.statements.find(node => ts.isFunctionDeclaration(node) && node.name?.text === 'windows');
17
+ assert.ok(declaration && ts.isFunctionDeclaration(declaration));
18
+ const compiled = ts.transpileModule(declaration.getText(ast), { compilerOptions: {
19
+ target: ts.ScriptTarget.ES2023, module: ts.ModuleKind.CommonJS
20
+ } }).outputText;
21
+ let calls = 0;
22
+ const launch = compileFunction(compiled + '\nreturn windows;', ['currentBootstrapHostScope', 'execFile', 'windowsArgs', 'captureBootstrapHostChild'])(() => undefined, (file, args, options, done) => {
23
+ calls++;
24
+ assert.equal(file, '/init');
25
+ assert.deepEqual(args, ['public-arguments']);
26
+ assert.equal(options.cwd, '/mnt/c/Windows/System32', 'Linux cwd must not become a Windows UNC current directory');
27
+ assert.equal(options.timeout, 15000);
28
+ assert.equal(options.maxBuffer, 16384);
29
+ done(null, '{"public":true}');
30
+ return {};
31
+ }, () => ['public-arguments'], () => { throw new Error('no setup scope in this fixture'); });
32
+ assert.deepEqual(await launch('public-script'), { stdout: '{"public":true}' });
33
+ assert.equal(calls, 1);
34
+ });
35
+ async function fixture(t) {
36
+ const root = await realpath(await mkdtemp(join(tmpdir(), 'dharma-wsl-host-')));
37
+ t.after(() => rm(root, { recursive: true, force: true }));
38
+ const scripts = [];
39
+ let exists = false;
40
+ let running = false;
41
+ let loseRegistrationResponse = false;
42
+ const options = { platform: 'linux', home: join(root, 'device'), userHome: root,
43
+ workspace: '/fixtures/repo', launcher: '/fixtures/repo/.dharma/bin/dharma',
44
+ policy: '/fixtures/repo/.dharma/approved-policy.json', version: '0.2.198',
45
+ run: async () => ({ stdout: 'enabled\n' }),
46
+ wslHost: {
47
+ context: async () => ({ distribution: 'Ubuntu', linuxUser: 'maatru' }),
48
+ run: async (script) => {
49
+ scripts.push(script);
50
+ if (script.includes('dharma-wsl-host:identity'))
51
+ return { stdout: JSON.stringify({
52
+ sid: 'S-1-5-21-123-456-789-1001', executable: 'C:\\Windows\\System32\\wsl.exe'
53
+ }) };
54
+ if (script.includes('dharma-wsl-host:register')) {
55
+ exists = true;
56
+ if (loseRegistrationResponse)
57
+ throw new Error('registration response lost');
58
+ }
59
+ if (script.includes('dharma-wsl-host:start'))
60
+ running = true;
61
+ if (script.includes('dharma-wsl-host:disable')) {
62
+ exists = false;
63
+ running = false;
64
+ }
65
+ return { stdout: JSON.stringify({ exists, enabled: exists, running }) };
66
+ },
67
+ },
68
+ };
69
+ return { options, scripts, foreignTask: () => { exists = true; }, loseResponse: () => { loseRegistrationResponse = true; } };
70
+ }
71
+ function registeredTaskAction(scripts) {
72
+ const registration = scripts.find(script => script.includes('dharma-wsl-host:register'));
73
+ const match = /New-ScheduledTaskAction -Execute '([^']+)' -Argument '([^']+)'/.exec(registration);
74
+ assert.ok(match, 'expected one fixed task action');
75
+ return { execute: match[1], arguments: match[2] };
76
+ }
77
+ test('WSL task uses the verified PowerShell host for its fixed native wait action', async (t) => {
78
+ const f = await fixture(t);
79
+ await enableRelayAutostart(f.options);
80
+ const action = registeredTaskAction(f.scripts);
81
+ assert.equal(action.execute, 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe');
82
+ assert.match(action.arguments, /^-NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -EncodedCommand [A-Za-z0-9+/=]+$/);
83
+ const script = Buffer.from(action.arguments.split(' ').at(-1), 'base64').toString('utf16le');
84
+ assert.equal(script, "$ErrorActionPreference='Stop'; & 'C:\\Windows\\System32\\wsl.exe' --distribution 'Ubuntu' --user 'maatru' --cd / --exec /usr/bin/systemctl --user start --wait dharma-agent-fabric.service; exit $LASTEXITCODE");
85
+ assert.doesNotMatch(script, /ExecutionPolicy|credential|password|token|grant|Start-Process|Invoke-Expression/i);
86
+ });
87
+ test('optional WSL task lookup distinguishes exact absence from a failed scheduler read', async () => {
88
+ const source = await readFile(new URL('../src/wslRelayHost.ts', import.meta.url), 'utf8');
89
+ const ast = ts.createSourceFile('wslRelayHost.ts', source, ts.ScriptTarget.Latest, true);
90
+ const declaration = ast.statements.find(node => ts.isFunctionDeclaration(node) && node.name?.text === 'lookup');
91
+ assert.ok(declaration && ts.isFunctionDeclaration(declaration));
92
+ const compiled = ts.transpileModule(declaration.getText(ast), { compilerOptions: {
93
+ target: ts.ScriptTarget.ES2023, module: ts.ModuleKind.CommonJS
94
+ } }).outputText;
95
+ const lookup = compileFunction(compiled + '\nreturn lookup;', ['literal'])((s) => `'${s.replaceAll("'", "''")}'`);
96
+ const query = lookup({ taskName: 'SyntheticFixture' });
97
+ assert.doesNotMatch(query, /SilentlyContinue/);
98
+ assert.match(query, /-ErrorAction Stop/);
99
+ assert.match(query, /CmdletizationQuery_NotFound,Get-ScheduledTask/);
100
+ assert.match(query, /ObjectNotFound/);
101
+ if (process.platform === 'win32') {
102
+ for (const id of ['CmdletizationQuery_NotFound,Get-ScheduledTask', 'AccessDenied', 'SchedulerUnavailable']) {
103
+ const script = `function Get-ScheduledTask { throw [System.Management.Automation.ErrorRecord]::new(`
104
+ + `[Exception]::new('synthetic'), '${id}', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $null) }; `
105
+ + `try { ${query}; if($null -eq $task){[Console]::Out.Write('absent')} } catch {[Console]::Out.Write('failed')} `;
106
+ const result = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-EncodedCommand',
107
+ Buffer.from(script, 'utf16le').toString('base64')], { encoding: 'utf8', timeout: 15000, windowsHide: true });
108
+ assert.equal(result.status, 0, result.stderr);
109
+ assert.equal(result.stdout, id.startsWith('CmdletizationQuery_NotFound,') ? 'absent' : 'failed');
110
+ }
111
+ }
112
+ });
113
+ test('WSL startup registers an exact user-logon host action instead of relying on systemd lifetime', async (t) => {
114
+ const { options, scripts } = await fixture(t);
115
+ await enableRelayAutostart(options);
116
+ assert(scripts.some(script => script.includes('dharma-wsl-host:register')), 'an enabled Linux service alone cannot keep the WSL distro alive');
117
+ const receipt = await readFile(join(options.home, 'relay', 'wsl-host.json'), 'utf8');
118
+ assert.doesNotMatch(receipt, /password|token|grant|credential/i);
119
+ const action = scripts.find(script => script.includes('dharma-wsl-host:register'));
120
+ const nativeAction = registeredTaskAction(scripts);
121
+ assert.match(Buffer.from(nativeAction.arguments.split(' ').at(-1), 'base64').toString('utf16le'), /start --wait dharma-agent-fabric\.service/);
122
+ assert.match(action, /-LogonType Interactive -RunLevel Limited/);
123
+ assert.match(action, /New-ScheduledTaskTrigger -AtLogOn -User \$current\.Name/);
124
+ assert.match(action, /New-ScheduledTaskPrincipal -UserId \$current\.Name/);
125
+ assert.match(action, /Export-ScheduledTask -TaskPath/);
126
+ assert.match(action, /\$principals\[0\]\.UserId -cne \$current\.User\.Value/);
127
+ assert.doesNotMatch(action, /-Force|ExecutionPolicy|wsl.*--shutdown|sleep infinity/);
128
+ const status = await relayAutostartStatus(options);
129
+ assert.equal(status.state, 'enabled');
130
+ assert.equal(Reflect.get(status, 'restartCoverage'), 'wsl-host-logon');
131
+ assert.equal(Reflect.get(status, 'hostLifecycle'), 'registered');
132
+ await startRelayAutostart(options);
133
+ assert.equal(Reflect.get(await relayAutostartStatus(options), 'hostLifecycle'), 'running');
134
+ const registrationCalls = scripts.filter(script => script.includes('dharma-wsl-host:register')).length;
135
+ await enableRelayAutostart(options);
136
+ assert.equal(scripts.filter(script => script.includes('dharma-wsl-host:register')).length, registrationCalls);
137
+ await disableRelayAutostart(options);
138
+ assert(scripts.some(script => script.includes('dharma-wsl-host:disable')));
139
+ await assert.rejects(readFile(join(options.home, 'relay', 'wsl-host.json')), { code: 'ENOENT' });
140
+ });
141
+ test('the actual WSL guard validates the persisted SID rather than a normalized account alias', { skip: process.platform !== 'win32' }, async (t) => {
142
+ const f = await fixture(t);
143
+ await enableRelayAutostart(f.options);
144
+ const preamble = f.scripts.find(s => s.includes('dharma-wsl-host:status'));
145
+ const start = preamble.indexOf('function '), end = preamble.indexOf('if ($null -eq $task)');
146
+ assert.ok(start > 0 && end > start);
147
+ const guard = preamble.slice(start, end);
148
+ const task = { Description: 'synthetic', Actions: [{ Execute: 'C:\\Windows\\System32\\wsl.exe', Arguments: 'synthetic' }],
149
+ Principal: { UserId: '', LogonType: 'Interactive', RunLevel: 'Limited' },
150
+ Triggers: [{ CimClass: { CimClassName: 'MSFT_TaskLogonTrigger' }, Enabled: true, UserId: '' }],
151
+ Settings: { MultipleInstances: 'IgnoreNew', ExecutionTimeLimit: 'PT0S', RestartCount: 0, DisallowStartIfOnBatteries: false, StopIfGoingOnBatteries: false } };
152
+ const receipt = JSON.parse(await readFile(join(f.options.home, 'relay', 'wsl-host.json'), 'utf8'));
153
+ const action = registeredTaskAction(f.scripts);
154
+ task.Description = receipt.description;
155
+ task.Actions[0].Execute = action.execute;
156
+ task.Actions[0].Arguments = action.arguments;
157
+ for (const { foreign, legacyDirectAction } of [{ foreign: false, legacyDirectAction: false },
158
+ { foreign: true, legacyDirectAction: false }, { foreign: false, legacyDirectAction: true }]) {
159
+ const rejected = foreign || legacyDirectAction;
160
+ const taskFixture = structuredClone(task);
161
+ if (legacyDirectAction) {
162
+ taskFixture.Actions[0].Execute = receipt.executable;
163
+ taskFixture.Actions[0].Arguments = receipt.arguments;
164
+ }
165
+ const script = `$ErrorActionPreference='Stop';$current=[System.Security.Principal.WindowsIdentity]::GetCurrent(); `
166
+ + `$fixturePrincipalSid=${foreign ? "'S-1-5-18'" : '$current.User.Value'}; `
167
+ + `function Export-ScheduledTask { '<Task><Principals><Principal><UserId>'+$fixturePrincipalSid+'</UserId></Principal></Principals></Task>' }; `
168
+ + `$task=ConvertFrom-Json ([Console]::In.ReadToEnd());$task.Principal.UserId=($current.Name -split '\\\\')[-1]; `
169
+ + `$task.Triggers[0].UserId=$current.Name; ${guard}; `
170
+ + `try{Assert-OwnedTask $task;[Console]::Out.Write('owned')}catch{[Console]::Out.Write('refused');`
171
+ + `if(!${rejected ? '$true' : '$false'}){[Console]::Error.Write($_.Exception.Message)}}`;
172
+ const result = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(script, 'utf16le').toString('base64')], { input: JSON.stringify(taskFixture), encoding: 'utf8', timeout: 15000, windowsHide: true });
173
+ assert.equal(result.status, 0, result.stderr);
174
+ assert.equal(result.stdout, rejected ? 'refused' : 'owned', result.stderr);
175
+ }
176
+ });
177
+ test('a foreign WSL host task is refused before startup registration writes', async (t) => {
178
+ const f = await fixture(t);
179
+ f.foreignTask();
180
+ await assert.rejects(assertRelayStartupOwnership(f.options), /autostart_conflict/);
181
+ await assert.rejects(enableRelayAutostart(f.options), /autostart_conflict/);
182
+ assert(!f.scripts.some(script => script.includes('dharma-wsl-host:register')));
183
+ await assert.rejects(readFile(join(f.options.home, 'relay', 'autostart.json')), { code: 'ENOENT' });
184
+ });
185
+ test('a lost registration response preserves ownership and readback reconciles without replacement', async (t) => {
186
+ const f = await fixture(t);
187
+ f.loseResponse();
188
+ await assert.rejects(enableRelayAutostart(f.options), /wsl_host_startup_unavailable/);
189
+ assert.equal((await relayAutostartStatus(f.options)).state, 'enabled');
190
+ const before = f.scripts.filter(script => script.includes('dharma-wsl-host:register')).length;
191
+ await enableRelayAutostart(f.options);
192
+ assert.equal(f.scripts.filter(script => script.includes('dharma-wsl-host:register')).length, before);
193
+ });
194
+ test('changed WSL recipient and injected host fields cannot be adopted, started or disabled', async (t) => {
195
+ const f = await fixture(t);
196
+ await enableRelayAutostart(f.options);
197
+ const path = join(f.options.home, 'relay', 'wsl-host.json');
198
+ const original = await readFile(path, 'utf8');
199
+ const record = JSON.parse(original);
200
+ for (const delta of [{ windowsSid: 'S-1-5-21-123-456-789-9001' }, { arguments: 'arbitrary.exe' },
201
+ { distribution: 'foreign' }, { extra: 'CANARY_PRIVATE_MATERIAL' }]) {
202
+ await writeFile(path, JSON.stringify({ ...record, ...delta }));
203
+ f.scripts.length = 0;
204
+ assert.equal((await relayAutostartStatus(f.options)).state, 'unavailable');
205
+ await assert.rejects(startRelayAutostart(f.options), /autostart_conflict|unavailable/);
206
+ await assert.rejects(disableRelayAutostart(f.options), /autostart_conflict|unavailable/);
207
+ assert(!f.scripts.some(script => /dharma-wsl-host:(register|start|disable)/.test(script)));
208
+ }
209
+ });
210
+ test('unavailable WSL interop and malformed distro metadata fail before startup writes', async (t) => {
211
+ const f = await fixture(t);
212
+ const badContexts = [{ distribution: 'Ubuntu"; cmd', linuxUser: 'maatru' },
213
+ { distribution: 'Ubuntu\n', linuxUser: 'maatru' }, { distribution: 'Ubuntu', linuxUser: 'maatru;cmd' }];
214
+ for (const current of badContexts) {
215
+ await assert.rejects(enableRelayAutostart({ ...f.options, wslHost: { ...f.options.wslHost,
216
+ context: async () => current } }), /wsl_host_startup_unavailable/);
217
+ }
218
+ await assert.rejects(enableRelayAutostart({ ...f.options, wslHost: { ...f.options.wslHost,
219
+ run: async () => { throw new Error('interop unavailable'); } } }), /wsl_host_startup_unavailable/);
220
+ await assert.rejects(readFile(join(f.options.home, 'relay', 'autostart.json')), { code: 'ENOENT' });
221
+ assert.deepEqual(f.scripts, []);
222
+ });
223
+ test('WSL cannot report complete startup coverage after its host receipt is lost', async (t) => {
224
+ const { options } = await fixture(t);
225
+ await enableRelayAutostart(options);
226
+ await rm(join(options.home, 'relay', 'wsl-host.json'), { force: true });
227
+ const status = await relayAutostartStatus(options);
228
+ assert.equal(status.state, 'unavailable');
229
+ assert.equal(status.reason, 'wsl_host_startup_unavailable');
230
+ });
231
+ test('bare Linux startup does not query or register any Windows host task', async (t) => {
232
+ const { options, scripts } = await fixture(t);
233
+ const bare = { ...options, wslHost: { ...options.wslHost, context: async () => null } };
234
+ await enableRelayAutostart(bare);
235
+ assert.equal((await relayAutostartStatus(bare)).state, 'enabled');
236
+ assert.deepEqual(scripts, []);
237
+ });
238
+ test('injected OS controls also contain Windows interop instead of escaping through a real runner', async (t) => {
239
+ const f = await fixture(t);
240
+ const seen = [];
241
+ const options = { ...f.options, wslHost: { context: f.options.wslHost.context },
242
+ run: async (file, args) => {
243
+ seen.push(file);
244
+ if (file === 'systemctl')
245
+ return { stdout: 'enabled\n' };
246
+ assert.equal(file, '/init');
247
+ return f.options.wslHost.run(Buffer.from(args.at(-1), 'base64').toString('utf16le'));
248
+ } };
249
+ await enableRelayAutostart(options);
250
+ assert(seen.includes('/init'));
251
+ });
252
+ test('withdrawal during WSL registration preserves the receipt but admits no later OS action', async (t) => {
253
+ const f = await fixture(t), controller = new AbortController(), now = Date.now();
254
+ const prepared = prepareCodexBootstrapHost({ workspace: f.options.userHome, signal: controller.signal, current: async () => true,
255
+ intent: { schema: 'dharma.codex-setup-intent/v1', operationId: '11111111-1111-4111-8111-111111111111',
256
+ setupReference: '22222222-2222-4222-8222-222222222222', organizationId: 'org_demo',
257
+ recipientMembershipId: '33333333-3333-4333-8333-333333333333', origin: 'https://hq.example',
258
+ repositoryFingerprint: `sha256:${'a'.repeat(64)}`, policyRevision: 'policy-v1',
259
+ scopeDigest: `sha256:${'a'.repeat(64)}`, contractDigest: `sha256:${'b'.repeat(64)}`,
260
+ hostContextId: '44444444-4444-4444-8444-444444444444', issuedAt: new Date(now - 1000).toISOString(),
261
+ expiresAt: new Date(now + 60000).toISOString() } });
262
+ t.after(() => prepared.scope.close());
263
+ const options = { ...f.options, wslHost: { ...f.options.wslHost, run: async (script) => {
264
+ const result = await f.options.wslHost.run(script);
265
+ if (script.includes('dharma-wsl-host:register'))
266
+ controller.abort();
267
+ return result;
268
+ } } };
269
+ await assert.rejects(runCodexBootstrapHostScope(prepared.scope, () => enableRelayAutostart(options)), /scope_unavailable/);
270
+ assert(f.scripts.at(-1)?.includes('dharma-wsl-host:register'));
271
+ assert.equal(JSON.parse(await readFile(join(options.home, 'relay', 'wsl-host.json'), 'utf8')).schema, 'dharma.wsl-relay-host/v1');
272
+ });
273
+ test('WSL systemd startup resolves missing session metadata only from its owned binding', () => {
274
+ const installed = { schema: 'dharma.wsl-relay-host/v1', distribution: 'Ubuntu', linuxUser: 'maatru' };
275
+ assert.deepEqual(resolveWslRelayContext(undefined, 'maatru', installed), { distribution: 'Ubuntu', linuxUser: 'maatru' });
276
+ for (const value of [null, {}, { ...installed, linuxUser: 'other' }, { ...installed, distribution: 'Ubuntu\n' }]) {
277
+ assert.throws(() => resolveWslRelayContext(undefined, 'maatru', value), /wsl_host_startup_unavailable/);
278
+ }
279
+ });
280
+ test('WSL host receipt schema excludes secrets and unbounded command authority', async (t) => {
281
+ const f = await fixture(t);
282
+ await enableRelayAutostart(f.options);
283
+ const record = JSON.parse(await readFile(join(f.options.home, 'relay', 'wsl-host.json'), 'utf8'));
284
+ const schema = 'https://schemas.dharma-ai.io/wsl-relay-host/v1';
285
+ const validate = (value) => validateContract(join(import.meta.dirname, 'schemas'), schema, value);
286
+ assert.equal((await validate(record)).ok, true);
287
+ for (const delta of [{ token: 'CANARY_NEVER_ALLOWED' }, { password: 'CANARY_NEVER_ALLOWED' },
288
+ { arguments: 'arbitrary.exe' }, { windowsSid: '*' }, { linuxUser: 'user;cmd' }]) {
289
+ assert.equal((await validate({ ...record, ...delta })).ok, false);
290
+ }
291
+ });
292
+ test('generated WSL host commands pass the actual Windows PowerShell parser without execution', { skip: process.platform !== 'win32' }, async (t) => {
293
+ const f = await fixture(t);
294
+ await enableRelayAutostart(f.options);
295
+ await startRelayAutostart(f.options);
296
+ await disableRelayAutostart(f.options);
297
+ const script = `$items=ConvertFrom-Json ([Console]::In.ReadToEnd()); `
298
+ + `foreach($item in $items) {$tokens=$null;$errors=$null; `
299
+ + `[System.Management.Automation.Language.Parser]::ParseInput($item,[ref]$tokens,[ref]$errors)|Out-Null; `
300
+ + `if ($errors.Count -gt 0) {[Console]::Error.Write('generated_wsl_host_parse_error');exit 1}}; `
301
+ + `[Console]::Out.Write($items.Count)`;
302
+ const result = spawnSync('powershell.exe', ['-NoLogo', '-NoProfile', '-NonInteractive', '-EncodedCommand',
303
+ Buffer.from(script, 'utf16le').toString('base64')], { input: JSON.stringify(f.scripts), encoding: 'utf8', timeout: 15000, windowsHide: true, maxBuffer: 16384 });
304
+ assert.equal(result.error, undefined);
305
+ assert.equal(result.status, 0, result.stderr);
306
+ assert.equal(Number(result.stdout), f.scripts.length);
307
+ });
308
+ //# sourceMappingURL=wslRelayHost.test.js.map