@telora/daemon 0.17.53 → 0.17.59
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/build-info.json +2 -2
- package/dist/auth-liveness.d.ts +41 -0
- package/dist/auth-liveness.d.ts.map +1 -0
- package/dist/auth-liveness.js +68 -0
- package/dist/auth-liveness.js.map +1 -0
- package/dist/backends/agent-backend.d.ts +9 -0
- package/dist/backends/agent-backend.d.ts.map +1 -1
- package/dist/backends/claude/claude-backend.d.ts.map +1 -1
- package/dist/backends/claude/claude-backend.js +8 -0
- package/dist/backends/claude/claude-backend.js.map +1 -1
- package/dist/backends/codex/codex-backend.d.ts +9 -4
- package/dist/backends/codex/codex-backend.d.ts.map +1 -1
- package/dist/backends/codex/codex-backend.js +13 -4
- package/dist/backends/codex/codex-backend.js.map +1 -1
- package/dist/cli/connect.d.ts.map +1 -1
- package/dist/cli/connect.js +10 -0
- package/dist/cli/connect.js.map +1 -1
- package/dist/delivery-advance-block.d.ts +60 -0
- package/dist/delivery-advance-block.d.ts.map +1 -0
- package/dist/delivery-advance-block.js +89 -0
- package/dist/delivery-advance-block.js.map +1 -0
- package/dist/delivery-lifecycle.d.ts +2 -22
- package/dist/delivery-lifecycle.d.ts.map +1 -1
- package/dist/delivery-lifecycle.js +5 -49
- package/dist/delivery-lifecycle.js.map +1 -1
- package/dist/focus-engine.d.ts.map +1 -1
- package/dist/focus-engine.js +12 -0
- package/dist/focus-engine.js.map +1 -1
- package/dist/focus-executor.d.ts +1 -1
- package/dist/focus-executor.d.ts.map +1 -1
- package/dist/focus-executor.js +41 -4
- package/dist/focus-executor.js.map +1 -1
- package/dist/queries/issues.d.ts +14 -0
- package/dist/queries/issues.d.ts.map +1 -1
- package/dist/queries/issues.js +23 -0
- package/dist/queries/issues.js.map +1 -1
- package/dist/scanners/deps.d.ts +16 -0
- package/dist/scanners/deps.d.ts.map +1 -1
- package/dist/scanners/deps.js +39 -0
- package/dist/scanners/deps.js.map +1 -1
- package/dist/spawn-environment.d.ts +38 -1
- package/dist/spawn-environment.d.ts.map +1 -1
- package/dist/spawn-environment.js +73 -4
- package/dist/spawn-environment.js.map +1 -1
- package/dist/spawn-sandbox.d.ts +117 -0
- package/dist/spawn-sandbox.d.ts.map +1 -0
- package/dist/spawn-sandbox.js +210 -0
- package/dist/spawn-sandbox.js.map +1 -0
- package/dist/staleness.d.ts.map +1 -1
- package/dist/staleness.js +13 -2
- package/dist/staleness.js.map +1 -1
- package/dist/supabase.d.ts +1 -1
- package/dist/supabase.d.ts.map +1 -1
- package/dist/supabase.js +1 -1
- package/dist/supabase.js.map +1 -1
- package/dist/types/config.d.ts +40 -0
- package/dist/types/config.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/scanners/deps.d.ts
CHANGED
|
@@ -58,6 +58,14 @@ export interface NpmAuditResult {
|
|
|
58
58
|
exitCode: number;
|
|
59
59
|
}
|
|
60
60
|
export type NpmAuditRunner = (repoPath: string) => Promise<NpmAuditResult>;
|
|
61
|
+
/** Coverage breadcrumb emitted when the Node-project gate skips the audit. */
|
|
62
|
+
export declare const NO_NODE_PROJECT_SKIP_REASON = "no_node_project_at_repo_root";
|
|
63
|
+
/**
|
|
64
|
+
* True when `repoPath` is a Node project AT its root: a package.json and at
|
|
65
|
+
* least one recognized lockfile both present. This is the precondition for
|
|
66
|
+
* running `npm audit` without it walking up the directory tree.
|
|
67
|
+
*/
|
|
68
|
+
declare function defaultHasNodeProjectAtRoot(repoPath: string): boolean;
|
|
61
69
|
declare function mapSeverity(s: NpmSeverity | undefined): Severity | null;
|
|
62
70
|
declare function parseAuditJson(raw: string): NpmAuditOutput;
|
|
63
71
|
export interface DepsScannerExternalDeps {
|
|
@@ -86,6 +94,13 @@ export interface DepsScannerExternalDeps {
|
|
|
86
94
|
}>;
|
|
87
95
|
/** Optional local IOC feed loader; default reads from security_ioc_feed_entries. */
|
|
88
96
|
loadLocalIocFeed?: (organizationId: string, iocClass?: string) => Promise<IocFeedEntry[]>;
|
|
97
|
+
/**
|
|
98
|
+
* Optional Node-project detector; default checks for package.json + a
|
|
99
|
+
* recognized lockfile at the repo root. When it returns false the scan is
|
|
100
|
+
* skipped (no npm audit run, no walk-up). Injectable so unit tests can
|
|
101
|
+
* exercise both the skip and the normal audit path without a real fs.
|
|
102
|
+
*/
|
|
103
|
+
hasNodeProjectAtRoot?: (repoPath: string) => boolean;
|
|
89
104
|
}
|
|
90
105
|
export declare function createDepsScanner(opts: DepsScannerExternalDeps): Scanner;
|
|
91
106
|
declare function computePackagesAudited(audit: NpmAuditOutput): number;
|
|
@@ -93,6 +108,7 @@ export declare const depsScanner: Scanner;
|
|
|
93
108
|
/** Test seam re-export for unit tests. */
|
|
94
109
|
export declare const _internal: {
|
|
95
110
|
defaultRunNpmAudit: NpmAuditRunner;
|
|
111
|
+
defaultHasNodeProjectAtRoot: typeof defaultHasNodeProjectAtRoot;
|
|
96
112
|
mapSeverity: typeof mapSeverity;
|
|
97
113
|
parseAuditJson: typeof parseAuditJson;
|
|
98
114
|
computePackagesAudited: typeof computePackagesAudited;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../src/scanners/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../src/scanners/deps.ts"],"names":[],"mappings":"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"}
|
package/dist/scanners/deps.js
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* @module scanners/deps
|
|
15
15
|
*/
|
|
16
16
|
import { spawn } from 'node:child_process';
|
|
17
|
+
import { existsSync } from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
17
19
|
import { queryOsv } from '../feeds/osv.js';
|
|
18
20
|
import { queryGhsa } from '../feeds/ghsa.js';
|
|
19
21
|
import { loadLocalIocFeed, matchesPattern } from '../feeds/local.js';
|
|
@@ -36,6 +38,34 @@ const defaultRunNpmAudit = (repoPath) => new Promise((resolve, reject) => {
|
|
|
36
38
|
});
|
|
37
39
|
});
|
|
38
40
|
// ---------------------------------------------------------------------------
|
|
41
|
+
// Node-project gate
|
|
42
|
+
//
|
|
43
|
+
// `npm audit`, when the cwd has no package.json/lockfile, walks UP the
|
|
44
|
+
// directory tree and audits the nearest Node project it finds. For a
|
|
45
|
+
// non-Node repo (e.g. an Ansible/Docker IaC repo) that misattributes
|
|
46
|
+
// another project's npm advisories to the wrong product. We gate the audit
|
|
47
|
+
// on a Node project being present AT the repo root: package.json plus a
|
|
48
|
+
// recognized lockfile. Absent either, the scan is skipped entirely.
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
const RECOGNIZED_LOCKFILES = [
|
|
51
|
+
'package-lock.json',
|
|
52
|
+
'npm-shrinkwrap.json',
|
|
53
|
+
'pnpm-lock.yaml',
|
|
54
|
+
'yarn.lock',
|
|
55
|
+
];
|
|
56
|
+
/** Coverage breadcrumb emitted when the Node-project gate skips the audit. */
|
|
57
|
+
export const NO_NODE_PROJECT_SKIP_REASON = 'no_node_project_at_repo_root';
|
|
58
|
+
/**
|
|
59
|
+
* True when `repoPath` is a Node project AT its root: a package.json and at
|
|
60
|
+
* least one recognized lockfile both present. This is the precondition for
|
|
61
|
+
* running `npm audit` without it walking up the directory tree.
|
|
62
|
+
*/
|
|
63
|
+
function defaultHasNodeProjectAtRoot(repoPath) {
|
|
64
|
+
if (!existsSync(join(repoPath, 'package.json')))
|
|
65
|
+
return false;
|
|
66
|
+
return RECOGNIZED_LOCKFILES.some((lockfile) => existsSync(join(repoPath, lockfile)));
|
|
67
|
+
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
39
69
|
// Severity mapping
|
|
40
70
|
// ---------------------------------------------------------------------------
|
|
41
71
|
function mapSeverity(s) {
|
|
@@ -88,9 +118,17 @@ export function createDepsScanner(opts) {
|
|
|
88
118
|
const osv = opts.queryOsv ?? ((input) => queryOsv({ packages: input.packages }));
|
|
89
119
|
const ghsa = opts.queryGhsa ?? ((input) => queryGhsa({ packages: input.packages, githubToken: input.githubToken }));
|
|
90
120
|
const local = opts.loadLocalIocFeed ?? loadLocalIocFeed;
|
|
121
|
+
const hasNodeProjectAtRoot = opts.hasNodeProjectAtRoot ?? defaultHasNodeProjectAtRoot;
|
|
91
122
|
return {
|
|
92
123
|
iocClass: 'deps',
|
|
93
124
|
async scan(ctx) {
|
|
125
|
+
// Gate on a Node project at the repo root BEFORE spawning npm audit.
|
|
126
|
+
// A non-Node repo (no package.json + lockfile) would otherwise let
|
|
127
|
+
// npm audit walk UP the tree and misattribute another project's
|
|
128
|
+
// advisories to this product.
|
|
129
|
+
if (!hasNodeProjectAtRoot(ctx.repoPath)) {
|
|
130
|
+
return { findings: [], coverage: { skipped: NO_NODE_PROJECT_SKIP_REASON } };
|
|
131
|
+
}
|
|
94
132
|
const { stdout, exitCode } = await opts.runNpmAudit(ctx.repoPath);
|
|
95
133
|
let audit;
|
|
96
134
|
try {
|
|
@@ -235,6 +273,7 @@ export const depsScanner = createDepsScanner({
|
|
|
235
273
|
/** Test seam re-export for unit tests. */
|
|
236
274
|
export const _internal = {
|
|
237
275
|
defaultRunNpmAudit,
|
|
276
|
+
defaultHasNodeProjectAtRoot,
|
|
238
277
|
mapSeverity,
|
|
239
278
|
parseAuditJson,
|
|
240
279
|
computePackagesAudited,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../../src/scanners/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../../src/scanners/deps.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,41 @@
|
|
|
11
11
|
* is preserved because it is set intentionally.
|
|
12
12
|
*/
|
|
13
13
|
import type { DaemonConfig } from './types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Environment allowlist for spawned agents (ambient-authority reduction).
|
|
16
|
+
*
|
|
17
|
+
* The daemon used to spread its entire `process.env` into every spawn, so an
|
|
18
|
+
* agent inherited the operator's SSH agent socket, cloud-CLI credentials,
|
|
19
|
+
* registry tokens, and arbitrary host env -- the full operator identity. We now
|
|
20
|
+
* build the spawn environment from an explicit allowlist: only the keys an
|
|
21
|
+
* agent legitimately needs reach it. Everything else (SSH_AUTH_SOCK, AWS_*,
|
|
22
|
+
* GOOGLE_*, GITHUB_TOKEN, NPM_TOKEN, KUBECONFIG, ...) is dropped by construction.
|
|
23
|
+
*
|
|
24
|
+
* Anything the daemon must inject regardless (TELORA_DAEMON_AGENT,
|
|
25
|
+
* TELORA_MCP_PROFILE, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS, OTEL_*, and the
|
|
26
|
+
* per-spawn fetched model secret from fetchBackendEnvExtras) is added explicitly
|
|
27
|
+
* AFTER this filter and is unaffected by it.
|
|
28
|
+
*
|
|
29
|
+
* See docs/security-posture-daemon-execution.md for the rationale and the
|
|
30
|
+
* dedicated-service-user complement.
|
|
31
|
+
*/
|
|
32
|
+
export declare const SPAWN_ENV_ALLOWLIST_EXACT: readonly string[];
|
|
33
|
+
/**
|
|
34
|
+
* Prefix families allowed through. A var is allowed when it equals an exact key
|
|
35
|
+
* above OR starts with one of these prefixes. Kept deliberately narrow:
|
|
36
|
+
* - LC_* locale
|
|
37
|
+
* - GIT_* git author/committer/config the agent needs for local commits
|
|
38
|
+
* (push credentials are NOT here -- the daemon does merge-back)
|
|
39
|
+
* - TELORA_* the agent's MCP server needs URL/tracker/org/product ids
|
|
40
|
+
* - XDG_* config/cache dirs claude/codex may resolve
|
|
41
|
+
* - OTEL_* telemetry (also injected explicitly, but allow inherited ones)
|
|
42
|
+
* - ANTHROPIC_* / OPENAI_* / CODEX_* provider config (base url, etc.)
|
|
43
|
+
*/
|
|
44
|
+
export declare const SPAWN_ENV_ALLOWLIST_PREFIXES: readonly string[];
|
|
45
|
+
/**
|
|
46
|
+
* Pick the allowlisted subset of an environment object. Pure -- exported for tests.
|
|
47
|
+
*/
|
|
48
|
+
export declare function pickAllowedEnv(source: Record<string, string | undefined>): Record<string, string | undefined>;
|
|
14
49
|
/**
|
|
15
50
|
* IDs for OTEL resource attribute correlation. The org/focus/session/delivery
|
|
16
51
|
* fields are optional -- not every spawn knows all of them.
|
|
@@ -62,7 +97,9 @@ export declare function buildLeveredSpawnEnvironment(config: DaemonConfig, ids:
|
|
|
62
97
|
/**
|
|
63
98
|
* Build a clean environment for a spawned agent or team lead process.
|
|
64
99
|
*
|
|
65
|
-
* - Copies process.env
|
|
100
|
+
* - Copies ONLY the allowlisted subset of process.env (pickAllowedEnv) -- the
|
|
101
|
+
* operator's SSH/cloud/registry credentials and arbitrary host env never reach
|
|
102
|
+
* the agent
|
|
66
103
|
* - Sets TELORA_DAEMON_AGENT=1 and TELORA_MCP_PROFILE=execution
|
|
67
104
|
* - Enables CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
|
|
68
105
|
* - Strips CLAUDECODE, CLAUDE_CODE_*, and CLAUDECODE_* (except CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spawn-environment.d.ts","sourceRoot":"","sources":["../src/spawn-environment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAgB,SAAQ,QAAQ;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,YAAY,EACpB,GAAG,EAAE,eAAe,GACnB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAEpC;AAED
|
|
1
|
+
{"version":3,"file":"spawn-environment.d.ts","sourceRoot":"","sources":["../src/spawn-environment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EAiBtD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,EAAE,SAAS,MAAM,EAEzD,CAAC;AAEF;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACzC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAYpC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAgB,SAAQ,QAAQ;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,YAAY,EACpB,GAAG,EAAE,eAAe,GACnB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAEpC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EACpB,GAAG,EAAE,QAAQ,GACZ,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAgCpC;AAED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAcjC"}
|
|
@@ -12,6 +12,71 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { stripClaudeCodeEnvVars, buildOtelEnv } from '@telora/daemon-core';
|
|
14
14
|
import { callApi } from './queries/shared.js';
|
|
15
|
+
/**
|
|
16
|
+
* Environment allowlist for spawned agents (ambient-authority reduction).
|
|
17
|
+
*
|
|
18
|
+
* The daemon used to spread its entire `process.env` into every spawn, so an
|
|
19
|
+
* agent inherited the operator's SSH agent socket, cloud-CLI credentials,
|
|
20
|
+
* registry tokens, and arbitrary host env -- the full operator identity. We now
|
|
21
|
+
* build the spawn environment from an explicit allowlist: only the keys an
|
|
22
|
+
* agent legitimately needs reach it. Everything else (SSH_AUTH_SOCK, AWS_*,
|
|
23
|
+
* GOOGLE_*, GITHUB_TOKEN, NPM_TOKEN, KUBECONFIG, ...) is dropped by construction.
|
|
24
|
+
*
|
|
25
|
+
* Anything the daemon must inject regardless (TELORA_DAEMON_AGENT,
|
|
26
|
+
* TELORA_MCP_PROFILE, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS, OTEL_*, and the
|
|
27
|
+
* per-spawn fetched model secret from fetchBackendEnvExtras) is added explicitly
|
|
28
|
+
* AFTER this filter and is unaffected by it.
|
|
29
|
+
*
|
|
30
|
+
* See docs/security-posture-daemon-execution.md for the rationale and the
|
|
31
|
+
* dedicated-service-user complement.
|
|
32
|
+
*/
|
|
33
|
+
export const SPAWN_ENV_ALLOWLIST_EXACT = [
|
|
34
|
+
// Core shell / process
|
|
35
|
+
'PATH', 'HOME', 'USER', 'LOGNAME', 'SHELL', 'PWD',
|
|
36
|
+
// Locale / terminal
|
|
37
|
+
'LANG', 'LANGUAGE', 'TERM', 'TERMINFO', 'TZ', 'COLORTERM', 'EDITOR', 'PAGER',
|
|
38
|
+
// Temp dirs
|
|
39
|
+
'TMPDIR', 'TMP', 'TEMP',
|
|
40
|
+
// Node runtime (NOT NODE_OPTIONS -- avoid inherited --require injection)
|
|
41
|
+
'NODE_PATH',
|
|
42
|
+
// TLS / CA bundles (needed for https to Telora/model APIs behind custom CAs)
|
|
43
|
+
'NODE_EXTRA_CA_CERTS', 'SSL_CERT_FILE', 'SSL_CERT_DIR', 'CURL_CA_BUNDLE', 'REQUESTS_CA_BUNDLE',
|
|
44
|
+
// Proxies (egress through a corporate proxy must still work)
|
|
45
|
+
'HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY', 'ALL_PROXY',
|
|
46
|
+
'http_proxy', 'https_proxy', 'no_proxy', 'all_proxy',
|
|
47
|
+
// Model/provider API keys the agent backend needs (claude reads ANTHROPIC_API_KEY;
|
|
48
|
+
// codex reads CODEX_API_KEY/OPENAI_API_KEY -- the fetched secret is also merged later)
|
|
49
|
+
'ANTHROPIC_API_KEY', 'OPENAI_API_KEY', 'CODEX_API_KEY',
|
|
50
|
+
];
|
|
51
|
+
/**
|
|
52
|
+
* Prefix families allowed through. A var is allowed when it equals an exact key
|
|
53
|
+
* above OR starts with one of these prefixes. Kept deliberately narrow:
|
|
54
|
+
* - LC_* locale
|
|
55
|
+
* - GIT_* git author/committer/config the agent needs for local commits
|
|
56
|
+
* (push credentials are NOT here -- the daemon does merge-back)
|
|
57
|
+
* - TELORA_* the agent's MCP server needs URL/tracker/org/product ids
|
|
58
|
+
* - XDG_* config/cache dirs claude/codex may resolve
|
|
59
|
+
* - OTEL_* telemetry (also injected explicitly, but allow inherited ones)
|
|
60
|
+
* - ANTHROPIC_* / OPENAI_* / CODEX_* provider config (base url, etc.)
|
|
61
|
+
*/
|
|
62
|
+
export const SPAWN_ENV_ALLOWLIST_PREFIXES = [
|
|
63
|
+
'LC_', 'GIT_', 'TELORA_', 'XDG_', 'OTEL_', 'ANTHROPIC_', 'OPENAI_', 'CODEX_',
|
|
64
|
+
];
|
|
65
|
+
/**
|
|
66
|
+
* Pick the allowlisted subset of an environment object. Pure -- exported for tests.
|
|
67
|
+
*/
|
|
68
|
+
export function pickAllowedEnv(source) {
|
|
69
|
+
const out = {};
|
|
70
|
+
for (const [key, value] of Object.entries(source)) {
|
|
71
|
+
if (value === undefined)
|
|
72
|
+
continue;
|
|
73
|
+
if (SPAWN_ENV_ALLOWLIST_EXACT.includes(key) ||
|
|
74
|
+
SPAWN_ENV_ALLOWLIST_PREFIXES.some((p) => key.startsWith(p))) {
|
|
75
|
+
out[key] = value;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
15
80
|
/**
|
|
16
81
|
* Build a clean environment for a LEVERED spawn -- the focus team-lead, the
|
|
17
82
|
* audit assessor, or any spawn running an attributable execution phase against
|
|
@@ -27,7 +92,9 @@ export function buildLeveredSpawnEnvironment(config, ids) {
|
|
|
27
92
|
/**
|
|
28
93
|
* Build a clean environment for a spawned agent or team lead process.
|
|
29
94
|
*
|
|
30
|
-
* - Copies process.env
|
|
95
|
+
* - Copies ONLY the allowlisted subset of process.env (pickAllowedEnv) -- the
|
|
96
|
+
* operator's SSH/cloud/registry credentials and arbitrary host env never reach
|
|
97
|
+
* the agent
|
|
31
98
|
* - Sets TELORA_DAEMON_AGENT=1 and TELORA_MCP_PROFILE=execution
|
|
32
99
|
* - Enables CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
|
|
33
100
|
* - Strips CLAUDECODE, CLAUDE_CODE_*, and CLAUDECODE_* (except CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS)
|
|
@@ -40,10 +107,12 @@ export function buildLeveredSpawnEnvironment(config, ids) {
|
|
|
40
107
|
* applicable (and for tests that exercise the env plumbing without a phase).
|
|
41
108
|
*/
|
|
42
109
|
export function buildSpawnEnvironment(config, ids) {
|
|
43
|
-
// Start
|
|
44
|
-
//
|
|
110
|
+
// Start from the ALLOWLISTED subset of process.env (ambient-authority
|
|
111
|
+
// reduction -- never the full operator environment), add daemon-specific
|
|
112
|
+
// vars, then strip inherited Claude Code session markers (preserving
|
|
113
|
+
// AGENT_TEAMS).
|
|
45
114
|
const spawnEnv = stripClaudeCodeEnvVars({
|
|
46
|
-
...process.env,
|
|
115
|
+
...pickAllowedEnv(process.env),
|
|
47
116
|
TELORA_DAEMON_AGENT: '1',
|
|
48
117
|
TELORA_MCP_PROFILE: 'execution',
|
|
49
118
|
// Agent Teams always enabled -- focus-level execution model
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spawn-environment.js","sourceRoot":"","sources":["../src/spawn-environment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"spawn-environment.js","sourceRoot":"","sources":["../src/spawn-environment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OS sandbox for spawned agents -- "make the worktree boundary true" (D3).
|
|
3
|
+
*
|
|
4
|
+
* The daemon spawns agents with --dangerously-skip-permissions /
|
|
5
|
+
* --dangerously-bypass-approvals-and-sandbox. The ONLY isolation around such a
|
|
6
|
+
* spawn used to be a git worktree, which bounds the git branch but NOT the OS:
|
|
7
|
+
* the agent could read sibling repos, the operator's home, SSH/cloud creds, and
|
|
8
|
+
* reach the network freely. This module wraps the spawn command in an OS
|
|
9
|
+
* sandbox (bubblewrap on Linux) so the agent's filesystem is confined to its
|
|
10
|
+
* worktree plus an explicit read-only allowlist (toolchain + model-auth config),
|
|
11
|
+
* with privileged capabilities and namespaces dropped.
|
|
12
|
+
*
|
|
13
|
+
* Posture (see docs/security-posture-daemon-execution.md):
|
|
14
|
+
* - FILESYSTEM confinement + capability/namespace isolation are ENFORCED by bwrap.
|
|
15
|
+
* - OUTBOUND EGRESS allowlisting is NOT enforced here (bubblewrap has no L3/L7
|
|
16
|
+
* egress filter); it is a documented residual gap. Network is shared so the
|
|
17
|
+
* agent can still reach the Telora API / git / registries / model API.
|
|
18
|
+
*
|
|
19
|
+
* FAIL-CLOSED: an EXPLICIT 'bwrap' mode whose sandbox cannot initialize REFUSES
|
|
20
|
+
* the spawn (throws SandboxUnavailableError) rather than running unconfined.
|
|
21
|
+
*
|
|
22
|
+
* DEFAULT is 'off' (see resolveSandboxMode): auto-enabling a sandbox whose
|
|
23
|
+
* per-host read-bind set has not been validated could break real spawns, so
|
|
24
|
+
* operators opt in to 'bwrap' after the per-host validation in
|
|
25
|
+
* docs/runbook-daemon-service-user.md. On Linux with bwrap present we log a
|
|
26
|
+
* recommendation to enable it.
|
|
27
|
+
*
|
|
28
|
+
* Pure command construction (buildSandboxCommand) takes injected deps so it is
|
|
29
|
+
* unit-testable without a real bubblewrap.
|
|
30
|
+
*/
|
|
31
|
+
import type { DaemonConfig, SandboxConfig, SandboxMode } from './types.js';
|
|
32
|
+
/** Thrown when an explicitly-required sandbox cannot initialize (fail-closed). */
|
|
33
|
+
export declare class SandboxUnavailableError extends Error {
|
|
34
|
+
constructor(detail: string);
|
|
35
|
+
}
|
|
36
|
+
/** Default bubblewrap executable name (overridable via deps for tests). */
|
|
37
|
+
export declare const BWRAP_COMMAND = "bwrap";
|
|
38
|
+
/** Return true if an executable name/path exists on the host PATH. */
|
|
39
|
+
export declare function commandOnPath(command: string, env?: NodeJS.ProcessEnv): boolean;
|
|
40
|
+
/** Is bubblewrap available on this host? */
|
|
41
|
+
export declare function isBwrapAvailable(deps?: {
|
|
42
|
+
commandExists?: (cmd: string) => boolean;
|
|
43
|
+
bwrapCommand?: string;
|
|
44
|
+
}): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Resolve the effective sandbox mode.
|
|
47
|
+
*
|
|
48
|
+
* - explicit config.sandbox.mode wins (and is honored even if unavailable --
|
|
49
|
+
* buildSandboxCommand then fail-closes).
|
|
50
|
+
* - unset + darwin => 'off' (dev; bwrap is Linux-only).
|
|
51
|
+
* - unset + linux => 'off' (safe default), with a warning health event emitted
|
|
52
|
+
* when bwrap is available. Operators opt in explicitly after per-host validation
|
|
53
|
+
* -- see docs/runbook-daemon-service-user.md.
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveSandboxMode(sandbox: SandboxConfig | undefined, deps?: {
|
|
56
|
+
platform?: NodeJS.Platform;
|
|
57
|
+
bwrapAvailable?: boolean;
|
|
58
|
+
logRecommendation?: (msg: string) => void;
|
|
59
|
+
}): SandboxMode;
|
|
60
|
+
export interface SandboxPolicy {
|
|
61
|
+
/** The worktree -- bound read-write; the agent's only writable host tree. */
|
|
62
|
+
worktreePath: string;
|
|
63
|
+
/** Extra host paths exposed read-only (toolchain, model-auth config, certs). */
|
|
64
|
+
readOnlyPaths?: readonly string[];
|
|
65
|
+
}
|
|
66
|
+
export interface BuildSandboxArgs {
|
|
67
|
+
/** The inner command that would be spawned without a sandbox (e.g. 'claude'). */
|
|
68
|
+
command: string;
|
|
69
|
+
/** The inner command's args. */
|
|
70
|
+
args: readonly string[];
|
|
71
|
+
/** Filesystem policy. */
|
|
72
|
+
policy: SandboxPolicy;
|
|
73
|
+
/** Effective mode (from resolveSandboxMode). */
|
|
74
|
+
mode: SandboxMode;
|
|
75
|
+
/** Whether bubblewrap is available (injected for tests). */
|
|
76
|
+
bwrapAvailable: boolean;
|
|
77
|
+
/** bwrap executable (default 'bwrap'). */
|
|
78
|
+
bwrapCommand?: string;
|
|
79
|
+
/** Called once when mode resolves to running UNCONFINED, for loud logging. */
|
|
80
|
+
onUnconfined?: (reason: string) => void;
|
|
81
|
+
}
|
|
82
|
+
export interface SandboxedCommand {
|
|
83
|
+
command: string;
|
|
84
|
+
args: string[];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Build the (possibly sandbox-wrapped) command + args for a spawn.
|
|
88
|
+
*
|
|
89
|
+
* mode 'off' -> returns the inner command unchanged and emits a loud
|
|
90
|
+
* "running unconfined" signal (the spawn has the daemon user's
|
|
91
|
+
* full authority).
|
|
92
|
+
* mode 'bwrap' -> if bwrap is unavailable, THROWS SandboxUnavailableError
|
|
93
|
+
* (fail-closed); otherwise returns a bwrap invocation that binds
|
|
94
|
+
* the worktree read-write, the readOnlyPaths read-only, system
|
|
95
|
+
* dirs read-only, and drops privileged namespaces.
|
|
96
|
+
*/
|
|
97
|
+
export declare function buildSandboxCommand(opts: BuildSandboxArgs): SandboxedCommand;
|
|
98
|
+
/**
|
|
99
|
+
* High-level helper used by the spawn path: resolve mode from config, derive the
|
|
100
|
+
* read-only allowlist (toolchain + model-auth config), and build the wrapped
|
|
101
|
+
* command. Emits a health event on unconfined runs and refuses (throws) when an
|
|
102
|
+
* explicitly-required sandbox is unavailable.
|
|
103
|
+
*/
|
|
104
|
+
export declare function wrapSpawnCommand(config: DaemonConfig, spawn: {
|
|
105
|
+
command: string;
|
|
106
|
+
args: readonly string[];
|
|
107
|
+
worktreePath: string;
|
|
108
|
+
}): SandboxedCommand;
|
|
109
|
+
/**
|
|
110
|
+
* Derive the read-only host paths a spawn legitimately needs: the toolchain
|
|
111
|
+
* (the backend command's dir + the daemon's own node), the agent's model-auth
|
|
112
|
+
* config under HOME (~/.claude.json, ~/.claude, ~/.codex), and any extra paths
|
|
113
|
+
* configured. Kept narrow -- this is the allowlist that decides what the agent
|
|
114
|
+
* can read OUTSIDE its worktree. Exported for tests.
|
|
115
|
+
*/
|
|
116
|
+
export declare function deriveReadOnlyPaths(config: DaemonConfig, backendCommand: string): string[];
|
|
117
|
+
//# sourceMappingURL=spawn-sandbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-sandbox.d.ts","sourceRoot":"","sources":["../src/spawn-sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE3E,kFAAkF;AAClF,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,MAAM,EAAE,MAAM;CAI3B;AAED,2EAA2E;AAC3E,eAAO,MAAM,aAAa,UAAU,CAAC;AAErC,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAI5F;AAED,4CAA4C;AAC5C,wBAAgB,gBAAgB,CAC9B,IAAI,GAAE;IAAE,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7E,OAAO,CAIT;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,aAAa,GAAG,SAAS,EAClC,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAAC,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAO,GAC7G,WAAW,CAwBb;AAED,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,YAAY,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,yBAAyB;IACzB,MAAM,EAAE,aAAa,CAAC;IACtB,gDAAgD;IAChD,IAAI,EAAE,WAAW,CAAC;IAClB,4DAA4D;IAC5D,cAAc,EAAE,OAAO,CAAC;IACxB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG,gBAAgB,CA0D5E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACxE,gBAAgB,CAqBlB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,CA0B1F"}
|