agents-bridge 0.3.9 → 0.3.11
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/agents/cli-runner.d.ts.map +1 -1
- package/dist/agents/cli-runner.js +5 -29
- package/dist/agents/cli-runner.js.map +1 -1
- package/dist/agents/codex-app-server-runtime.d.ts.map +1 -1
- package/dist/agents/codex-app-server-runtime.js +4 -3
- package/dist/agents/codex-app-server-runtime.js.map +1 -1
- package/dist/agents/model-control-files.d.ts +10 -4
- package/dist/agents/model-control-files.d.ts.map +1 -1
- package/dist/agents/model-control-files.js +127 -79
- package/dist/agents/model-control-files.js.map +1 -1
- package/dist/agents/platform-spawn.d.ts +2 -0
- package/dist/agents/platform-spawn.d.ts.map +1 -0
- package/dist/agents/platform-spawn.js +4 -0
- package/dist/agents/platform-spawn.js.map +1 -0
- package/dist/agents/process-tree.d.ts +4 -0
- package/dist/agents/process-tree.d.ts.map +1 -0
- package/dist/agents/process-tree.js +46 -0
- package/dist/agents/process-tree.js.map +1 -0
- package/dist/agents/trusted-launcher.d.ts.map +1 -1
- package/dist/agents/trusted-launcher.js +7 -3
- package/dist/agents/trusted-launcher.js.map +1 -1
- package/dist/agents/windows-model-control-security.d.ts +4 -0
- package/dist/agents/windows-model-control-security.d.ts.map +1 -0
- package/dist/agents/windows-model-control-security.js +116 -0
- package/dist/agents/windows-model-control-security.js.map +1 -0
- package/dist/channels/botlink.d.ts.map +1 -1
- package/dist/channels/botlink.js +3 -1
- package/dist/channels/botlink.js.map +1 -1
- package/dist/cli/cmd-start.d.ts.map +1 -1
- package/dist/cli/cmd-start.js +12 -8
- package/dist/cli/cmd-start.js.map +1 -1
- package/dist/cli/cmd-stop.d.ts.map +1 -1
- package/dist/cli/cmd-stop.js +2 -1
- package/dist/cli/cmd-stop.js.map +1 -1
- package/dist/cli/cmd-update.d.ts +1 -0
- package/dist/cli/cmd-update.d.ts.map +1 -1
- package/dist/cli/cmd-update.js +3 -2
- package/dist/cli/cmd-update.js.map +1 -1
- package/dist/cli/temporary-files.d.ts +8 -0
- package/dist/cli/temporary-files.d.ts.map +1 -0
- package/dist/cli/temporary-files.js +43 -0
- package/dist/cli/temporary-files.js.map +1 -0
- package/dist/cli/update-check.d.ts.map +1 -1
- package/dist/cli/update-check.js +3 -2
- package/dist/cli/update-check.js.map +1 -1
- package/dist/cloud/main.js +2 -0
- package/dist/cloud/main.js.map +1 -1
- package/dist/config/attachment-handoff.d.ts.map +1 -1
- package/dist/config/attachment-handoff.js +12 -8
- package/dist/config/attachment-handoff.js.map +1 -1
- package/dist/config/paths.d.ts.map +1 -1
- package/dist/config/paths.js +2 -1
- package/dist/config/paths.js.map +1 -1
- package/dist/config/platform-paths.d.ts +6 -0
- package/dist/config/platform-paths.d.ts.map +1 -0
- package/dist/config/platform-paths.js +29 -0
- package/dist/config/platform-paths.js.map +1 -0
- package/dist/config/zod-schema.d.ts +2 -2
- package/dist/config/zod-schema.d.ts.map +1 -1
- package/dist/config/zod-schema.js +2 -1
- package/dist/config/zod-schema.js.map +1 -1
- package/dist/runtime-activity-snapshot.d.ts.map +1 -1
- package/dist/runtime-activity-snapshot.js +2 -0
- package/dist/runtime-activity-snapshot.js.map +1 -1
- package/package.json +7 -3
- package/scripts/windows-smoke.mjs +98 -0
|
@@ -2,100 +2,148 @@ import { constants } from 'node:fs';
|
|
|
2
2
|
import { lstat, mkdir, open, realpath, rename, unlink } from 'node:fs/promises';
|
|
3
3
|
import { dirname, resolve } from 'node:path';
|
|
4
4
|
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { ensureWindowsModelControlSecurity, sameWindowsModelControlPath } from './windows-model-control-security.js';
|
|
5
6
|
const MAX_MODEL_CONTROL_FILE_BYTES = 64 * 1024;
|
|
6
7
|
function expectedUid() {
|
|
7
8
|
return typeof process.geteuid === 'function' ? process.geteuid() : typeof process.getuid === 'function' ? process.getuid() : undefined;
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if ((info.mode & 0o777) !== 0o600)
|
|
31
|
-
throw new Error('INSECURE_MODEL_CONTROL_FILE_MODE');
|
|
32
|
-
if (info.size > MAX_MODEL_CONTROL_FILE_BYTES)
|
|
33
|
-
throw new Error('MODEL_CONTROL_FILE_TOO_LARGE');
|
|
34
|
-
}
|
|
35
|
-
export async function readSecureModelControlFile(path) {
|
|
36
|
-
await ensureSecureModelControlDirectory(dirname(path));
|
|
37
|
-
const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
38
|
-
try {
|
|
39
|
-
await validateOpenFile(file);
|
|
40
|
-
return await file.readFile('utf8');
|
|
41
|
-
}
|
|
42
|
-
finally {
|
|
43
|
-
await file.close();
|
|
10
|
+
// The explicit platform/security dependencies let non-Windows CI exercise the
|
|
11
|
+
// complete Windows IO lifecycle without claiming native ACL/OS acceptance.
|
|
12
|
+
export function createModelControlFileAccess({ platform = process.platform, windowsSecurity = ensureWindowsModelControlSecurity, } = {}) {
|
|
13
|
+
const windows = platform === 'win32';
|
|
14
|
+
const noFollow = windows ? 0 : constants.O_NOFOLLOW;
|
|
15
|
+
async function ensureSecureModelControlDirectory(path) {
|
|
16
|
+
const directory = resolve(path);
|
|
17
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
18
|
+
const info = await lstat(directory);
|
|
19
|
+
if (!info.isDirectory() || info.isSymbolicLink())
|
|
20
|
+
throw new Error('INSECURE_MODEL_CONTROL_DIRECTORY');
|
|
21
|
+
const uid = expectedUid();
|
|
22
|
+
if (!windows && uid !== undefined && info.uid !== uid)
|
|
23
|
+
throw new Error('INSECURE_MODEL_CONTROL_DIRECTORY_OWNER');
|
|
24
|
+
if (!windows && (info.mode & 0o022) !== 0)
|
|
25
|
+
throw new Error('INSECURE_MODEL_CONTROL_DIRECTORY_MODE');
|
|
26
|
+
const canonical = await realpath(directory);
|
|
27
|
+
if (windows ? !sameWindowsModelControlPath(canonical, directory) : canonical !== directory)
|
|
28
|
+
throw new Error('INSECURE_MODEL_CONTROL_DIRECTORY_PATH');
|
|
29
|
+
if (windows)
|
|
30
|
+
await windowsSecurity(directory, 'directory');
|
|
44
31
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
32
|
+
async function validateOpenFile(file, path) {
|
|
33
|
+
const info = await file.stat();
|
|
34
|
+
if (!info.isFile() || info.isSymbolicLink())
|
|
35
|
+
throw new Error('INSECURE_MODEL_CONTROL_FILE_TYPE');
|
|
36
|
+
const uid = expectedUid();
|
|
37
|
+
if (!windows && uid !== undefined && info.uid !== uid)
|
|
38
|
+
throw new Error('INSECURE_MODEL_CONTROL_FILE_OWNER');
|
|
39
|
+
if (!windows && (info.mode & 0o777) !== 0o600)
|
|
40
|
+
throw new Error('INSECURE_MODEL_CONTROL_FILE_MODE');
|
|
41
|
+
if (info.size > MAX_MODEL_CONTROL_FILE_BYTES)
|
|
42
|
+
throw new Error('MODEL_CONTROL_FILE_TOO_LARGE');
|
|
43
|
+
if (windows) {
|
|
44
|
+
const entry = await lstat(path);
|
|
45
|
+
if (!entry.isFile() || entry.isSymbolicLink() || entry.dev !== info.dev || entry.ino !== info.ino || entry.nlink !== 1)
|
|
46
|
+
throw new Error('INSECURE_MODEL_CONTROL_FILE_TYPE');
|
|
47
|
+
const canonical = await realpath(path);
|
|
48
|
+
if (!sameWindowsModelControlPath(canonical, resolve(path)))
|
|
49
|
+
throw new Error('INSECURE_MODEL_CONTROL_FILE_PATH');
|
|
50
|
+
await windowsSecurity(path, 'file');
|
|
51
|
+
}
|
|
53
52
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
async function openExisting(path) {
|
|
54
|
+
// O_NOFOLLOW is unavailable on Windows. Check before opening, then compare
|
|
55
|
+
// the opened file's identity to lstat before reading any secret bytes.
|
|
56
|
+
if (windows) {
|
|
57
|
+
const entry = await lstat(path);
|
|
58
|
+
if (!entry.isFile() || entry.isSymbolicLink())
|
|
59
|
+
throw new Error('INSECURE_MODEL_CONTROL_FILE_TYPE');
|
|
60
|
+
}
|
|
61
|
+
return open(path, constants.O_RDONLY | noFollow);
|
|
63
62
|
}
|
|
64
|
-
|
|
65
|
-
await
|
|
63
|
+
async function readSecureModelControlFile(path) {
|
|
64
|
+
await ensureSecureModelControlDirectory(dirname(path));
|
|
65
|
+
const file = await openExisting(path);
|
|
66
|
+
try {
|
|
67
|
+
await validateOpenFile(file, path);
|
|
68
|
+
return await file.readFile('utf8');
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
await file.close();
|
|
72
|
+
}
|
|
66
73
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
74
|
+
async function syncDirectory(path) {
|
|
75
|
+
// Node cannot open/fsync a Windows directory with these POSIX flags.
|
|
76
|
+
// File contents are still fsynced before close/atomic rename below.
|
|
77
|
+
if (windows)
|
|
78
|
+
return;
|
|
79
|
+
const directory = await open(path, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
73
80
|
try {
|
|
74
|
-
await
|
|
81
|
+
await directory.sync();
|
|
75
82
|
}
|
|
76
83
|
finally {
|
|
77
|
-
await
|
|
84
|
+
await directory.close();
|
|
78
85
|
}
|
|
79
86
|
}
|
|
80
|
-
|
|
81
|
-
if (
|
|
87
|
+
async function createSecureModelControlFile(path, contents) {
|
|
88
|
+
if (Buffer.byteLength(contents, 'utf8') > MAX_MODEL_CONTROL_FILE_BYTES)
|
|
89
|
+
throw new Error('MODEL_CONTROL_FILE_TOO_LARGE');
|
|
90
|
+
await ensureSecureModelControlDirectory(dirname(path));
|
|
91
|
+
const file = await open(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | noFollow, 0o600);
|
|
92
|
+
try {
|
|
93
|
+
await validateOpenFile(file, path);
|
|
94
|
+
await file.writeFile(contents);
|
|
95
|
+
await validateOpenFile(file, path);
|
|
96
|
+
await file.sync();
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
await file.close().catch(() => undefined);
|
|
100
|
+
await unlink(path).catch(() => undefined);
|
|
82
101
|
throw error;
|
|
102
|
+
}
|
|
103
|
+
await file.close();
|
|
104
|
+
await syncDirectory(dirname(path));
|
|
83
105
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
await
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
106
|
+
async function writeSecureModelControlFile(path, contents) {
|
|
107
|
+
if (Buffer.byteLength(contents, 'utf8') > MAX_MODEL_CONTROL_FILE_BYTES)
|
|
108
|
+
throw new Error('MODEL_CONTROL_FILE_TOO_LARGE');
|
|
109
|
+
await ensureSecureModelControlDirectory(dirname(path));
|
|
110
|
+
try {
|
|
111
|
+
const existing = await openExisting(path);
|
|
112
|
+
try {
|
|
113
|
+
await validateOpenFile(existing, path);
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
await existing.close();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
if (error?.code !== 'ENOENT')
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
const temporaryPath = `${path}.${randomUUID()}.tmp`;
|
|
124
|
+
const file = await open(temporaryPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | noFollow, 0o600);
|
|
125
|
+
try {
|
|
126
|
+
await validateOpenFile(file, temporaryPath);
|
|
127
|
+
await file.writeFile(contents);
|
|
128
|
+
await validateOpenFile(file, temporaryPath);
|
|
129
|
+
await file.sync();
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
await file.close().catch(() => undefined);
|
|
133
|
+
await unlink(temporaryPath).catch(() => undefined);
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
await file.close();
|
|
137
|
+
try {
|
|
138
|
+
await rename(temporaryPath, path);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
await unlink(temporaryPath).catch(() => undefined);
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
await syncDirectory(dirname(path));
|
|
96
145
|
}
|
|
97
|
-
|
|
98
|
-
await rename(temporaryPath, path);
|
|
99
|
-
await syncDirectory(dirname(path));
|
|
146
|
+
return { ensureSecureModelControlDirectory, readSecureModelControlFile, createSecureModelControlFile, writeSecureModelControlFile };
|
|
100
147
|
}
|
|
148
|
+
export const { ensureSecureModelControlDirectory, readSecureModelControlFile, createSecureModelControlFile, writeSecureModelControlFile, } = createModelControlFileAccess();
|
|
101
149
|
//# sourceMappingURL=model-control-files.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-control-files.js","sourceRoot":"","sources":["../../src/agents/model-control-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC/E,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"model-control-files.js","sourceRoot":"","sources":["../../src/agents/model-control-files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-spawn.d.ts","sourceRoot":"","sources":["../../src/agents/platform-spawn.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,KAAK,sCAAmB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-spawn.js","sourceRoot":"","sources":["../../src/agents/platform-spawn.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,aAAa,CAAA;AAEpC,gFAAgF;AAChF,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ChildProcess } from 'node:child_process';
|
|
2
|
+
export declare function terminateProcess(pid: number, signal?: NodeJS.Signals, platform?: NodeJS.Platform): Promise<void>;
|
|
3
|
+
export declare function terminateChildProcess(child: ChildProcess): void;
|
|
4
|
+
//# sourceMappingURL=process-tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-tree.d.ts","sourceRoot":"","sources":["../../src/agents/process-tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGhE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,OAAmB,EAAE,QAAQ,kBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAc5H;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAM/D"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { win32 } from 'node:path';
|
|
3
|
+
export function terminateProcess(pid, signal = 'SIGTERM', platform = process.platform) {
|
|
4
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
5
|
+
return Promise.reject(new Error('Invalid owned process id'));
|
|
6
|
+
if (platform !== 'win32') {
|
|
7
|
+
try {
|
|
8
|
+
process.kill(pid, signal);
|
|
9
|
+
return Promise.resolve();
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
return Promise.reject(error);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
// Node kills only the cmd.exe shim on Windows; taskkill /T also stops the
|
|
16
|
+
// owned CLI descendant. Never pass a process name, wildcard, or a shell.
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
execFile(win32.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'taskkill.exe'), ['/PID', String(pid), '/T', '/F'], { windowsHide: true }, error => {
|
|
19
|
+
if (!error) {
|
|
20
|
+
resolve();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
process.kill(pid, 0);
|
|
25
|
+
}
|
|
26
|
+
catch (gone) {
|
|
27
|
+
reject(gone);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
reject(error);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export function terminateChildProcess(child) {
|
|
35
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
36
|
+
return;
|
|
37
|
+
if (process.platform !== 'win32' || !child.pid) {
|
|
38
|
+
child.kill();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
void terminateProcess(child.pid).catch(() => {
|
|
42
|
+
if (child.exitCode === null && child.signalCode === null)
|
|
43
|
+
child.kill();
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=process-tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-tree.js","sourceRoot":"","sources":["../../src/agents/process-tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAqB,MAAM,oBAAoB,CAAA;AAChE,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAA;AAEjC,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,SAAyB,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ;IAC3G,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAA;IACxG,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,IAAI,CAAC;YAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAAC,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;QAAC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAAC,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAAC,CAAC;IAC5G,CAAC;IACD,0EAA0E;IAC1E,yEAAyE;IACzE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,aAAa,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,KAAK,CAAC,EAAE;YAC1J,IAAI,CAAC,KAAK,EAAE,CAAC;gBAAC,OAAO,EAAE,CAAC;gBAAC,OAAM;YAAC,CAAC;YACjC,IAAI,CAAC;gBAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;YAAC,CAAC;YAAC,OAAO,IAAI,EAAE,CAAC;gBAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAAC,OAAM;YAAC,CAAC;YAClE,MAAM,CAAC,KAAK,CAAC,CAAA;QACf,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAmB;IACvD,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI;QAAE,OAAM;IAChE,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAAC,OAAM;IAAC,CAAC;IACxE,KAAK,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QAC1C,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI;YAAE,KAAK,CAAC,IAAI,EAAE,CAAA;IACxE,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trusted-launcher.d.ts","sourceRoot":"","sources":["../../src/agents/trusted-launcher.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;IACtB,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CACxB,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"trusted-launcher.d.ts","sourceRoot":"","sources":["../../src/agents/trusted-launcher.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;IACtB,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CACxB,GAAG,YAAY,CAuBf"}
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
-
import { basename, relative, resolve } from 'node:path';
|
|
2
|
+
import { basename, relative, resolve, sep } from 'node:path';
|
|
3
3
|
export function resolveTrustedSpawn(input) {
|
|
4
4
|
const cwd = resolve(input.cwd ?? process.cwd());
|
|
5
5
|
const launcherSocket = process.env.RUNTIME_LAUNCHER_SOCKET;
|
|
6
6
|
if (!launcherSocket) {
|
|
7
|
-
|
|
7
|
+
// Consumers use cross-spawn for Windows npm shims. Enabling shell here
|
|
8
|
+
// would bypass its escaping and break paths/user arguments containing spaces.
|
|
9
|
+
return { command: input.command, args: input.args, cwd, env: input.env ?? process.env, shell: false };
|
|
8
10
|
}
|
|
11
|
+
if (process.platform === 'win32')
|
|
12
|
+
throw new Error('TRUSTED_RUNTIME_LAUNCHER_REQUIRES_LINUX');
|
|
9
13
|
const profile = profileForCommand(input.command);
|
|
10
14
|
if (!profile)
|
|
11
15
|
throw new Error('CLI executable is not authorized by the trusted launcher');
|
|
12
16
|
const workspace = resolve(process.env.WORKSPACE_ROOT ?? '/workspace');
|
|
13
17
|
const cwdRel = relative(workspace, cwd) || '.';
|
|
14
|
-
if (cwdRel === '..' || cwdRel.startsWith(`..${
|
|
18
|
+
if (cwdRel === '..' || cwdRel.startsWith(`..${sep}`)) {
|
|
15
19
|
throw new Error('CLI working directory is outside the trusted workspace');
|
|
16
20
|
}
|
|
17
21
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trusted-launcher.js","sourceRoot":"","sources":["../../src/agents/trusted-launcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"trusted-launcher.js","sourceRoot":"","sources":["../../src/agents/trusted-launcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function sameWindowsModelControlPath(left: string, right: string): boolean;
|
|
2
|
+
export declare function validateWindowsModelControlAcl(value: unknown, kind?: 'directory' | 'file'): void;
|
|
3
|
+
export declare function ensureWindowsModelControlSecurity(path: string, kind?: 'directory' | 'file'): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=windows-model-control-security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows-model-control-security.d.ts","sourceRoot":"","sources":["../../src/agents/windows-model-control-security.ts"],"names":[],"mappings":"AAuDA,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEhF;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,GAAE,WAAW,GAAG,MAAe,GAAG,IAAI,CA+BxG;AAED,wBAAsB,iCAAiC,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,WAAW,GAAG,MAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBxH"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { win32 } from 'node:path';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
const execute = promisify(execFile);
|
|
5
|
+
const TRUSTED_SYSTEM_SIDS = new Set(['S-1-5-18', 'S-1-5-32-544']); // SYSTEM, Administrators
|
|
6
|
+
// Use SIDs rather than localized account names. Inspect inherited ACEs too; a
|
|
7
|
+
// Unix mode returned by stat on Windows says nothing about the actual DACL.
|
|
8
|
+
const INSPECT_ACL = `
|
|
9
|
+
$ErrorActionPreference = 'Stop'
|
|
10
|
+
$item = Get-Item -LiteralPath $env:AGENTS_BRIDGE_ACL_TARGET -Force
|
|
11
|
+
$cursor = $item
|
|
12
|
+
while ($null -ne $cursor) {
|
|
13
|
+
if (($cursor.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) { throw 'MODEL_CONTROL_REPARSE_POINT' }
|
|
14
|
+
if ($cursor -is [IO.DirectoryInfo]) { $cursor = $cursor.Parent } else { $cursor = $cursor.Directory }
|
|
15
|
+
}
|
|
16
|
+
$acl = Get-Acl -LiteralPath $env:AGENTS_BRIDGE_ACL_TARGET
|
|
17
|
+
$current = [Security.Principal.WindowsIdentity]::GetCurrent().User.Value
|
|
18
|
+
$owner = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
|
|
19
|
+
if ($env:AGENTS_BRIDGE_ACL_KIND -eq 'file') {
|
|
20
|
+
if ($item -isnot [IO.FileInfo] -or $owner -notin @($current, 'S-1-5-18', 'S-1-5-32-544')) { throw 'MODEL_CONTROL_UNTRUSTED_OWNER' }
|
|
21
|
+
# Only model-control files are privatized, before any secret bytes are read
|
|
22
|
+
# or written. Never change a parent directory or a user's workspace ACL.
|
|
23
|
+
$needsPrivacy = $false
|
|
24
|
+
foreach ($rule in @($acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier]))) {
|
|
25
|
+
if ($rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and $rule.IdentityReference.Value -notin @($current, 'S-1-5-18', 'S-1-5-32-544') -and [long]$rule.FileSystemRights -ne 0) { $needsPrivacy = $true }
|
|
26
|
+
}
|
|
27
|
+
if ($needsPrivacy) {
|
|
28
|
+
$acl.SetAccessRuleProtection($true, $false)
|
|
29
|
+
foreach ($rule in @($acl.GetAccessRules($true, $false, [Security.Principal.SecurityIdentifier]))) { [void]$acl.RemoveAccessRuleSpecific($rule) }
|
|
30
|
+
foreach ($sid in @($current, 'S-1-5-18', 'S-1-5-32-544')) {
|
|
31
|
+
$identity = [Security.Principal.SecurityIdentifier]::new($sid)
|
|
32
|
+
$rule = [Security.AccessControl.FileSystemAccessRule]::new($identity, [Security.AccessControl.FileSystemRights]::FullControl, [Security.AccessControl.AccessControlType]::Allow)
|
|
33
|
+
[void]$acl.AddAccessRule($rule)
|
|
34
|
+
}
|
|
35
|
+
Set-Acl -LiteralPath $env:AGENTS_BRIDGE_ACL_TARGET -AclObject $acl
|
|
36
|
+
$acl = Get-Acl -LiteralPath $env:AGENTS_BRIDGE_ACL_TARGET
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
$rules = @($acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier]) | ForEach-Object {
|
|
40
|
+
@{
|
|
41
|
+
sid = $_.IdentityReference.Value
|
|
42
|
+
allow = ($_.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow)
|
|
43
|
+
rights = [long]$_.FileSystemRights
|
|
44
|
+
inheritOnly = (($_.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -ne 0)
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
@{
|
|
48
|
+
currentSid = [Security.Principal.WindowsIdentity]::GetCurrent().User.Value
|
|
49
|
+
ownerSid = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
|
|
50
|
+
rules = $rules
|
|
51
|
+
} | ConvertTo-Json -Depth 4 -Compress
|
|
52
|
+
`;
|
|
53
|
+
export function sameWindowsModelControlPath(left, right) {
|
|
54
|
+
return win32.normalize(left).toLowerCase() === win32.normalize(right).toLowerCase();
|
|
55
|
+
}
|
|
56
|
+
export function validateWindowsModelControlAcl(value, kind = 'file') {
|
|
57
|
+
const invalid = (detail = 'invalid ACL data') => new Error(`INSECURE_MODEL_CONTROL_WINDOWS_ACL: ${kind}: ${detail}`);
|
|
58
|
+
if (!value || typeof value !== 'object')
|
|
59
|
+
throw invalid();
|
|
60
|
+
const acl = value;
|
|
61
|
+
if (typeof acl.currentSid !== 'string' || !/^S-1-\d+(?:-\d+)+$/.test(acl.currentSid)
|
|
62
|
+
|| typeof acl.ownerSid !== 'string' || !Array.isArray(acl.rules))
|
|
63
|
+
throw invalid();
|
|
64
|
+
const trusted = new Set([acl.currentSid, ...TRUSTED_SYSTEM_SIDS]);
|
|
65
|
+
if (!trusted.has(acl.ownerSid))
|
|
66
|
+
throw invalid(`untrusted owner ${acl.ownerSid}`);
|
|
67
|
+
let effectiveAllow = false;
|
|
68
|
+
for (const entry of acl.rules) {
|
|
69
|
+
if (!entry || typeof entry !== 'object')
|
|
70
|
+
throw invalid();
|
|
71
|
+
const rule = entry;
|
|
72
|
+
if (typeof rule.sid !== 'string' || typeof rule.allow !== 'boolean'
|
|
73
|
+
|| typeof rule.inheritOnly !== 'boolean' || typeof rule.rights !== 'number'
|
|
74
|
+
|| !Number.isSafeInteger(rule.rights) || rule.rights < -0x80000000 || rule.rights > 0xffffffff)
|
|
75
|
+
throw invalid();
|
|
76
|
+
if (!rule.allow || rule.rights === 0)
|
|
77
|
+
continue;
|
|
78
|
+
// Inherit-only grants still expose newly created state/temporary files.
|
|
79
|
+
if (!trusted.has(rule.sid) && !(rule.sid === 'S-1-3-0' && rule.inheritOnly)) {
|
|
80
|
+
// Match the POSIX directory policy: listing/traversal is safe; creating,
|
|
81
|
+
// replacing, deleting or changing permissions is not. Inherited file
|
|
82
|
+
// grants are removed by the private-file policy before accessing bytes.
|
|
83
|
+
// ReadData/ReadEA/Execute/ReadAttributes/ReadControl/Synchronize plus
|
|
84
|
+
// GenericRead/GenericExecute. Reject unknown rights as well as writes.
|
|
85
|
+
const outsideReadRights = (rule.rights >>> 0) & ~0xa01200a9;
|
|
86
|
+
if (kind === 'file' || (!rule.inheritOnly && outsideReadRights !== 0))
|
|
87
|
+
throw invalid(`unsafe allow ${rule.sid} rights=${rule.rights}`);
|
|
88
|
+
}
|
|
89
|
+
if (!rule.inheritOnly)
|
|
90
|
+
effectiveAllow = true;
|
|
91
|
+
}
|
|
92
|
+
// Also rejects empty/missing and null DACL representations rather than
|
|
93
|
+
// treating "no rules returned" as proof of privacy.
|
|
94
|
+
if (!effectiveAllow)
|
|
95
|
+
throw invalid();
|
|
96
|
+
}
|
|
97
|
+
export async function ensureWindowsModelControlSecurity(path, kind = 'file') {
|
|
98
|
+
const executable = win32.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
|
|
99
|
+
let snapshot;
|
|
100
|
+
try {
|
|
101
|
+
const { stdout } = await execute(executable, [
|
|
102
|
+
'-NoLogo', '-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(INSPECT_ACL, 'utf16le').toString('base64'),
|
|
103
|
+
], {
|
|
104
|
+
env: { ...process.env, AGENTS_BRIDGE_ACL_TARGET: path, AGENTS_BRIDGE_ACL_KIND: kind },
|
|
105
|
+
windowsHide: true, timeout: 10_000, maxBuffer: 128 * 1024,
|
|
106
|
+
});
|
|
107
|
+
snapshot = JSON.parse(stdout.replace(/^\uFEFF/, '').trim());
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Do not include shell output, environment, or a control-file path in logs.
|
|
111
|
+
// Fail closed if PowerShell/ACL inspection is unavailable.
|
|
112
|
+
throw new Error('MODEL_CONTROL_WINDOWS_ACL_UNAVAILABLE: Windows PowerShell ACL inspection failed');
|
|
113
|
+
}
|
|
114
|
+
validateWindowsModelControlAcl(snapshot, kind);
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=windows-model-control-security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows-model-control-security.js","sourceRoot":"","sources":["../../src/agents/windows-model-control-security.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"botlink.d.ts","sourceRoot":"","sources":["../../src/channels/botlink.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"botlink.d.ts","sourceRoot":"","sources":["../../src/channels/botlink.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAmB,MAAM,mBAAmB,CAAA;AAgBvF,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAmDD,qBAAa,gBAAiB,SAAQ,KAAK;IAEvC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM;gBADd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM;CAIjB;AAED,qBAAa,eAAgB,SAAQ,KAAK;IAEtC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS;gBAD7B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAAG,SAAS,EACtC,MAAM,EAAE,MAAM;CAIjB;AAED,KAAK,aAAa,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAiBvE,qBAAa,cAAe,YAAW,aAAa;IAMtC,OAAO,CAAC,QAAQ,CAAC,IAAI;IALjC,EAAE,SAAY;IAEd,OAAO,CAAC,QAAQ,CAA2C;IAC3D,OAAO,CAAC,GAAG,CAA8B;gBAEZ,IAAI,GAAE,aAAqB;IAElD,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB7D,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B9D,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAejB,YAAY;YAoCZ,cAAc;YAQd,aAAa;IAsB3B,OAAO,CAAC,uBAAuB;IAM/B,OAAO,CAAC,qBAAqB;YAQf,WAAW;YAYX,QAAQ;IA2ItB,OAAO,CAAC,gBAAgB;YAwBV,kBAAkB;YAmBlB,cAAc;IAS5B,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,kBAAkB;YAqBZ,OAAO;YAmDP,iBAAiB;YAwEjB,mBAAmB;YAoCnB,YAAY;IA+B1B,OAAO,CAAC,mBAAmB;CAY5B;AAuCD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAY5F"}
|
package/dist/channels/botlink.js
CHANGED
|
@@ -4,6 +4,7 @@ import { mkdirSync, renameSync, rmSync } from 'node:fs';
|
|
|
4
4
|
import { randomUUID } from 'node:crypto';
|
|
5
5
|
import { ManagedReceipts } from './managed-receipts.js';
|
|
6
6
|
import { basename, join } from 'node:path';
|
|
7
|
+
import { assertAttachmentStorageId, safeAttachmentFileName } from '../config/platform-paths.js';
|
|
7
8
|
import { createWriteStream } from 'node:fs';
|
|
8
9
|
import { pipeline } from 'node:stream/promises';
|
|
9
10
|
import { registerChannel } from './registry.js';
|
|
@@ -487,6 +488,7 @@ export class BotlinkChannel {
|
|
|
487
488
|
return attachments;
|
|
488
489
|
}
|
|
489
490
|
async downloadFile(account, fileId, fileName, signal) {
|
|
491
|
+
assertAttachmentStorageId(String(fileId));
|
|
490
492
|
const fileInfo = await this.request(account, 'getFile', { file_id: fileId }, signal);
|
|
491
493
|
const baseUrl = account.config.gateway_url.replace(/\/+$/, '');
|
|
492
494
|
const fileUrl = `${baseUrl}/file/bot${account.config.bot_token}/${fileInfo.file_path.replace(/^\/+/, '')}`;
|
|
@@ -560,7 +562,7 @@ export function resolveTelegramSenderName(user) {
|
|
|
560
562
|
return username || undefined;
|
|
561
563
|
}
|
|
562
564
|
function sanitizeFileName(fileName) {
|
|
563
|
-
return fileName
|
|
565
|
+
return safeAttachmentFileName(fileName);
|
|
564
566
|
}
|
|
565
567
|
function getNextOffset(update) {
|
|
566
568
|
return Number.isInteger(update.update_id) ? Number(update.update_id) + 1 : undefined;
|