@bo-agent/sandbox-windows-acl 0.0.1
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/lib/.tsbuildinfo +1 -0
- package/lib/acl.d.ts +83 -0
- package/lib/acl.d.ts.map +1 -0
- package/lib/acl.js +255 -0
- package/lib/acl.js.map +1 -0
- package/lib/errors.d.ts +15 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +20 -0
- package/lib/errors.js.map +1 -0
- package/lib/ffi.d.ts +252 -0
- package/lib/ffi.d.ts.map +1 -0
- package/lib/ffi.js +382 -0
- package/lib/ffi.js.map +1 -0
- package/lib/grant.d.ts +60 -0
- package/lib/grant.d.ts.map +1 -0
- package/lib/grant.js +102 -0
- package/lib/grant.js.map +1 -0
- package/lib/index.d.ts +168 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +349 -0
- package/lib/index.js.map +1 -0
- package/lib/invariant.d.ts +15 -0
- package/lib/invariant.d.ts.map +1 -0
- package/lib/invariant.js +17 -0
- package/lib/invariant.js.map +1 -0
- package/lib/path-boundary.d.ts +20 -0
- package/lib/path-boundary.d.ts.map +1 -0
- package/lib/path-boundary.js +37 -0
- package/lib/path-boundary.js.map +1 -0
- package/lib/runner.d.ts +47 -0
- package/lib/runner.d.ts.map +1 -0
- package/lib/runner.js +222 -0
- package/lib/runner.js.map +1 -0
- package/lib/spawn.d.ts +103 -0
- package/lib/spawn.d.ts.map +1 -0
- package/lib/spawn.js +307 -0
- package/lib/spawn.js.map +1 -0
- package/lib/token.d.ts +91 -0
- package/lib/token.d.ts.map +1 -0
- package/lib/token.js +200 -0
- package/lib/token.js.map +1 -0
- package/lib/win32-abi.d.ts +178 -0
- package/lib/win32-abi.d.ts.map +1 -0
- package/lib/win32-abi.js +230 -0
- package/lib/win32-abi.js.map +1 -0
- package/lib/workspace-sid.d.ts +41 -0
- package/lib/workspace-sid.d.ts.map +1 -0
- package/lib/workspace-sid.js +52 -0
- package/lib/workspace-sid.js.map +1 -0
- package/package.json +33 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windows ACL write-restriction sandbox backend for the DeepSeek Harness
|
|
3
|
+
* sandbox seam. Mirrors the mechanism of github.com/huoyaoyuan/
|
|
4
|
+
* windows-acl-restrict-poc @ 10e4dfb (the fixed revision): a WRITE_RESTRICTED
|
|
5
|
+
* token whose restricting SIDs include distinct workspace and temp write
|
|
6
|
+
* SIDs that this sandbox adds to their owning directories' DACLs — the
|
|
7
|
+
* intersection check then allows writes exactly where either capability has
|
|
8
|
+
* a Write ACE, and nowhere else those SIDs are concerned (the check ALSO
|
|
9
|
+
* inherits the ambient write ACEs of the other restricting SIDs — the
|
|
10
|
+
* keep-alive group logon SID + Everyone; Authenticated Users, INTERACTIVE,
|
|
11
|
+
* and LOCAL are absent from both lists — see the seam's dual-list contract
|
|
12
|
+
* in `packages/sandbox/sandbox-local` and the package README's Modes section
|
|
13
|
+
* for the complete boundary). The write SID is the per-WORKSPACE identity
|
|
14
|
+
* ({@link workspaceWriteSid}): deterministic from the canonical workspace
|
|
15
|
+
* path, so the workspace-root ACE materializes once per workspace per
|
|
16
|
+
* machine and every later provision hits the exact-ACE skip — the
|
|
17
|
+
* grant-reuse story the per-session random SID paid a full tree propagation
|
|
18
|
+
* per session for. Each private temp directory instead receives its own SID,
|
|
19
|
+
* so sibling sessions sharing a workspace cannot enter one another's temp
|
|
20
|
+
* trees. Unlike the POC, every API failure throws with the API
|
|
21
|
+
* name and exact Win32 code; a child is NEVER spawned unrestricted.
|
|
22
|
+
*
|
|
23
|
+
* Known boundaries (inherent to restricted tokens, not this port):
|
|
24
|
+
* - writes are restricted; reads, network, and process visibility are NOT
|
|
25
|
+
* (WRITE_RESTRICTED intersects only write accesses);
|
|
26
|
+
* - console isolation is unavailable — children share the host console
|
|
27
|
+
* (CREATE_NO_WINDOW / CREATE_NEW_CONSOLE children die with
|
|
28
|
+
* STATUS_DLL_INIT_FAILED under the restriction);
|
|
29
|
+
* - the private temp directory and every writable directory must be owned by the
|
|
30
|
+
* caller (owner-implicit WRITE_DAC);
|
|
31
|
+
* - grants are standing ACE mutations on real directories. WORKSPACE grants
|
|
32
|
+
* are deliberately never revoked — the ACE is the cross-session reuse
|
|
33
|
+
* cache (revoking would force the next session to re-propagate the whole
|
|
34
|
+
* tree). TEMP grants are revocable: dispose() removes them so a standing
|
|
35
|
+
* inheritable ACE never outlives its session's temp directory. The
|
|
36
|
+
* ambient temp root is never granted implicitly. With `manageDacls: false`
|
|
37
|
+
* the CALLER owns the DACLs (the sandbox seam's grant reuse):
|
|
38
|
+
* init()/dispose() skip grant/revoke entirely and the caller must not
|
|
39
|
+
* revoke under live children.
|
|
40
|
+
* @module @bo-agent/sandbox-windows-acl
|
|
41
|
+
*/
|
|
42
|
+
import { existsSync, statSync } from 'node:fs';
|
|
43
|
+
import { resolve } from 'node:path';
|
|
44
|
+
import { grantWrite, revokeWrite } from "./acl.js";
|
|
45
|
+
import { Win32Error } from "./errors.js";
|
|
46
|
+
import { allocPtrSlot, decodePtr, isNullPtr, throwLastError, win32 } from "./ffi.js";
|
|
47
|
+
import { assertPrivateTempDisjoint } from "./path-boundary.js";
|
|
48
|
+
import { drainPipe, spawnSandboxed, spawnSandboxedInherited, waitForExit } from "./spawn.js";
|
|
49
|
+
import { createRestrictedToken, findLogonSid, makeWellKnownSid, openCurrentProcessToken, setTokenDefaultDaclGrant } from "./token.js";
|
|
50
|
+
import * as abi from "./win32-abi.js";
|
|
51
|
+
export { quoteArg } from "./spawn.js";
|
|
52
|
+
export { AclWriteGrant } from "./grant.js";
|
|
53
|
+
export { assertTempRootOutsideWorkspace } from "./path-boundary.js";
|
|
54
|
+
export { tempWriteSid, workspaceWriteSid } from "./workspace-sid.js";
|
|
55
|
+
export { Win32Error } from "./errors.js";
|
|
56
|
+
/** Free one optional SID while retaining a failure for best-effort sibling cleanup. */
|
|
57
|
+
function freeSidBestEffort(api, sidPtr, label, failures) {
|
|
58
|
+
if (sidPtr === undefined)
|
|
59
|
+
return;
|
|
60
|
+
try {
|
|
61
|
+
const freed = api.localFree(sidPtr);
|
|
62
|
+
if (!isNullPtr(freed))
|
|
63
|
+
throwLastError(api, 'LocalFree', label);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
failures.push(error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* One write-restricted sandbox instance: token + write-SID grants + spawn.
|
|
71
|
+
* `init()` is fail-closed — any Win32 failure revokes the revocable (temp)
|
|
72
|
+
* grants and throws; `dispose()` revokes the temp grants, leaves the
|
|
73
|
+
* standing workspace ACEs in place (the cross-instance reuse cache), frees
|
|
74
|
+
* every allocation, and reports every cleanup failure. With
|
|
75
|
+
* `manageDacls: false` the caller owns the grants (the sandbox seam's grant
|
|
76
|
+
* reuse): init() applies none and dispose() revokes none.
|
|
77
|
+
*/
|
|
78
|
+
export class AclSandbox {
|
|
79
|
+
/** Absolute writable directories (constructor-validated). */
|
|
80
|
+
writableDirs;
|
|
81
|
+
/** The workspace SID string whose ACEs form the workspace allowlist. */
|
|
82
|
+
writeSid;
|
|
83
|
+
/** The private temp directory's write SID (workspace-write with temp only). */
|
|
84
|
+
tempWriteSid;
|
|
85
|
+
/** The file-effect mode — the restricted token's restricting-SID list selection. */
|
|
86
|
+
mode;
|
|
87
|
+
tempDirOption;
|
|
88
|
+
manageDacls;
|
|
89
|
+
tempDirResolved;
|
|
90
|
+
api;
|
|
91
|
+
token;
|
|
92
|
+
writeSidPtr;
|
|
93
|
+
tempWriteSidPtr;
|
|
94
|
+
/** The well-known/logon SID allocations init() makes; freed by dispose() alongside the write SIDs. */
|
|
95
|
+
sidAllocations = [];
|
|
96
|
+
grantedPaths = [];
|
|
97
|
+
constructor(options) {
|
|
98
|
+
this.mode = options.mode;
|
|
99
|
+
this.manageDacls = options.manageDacls ?? true;
|
|
100
|
+
this.writableDirs = options.writableDirs.map((directory) => {
|
|
101
|
+
const absolute = resolve(directory);
|
|
102
|
+
if (!existsSync(absolute) || !statSync(absolute).isDirectory()) {
|
|
103
|
+
throw new Error(`AclSandbox writable dir does not exist or is not a directory: ${absolute}`);
|
|
104
|
+
}
|
|
105
|
+
return absolute;
|
|
106
|
+
});
|
|
107
|
+
this.tempDirOption = options.tempDir;
|
|
108
|
+
this.writeSid = options.writeSid;
|
|
109
|
+
this.tempWriteSid = options.tempWriteSid;
|
|
110
|
+
if (this.mode === 'workspace-write' && this.writeSid === undefined) {
|
|
111
|
+
throw new Error('AclSandbox workspace-write requires a write SID — derive it from the workspace via workspaceWriteSid()');
|
|
112
|
+
}
|
|
113
|
+
if (this.mode === 'workspace-write' && this.tempDirOption === undefined) {
|
|
114
|
+
throw new Error('AclSandbox workspace-write requires an explicit private temp directory or null');
|
|
115
|
+
}
|
|
116
|
+
if (this.mode === 'read-only' && this.tempDirOption !== undefined && this.tempDirOption !== null) {
|
|
117
|
+
throw new Error('AclSandbox read-only does not accept a temp directory');
|
|
118
|
+
}
|
|
119
|
+
if (this.mode === 'read-only' && (this.writeSid !== undefined || this.tempWriteSid !== undefined)) {
|
|
120
|
+
throw new Error('AclSandbox read-only does not accept write SIDs');
|
|
121
|
+
}
|
|
122
|
+
if (this.mode === 'workspace-write' && this.tempDirOption !== null && this.tempWriteSid === undefined) {
|
|
123
|
+
throw new Error('AclSandbox workspace-write with temp requires a temp write SID — derive it via tempWriteSid()');
|
|
124
|
+
}
|
|
125
|
+
if (this.tempDirOption === null && this.tempWriteSid !== undefined) {
|
|
126
|
+
throw new Error('AclSandbox temp write SID requires a temp directory');
|
|
127
|
+
}
|
|
128
|
+
if (this.writeSid !== undefined && this.tempWriteSid === this.writeSid) {
|
|
129
|
+
throw new Error('AclSandbox workspace and temp write SIDs must be distinct');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** Resolved temp directory (available after init; null when temp grants are disabled). */
|
|
133
|
+
get tempDir() {
|
|
134
|
+
return this.tempDirResolved;
|
|
135
|
+
}
|
|
136
|
+
/** Create the restricted token and apply the capability-SID grants. Idempotent-unsafe: once per instance. */
|
|
137
|
+
async init() {
|
|
138
|
+
if (this.api !== undefined)
|
|
139
|
+
throw new Error('AclSandbox is already initialized');
|
|
140
|
+
const api = await win32();
|
|
141
|
+
const currentToken = openCurrentProcessToken(api);
|
|
142
|
+
let currentTokenOpen = true;
|
|
143
|
+
let restrictedToken;
|
|
144
|
+
try {
|
|
145
|
+
const parseSid = (sid) => {
|
|
146
|
+
const sidSlot = allocPtrSlot();
|
|
147
|
+
if (api.convertStringSidToSidW(sid, sidSlot) === 0) {
|
|
148
|
+
throwLastError(api, 'ConvertStringSidToSidW', sid);
|
|
149
|
+
}
|
|
150
|
+
const parsedSid = decodePtr(sidSlot);
|
|
151
|
+
if (parsedSid === null)
|
|
152
|
+
throw new Win32Error('ConvertStringSidToSidW', api.getLastError(), sid);
|
|
153
|
+
return parsedSid;
|
|
154
|
+
};
|
|
155
|
+
this.writeSidPtr = this.writeSid === undefined ? undefined : parseSid(this.writeSid);
|
|
156
|
+
this.tempWriteSidPtr = this.tempWriteSid === undefined ? undefined : parseSid(this.tempWriteSid);
|
|
157
|
+
const tempDir = this.mode === 'read-only' || this.tempDirOption === null ? null : this.tempDirOption;
|
|
158
|
+
/* v8 ignore next -- constructor validation requires workspace-write to supply
|
|
159
|
+
an explicit temp directory or null; the other branches normalize to null. */
|
|
160
|
+
if (tempDir === undefined)
|
|
161
|
+
throw new Error('AclSandbox workspace-write temp directory was not resolved');
|
|
162
|
+
if (tempDir !== null) {
|
|
163
|
+
if (!existsSync(tempDir) || !statSync(tempDir).isDirectory()) {
|
|
164
|
+
throw new Error(`AclSandbox temp dir does not exist or is not a directory: ${tempDir}`);
|
|
165
|
+
}
|
|
166
|
+
assertPrivateTempDisjoint(this.writableDirs, tempDir);
|
|
167
|
+
}
|
|
168
|
+
this.tempDirResolved = tempDir;
|
|
169
|
+
// manageDacls: false — the caller (the sandbox seam's grant) already
|
|
170
|
+
// materialized the ACEs; this instance must neither add nor remove any.
|
|
171
|
+
// When this instance owns the DACLs, writableDir ACEs are STANDING (the
|
|
172
|
+
// per-workspace reuse cache — dispose() never revokes them, or the next
|
|
173
|
+
// provision would re-propagate the whole tree) and the temp ACE is
|
|
174
|
+
// REVOCABLE (dispose() removes it before the private directory is
|
|
175
|
+
// deleted; the ambient temp root is never granted).
|
|
176
|
+
if (this.manageDacls) {
|
|
177
|
+
if (this.writeSidPtr !== undefined) {
|
|
178
|
+
for (const path of this.writableDirs) {
|
|
179
|
+
grantWrite(api, path, this.writeSidPtr);
|
|
180
|
+
}
|
|
181
|
+
if (tempDir !== null && this.tempWriteSidPtr !== undefined) {
|
|
182
|
+
// Record BEFORE granting: grantWrite can throw after a successful
|
|
183
|
+
// apply (a LocalFree failure), and the fail-closed catch must still
|
|
184
|
+
// revoke that path (revoking an ungranted path is a no-op merge).
|
|
185
|
+
this.grantedPaths.push({ path: tempDir, sidPtr: this.tempWriteSidPtr });
|
|
186
|
+
grantWrite(api, tempDir, this.tempWriteSidPtr);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const logonSid = findLogonSid(api, currentToken);
|
|
191
|
+
this.sidAllocations.push(logonSid);
|
|
192
|
+
const worldSid = makeWellKnownSid(api, abi.WinWorldSid);
|
|
193
|
+
this.sidAllocations.push(worldSid);
|
|
194
|
+
const writeSids = [this.writeSidPtr, this.tempWriteSidPtr].filter((sid) => sid !== undefined);
|
|
195
|
+
restrictedToken = createRestrictedToken(api, currentToken, logonSid, writeSids, { world: worldSid }, this.mode);
|
|
196
|
+
this.token = restrictedToken;
|
|
197
|
+
// The restricted token's default DACL still names only the user's
|
|
198
|
+
// ambient SIDs — none of the restricting SIDs. Every NEW object the
|
|
199
|
+
// confined process creates (anonymous stdio pipes, sync objects) takes
|
|
200
|
+
// its DACL from that default, so the write pass-2 check would deny
|
|
201
|
+
// pipe creation (ERROR_ACCESS_DENIED; Node EPERM) and break every
|
|
202
|
+
// piped-stdio grandchild spawn. Merge a full-access ACE for a
|
|
203
|
+
// restricting SID (the PRIVATE temp SID when present, otherwise the
|
|
204
|
+
// workspace SID, or Everyone under read-only): new-object creation
|
|
205
|
+
// stays gated by the parent object's DACL, while the new object's own
|
|
206
|
+
// DACL passes pass-2. Choosing the temp SID prevents default-DACL
|
|
207
|
+
// objects in one session's temp tree from acquiring the shared
|
|
208
|
+
// workspace capability.
|
|
209
|
+
setTokenDefaultDaclGrant(api, restrictedToken, this.tempWriteSidPtr ?? this.writeSidPtr ?? worldSid);
|
|
210
|
+
if (api.closeHandle(currentToken) === 0)
|
|
211
|
+
throwLastError(api, 'CloseHandle', 'current process token');
|
|
212
|
+
currentTokenOpen = false;
|
|
213
|
+
this.api = api;
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
// Fail-closed cleanup: never leave a revocable (temp) grant or SID
|
|
217
|
+
// allocation behind a failed init. Standing workspace ACEs are NOT
|
|
218
|
+
// revoked — they are the intended end state (the reuse cache), not an
|
|
219
|
+
// error artifact.
|
|
220
|
+
const cleanupFailures = [];
|
|
221
|
+
if (currentTokenOpen && api.closeHandle(currentToken) === 0) {
|
|
222
|
+
cleanupFailures.push(new Win32Error('CloseHandle', api.getLastError(), 'current process token after init failure'));
|
|
223
|
+
}
|
|
224
|
+
if (restrictedToken !== undefined && api.closeHandle(restrictedToken) === 0) {
|
|
225
|
+
cleanupFailures.push(new Win32Error('CloseHandle', api.getLastError(), 'restricted token after init failure'));
|
|
226
|
+
}
|
|
227
|
+
for (const grant of this.grantedPaths) {
|
|
228
|
+
try {
|
|
229
|
+
revokeWrite(api, grant.path, grant.sidPtr);
|
|
230
|
+
}
|
|
231
|
+
catch (cleanupError) {
|
|
232
|
+
cleanupFailures.push(cleanupError);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
for (const [label, sidPtr] of [['workspace write SID', this.writeSidPtr], ['temp write SID', this.tempWriteSidPtr]]) {
|
|
236
|
+
freeSidBestEffort(api, sidPtr, label, cleanupFailures);
|
|
237
|
+
}
|
|
238
|
+
for (const sidPtr of this.sidAllocations.splice(0)) {
|
|
239
|
+
freeSidBestEffort(api, sidPtr, 'init SID allocation', cleanupFailures);
|
|
240
|
+
}
|
|
241
|
+
this.token = undefined;
|
|
242
|
+
this.writeSidPtr = undefined;
|
|
243
|
+
this.tempWriteSidPtr = undefined;
|
|
244
|
+
this.tempDirResolved = undefined;
|
|
245
|
+
this.grantedPaths = [];
|
|
246
|
+
if (cleanupFailures.length > 0) {
|
|
247
|
+
throw new AggregateError([error, ...cleanupFailures], `AclSandbox init failed and ${cleanupFailures.length} cleanup operation(s) also failed`);
|
|
248
|
+
}
|
|
249
|
+
throw error;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Spawn a process under the restricted token. Fails closed: throws on every
|
|
254
|
+
* Win32 failure; the child is never created unrestricted. With
|
|
255
|
+
* `stdio: 'inherit'` the child shares the caller's stdio directly and is
|
|
256
|
+
* placed in a kill-on-close job (dies with the caller). Call dispose() only
|
|
257
|
+
* after all children have exited — revoking grants under a live child
|
|
258
|
+
* removes its remaining write allowance.
|
|
259
|
+
* @param options - the program, argv/cwd, and stdio shape.
|
|
260
|
+
* @returns the running child.
|
|
261
|
+
*/
|
|
262
|
+
spawn(options) {
|
|
263
|
+
const api = this.api;
|
|
264
|
+
const token = this.token;
|
|
265
|
+
if (api === undefined || token === undefined)
|
|
266
|
+
throw new Error('AclSandbox is not initialized: call init() first');
|
|
267
|
+
const args = options.args ?? [];
|
|
268
|
+
const cwd = options.cwd ?? process.cwd();
|
|
269
|
+
if (options.stdio === 'inherit') {
|
|
270
|
+
const native = spawnSandboxedInherited(api, token, { command: options.command, args, cwd });
|
|
271
|
+
let exitCodePromise;
|
|
272
|
+
return {
|
|
273
|
+
pid: native.pid,
|
|
274
|
+
wait: async () => {
|
|
275
|
+
exitCodePromise ??= Promise.resolve(waitForExit(api, native.process));
|
|
276
|
+
const exitCode = await exitCodePromise;
|
|
277
|
+
if (api.closeHandle(native.job) === 0)
|
|
278
|
+
throwLastError(api, 'CloseHandle', 'kill-on-close job');
|
|
279
|
+
return { stdout: Buffer.alloc(0), stderr: Buffer.alloc(0), exitCode };
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
const native = spawnSandboxed(api, token, { command: options.command, args, cwd });
|
|
284
|
+
const stdout = drainPipe(api, native.stdoutRead);
|
|
285
|
+
const stderr = drainPipe(api, native.stderrRead);
|
|
286
|
+
// waitForExit is deliberately NOT started here: WaitForSingleObject blocks
|
|
287
|
+
// the thread and would starve the drains while the child is still running
|
|
288
|
+
// (pipe-buffer deadlock). The drains resolve only after the child closed
|
|
289
|
+
// its pipe ends — by then the wait returns immediately.
|
|
290
|
+
let exitCodePromise;
|
|
291
|
+
return {
|
|
292
|
+
pid: native.pid,
|
|
293
|
+
wait: async () => {
|
|
294
|
+
const stdoutBuffer = await stdout;
|
|
295
|
+
const stderrBuffer = await stderr;
|
|
296
|
+
exitCodePromise ??= Promise.resolve(waitForExit(api, native.process));
|
|
297
|
+
return { stdout: stdoutBuffer, stderr: stderrBuffer, exitCode: await exitCodePromise };
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Revoke the revocable (temp) grants, free the SID, close the token; the
|
|
303
|
+
* standing workspace ACEs stay (the reuse cache). Reports every cleanup
|
|
304
|
+
* failure.
|
|
305
|
+
*/
|
|
306
|
+
dispose() {
|
|
307
|
+
const api = this.api;
|
|
308
|
+
if (api === undefined)
|
|
309
|
+
return;
|
|
310
|
+
const failures = [];
|
|
311
|
+
if (this.manageDacls) {
|
|
312
|
+
for (const grant of this.grantedPaths) {
|
|
313
|
+
try {
|
|
314
|
+
revokeWrite(api, grant.path, grant.sidPtr);
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
failures.push(error);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
for (const [label, sidPtr] of [['workspace write SID', this.writeSidPtr], ['temp write SID', this.tempWriteSidPtr]]) {
|
|
322
|
+
freeSidBestEffort(api, sidPtr, label, failures);
|
|
323
|
+
}
|
|
324
|
+
const token = this.token;
|
|
325
|
+
/* v8 ignore next -- init assigns this.api only after this.token, so an initialized instance always
|
|
326
|
+
has its token; the guard mirrors the write-SID guard. */
|
|
327
|
+
if (token !== undefined) {
|
|
328
|
+
try {
|
|
329
|
+
if (api.closeHandle(token) === 0)
|
|
330
|
+
throwLastError(api, 'CloseHandle', 'restricted token');
|
|
331
|
+
}
|
|
332
|
+
catch (error) {
|
|
333
|
+
failures.push(error);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
for (const sidPtr of this.sidAllocations.splice(0)) {
|
|
337
|
+
freeSidBestEffort(api, sidPtr, 'init SID allocation', failures);
|
|
338
|
+
}
|
|
339
|
+
this.api = undefined;
|
|
340
|
+
this.token = undefined;
|
|
341
|
+
this.writeSidPtr = undefined;
|
|
342
|
+
this.tempWriteSidPtr = undefined;
|
|
343
|
+
this.grantedPaths = [];
|
|
344
|
+
if (failures.length > 0) {
|
|
345
|
+
throw new AggregateError(failures, `AclSandbox dispose completed with ${failures.length} cleanup failure(s)`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion stub.
|
|
3
|
+
*
|
|
4
|
+
* This product does not enforce runtime invariants; the public contract
|
|
5
|
+
* exposed here is a structural declaration (`name`, `inject`, `apply`)
|
|
6
|
+
* rather than runtime behavior. The companion slots into a Cordis context
|
|
7
|
+
* without doing anything, so consumers that wire it up see the same surface
|
|
8
|
+
* shape regardless of whether invariants are turned on.
|
|
9
|
+
*
|
|
10
|
+
* @module @bo-agent/sandbox-windows-acl/invariant
|
|
11
|
+
*/
|
|
12
|
+
export declare const name = "sandbox-windows-acl-invariant";
|
|
13
|
+
export declare const inject: string[];
|
|
14
|
+
export declare const apply: () => Promise<() => void>;
|
|
15
|
+
//# sourceMappingURL=invariant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariant.d.ts","sourceRoot":"","sources":["../src/invariant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,eAAO,MAAM,IAAI,kCAAkC,CAAA;AACnD,eAAO,MAAM,MAAM,EAAE,MAAM,EAAO,CAAA;AAClC,eAAO,MAAM,KAAK,QAAa,OAAO,CAAC,MAAM,IAAI,CAAa,CAAA"}
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion stub.
|
|
3
|
+
*
|
|
4
|
+
* This product does not enforce runtime invariants; the public contract
|
|
5
|
+
* exposed here is a structural declaration (`name`, `inject`, `apply`)
|
|
6
|
+
* rather than runtime behavior. The companion slots into a Cordis context
|
|
7
|
+
* without doing anything, so consumers that wire it up see the same surface
|
|
8
|
+
* shape regardless of whether invariants are turned on.
|
|
9
|
+
*
|
|
10
|
+
* @module @bo-agent/sandbox-windows-acl/invariant
|
|
11
|
+
*/
|
|
12
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
13
|
+
export const name = 'sandbox-windows-acl-invariant';
|
|
14
|
+
export const inject = [];
|
|
15
|
+
export const apply = async () => () => { };
|
|
16
|
+
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
17
|
+
//# sourceMappingURL=invariant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariant.js","sourceRoot":"","sources":["../src/invariant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,sDAAsD;AACtD,MAAM,CAAC,MAAM,IAAI,GAAG,+BAA+B,CAAA;AACnD,MAAM,CAAC,MAAM,MAAM,GAAa,EAAE,CAAA;AAClC,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,IAAyB,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC,CAAA;AAC9D,qDAAqD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical directory-boundary checks for the Windows ACL workspace and
|
|
3
|
+
* private-temp capabilities.
|
|
4
|
+
* @module @bo-agent/sandbox-windows-acl/path-boundary
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Reject a temp parent that is inside the workspace: every child created
|
|
8
|
+
* below it would inherit the standing workspace capability.
|
|
9
|
+
* @param workspaceRoot - the canonical workspace root that receives the standing ACE.
|
|
10
|
+
* @param tempRoot - the existing parent beneath which a private temp child would be created.
|
|
11
|
+
*/
|
|
12
|
+
export declare function assertTempRootOutsideWorkspace(workspaceRoot: string, tempRoot: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Reject overlap between an actual private temp directory and any writable
|
|
15
|
+
* directory: either inheritance direction would merge the two capabilities.
|
|
16
|
+
* @param writableDirs - directories carrying the standing workspace capability.
|
|
17
|
+
* @param tempDir - the existing directory carrying the revocable temp capability.
|
|
18
|
+
*/
|
|
19
|
+
export declare function assertPrivateTempDisjoint(writableDirs: readonly string[], tempDir: string): void;
|
|
20
|
+
//# sourceMappingURL=path-boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-boundary.d.ts","sourceRoot":"","sources":["../src/path-boundary.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAI5F;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAMhG"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical directory-boundary checks for the Windows ACL workspace and
|
|
3
|
+
* private-temp capabilities.
|
|
4
|
+
* @module @bo-agent/sandbox-windows-acl/path-boundary
|
|
5
|
+
*/
|
|
6
|
+
import { realpathSync } from 'node:fs';
|
|
7
|
+
import { isAbsolute, relative, sep } from 'node:path';
|
|
8
|
+
/** Whether `root` is the same canonical directory as `candidate` or contains it. */
|
|
9
|
+
function containsDirectory(root, candidate) {
|
|
10
|
+
const relation = relative(realpathSync.native(root), realpathSync.native(candidate));
|
|
11
|
+
return relation === '' || (!isAbsolute(relation) && relation !== '..' && !relation.startsWith(`..${sep}`));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Reject a temp parent that is inside the workspace: every child created
|
|
15
|
+
* below it would inherit the standing workspace capability.
|
|
16
|
+
* @param workspaceRoot - the canonical workspace root that receives the standing ACE.
|
|
17
|
+
* @param tempRoot - the existing parent beneath which a private temp child would be created.
|
|
18
|
+
*/
|
|
19
|
+
export function assertTempRootOutsideWorkspace(workspaceRoot, tempRoot) {
|
|
20
|
+
if (containsDirectory(workspaceRoot, tempRoot)) {
|
|
21
|
+
throw new Error(`Windows ACL temp root must be outside the workspace: workspace=${workspaceRoot}; temp=${tempRoot}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Reject overlap between an actual private temp directory and any writable
|
|
26
|
+
* directory: either inheritance direction would merge the two capabilities.
|
|
27
|
+
* @param writableDirs - directories carrying the standing workspace capability.
|
|
28
|
+
* @param tempDir - the existing directory carrying the revocable temp capability.
|
|
29
|
+
*/
|
|
30
|
+
export function assertPrivateTempDisjoint(writableDirs, tempDir) {
|
|
31
|
+
for (const writableDir of writableDirs) {
|
|
32
|
+
if (containsDirectory(writableDir, tempDir) || containsDirectory(tempDir, writableDir)) {
|
|
33
|
+
throw new Error(`AclSandbox private temp directory must be disjoint from writable directories: writable=${writableDir}; temp=${tempDir}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=path-boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-boundary.js","sourceRoot":"","sources":["../src/path-boundary.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAErD,oFAAoF;AACpF,SAAS,iBAAiB,CAAC,IAAY,EAAE,SAAiB;IACxD,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAA;IACpF,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAA;AAC5G,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,8BAA8B,CAAC,aAAqB,EAAE,QAAgB;IACpF,IAAI,iBAAiB,CAAC,aAAa,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,kEAAkE,aAAa,UAAU,QAAQ,EAAE,CAAC,CAAA;IACtH,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CAAC,YAA+B,EAAE,OAAe;IACxF,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,IAAI,iBAAiB,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,iBAAiB,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC;YACvF,MAAM,IAAI,KAAK,CAAC,0FAA0F,WAAW,UAAU,OAAO,EAAE,CAAC,CAAA;QAC3I,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/lib/runner.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The windows-acl confinement runner: the argv-prefix wrapper the sandbox
|
|
3
|
+
* seam spawns in place of the caller's command. It creates the
|
|
4
|
+
* WRITE_RESTRICTED token with the workspace write-SID allowlist, spawns the
|
|
5
|
+
* wrapped argv under it with the CALLER'S stdio inherited (bytes flow
|
|
6
|
+
* straight through), mirrors the child's exit code, and revokes its temp
|
|
7
|
+
* grant on exit (workspace ACEs stay standing as the reuse cache).
|
|
8
|
+
*
|
|
9
|
+
* Stable argv contract (the seam builds it; a native-exe replacement would
|
|
10
|
+
* keep the same contract):
|
|
11
|
+
* [node, runner.js, '--workspace', <dir>, '--temp', <dir>,
|
|
12
|
+
* '--mode', <read-only|workspace-write>,
|
|
13
|
+
* ['--write-sid', <S-1-4-…>,
|
|
14
|
+
* '--temp-write-sid', <S-1-4-…>], '--', <argv...>]
|
|
15
|
+
*
|
|
16
|
+
* Modes:
|
|
17
|
+
* - workspace-write: the workspace and temp directories carry distinct
|
|
18
|
+
* capability-SID Write grants; other ACL-addressable writes are denied
|
|
19
|
+
* except for the documented Everyone and hard-link boundaries.
|
|
20
|
+
* - read-only: no capability-SID grants; the restricting list carries no
|
|
21
|
+
* capability SID, so a standing grant ACE from an earlier
|
|
22
|
+
* workspace-write period stays inert. BOTH modes drop Authenticated Users
|
|
23
|
+
* (CIM unavailable — documented in README) and INTERACTIVE/LOCAL (the
|
|
24
|
+
* Public tree writes are denied); the two lists share the keep-alive group
|
|
25
|
+
* (logon SID, EVERYONE) and differ only by the capabilities.
|
|
26
|
+
*
|
|
27
|
+
* `--write-sid` + `--temp-write-sid`: the seam's grant contract — the
|
|
28
|
+
* CALLER has already materialized distinct workspace and private-temp ACEs
|
|
29
|
+
* and owns their revocation, so the runner neither grants nor revokes
|
|
30
|
+
* (`manageDacls: false`). Both values are checked against their owning paths.
|
|
31
|
+
* Without the pair (standalone/agentless use), workspace-write treats
|
|
32
|
+
* `--temp` as a ROOT, creates a random private child directory, derives its
|
|
33
|
+
* own temp SID, and removes that directory after the child exits. In both
|
|
34
|
+
* flows the runner rewrites TMP/TEMP in its OWN environment to the private
|
|
35
|
+
* directory before spawning; the child inherits that block (`lpEnvironment`
|
|
36
|
+
* NULL; an explicit block through koffi trips ERROR_INVALID_PARAMETER in
|
|
37
|
+
* CreateProcessAsUserW, verified empirically). Read-only leaves the ambient
|
|
38
|
+
* temp entries untouched (writes there are denied anyway).
|
|
39
|
+
*
|
|
40
|
+
* Failure contract: every runner-side failure (bad args, missing
|
|
41
|
+
* directories, token/grant/spawn errors) prints `windows-acl-run: <detail>`
|
|
42
|
+
* to stderr and exits 127 — the seam's RUNNER_FAILURE_RULES matches that
|
|
43
|
+
* signature. The child is NEVER spawned unrestricted.
|
|
44
|
+
* @module @bo-agent/sandbox-windows-acl/runner
|
|
45
|
+
*/
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG"}
|