@vellumai/credential-executor 0.10.6-dev.202607071937.200b337 → 0.10.6-dev.202607072040.fb971ce
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/package.json +1 -1
- package/src/__tests__/local-standalone.test.ts +5 -36
- package/src/__tests__/transport.test.ts +7 -7
- package/src/main.ts +23 -59
- package/src/paths.ts +4 -5
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Local CES
|
|
2
|
+
* Local CES sibling test (real entrypoint subprocess).
|
|
3
3
|
*
|
|
4
|
-
* Spawns the actual `main.ts` entrypoint with
|
|
5
|
-
*
|
|
6
|
-
* opt-in) — and verifies that CES:
|
|
4
|
+
* Spawns the actual `main.ts` entrypoint with **stdin closed** — the way the
|
|
5
|
+
* CLI launches the sibling — and verifies that CES:
|
|
7
6
|
*
|
|
8
7
|
* 1. binds its Unix socket and serves RPC despite having no stdio parent
|
|
9
8
|
* (lifecycle anchored to SIGTERM, not stdin), and
|
|
@@ -145,12 +144,12 @@ describe("local CES standalone sibling (real entrypoint)", () => {
|
|
|
145
144
|
|
|
146
145
|
const localMain = resolve(__dirname, "..", "main.ts");
|
|
147
146
|
|
|
148
|
-
//
|
|
147
|
+
// stdin closed is how the CLI launches the sibling — CES serves over a
|
|
148
|
+
// Unix socket, not stdio.
|
|
149
149
|
proc = Bun.spawn({
|
|
150
150
|
cmd: [process.execPath, localMain],
|
|
151
151
|
env: {
|
|
152
152
|
...process.env,
|
|
153
|
-
CES_STANDALONE: "1",
|
|
154
153
|
CES_LOCAL_SOCKET: socketPath,
|
|
155
154
|
CREDENTIAL_SECURITY_DIR: securityDir,
|
|
156
155
|
VELLUM_WORKSPACE_DIR: workspaceDir,
|
|
@@ -200,34 +199,4 @@ describe("local CES standalone sibling (real entrypoint)", () => {
|
|
|
200
199
|
]);
|
|
201
200
|
expect(exited).toBe(true);
|
|
202
201
|
}, 30_000);
|
|
203
|
-
|
|
204
|
-
test("without CES_STANDALONE, exits when stdin closes (stdio child)", async () => {
|
|
205
|
-
tmpDir = mkdtempSync(join(tmpdir(), "ces-stdio-"));
|
|
206
|
-
const securityDir = join(tmpDir, "protected");
|
|
207
|
-
const workspaceDir = join(tmpDir, "workspace");
|
|
208
|
-
mkdirSync(securityDir, { recursive: true });
|
|
209
|
-
mkdirSync(workspaceDir, { recursive: true });
|
|
210
|
-
|
|
211
|
-
const localMain = resolve(__dirname, "..", "main.ts");
|
|
212
|
-
|
|
213
|
-
// Default mode: stdin "ignore" EOFs immediately, so the stdio server's
|
|
214
|
-
// input stream ends and CES shuts down on its own — the today behavior.
|
|
215
|
-
proc = Bun.spawn({
|
|
216
|
-
cmd: [process.execPath, localMain],
|
|
217
|
-
env: {
|
|
218
|
-
...process.env,
|
|
219
|
-
CREDENTIAL_SECURITY_DIR: securityDir,
|
|
220
|
-
VELLUM_WORKSPACE_DIR: workspaceDir,
|
|
221
|
-
},
|
|
222
|
-
stdin: "ignore",
|
|
223
|
-
stdout: "ignore",
|
|
224
|
-
stderr: "ignore",
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
const exited = await Promise.race([
|
|
228
|
-
proc.exited.then(() => true),
|
|
229
|
-
delay(10_000).then(() => false),
|
|
230
|
-
]);
|
|
231
|
-
expect(exited).toBe(true);
|
|
232
|
-
}, 20_000);
|
|
233
202
|
});
|
|
@@ -203,17 +203,17 @@ describe("health probes", () => {
|
|
|
203
203
|
});
|
|
204
204
|
|
|
205
205
|
// ---------------------------------------------------------------------------
|
|
206
|
-
// 3. Local
|
|
206
|
+
// 3. Local socket transport not inherited by subprocesses
|
|
207
207
|
// ---------------------------------------------------------------------------
|
|
208
208
|
|
|
209
209
|
describe("local entrypoint transport isolation", () => {
|
|
210
|
-
test("main.ts serves over
|
|
210
|
+
test("main.ts serves over a Unix socket, never stdio or a TCP listener", () => {
|
|
211
211
|
const src = readFileSync(resolve(__dirname, "..", "main.ts"), "utf-8");
|
|
212
|
-
//
|
|
213
|
-
expect(src).toMatch(/process\.stdin/);
|
|
214
|
-
expect(src).toMatch(/process\.stdout/);
|
|
215
|
-
//
|
|
216
|
-
// never
|
|
212
|
+
// Socket transport only — no stdio-child transport.
|
|
213
|
+
expect(src).not.toMatch(/process\.stdin/);
|
|
214
|
+
expect(src).not.toMatch(/process\.stdout/);
|
|
215
|
+
// Listens on a Unix socket path only — never a numeric TCP port — and
|
|
216
|
+
// never opens an HTTP server.
|
|
217
217
|
expect(src).not.toMatch(/Bun\.serve\(/);
|
|
218
218
|
expect(src).not.toMatch(/\.listen\(\d+/);
|
|
219
219
|
});
|
package/src/main.ts
CHANGED
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
/**
|
|
3
|
-
* Local CES entrypoint.
|
|
3
|
+
* Local CES entrypoint. Serves RPC over a Unix socket (`getLocalSocketPath()`),
|
|
4
|
+
* launched independently by the CLI as a sibling process. Runs until SIGTERM.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* - **standalone sibling (`CES_STANDALONE=1`):** CES is launched independently
|
|
10
|
-
* by the CLI (the opt-in), serves RPC over a
|
|
11
|
-
* Unix socket (`getLocalSocketPath()`), and runs until SIGTERM — no stdio.
|
|
12
|
-
* This is the direction local CES is converging on; the socket-serving here
|
|
13
|
-
* is temporary scaffolding to be folded into a single unified CES entrypoint.
|
|
14
|
-
*
|
|
15
|
-
* Local mode never opens a TCP listener. Neither the stdio transport nor the
|
|
16
|
-
* Unix socket's listening fd is inherited by shell subprocesses spawned by CES
|
|
17
|
-
* (e.g. for `run_authenticated_command`): Bun's `Bun.spawn` defaults to "pipe"
|
|
18
|
-
* for stdio, and the listening socket is not passed to those subprocesses.
|
|
6
|
+
* Local mode never opens a TCP listener. The Unix socket's listening fd is not
|
|
7
|
+
* inherited by shell subprocesses spawned by CES (e.g. for
|
|
8
|
+
* `run_authenticated_command`): Bun's `Bun.spawn` defaults to "pipe" for
|
|
9
|
+
* stdio, and the listening socket is not passed to those subprocesses.
|
|
19
10
|
*/
|
|
20
11
|
|
|
21
12
|
import { mkdirSync, unlinkSync } from "node:fs";
|
|
@@ -351,12 +342,11 @@ function buildHandlers(secureKeyBackend: SecureKeyBackend): RpcHandlerRegistry {
|
|
|
351
342
|
// ---------------------------------------------------------------------------
|
|
352
343
|
|
|
353
344
|
/**
|
|
354
|
-
* Serve RPC over a Unix socket
|
|
345
|
+
* Serve RPC over a Unix socket.
|
|
355
346
|
*
|
|
356
347
|
* Binds the socket, accepts connections concurrently (each served by its own
|
|
357
348
|
* CesRpcServer over the shared handler registry), and unlinks the socket when
|
|
358
|
-
* the signal aborts.
|
|
359
|
-
* into a single unified CES entrypoint shared with the managed sidecar.
|
|
349
|
+
* the signal aborts.
|
|
360
350
|
*/
|
|
361
351
|
function serveStandaloneSocket(opts: {
|
|
362
352
|
socketPath: string;
|
|
@@ -439,14 +429,8 @@ async function main(): Promise<void> {
|
|
|
439
429
|
initLogger({ dir: getCesLogDir(), retentionDays: 30 });
|
|
440
430
|
const log = getLogger("main");
|
|
441
431
|
|
|
442
|
-
// `CES_STANDALONE=1` runs CES as an independent, CLI-launched sibling over a
|
|
443
|
-
// Unix socket; otherwise CES is the assistant's stdio child, as today.
|
|
444
|
-
const standalone = process.env["CES_STANDALONE"] === "1";
|
|
445
|
-
|
|
446
432
|
log.info(
|
|
447
|
-
`Starting CES v${CES_PROTOCOL_VERSION} (local mode,
|
|
448
|
-
standalone ? "standalone socket" : "stdio"
|
|
449
|
-
} transport)`,
|
|
433
|
+
`Starting CES v${CES_PROTOCOL_VERSION} (local mode, socket transport)`,
|
|
450
434
|
);
|
|
451
435
|
|
|
452
436
|
const controller = new AbortController();
|
|
@@ -485,43 +469,23 @@ async function main(): Promise<void> {
|
|
|
485
469
|
error: (msg: string, ...args: unknown[]) => rpcLog.error({ args }, msg),
|
|
486
470
|
};
|
|
487
471
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
serveStandaloneSocket({
|
|
492
|
-
socketPath: getLocalSocketPath(),
|
|
493
|
-
handlers,
|
|
494
|
-
signal: controller.signal,
|
|
495
|
-
logger: rpcLogger,
|
|
496
|
-
log,
|
|
497
|
-
});
|
|
498
|
-
await new Promise<void>((resolve) => {
|
|
499
|
-
if (controller.signal.aborted) {
|
|
500
|
-
resolve();
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
|
-
controller.signal.addEventListener("abort", () => resolve(), {
|
|
504
|
-
once: true,
|
|
505
|
-
});
|
|
506
|
-
});
|
|
507
|
-
log.info("Server stopped.");
|
|
508
|
-
return;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
// Default: serve the spawning assistant over stdio. stdin closing (parent
|
|
512
|
-
// exit) or SIGTERM shuts CES down.
|
|
513
|
-
const server = new CesRpcServer({
|
|
514
|
-
input: process.stdin,
|
|
515
|
-
output: process.stdout,
|
|
472
|
+
// Serve over a Unix socket and run until a shutdown signal.
|
|
473
|
+
serveStandaloneSocket({
|
|
474
|
+
socketPath: getLocalSocketPath(),
|
|
516
475
|
handlers,
|
|
517
|
-
logger: rpcLogger,
|
|
518
476
|
signal: controller.signal,
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
477
|
+
logger: rpcLogger,
|
|
478
|
+
log,
|
|
479
|
+
});
|
|
480
|
+
await new Promise<void>((resolve) => {
|
|
481
|
+
if (controller.signal.aborted) {
|
|
482
|
+
resolve();
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
controller.signal.addEventListener("abort", () => resolve(), {
|
|
486
|
+
once: true,
|
|
487
|
+
});
|
|
522
488
|
});
|
|
523
|
-
|
|
524
|
-
await server.serve();
|
|
525
489
|
log.info("Server stopped.");
|
|
526
490
|
}
|
|
527
491
|
|
package/src/paths.ts
CHANGED
|
@@ -141,7 +141,7 @@ export function getBootstrapSocketPath(): string {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
// ---------------------------------------------------------------------------
|
|
144
|
-
// Local-mode
|
|
144
|
+
// Local-mode CES socket
|
|
145
145
|
// ---------------------------------------------------------------------------
|
|
146
146
|
|
|
147
147
|
/** Default local-mode CES socket filename (under the local data root). */
|
|
@@ -150,10 +150,9 @@ const LOCAL_SOCKET_NAME = "ces.sock";
|
|
|
150
150
|
/**
|
|
151
151
|
* Return the path to the local-mode CES Unix socket.
|
|
152
152
|
*
|
|
153
|
-
* Used when local CES runs as a
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
* directory permissions are the access boundary.
|
|
153
|
+
* Used when local CES runs as a CLI-launched sibling process. The socket
|
|
154
|
+
* lives under the CES-private local data root, whose directory permissions
|
|
155
|
+
* are the access boundary.
|
|
157
156
|
*
|
|
158
157
|
* Priority:
|
|
159
158
|
* 1. `CES_LOCAL_SOCKET` env var (full file path override; the CLI sets this
|