@mycadet/credential-executor 0.12.6-dev.202610080102.d7d1bec → 0.12.6-dev.202610082233.54244ee
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__/managed-reconnect.test.ts +0 -3
- package/src/__tests__/transport.test.ts +14 -22
- package/src/cli.ts +5 -35
- package/src/main.ts +4 -14
- package/src/materializers/local-secure-key-backend.ts +25 -22
- package/src/paths.ts +26 -35
package/package.json
CHANGED
|
@@ -179,10 +179,8 @@ describe("managed CES reconnection (real entrypoint)", () => {
|
|
|
179
179
|
const socketPath = resolveIpcEndpoint("ces", {
|
|
180
180
|
workspaceDir: socketDir,
|
|
181
181
|
}).path;
|
|
182
|
-
const assistantDataMount = join(tmpDir, "assistant-data-ro");
|
|
183
182
|
mkdirSync(dataDir, { recursive: true });
|
|
184
183
|
mkdirSync(socketDir, { recursive: true });
|
|
185
|
-
mkdirSync(join(assistantDataMount, ".cadet"), { recursive: true });
|
|
186
184
|
|
|
187
185
|
const healthPort = await pickFreePort();
|
|
188
186
|
const managedMain = resolve(__dirname, "..", "main.ts");
|
|
@@ -195,7 +193,6 @@ describe("managed CES reconnection (real entrypoint)", () => {
|
|
|
195
193
|
CES_DATA_DIR: dataDir,
|
|
196
194
|
CES_BOOTSTRAP_SOCKET_DIR: socketDir,
|
|
197
195
|
CES_HEALTH_PORT: String(healthPort),
|
|
198
|
-
CES_ASSISTANT_DATA_MOUNT: assistantDataMount,
|
|
199
196
|
},
|
|
200
197
|
stdout: "ignore",
|
|
201
198
|
stderr: "ignore",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import { describe, expect, test } from "bun:test";
|
|
16
16
|
import { readFileSync } from "node:fs";
|
|
17
|
-
import { resolve } from "node:path";
|
|
17
|
+
import { join, resolve } from "node:path";
|
|
18
18
|
import { PassThrough } from "node:stream";
|
|
19
19
|
|
|
20
20
|
import { resolveIpcEndpoint } from "@mycadet/ipc-server-utils";
|
|
@@ -355,25 +355,11 @@ describe("CesRpcServer", () => {
|
|
|
355
355
|
// ---------------------------------------------------------------------------
|
|
356
356
|
|
|
357
357
|
describe("CES data paths", () => {
|
|
358
|
-
test("
|
|
359
|
-
const root = getCesDataRoot("local");
|
|
360
|
-
expect(root).toMatch(/protected[/\\]credential-executor$/);
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
test("managed mode data root defaults to /ces-data", () => {
|
|
364
|
-
const savedDir = process.env["CES_DATA_DIR"];
|
|
365
|
-
delete process.env["CES_DATA_DIR"];
|
|
366
|
-
try {
|
|
367
|
-
expect(getCesDataRoot("managed")).toBe("/ces-data");
|
|
368
|
-
} finally {
|
|
369
|
-
if (savedDir !== undefined) process.env["CES_DATA_DIR"] = savedDir;
|
|
370
|
-
}
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
test("managed mode data root respects CES_DATA_DIR env var", () => {
|
|
358
|
+
test("data root resolves CES_DATA_DIR in any mode", () => {
|
|
374
359
|
const savedDir = process.env["CES_DATA_DIR"];
|
|
375
360
|
process.env["CES_DATA_DIR"] = "/custom/ces-data";
|
|
376
361
|
try {
|
|
362
|
+
expect(getCesDataRoot("local")).toBe("/custom/ces-data");
|
|
377
363
|
expect(getCesDataRoot("managed")).toBe("/custom/ces-data");
|
|
378
364
|
} finally {
|
|
379
365
|
if (savedDir !== undefined) {
|
|
@@ -384,11 +370,17 @@ describe("CES data paths", () => {
|
|
|
384
370
|
}
|
|
385
371
|
});
|
|
386
372
|
|
|
387
|
-
test("
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
373
|
+
test("data root falls back to ./ces-data (cwd convention)", () => {
|
|
374
|
+
const savedDir = process.env["CES_DATA_DIR"];
|
|
375
|
+
delete process.env["CES_DATA_DIR"];
|
|
376
|
+
try {
|
|
377
|
+
expect(getCesDataRoot("managed")).toBe(
|
|
378
|
+
join(process.cwd(), "ces-data"),
|
|
379
|
+
);
|
|
380
|
+
expect(getCesDataRoot("local")).toBe(join(process.cwd(), "ces-data"));
|
|
381
|
+
} finally {
|
|
382
|
+
if (savedDir !== undefined) process.env["CES_DATA_DIR"] = savedDir;
|
|
383
|
+
}
|
|
392
384
|
});
|
|
393
385
|
|
|
394
386
|
test("getBootstrapSocketPath defaults to /run/ces-bootstrap", () => {
|
package/src/cli.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
/**
|
|
3
|
-
* CES CLI — lightweight credential CRUD for the
|
|
3
|
+
* CES CLI — lightweight credential CRUD for the encrypted key store.
|
|
4
4
|
*
|
|
5
5
|
* Operates directly on the encrypted key store (`keys.enc` + `store.key`)
|
|
6
6
|
* without requiring the RPC server, HTTP routes, or a running assistant.
|
|
@@ -15,40 +15,11 @@
|
|
|
15
15
|
*
|
|
16
16
|
* Environment variables:
|
|
17
17
|
* CREDENTIAL_SECURITY_DIR — directory containing `keys.enc` + `store.key`
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* When neither is set, defaults to `~/.cadet/protected/` (local mode).
|
|
18
|
+
* (falls back to `./ces-security`)
|
|
21
19
|
*/
|
|
22
20
|
|
|
23
|
-
import { join } from "node:path";
|
|
24
|
-
import { homedir } from "node:os";
|
|
25
21
|
import { createLocalSecureKeyBackend } from "./materializers/local-secure-key-backend.js";
|
|
26
|
-
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
// Path resolution (mirrors the managed-mode path in main.ts)
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
|
|
31
|
-
function resolveCadetRoot(): string {
|
|
32
|
-
const secDir = process.env["CREDENTIAL_SECURITY_DIR"]?.trim();
|
|
33
|
-
if (secDir) {
|
|
34
|
-
// CREDENTIAL_SECURITY_DIR points directly at the dir containing
|
|
35
|
-
// keys.enc, but createLocalSecureKeyBackend wants the parent
|
|
36
|
-
// (.cadet root) and appends /protected/ itself — unless
|
|
37
|
-
// CREDENTIAL_SECURITY_DIR is set, in which case the backend reads
|
|
38
|
-
// from that dir directly. So we pass dirname(secDir) as cadetRoot.
|
|
39
|
-
// Actually, looking at resolveSecurityDir(): if CREDENTIAL_SECURITY_DIR
|
|
40
|
-
// is set it uses that directly, ignoring cadetRoot. So cadetRoot
|
|
41
|
-
// can be anything — the env var takes precedence.
|
|
42
|
-
return join(secDir, "..");
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const mount = process.env["CES_ASSISTANT_DATA_MOUNT"]?.trim();
|
|
46
|
-
if (mount) {
|
|
47
|
-
return join(mount, ".cadet");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return join(homedir(), ".cadet");
|
|
51
|
-
}
|
|
22
|
+
import { getSecurityDir } from "./paths.js";
|
|
52
23
|
|
|
53
24
|
// ---------------------------------------------------------------------------
|
|
54
25
|
// CLI
|
|
@@ -62,8 +33,7 @@ async function main(): Promise<void> {
|
|
|
62
33
|
process.exit(0);
|
|
63
34
|
}
|
|
64
35
|
|
|
65
|
-
const
|
|
66
|
-
const backend = createLocalSecureKeyBackend(cadetRoot);
|
|
36
|
+
const backend = createLocalSecureKeyBackend(getSecurityDir());
|
|
67
37
|
|
|
68
38
|
switch (command) {
|
|
69
39
|
case "list": {
|
|
@@ -149,7 +119,7 @@ Account format:
|
|
|
149
119
|
|
|
150
120
|
Environment:
|
|
151
121
|
CREDENTIAL_SECURITY_DIR Directory containing keys.enc + store.key
|
|
152
|
-
|
|
122
|
+
(falls back to ./ces-security)`);
|
|
153
123
|
}
|
|
154
124
|
|
|
155
125
|
main().catch((err) => {
|
package/src/main.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
import { mkdirSync } from "node:fs";
|
|
21
21
|
import { createServer as createNetServer, type Socket } from "node:net";
|
|
22
|
-
import { dirname
|
|
22
|
+
import { dirname } from "node:path";
|
|
23
23
|
import { Readable, Writable } from "node:stream";
|
|
24
24
|
|
|
25
25
|
import {
|
|
@@ -345,19 +345,9 @@ async function main(): Promise<void> {
|
|
|
345
345
|
process.on("SIGINT", shutdown);
|
|
346
346
|
|
|
347
347
|
// -- Secure key backend + migrations --------------------------------------
|
|
348
|
-
//
|
|
349
|
-
//
|
|
350
|
-
|
|
351
|
-
// - Managed: join(assistantDataMount, ".cadet") — the assistant data mount.
|
|
352
|
-
const secureKeyBackend =
|
|
353
|
-
mode === "managed"
|
|
354
|
-
? createLocalSecureKeyBackend(
|
|
355
|
-
join(
|
|
356
|
-
process.env["CES_ASSISTANT_DATA_MOUNT"] ?? "/assistant-data-ro",
|
|
357
|
-
".cadet",
|
|
358
|
-
),
|
|
359
|
-
)
|
|
360
|
-
: createLocalSecureKeyBackend(dirname(getSecurityDir()));
|
|
348
|
+
// Both modes resolve the store location through getSecurityDir() (env var,
|
|
349
|
+
// cwd fallback convention) — see paths.ts.
|
|
350
|
+
const secureKeyBackend = createLocalSecureKeyBackend(getSecurityDir());
|
|
361
351
|
|
|
362
352
|
await runCesMigrations(
|
|
363
353
|
getCesDataRoot(mode),
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* CES-native SecureKeyBackend for **local mode only**.
|
|
3
3
|
*
|
|
4
4
|
* In local mode, CES runs as a child process of the assistant on the same
|
|
5
|
-
* machine as the same user and can read/write the
|
|
6
|
-
*
|
|
5
|
+
* machine as the same user and can read/write the encrypted key store file
|
|
6
|
+
* at `<ces-security>/keys.enc`.
|
|
7
7
|
*
|
|
8
8
|
* This implementation replicates the encryption/decryption logic from the
|
|
9
9
|
* assistant's `encrypted-store.ts` without importing assistant-internal
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* Two store formats are supported:
|
|
16
16
|
*
|
|
17
17
|
* - **v2 (primary):** AES-256-GCM with a random 32-byte key stored at
|
|
18
|
-
* `<
|
|
18
|
+
* `<ces-security>/store.key`. The key is machine-independent —
|
|
19
19
|
* any process that can read the key file can decrypt the store.
|
|
20
20
|
*
|
|
21
21
|
* - **v1 (legacy):** AES-256-GCM with a key derived from machine-specific
|
|
@@ -106,13 +106,14 @@ const KEYS_ENC_FILENAME = "keys.enc";
|
|
|
106
106
|
*
|
|
107
107
|
* When `CREDENTIAL_SECURITY_DIR` is set, files are read from (and written to)
|
|
108
108
|
* that directory directly. This allows Docker deployments to mount a separate
|
|
109
|
-
* CES-only security volume
|
|
109
|
+
* CES-only security volume, and the CLI to point CES at the per-instance
|
|
110
|
+
* security dir.
|
|
110
111
|
*
|
|
111
|
-
* When the env var is unset, falls back to
|
|
112
|
-
*
|
|
112
|
+
* When the env var is unset, falls back to the passed-in default
|
|
113
|
+
* (`./ces-security` under the cwd fallback convention).
|
|
113
114
|
*/
|
|
114
|
-
function resolveSecurityDir(
|
|
115
|
-
return process.env.CREDENTIAL_SECURITY_DIR ||
|
|
115
|
+
function resolveSecurityDir(securityDir: string): string {
|
|
116
|
+
return process.env.CREDENTIAL_SECURITY_DIR?.trim() || securityDir;
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
/**
|
|
@@ -120,9 +121,9 @@ function resolveSecurityDir(cadetRoot: string): string {
|
|
|
120
121
|
* Returns the raw 32-byte key buffer, or null if the file is missing,
|
|
121
122
|
* wrong size, or unreadable.
|
|
122
123
|
*/
|
|
123
|
-
function readStoreKey(
|
|
124
|
+
function readStoreKey(securityDir: string): Buffer | null {
|
|
124
125
|
try {
|
|
125
|
-
const keyPath = join(resolveSecurityDir(
|
|
126
|
+
const keyPath = join(resolveSecurityDir(securityDir), STORE_KEY_FILENAME);
|
|
126
127
|
if (!existsSync(keyPath)) return null;
|
|
127
128
|
const buf = readFileSync(keyPath);
|
|
128
129
|
if (buf.length !== KEY_LENGTH) return null;
|
|
@@ -140,15 +141,15 @@ function readStoreKey(cadetRoot: string): Buffer | null {
|
|
|
140
141
|
* Read or generate the v2 store key. If the key file does not exist,
|
|
141
142
|
* creates a new 32-byte random key and writes it atomically.
|
|
142
143
|
*/
|
|
143
|
-
function getOrReadStoreKey(
|
|
144
|
-
const existing = readStoreKey(
|
|
144
|
+
function getOrReadStoreKey(securityDir: string): Buffer {
|
|
145
|
+
const existing = readStoreKey(securityDir);
|
|
145
146
|
if (existing) return existing;
|
|
146
147
|
|
|
147
|
-
const
|
|
148
|
+
const resolvedSecurityDir = resolveSecurityDir(securityDir);
|
|
148
149
|
mkdirSync(securityDir, { recursive: true });
|
|
149
150
|
|
|
150
151
|
const key = randomBytes(KEY_LENGTH);
|
|
151
|
-
const keyPath = join(
|
|
152
|
+
const keyPath = join(resolvedSecurityDir, STORE_KEY_FILENAME);
|
|
152
153
|
const tmpPath = keyPath + `.tmp.${process.pid}`;
|
|
153
154
|
writeFileSync(tmpPath, key, { mode: 0o600 });
|
|
154
155
|
chmodSync(tmpPath, 0o600);
|
|
@@ -166,14 +167,14 @@ function getOrReadStoreKey(cadetRoot: string): Buffer {
|
|
|
166
167
|
*/
|
|
167
168
|
function getOrCreateStore(
|
|
168
169
|
storePath: string,
|
|
169
|
-
|
|
170
|
+
securityDir: string,
|
|
170
171
|
): { store: StoreFile; aesKey: Buffer } {
|
|
171
172
|
const existing = readStore(storePath);
|
|
172
173
|
if (existing) {
|
|
173
174
|
if (existing.version === 1) {
|
|
174
175
|
throw new Error("v1 store cannot be auto-initialized");
|
|
175
176
|
}
|
|
176
|
-
const storeKey = readStoreKey(
|
|
177
|
+
const storeKey = readStoreKey(securityDir);
|
|
177
178
|
if (!storeKey) {
|
|
178
179
|
throw new Error("v2 store exists but store.key is missing or corrupt");
|
|
179
180
|
}
|
|
@@ -181,7 +182,7 @@ function getOrCreateStore(
|
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
// No store exists — create a new empty v2 store
|
|
184
|
-
const aesKey = getOrReadStoreKey(
|
|
185
|
+
const aesKey = getOrReadStoreKey(securityDir);
|
|
185
186
|
const store: StoreFileV2 = { version: 2, entries: {} };
|
|
186
187
|
writeStore(store, storePath);
|
|
187
188
|
return { store, aesKey };
|
|
@@ -346,25 +347,27 @@ export class StoreUnavailableError extends Error {
|
|
|
346
347
|
* persisting refreshed OAuth tokens. `delete` removes a key from the
|
|
347
348
|
* encrypted store.
|
|
348
349
|
*
|
|
349
|
-
* @param
|
|
350
|
+
* @param securityDir - CES security directory (holds keys.enc + store.key).
|
|
350
351
|
* @param options.entropyOverride - If provided, used instead of local
|
|
351
352
|
* machine entropy for key derivation. In managed mode the CES sidecar
|
|
352
353
|
* runs in a different container with a different hostname/user, so it
|
|
353
354
|
* must use the assistant's entropy (read from the shared data mount)
|
|
354
355
|
* to derive the same AES key.
|
|
356
|
+
* @param securityDir Default CES security directory (used when
|
|
357
|
+
* CREDENTIAL_SECURITY_DIR is unset).
|
|
355
358
|
* @param options.entropyGetter - If provided, called on each `get()`/`set()`
|
|
356
359
|
* to lazily resolve entropy. This handles the startup race where the
|
|
357
360
|
* entropy file may not exist at construction time but appears later.
|
|
358
361
|
* Takes precedence over `entropyOverride`.
|
|
359
362
|
*/
|
|
360
363
|
export function createLocalSecureKeyBackend(
|
|
361
|
-
|
|
364
|
+
securityDir: string,
|
|
362
365
|
options?: {
|
|
363
366
|
entropyOverride?: string;
|
|
364
367
|
entropyGetter?: () => string | undefined;
|
|
365
368
|
},
|
|
366
369
|
): SecureKeyBackend {
|
|
367
|
-
const storePath = join(resolveSecurityDir(
|
|
370
|
+
const storePath = join(resolveSecurityDir(securityDir), KEYS_ENC_FILENAME);
|
|
368
371
|
const staticEntropy = options?.entropyOverride;
|
|
369
372
|
const entropyGetter = options?.entropyGetter;
|
|
370
373
|
|
|
@@ -389,7 +392,7 @@ export function createLocalSecureKeyBackend(
|
|
|
389
392
|
|
|
390
393
|
let aesKey: Buffer;
|
|
391
394
|
if (store.version === 2) {
|
|
392
|
-
const storeKey = readStoreKey(
|
|
395
|
+
const storeKey = readStoreKey(securityDir);
|
|
393
396
|
if (!storeKey) {
|
|
394
397
|
// The entry exists but the key material to decrypt it is unavailable
|
|
395
398
|
// (the cold-start race). Unavailable, NOT not-found.
|
|
@@ -427,7 +430,7 @@ export function createLocalSecureKeyBackend(
|
|
|
427
430
|
let aesKey: Buffer;
|
|
428
431
|
|
|
429
432
|
try {
|
|
430
|
-
const result = getOrCreateStore(storePath,
|
|
433
|
+
const result = getOrCreateStore(storePath, securityDir);
|
|
431
434
|
store = result.store;
|
|
432
435
|
aesKey = result.aesKey;
|
|
433
436
|
} catch {
|
package/src/paths.ts
CHANGED
|
@@ -2,25 +2,26 @@
|
|
|
2
2
|
* CES private data-root layout.
|
|
3
3
|
*
|
|
4
4
|
* Defines the directory structure for CES-private durable state (grants,
|
|
5
|
-
* audit logs, tool store)
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* audit logs, tool store) and CES-private security material (the encrypted
|
|
6
|
+
* store, `keys.enc` + `store.key`). This state is never stored on the
|
|
7
|
+
* assistant-visible workspace/data root — it lives in CES-only paths that
|
|
8
|
+
* the assistant process cannot read or write.
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
+
* Resolution convention (shared with the gateway and the assistant):
|
|
11
|
+
* every directory comes from its env var, falling back to
|
|
12
|
+
* `process.cwd()/<hardcoded-value>`:
|
|
10
13
|
*
|
|
11
|
-
* -
|
|
12
|
-
*
|
|
14
|
+
* - `CREDENTIAL_SECURITY_DIR` → `./ces-security`
|
|
15
|
+
* - `CES_DATA_DIR` → `./ces-data`
|
|
13
16
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* is a separate path and must never be used for CES-private writes.
|
|
17
|
+
* Managed containers set both explicitly (the platform template provisions
|
|
18
|
+
* `/ces-security` and `/ces-data` volumes); local mode sets them per
|
|
19
|
+
* instance dir via the CLI. The assistant-visible data root (where
|
|
20
|
+
* workspace, embeddings, etc. live) is a separate path and must never be
|
|
21
|
+
* used for CES-private writes.
|
|
20
22
|
*/
|
|
21
23
|
|
|
22
24
|
import { join } from "node:path";
|
|
23
|
-
import { homedir } from "node:os";
|
|
24
25
|
|
|
25
26
|
import { resolveIpcEndpoint } from "@mycadet/ipc-server-utils";
|
|
26
27
|
|
|
@@ -45,41 +46,31 @@ export function getCesMode(): CesMode {
|
|
|
45
46
|
// ---------------------------------------------------------------------------
|
|
46
47
|
|
|
47
48
|
/**
|
|
48
|
-
* Resolve the CES security directory.
|
|
49
|
+
* Resolve the CES security directory (contains `keys.enc` + `store.key`).
|
|
49
50
|
*
|
|
50
51
|
* Priority:
|
|
51
52
|
* 1. `CREDENTIAL_SECURITY_DIR` env var (set by the platform template for the
|
|
52
|
-
* CES container — `/ces-security` in managed mode
|
|
53
|
-
*
|
|
54
|
-
*
|
|
53
|
+
* CES container — `/ces-security` in managed mode; per-instance
|
|
54
|
+
* `<instanceDir>/ces-security` in local mode)
|
|
55
|
+
* 2. Default: `./ces-security` (cwd fallback convention)
|
|
55
56
|
*/
|
|
56
57
|
export function getSecurityDir(): string {
|
|
57
58
|
return (
|
|
58
59
|
process.env["CREDENTIAL_SECURITY_DIR"]?.trim() ||
|
|
59
|
-
join(
|
|
60
|
+
join(process.cwd(), "ces-security")
|
|
60
61
|
);
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
/**
|
|
64
|
-
*
|
|
65
|
+
* Return the CES-private data root (grants, audit logs, tool store).
|
|
65
66
|
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Return the CES-private data root.
|
|
73
|
-
*
|
|
74
|
-
* - Local: `<securityDir>/credential-executor/`
|
|
75
|
-
* - Managed: `CES_DATA_DIR` env var, or `/ces-data` by default
|
|
67
|
+
* Priority:
|
|
68
|
+
* 1. `CES_DATA_DIR` env var (set by the platform template — `/ces-data` in
|
|
69
|
+
* managed mode; per-instance `<instanceDir>/ces-data` in local mode)
|
|
70
|
+
* 2. Default: `./ces-data` (cwd fallback convention)
|
|
76
71
|
*/
|
|
77
|
-
export function getCesDataRoot(
|
|
78
|
-
|
|
79
|
-
if (resolvedMode === "managed") {
|
|
80
|
-
return process.env["CES_DATA_DIR"] ?? DEFAULT_MANAGED_CES_DATA_ROOT;
|
|
81
|
-
}
|
|
82
|
-
return join(getSecurityDir(), "credential-executor");
|
|
72
|
+
export function getCesDataRoot(_mode?: CesMode): string {
|
|
73
|
+
return process.env["CES_DATA_DIR"]?.trim() || join(process.cwd(), "ces-data");
|
|
83
74
|
}
|
|
84
75
|
|
|
85
76
|
// ---------------------------------------------------------------------------
|