@provos/ironcurtain 0.7.2 → 0.9.0
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/README.md +29 -100
- package/dist/auth/auth-command.d.ts +15 -0
- package/dist/auth/auth-command.js +424 -0
- package/dist/auth/auth-command.js.map +1 -0
- package/dist/auth/oauth-flow.d.ts +46 -0
- package/dist/auth/oauth-flow.js +279 -0
- package/dist/auth/oauth-flow.js.map +1 -0
- package/dist/auth/oauth-provider.d.ts +55 -0
- package/dist/auth/oauth-provider.js +73 -0
- package/dist/auth/oauth-provider.js.map +1 -0
- package/dist/auth/oauth-registry.d.ts +34 -0
- package/dist/auth/oauth-registry.js +69 -0
- package/dist/auth/oauth-registry.js.map +1 -0
- package/dist/auth/oauth-token-provider.d.ts +52 -0
- package/dist/auth/oauth-token-provider.js +159 -0
- package/dist/auth/oauth-token-provider.js.map +1 -0
- package/dist/auth/oauth-token-store.d.ts +30 -0
- package/dist/auth/oauth-token-store.js +93 -0
- package/dist/auth/oauth-token-store.js.map +1 -0
- package/dist/auth/providers/google-scopes.d.ts +35 -0
- package/dist/auth/providers/google-scopes.js +183 -0
- package/dist/auth/providers/google-scopes.js.map +1 -0
- package/dist/auth/providers/google.d.ts +2 -0
- package/dist/auth/providers/google.js +28 -0
- package/dist/auth/providers/google.js.map +1 -0
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/config/config-command.js +39 -1
- package/dist/config/config-command.js.map +1 -1
- package/dist/config/constitution-readonly.md +14 -11
- package/dist/config/constitution-user-base.md +15 -0
- package/dist/config/first-start.js +4 -1
- package/dist/config/first-start.js.map +1 -1
- package/dist/config/generated/test-scenarios.json +1 -1
- package/dist/config/generated/tool-annotations.json +10617 -296
- package/dist/config/generated-readonly/compiled-policy.json +787 -244
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.js +8 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/mcp-servers.json +31 -2
- package/dist/config/paths.d.ts +20 -0
- package/dist/config/paths.js +43 -0
- package/dist/config/paths.js.map +1 -1
- package/dist/config/types.d.ts +8 -0
- package/dist/config/user-config.d.ts +29 -0
- package/dist/config/user-config.js +30 -0
- package/dist/config/user-config.js.map +1 -1
- package/dist/cron/constitution-generator.d.ts +2 -1
- package/dist/cron/constitution-generator.js +35 -36
- package/dist/cron/constitution-generator.js.map +1 -1
- package/dist/cron/headless-transport.d.ts +4 -0
- package/dist/cron/headless-transport.js +1 -1
- package/dist/cron/headless-transport.js.map +1 -1
- package/dist/daemon/ironcurtain-daemon.js +7 -1
- package/dist/daemon/ironcurtain-daemon.js.map +1 -1
- package/dist/docker/adapters/claude-code.js +32 -5
- package/dist/docker/adapters/claude-code.js.map +1 -1
- package/dist/docker/agent-adapter.d.ts +40 -0
- package/dist/docker/claude-md-seed.d.ts +27 -0
- package/dist/docker/claude-md-seed.js +42 -0
- package/dist/docker/claude-md-seed.js.map +1 -0
- package/dist/docker/docker-agent-session.d.ts +3 -1
- package/dist/docker/docker-agent-session.js +51 -28
- package/dist/docker/docker-agent-session.js.map +1 -1
- package/dist/docker/docker-infrastructure.d.ts +15 -1
- package/dist/docker/docker-infrastructure.js +105 -9
- package/dist/docker/docker-infrastructure.js.map +1 -1
- package/dist/docker/docker-manager.d.ts +2 -0
- package/dist/docker/docker-manager.js +9 -1
- package/dist/docker/docker-manager.js.map +1 -1
- package/dist/docker/mitm-proxy.d.ts +65 -0
- package/dist/docker/mitm-proxy.js +288 -31
- package/dist/docker/mitm-proxy.js.map +1 -1
- package/dist/docker/package-types.d.ts +127 -0
- package/dist/docker/package-types.js +8 -0
- package/dist/docker/package-types.js.map +1 -0
- package/dist/docker/package-validator.d.ts +41 -0
- package/dist/docker/package-validator.js +90 -0
- package/dist/docker/package-validator.js.map +1 -0
- package/dist/docker/platform.d.ts +6 -6
- package/dist/docker/platform.js +8 -6
- package/dist/docker/platform.js.map +1 -1
- package/dist/docker/proxy-tools.d.ts +80 -0
- package/dist/docker/proxy-tools.js +248 -0
- package/dist/docker/proxy-tools.js.map +1 -0
- package/dist/docker/pty-session.d.ts +15 -0
- package/dist/docker/pty-session.js +253 -73
- package/dist/docker/pty-session.js.map +1 -1
- package/dist/docker/pty-types.d.ts +28 -0
- package/dist/docker/pty-types.js +2 -0
- package/dist/docker/pty-types.js.map +1 -1
- package/dist/docker/registry-proxy.d.ts +142 -0
- package/dist/docker/registry-proxy.js +856 -0
- package/dist/docker/registry-proxy.js.map +1 -0
- package/dist/escalation/escalation-watcher.d.ts +3 -1
- package/dist/escalation/escalation-watcher.js +6 -2
- package/dist/escalation/escalation-watcher.js.map +1 -1
- package/dist/escalation/listener-command.js +24 -10
- package/dist/escalation/listener-command.js.map +1 -1
- package/dist/escalation/listener-lock.d.ts +5 -0
- package/dist/escalation/listener-lock.js +14 -0
- package/dist/escalation/listener-lock.js.map +1 -1
- package/dist/index.js +16 -3
- package/dist/index.js.map +1 -1
- package/dist/memory/auto-save.d.ts +25 -0
- package/dist/memory/auto-save.js +89 -0
- package/dist/memory/auto-save.js.map +1 -0
- package/dist/memory/memory-annotations.d.ts +47 -0
- package/dist/memory/memory-annotations.js +87 -0
- package/dist/memory/memory-annotations.js.map +1 -0
- package/dist/memory/memory-prompt.d.ts +12 -0
- package/dist/memory/memory-prompt.js +20 -0
- package/dist/memory/memory-prompt.js.map +1 -0
- package/dist/memory/resolve-memory-path.d.ts +20 -0
- package/dist/memory/resolve-memory-path.js +30 -0
- package/dist/memory/resolve-memory-path.js.map +1 -0
- package/dist/mux/mux-app.d.ts +4 -0
- package/dist/mux/mux-app.js +246 -28
- package/dist/mux/mux-app.js.map +1 -1
- package/dist/mux/mux-command.d.ts +2 -2
- package/dist/mux/mux-command.js +14 -22
- package/dist/mux/mux-command.js.map +1 -1
- package/dist/mux/mux-escalation-manager.d.ts +9 -3
- package/dist/mux/mux-escalation-manager.js +69 -19
- package/dist/mux/mux-escalation-manager.js.map +1 -1
- package/dist/mux/mux-input-handler.d.ts +59 -3
- package/dist/mux/mux-input-handler.js +270 -32
- package/dist/mux/mux-input-handler.js.map +1 -1
- package/dist/mux/mux-renderer.d.ts +19 -1
- package/dist/mux/mux-renderer.js +466 -11
- package/dist/mux/mux-renderer.js.map +1 -1
- package/dist/mux/persona-scanner.d.ts +19 -0
- package/dist/mux/persona-scanner.js +53 -0
- package/dist/mux/persona-scanner.js.map +1 -0
- package/dist/mux/pty-bridge.d.ts +8 -0
- package/dist/mux/pty-bridge.js +19 -1
- package/dist/mux/pty-bridge.js.map +1 -1
- package/dist/mux/session-scanner.d.ts +18 -0
- package/dist/mux/session-scanner.js +65 -0
- package/dist/mux/session-scanner.js.map +1 -0
- package/dist/mux/types.d.ts +36 -1
- package/dist/mux/types.js +14 -1
- package/dist/mux/types.js.map +1 -1
- package/dist/persona/persona-command.js +130 -93
- package/dist/persona/persona-command.js.map +1 -1
- package/dist/persona/persona-prompt.d.ts +7 -7
- package/dist/persona/persona-prompt.js +14 -29
- package/dist/persona/persona-prompt.js.map +1 -1
- package/dist/persona/resolve.js +5 -2
- package/dist/persona/resolve.js.map +1 -1
- package/dist/pipeline/annotate.js +1 -7
- package/dist/pipeline/annotate.js.map +1 -1
- package/dist/pipeline/compile.d.ts +5 -2
- package/dist/pipeline/compile.js +23 -11
- package/dist/pipeline/compile.js.map +1 -1
- package/dist/pipeline/constitution-compiler.d.ts +302 -3
- package/dist/pipeline/constitution-compiler.js +285 -23
- package/dist/pipeline/constitution-compiler.js.map +1 -1
- package/dist/pipeline/generate-with-repair.d.ts +2 -2
- package/dist/pipeline/generate-with-repair.js +2 -2
- package/dist/pipeline/handwritten-scenarios.d.ts +20 -7
- package/dist/pipeline/handwritten-scenarios.js +20 -41
- package/dist/pipeline/handwritten-scenarios.js.map +1 -1
- package/dist/pipeline/list-resolver.d.ts +18 -20
- package/dist/pipeline/list-resolver.js +28 -36
- package/dist/pipeline/list-resolver.js.map +1 -1
- package/dist/pipeline/pipeline-runner.d.ts +102 -13
- package/dist/pipeline/pipeline-runner.js +497 -237
- package/dist/pipeline/pipeline-runner.js.map +1 -1
- package/dist/pipeline/pipeline-shared.d.ts +7 -9
- package/dist/pipeline/pipeline-shared.js +8 -18
- package/dist/pipeline/pipeline-shared.js.map +1 -1
- package/dist/pipeline/policy-verifier.d.ts +32 -5
- package/dist/pipeline/policy-verifier.js +137 -8
- package/dist/pipeline/policy-verifier.js.map +1 -1
- package/dist/pipeline/proxy-mcp-connections.d.ts +25 -0
- package/dist/pipeline/proxy-mcp-connections.js +121 -0
- package/dist/pipeline/proxy-mcp-connections.js.map +1 -0
- package/dist/pipeline/refresh-lists.js +21 -13
- package/dist/pipeline/refresh-lists.js.map +1 -1
- package/dist/pipeline/scenario-generator.d.ts +29 -49
- package/dist/pipeline/scenario-generator.js +180 -143
- package/dist/pipeline/scenario-generator.js.map +1 -1
- package/dist/pipeline/scenario-schema-validator.d.ts +51 -0
- package/dist/pipeline/scenario-schema-validator.js +132 -0
- package/dist/pipeline/scenario-schema-validator.js.map +1 -0
- package/dist/pipeline/tool-annotator.d.ts +9 -8
- package/dist/pipeline/tool-annotator.js +48 -95
- package/dist/pipeline/tool-annotator.js.map +1 -1
- package/dist/pipeline/types.d.ts +31 -24
- package/dist/sandbox/index.d.ts +26 -10
- package/dist/sandbox/index.js +151 -40
- package/dist/sandbox/index.js.map +1 -1
- package/dist/servers/fetch-server.js +10 -5
- package/dist/servers/fetch-server.js.map +1 -1
- package/dist/session/agent-session.d.ts +8 -20
- package/dist/session/agent-session.js +22 -70
- package/dist/session/agent-session.js.map +1 -1
- package/dist/session/base-transport.d.ts +17 -1
- package/dist/session/base-transport.js +25 -1
- package/dist/session/base-transport.js.map +1 -1
- package/dist/session/cli-transport.d.ts +5 -0
- package/dist/session/cli-transport.js +48 -25
- package/dist/session/cli-transport.js.map +1 -1
- package/dist/session/index.d.ts +25 -1
- package/dist/session/index.js +57 -8
- package/dist/session/index.js.map +1 -1
- package/dist/session/prompts.js +8 -9
- package/dist/session/prompts.js.map +1 -1
- package/dist/session/session-manager.d.ts +6 -0
- package/dist/session/session-manager.js +12 -0
- package/dist/session/session-manager.js.map +1 -1
- package/dist/session/types.d.ts +11 -1
- package/dist/session/types.js.map +1 -1
- package/dist/session/workspace-validation.js +37 -6
- package/dist/session/workspace-validation.js.map +1 -1
- package/dist/signal/signal-bot-daemon.js +24 -8
- package/dist/signal/signal-bot-daemon.js.map +1 -1
- package/dist/signal/signal-transport.d.ts +5 -2
- package/dist/signal/signal-transport.js +3 -3
- package/dist/signal/signal-transport.js.map +1 -1
- package/dist/trusted-process/approval-whitelist.d.ts +117 -0
- package/dist/trusted-process/approval-whitelist.js +237 -0
- package/dist/trusted-process/approval-whitelist.js.map +1 -0
- package/dist/trusted-process/gworkspace-credentials.d.ts +40 -0
- package/dist/trusted-process/gworkspace-credentials.js +45 -0
- package/dist/trusted-process/gworkspace-credentials.js.map +1 -0
- package/dist/trusted-process/index.d.ts +11 -1
- package/dist/trusted-process/index.js +83 -53
- package/dist/trusted-process/index.js.map +1 -1
- package/dist/trusted-process/mcp-proxy-server.d.ts +23 -0
- package/dist/trusted-process/mcp-proxy-server.js +409 -94
- package/dist/trusted-process/mcp-proxy-server.js.map +1 -1
- package/dist/trusted-process/policy-engine.d.ts +12 -3
- package/dist/trusted-process/policy-engine.js +33 -23
- package/dist/trusted-process/policy-engine.js.map +1 -1
- package/dist/trusted-process/policy-types.d.ts +17 -0
- package/dist/trusted-process/sandbox-integration.d.ts +23 -0
- package/dist/trusted-process/sandbox-integration.js +115 -3
- package/dist/trusted-process/sandbox-integration.js.map +1 -1
- package/dist/trusted-process/token-file-refresher.d.ts +69 -0
- package/dist/trusted-process/token-file-refresher.js +120 -0
- package/dist/trusted-process/token-file-refresher.js.map +1 -0
- package/dist/types/argument-roles.d.ts +7 -1
- package/dist/types/argument-roles.js +50 -0
- package/dist/types/argument-roles.js.map +1 -1
- package/dist/types/audit.d.ts +11 -0
- package/docker/Dockerfile.base +22 -0
- package/docker/Dockerfile.base.arm64 +44 -4
- package/docker/Dockerfile.claude-code +2 -2
- package/docker/entrypoint-claude-code.sh +24 -6
- package/package.json +8 -2
- package/src/config/constitution-user-base.md +15 -0
- package/src/config/generated/test-scenarios.json +1 -1
- package/src/config/generated/tool-annotations.json +10617 -296
- package/src/config/mcp-servers.json +31 -2
- package/dist/pipeline/mcp-connections.d.ts +0 -16
- package/dist/pipeline/mcp-connections.js +0 -61
- package/dist/pipeline/mcp-connections.js.map +0 -1
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
* for the availability check.
|
|
11
11
|
*/
|
|
12
12
|
import { SandboxManager } from '@anthropic-ai/sandbox-runtime';
|
|
13
|
-
import { writeFileSync, mkdirSync, rmSync, existsSync } from 'node:fs';
|
|
13
|
+
import { writeFileSync, readFileSync, mkdirSync, rmSync, existsSync, realpathSync } from 'node:fs';
|
|
14
14
|
import { join, resolve, dirname, isAbsolute } from 'node:path';
|
|
15
|
+
import { homedir } from 'node:os';
|
|
15
16
|
import { fileURLToPath } from 'node:url';
|
|
16
17
|
import { quote } from 'shell-quote';
|
|
18
|
+
import { expandTilde } from '../types/argument-roles.js';
|
|
17
19
|
// ── Constants ──────────────────────────────────────────────────────────────
|
|
18
20
|
/** Sensitive directories blocked from reads by default. */
|
|
19
21
|
const DEFAULT_DENY_READ = ['~/.ssh', '~/.gnupg', '~/.aws'];
|
|
@@ -62,12 +64,13 @@ export function resolveSandboxConfig(serverConfig, sessionSandboxDir, platformAv
|
|
|
62
64
|
const fsConfig = sandboxConfig.filesystem ?? {};
|
|
63
65
|
const networkConfig = sandboxConfig.network;
|
|
64
66
|
const allowWrite = buildAllowWrite(sessionSandboxDir, fsConfig.allowWrite ?? []);
|
|
67
|
+
const allowRead = (fsConfig.allowRead ?? []).map((p) => expandTilde(p));
|
|
65
68
|
const denyRead = fsConfig.denyRead ?? DEFAULT_DENY_READ;
|
|
66
69
|
const denyWrite = fsConfig.denyWrite ?? [];
|
|
67
70
|
const network = resolveNetworkConfig(networkConfig);
|
|
68
71
|
return {
|
|
69
72
|
sandboxed: true,
|
|
70
|
-
config: { allowWrite, denyRead, denyWrite, network },
|
|
73
|
+
config: { allowWrite, allowRead, denyRead, denyWrite, network },
|
|
71
74
|
};
|
|
72
75
|
}
|
|
73
76
|
/**
|
|
@@ -93,6 +96,7 @@ export function writeServerSettings(serverName, config, settingsDir) {
|
|
|
93
96
|
network,
|
|
94
97
|
filesystem: {
|
|
95
98
|
denyRead: config.denyRead,
|
|
99
|
+
allowRead: config.allowRead,
|
|
96
100
|
allowWrite: [...config.allowWrite, cwdPath],
|
|
97
101
|
denyWrite: config.denyWrite,
|
|
98
102
|
},
|
|
@@ -114,7 +118,16 @@ export function wrapServerCommand(serverName, command, args, sandboxConfig, sett
|
|
|
114
118
|
const settingsPath = join(settingsDir, `${serverName}.srt-settings.json`);
|
|
115
119
|
// Resolve relative paths in args to absolute so the command works when
|
|
116
120
|
// the proxy sets cwd to the per-server temp directory.
|
|
117
|
-
|
|
121
|
+
// Skip flags (-y, --foo) and npm package specifiers (contain @, e.g.
|
|
122
|
+
// @org/pkg, @org/pkg@1.0.0, or unscoped pkg@1.0.0).
|
|
123
|
+
const resolvedArgs = args.map((a) => {
|
|
124
|
+
if (isAbsolute(a) || a.startsWith('-') || a.includes('@'))
|
|
125
|
+
return a;
|
|
126
|
+
// Only resolve args that look like filesystem paths (contain / or .)
|
|
127
|
+
if (a.includes('/') || a.includes('.'))
|
|
128
|
+
return resolve(a);
|
|
129
|
+
return a;
|
|
130
|
+
});
|
|
118
131
|
const cmdString = quote([command, ...resolvedArgs]);
|
|
119
132
|
return {
|
|
120
133
|
command: SRT_BIN,
|
|
@@ -147,7 +160,106 @@ export function annotateSandboxViolation(errorMessage, serverSandboxed) {
|
|
|
147
160
|
return errorMessage;
|
|
148
161
|
return `[SANDBOX BLOCKED] ${errorMessage}`;
|
|
149
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Discovers filesystem paths required by the current Node.js installation.
|
|
165
|
+
*
|
|
166
|
+
* When a sandbox uses `denyRead: ["~"]`, node/npm installations under the
|
|
167
|
+
* home directory (nvm, volta, fnm, asdf) become unreadable. This function
|
|
168
|
+
* inspects the running process to find the actual installation paths and
|
|
169
|
+
* returns them for inclusion in `allowRead`.
|
|
170
|
+
*
|
|
171
|
+
* Returns deduplicated absolute real paths. Safe to call on any platform.
|
|
172
|
+
*/
|
|
173
|
+
export function discoverNodePaths() {
|
|
174
|
+
const paths = new Set();
|
|
175
|
+
// Resolve home through realpath so prefix comparisons work when
|
|
176
|
+
// homedir() involves symlinks (e.g., macOS /var → /private/var)
|
|
177
|
+
const home = safeRealPath(homedir()) ?? homedir();
|
|
178
|
+
// 1. Node.js binary -- follow symlinks to the real location
|
|
179
|
+
const execPath = safeRealPath(process.execPath);
|
|
180
|
+
if (execPath) {
|
|
181
|
+
// The binary is typically at <prefix>/bin/node; we want <prefix>
|
|
182
|
+
const binDir = dirname(execPath);
|
|
183
|
+
const prefix = dirname(binDir);
|
|
184
|
+
addIfUnderHome(paths, prefix, home);
|
|
185
|
+
}
|
|
186
|
+
// 2. Version manager root directories -- these contain node versions,
|
|
187
|
+
// global packages, and shims that the server process needs to read
|
|
188
|
+
const versionManagerRoots = [
|
|
189
|
+
{ envVar: 'NVM_DIR', fallback: '.nvm' },
|
|
190
|
+
{ envVar: 'VOLTA_HOME', fallback: '.volta' },
|
|
191
|
+
{ envVar: 'ASDF_DATA_DIR', fallback: '.asdf' },
|
|
192
|
+
];
|
|
193
|
+
for (const { envVar, fallback } of versionManagerRoots) {
|
|
194
|
+
const dir = process.env[envVar] ?? (home ? join(home, fallback) : '');
|
|
195
|
+
if (dir && existsSync(dir)) {
|
|
196
|
+
const realDir = safeRealPath(dir);
|
|
197
|
+
if (realDir)
|
|
198
|
+
addIfUnderHome(paths, realDir, home);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// 3. fnm uses a platform-specific default location
|
|
202
|
+
const fnmDir = process.env.FNM_DIR ??
|
|
203
|
+
(process.platform === 'darwin' && home
|
|
204
|
+
? join(home, 'Library', 'Application Support', 'fnm')
|
|
205
|
+
: home
|
|
206
|
+
? join(home, '.local', 'share', 'fnm')
|
|
207
|
+
: '');
|
|
208
|
+
if (fnmDir && existsSync(fnmDir)) {
|
|
209
|
+
const realDir = safeRealPath(fnmDir);
|
|
210
|
+
if (realDir)
|
|
211
|
+
addIfUnderHome(paths, realDir, home);
|
|
212
|
+
}
|
|
213
|
+
return [...paths];
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Rewrites an existing srt settings file to add additional allowRead
|
|
217
|
+
* and/or allowWrite paths. Used after OAuth setup discovers credential
|
|
218
|
+
* directories that weren't known when the settings were first written.
|
|
219
|
+
*
|
|
220
|
+
* Merges new paths with existing ones (deduplicating).
|
|
221
|
+
*/
|
|
222
|
+
export function rewriteServerSettings(settingsPath, additions) {
|
|
223
|
+
const content = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
224
|
+
const fs = content.filesystem ?? {};
|
|
225
|
+
if (additions.allowRead?.length) {
|
|
226
|
+
const existing = new Set(fs.allowRead ?? []);
|
|
227
|
+
for (const p of additions.allowRead)
|
|
228
|
+
existing.add(p);
|
|
229
|
+
fs.allowRead = [...existing];
|
|
230
|
+
}
|
|
231
|
+
if (additions.allowWrite?.length) {
|
|
232
|
+
const existing = new Set(fs.allowWrite ?? []);
|
|
233
|
+
for (const p of additions.allowWrite)
|
|
234
|
+
existing.add(p);
|
|
235
|
+
fs.allowWrite = [...existing];
|
|
236
|
+
}
|
|
237
|
+
content.filesystem = fs;
|
|
238
|
+
writeFileSync(settingsPath, JSON.stringify(content, null, 2));
|
|
239
|
+
}
|
|
150
240
|
// ── Internal helpers ───────────────────────────────────────────────────────
|
|
241
|
+
/**
|
|
242
|
+
* Resolves a path to its real (canonical) path, returning null on failure.
|
|
243
|
+
* Silently handles paths that don't exist or can't be resolved.
|
|
244
|
+
*/
|
|
245
|
+
function safeRealPath(p) {
|
|
246
|
+
try {
|
|
247
|
+
return realpathSync(p);
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Adds a path to the set only if it's under the home directory.
|
|
255
|
+
* Paths outside home don't need to be in allowRead since they
|
|
256
|
+
* aren't blocked by `denyRead: ["~"]`.
|
|
257
|
+
*/
|
|
258
|
+
function addIfUnderHome(paths, dir, home) {
|
|
259
|
+
if (home && dir.startsWith(home + '/')) {
|
|
260
|
+
paths.add(dir);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
151
263
|
/**
|
|
152
264
|
* Builds the allowWrite list with the session sandbox dir always included.
|
|
153
265
|
* Relative paths are resolved against the session sandbox directory.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox-integration.js","sourceRoot":"","sources":["../../src/trusted-process/sandbox-integration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"sandbox-integration.js","sourceRoot":"","sources":["../../src/trusted-process/sandbox-integration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAsCzD,8EAA8E;AAE9E,2DAA2D;AAC3D,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;AAE3D;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACjE,MAAM,OAAO,GAAG,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,gBAAgB,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAEpF,mFAAmF;AACnF,MAAM,qBAAqB,GAAG,+EAA+E,CAAC;AAE9G,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB;IACtC,MAAM,iBAAiB,GAAG,cAAc,CAAC,mBAAmB,EAAE,CAAC;IAE/D,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IACzD,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,cAAc,CAAC,iBAAiB,EAAE,CAAC;IAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AACjD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,YAA6B,EAC7B,iBAAyB,EACzB,iBAA0B,EAC1B,MAAiC;IAEjC,IAAI,YAAY,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QACnC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACjD,CAAC;IAED,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,mEAAmE,GAAG,iCAAiC,CACxG,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IAC9D,CAAC;IAED,MAAM,aAAa,GAAG,YAAY,CAAC,OAAO,IAAI,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,IAAI,EAAE,CAAC;IAChD,MAAM,aAAa,GAAG,aAAa,CAAC,OAAO,CAAC;IAE5C,MAAM,UAAU,GAAG,eAAe,CAAC,iBAAiB,EAAE,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;IACjF,MAAM,SAAS,GAAG,CAAC,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAExE,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IACxD,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAC;IAE3C,MAAM,OAAO,GAAG,oBAAoB,CAAC,aAAa,CAAC,CAAC;IAEpD,OAAO;QACL,SAAS,EAAE,IAAI;QACf,MAAM,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE;KAChE,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CACjC,UAAkB,EAClB,MAA6B,EAC7B,WAAmB;IAEnB,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,UAAU,oBAAoB,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,UAAU,MAAM,CAAC,CAAC;IACvD,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAExC,MAAM,OAAO,GACX,MAAM,CAAC,OAAO,KAAK,KAAK;QACtB,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE;QAC3C,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;IAErG,MAAM,QAAQ,GAAG;QACf,OAAO;QACP,UAAU,EAAE;YACV,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,UAAU,EAAE,CAAC,GAAG,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC;YAC3C,SAAS,EAAE,MAAM,CAAC,SAAS;SAC5B;KACF,CAAC;IAEF,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/D,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;AACnC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAkB,EAClB,OAAe,EACf,IAAuB,EACvB,aAAoC,EACpC,WAAmB;IAEnB,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC;QAC7B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;IACtC,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,UAAU,oBAAoB,CAAC,CAAC;IAC1E,uEAAuE;IACvE,uDAAuD;IACvD,qEAAqE;IACrE,oDAAoD;IACpD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAClC,IAAI,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC;QACpE,qEAAqE;QACrE,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,OAAO,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC;IAEpD,OAAO;QACL,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,CAAC;KAC5C,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAAmB;IACtD,IAAI,CAAC;QACH,MAAM,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,0DAA0D;IAC5D,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CAAC,YAAoB,EAAE,eAAwB;IACrF,IAAI,CAAC,eAAe;QAAE,OAAO,YAAY,CAAC;IAC1C,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,YAAY,CAAC;QAAE,OAAO,YAAY,CAAC;IAEnE,OAAO,qBAAqB,YAAY,EAAE,CAAC;AAC7C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,gEAAgE;IAChE,gEAAgE;IAChE,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC;IAElD,4DAA4D;IAC5D,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChD,IAAI,QAAQ,EAAE,CAAC;QACb,iEAAiE;QACjE,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/B,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,sEAAsE;IACtE,sEAAsE;IACtE,MAAM,mBAAmB,GAAgD;QACvE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE;QACvC,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE;QAC5C,EAAE,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,OAAO,EAAE;KAC/C,CAAC;IAEF,KAAK,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,mBAAmB,EAAE,CAAC;QACvD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACtE,IAAI,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,OAAO;gBAAE,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,mDAAmD;IACnD,MAAM,MAAM,GACV,OAAO,CAAC,GAAG,CAAC,OAAO;QACnB,CAAC,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,IAAI;YACpC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,KAAK,CAAC;YACrD,CAAC,CAAC,IAAI;gBACJ,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC;gBACtC,CAAC,CAAC,EAAE,CAAC,CAAC;IACZ,IAAI,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,OAAO;YAAE,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,YAAoB,EACpB,SAA0D;IAE1D,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAE7D,CAAC;IACF,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;IAEpC,IAAI,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QACrD,KAAK,MAAM,CAAC,IAAI,SAAS,CAAC,SAAS;YAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACrD,EAAE,CAAC,SAAS,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,EAAE,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QACtD,KAAK,MAAM,CAAC,IAAI,SAAS,CAAC,UAAU;YAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACtD,EAAE,CAAC,UAAU,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,UAAU,GAAG,EAAE,CAAC;IACxB,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,8EAA8E;AAE9E;;;GAGG;AACH,SAAS,YAAY,CAAC,CAAS;IAC7B,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,KAAkB,EAAE,GAAW,EAAE,IAAY;IACnE,IAAI,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;QACvC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,iBAAyB,EAAE,eAAkC;IACpF,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACjG,OAAO,CAAC,iBAAiB,EAAE,GAAG,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,SAAS,oBAAoB,CAAC,MAAgD;IAC5E,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAE1B,OAAO;QACL,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,EAAE;KAC1C,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe,EAAE,QAAgB;IACrE,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,SAAS,CAAC;QACR,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7D,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,wDAAwD;IACxD,OAAO,IAAI,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proactive OAuth credential file refresher for MCP servers.
|
|
3
|
+
*
|
|
4
|
+
* Runs in the proxy process. Periodically checks token expiry and
|
|
5
|
+
* writes fresh credential files before the access token expires.
|
|
6
|
+
* The MCP server's own loadCredentialsQuietly() re-reads the file
|
|
7
|
+
* on each tool call, picking up the refreshed token transparently.
|
|
8
|
+
*
|
|
9
|
+
* Why this lives in the proxy process (not session):
|
|
10
|
+
* - The proxy process spawns and owns the MCP server child processes
|
|
11
|
+
* - The proxy process has direct access to the credential file directory
|
|
12
|
+
* - The proxy process lifetime matches the MCP server lifetime
|
|
13
|
+
*/
|
|
14
|
+
/** Configuration for a single server's token refresh. */
|
|
15
|
+
export interface TokenRefreshConfig {
|
|
16
|
+
/** OAuth provider ID (e.g., 'google'). Used in log messages. */
|
|
17
|
+
readonly providerId: string;
|
|
18
|
+
/** Function to obtain a fresh access token. Calls OAuthTokenProvider. */
|
|
19
|
+
readonly getAccessToken: () => Promise<{
|
|
20
|
+
accessToken: string;
|
|
21
|
+
expiresAt: number;
|
|
22
|
+
scopes: readonly string[];
|
|
23
|
+
}>;
|
|
24
|
+
/** Function to write the credential file in the format the MCP server expects. */
|
|
25
|
+
readonly writeCredentialFile: (accessToken: string, expiresAt: number, scopes: readonly string[]) => void;
|
|
26
|
+
/** Optional callback to log to the session log (not just stderr). */
|
|
27
|
+
readonly logToSession?: (message: string) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Default refresh check interval: 5 minutes.
|
|
31
|
+
*
|
|
32
|
+
* Much shorter than the MCP server's own 45-minute interval, ensuring
|
|
33
|
+
* we always refresh well before the ~60-minute access token lifetime
|
|
34
|
+
* expires. With a 10-minute-before-expiry threshold, the worst case
|
|
35
|
+
* is 5 + 10 = 15 minutes before expiry.
|
|
36
|
+
*/
|
|
37
|
+
export declare const DEFAULT_REFRESH_INTERVAL_MS: number;
|
|
38
|
+
/**
|
|
39
|
+
* Refresh when within 10 minutes of expiry.
|
|
40
|
+
* Exported for test access.
|
|
41
|
+
*/
|
|
42
|
+
export declare const REFRESH_THRESHOLD_MS: number;
|
|
43
|
+
/**
|
|
44
|
+
* Manages proactive token refresh for a single MCP server.
|
|
45
|
+
*
|
|
46
|
+
* Checks token expiry on a timer and writes a fresh credential file
|
|
47
|
+
* before the access token expires. Errors are logged to stderr but
|
|
48
|
+
* never thrown (the refresher runs on an interval and must not crash).
|
|
49
|
+
*/
|
|
50
|
+
export declare class TokenFileRefresher {
|
|
51
|
+
private intervalHandle;
|
|
52
|
+
private inflight;
|
|
53
|
+
private currentExpiresAt;
|
|
54
|
+
private readonly config;
|
|
55
|
+
constructor(config: TokenRefreshConfig, initialExpiresAt: number);
|
|
56
|
+
/** Best-effort log to session log (if available) and stderr (errors only). */
|
|
57
|
+
private log;
|
|
58
|
+
/** Starts the periodic refresh check. Performs an immediate check first. */
|
|
59
|
+
start(intervalMs?: number): void;
|
|
60
|
+
/** Stops the periodic refresh and cleans up. */
|
|
61
|
+
stop(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Performs a single refresh check.
|
|
64
|
+
* Public for testing; normally called by the interval.
|
|
65
|
+
*
|
|
66
|
+
* Errors are caught and logged to stderr -- never propagated.
|
|
67
|
+
*/
|
|
68
|
+
refreshIfNeeded(): Promise<void>;
|
|
69
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proactive OAuth credential file refresher for MCP servers.
|
|
3
|
+
*
|
|
4
|
+
* Runs in the proxy process. Periodically checks token expiry and
|
|
5
|
+
* writes fresh credential files before the access token expires.
|
|
6
|
+
* The MCP server's own loadCredentialsQuietly() re-reads the file
|
|
7
|
+
* on each tool call, picking up the refreshed token transparently.
|
|
8
|
+
*
|
|
9
|
+
* Why this lives in the proxy process (not session):
|
|
10
|
+
* - The proxy process spawns and owns the MCP server child processes
|
|
11
|
+
* - The proxy process has direct access to the credential file directory
|
|
12
|
+
* - The proxy process lifetime matches the MCP server lifetime
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Default refresh check interval: 5 minutes.
|
|
16
|
+
*
|
|
17
|
+
* Much shorter than the MCP server's own 45-minute interval, ensuring
|
|
18
|
+
* we always refresh well before the ~60-minute access token lifetime
|
|
19
|
+
* expires. With a 10-minute-before-expiry threshold, the worst case
|
|
20
|
+
* is 5 + 10 = 15 minutes before expiry.
|
|
21
|
+
*/
|
|
22
|
+
export const DEFAULT_REFRESH_INTERVAL_MS = 5 * 60 * 1000;
|
|
23
|
+
/**
|
|
24
|
+
* Refresh when within 10 minutes of expiry.
|
|
25
|
+
* Exported for test access.
|
|
26
|
+
*/
|
|
27
|
+
export const REFRESH_THRESHOLD_MS = 10 * 60 * 1000;
|
|
28
|
+
/**
|
|
29
|
+
* Manages proactive token refresh for a single MCP server.
|
|
30
|
+
*
|
|
31
|
+
* Checks token expiry on a timer and writes a fresh credential file
|
|
32
|
+
* before the access token expires. Errors are logged to stderr but
|
|
33
|
+
* never thrown (the refresher runs on an interval and must not crash).
|
|
34
|
+
*/
|
|
35
|
+
export class TokenFileRefresher {
|
|
36
|
+
intervalHandle = null;
|
|
37
|
+
inflight = null;
|
|
38
|
+
currentExpiresAt;
|
|
39
|
+
config;
|
|
40
|
+
constructor(config, initialExpiresAt) {
|
|
41
|
+
this.config = config;
|
|
42
|
+
this.currentExpiresAt = initialExpiresAt;
|
|
43
|
+
}
|
|
44
|
+
/** Best-effort log to session log (if available) and stderr (errors only). */
|
|
45
|
+
log(message, isError = false) {
|
|
46
|
+
const prefix = `[token-refresher:${this.config.providerId}]`;
|
|
47
|
+
const full = `${prefix} ${message}`;
|
|
48
|
+
try {
|
|
49
|
+
this.config.logToSession?.(full);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Swallow — logging must never break the refresh loop.
|
|
53
|
+
}
|
|
54
|
+
if (isError) {
|
|
55
|
+
try {
|
|
56
|
+
process.stderr.write(`${full}\n`);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Swallow — logging must never break the refresh loop.
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Starts the periodic refresh check. Performs an immediate check first. */
|
|
64
|
+
start(intervalMs = DEFAULT_REFRESH_INTERVAL_MS) {
|
|
65
|
+
if (this.intervalHandle !== null)
|
|
66
|
+
return;
|
|
67
|
+
// Immediate check — catches tokens already near expiry at session start
|
|
68
|
+
void this.refreshIfNeeded();
|
|
69
|
+
this.intervalHandle = setInterval(() => {
|
|
70
|
+
void this.refreshIfNeeded();
|
|
71
|
+
}, intervalMs);
|
|
72
|
+
// Ensure the interval doesn't keep the process alive
|
|
73
|
+
this.intervalHandle.unref();
|
|
74
|
+
}
|
|
75
|
+
/** Stops the periodic refresh and cleans up. */
|
|
76
|
+
stop() {
|
|
77
|
+
if (this.intervalHandle !== null) {
|
|
78
|
+
clearInterval(this.intervalHandle);
|
|
79
|
+
this.intervalHandle = null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Performs a single refresh check.
|
|
84
|
+
* Public for testing; normally called by the interval.
|
|
85
|
+
*
|
|
86
|
+
* Errors are caught and logged to stderr -- never propagated.
|
|
87
|
+
*/
|
|
88
|
+
async refreshIfNeeded() {
|
|
89
|
+
// Guard against concurrent refreshes (slow network can overlap next tick)
|
|
90
|
+
if (this.inflight)
|
|
91
|
+
return;
|
|
92
|
+
try {
|
|
93
|
+
const now = Date.now();
|
|
94
|
+
const timeUntilExpiry = this.currentExpiresAt - now;
|
|
95
|
+
if (timeUntilExpiry > REFRESH_THRESHOLD_MS) {
|
|
96
|
+
return; // Token still has plenty of time
|
|
97
|
+
}
|
|
98
|
+
const minUntilExpiry = Math.round(timeUntilExpiry / 60_000);
|
|
99
|
+
this.log(`Refreshing token (${minUntilExpiry} min until expiry)`);
|
|
100
|
+
const refresh = (async () => {
|
|
101
|
+
const { accessToken, expiresAt, scopes } = await this.config.getAccessToken();
|
|
102
|
+
this.config.writeCredentialFile(accessToken, expiresAt, scopes);
|
|
103
|
+
this.currentExpiresAt = expiresAt;
|
|
104
|
+
const newMin = Math.round((expiresAt - Date.now()) / 60_000);
|
|
105
|
+
this.log(`Token refreshed successfully (new expiry in ${newMin} min)`);
|
|
106
|
+
})();
|
|
107
|
+
this.inflight = refresh;
|
|
108
|
+
await refresh;
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
// Log but don't throw -- this runs on an interval
|
|
112
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
113
|
+
this.log(`FAILED to refresh token: ${message}`, true);
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
this.inflight = null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=token-file-refresher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-file-refresher.js","sourceRoot":"","sources":["../../src/trusted-process/token-file-refresher.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* - opaque: no structural invariant (semantic meaning only)
|
|
15
15
|
*/
|
|
16
16
|
export type RoleCategory = 'path' | 'url' | 'identifier' | 'opaque';
|
|
17
|
-
export type ArgumentRole = 'read-path' | 'write-path' | 'delete-path' | 'write-history' | 'delete-history' | 'fetch-url' | 'git-remote-url' | 'github-owner' | 'github-repo' | 'branch-name' | 'commit-message' | 'none';
|
|
17
|
+
export type ArgumentRole = 'read-path' | 'write-path' | 'delete-path' | 'write-history' | 'delete-history' | 'fetch-url' | 'git-remote-url' | 'github-owner' | 'github-repo' | 'branch-name' | 'commit-message' | 'email-address' | 'email-body' | 'share-permission' | 'none';
|
|
18
18
|
export interface RoleDefinition {
|
|
19
19
|
readonly description: string;
|
|
20
20
|
readonly isResourceIdentifier: boolean;
|
|
@@ -46,6 +46,12 @@ export declare function expandTilde(filePath: string): string;
|
|
|
46
46
|
* directory inside the sandbox could escape containment checks.
|
|
47
47
|
*/
|
|
48
48
|
export declare function resolveRealPath(filePath: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Checks whether a target path is contained within a directory.
|
|
51
|
+
* Both paths are resolved to their real canonical form (following symlinks)
|
|
52
|
+
* before comparison, which neutralizes both path traversal and symlink attacks.
|
|
53
|
+
*/
|
|
54
|
+
export declare function isWithinDirectory(targetPath: string, directory: string): boolean;
|
|
49
55
|
export declare const ARGUMENT_ROLE_REGISTRY: ReadonlyMap<ArgumentRole, RoleDefinition>;
|
|
50
56
|
/** Returns the RoleDefinition for a role. Throws if not registered. */
|
|
51
57
|
export declare function getRoleDefinition(role: ArgumentRole): RoleDefinition;
|
|
@@ -71,6 +71,16 @@ export function resolveRealPath(filePath) {
|
|
|
71
71
|
return absolute;
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Checks whether a target path is contained within a directory.
|
|
76
|
+
* Both paths are resolved to their real canonical form (following symlinks)
|
|
77
|
+
* before comparison, which neutralizes both path traversal and symlink attacks.
|
|
78
|
+
*/
|
|
79
|
+
export function isWithinDirectory(targetPath, directory) {
|
|
80
|
+
const resolved = resolveRealPath(targetPath);
|
|
81
|
+
const resolvedDir = resolveRealPath(directory);
|
|
82
|
+
return resolved === resolvedDir || resolved.startsWith(resolvedDir + '/');
|
|
83
|
+
}
|
|
74
84
|
/** Identity function -- returns the value unchanged. */
|
|
75
85
|
function identity(value) {
|
|
76
86
|
return value;
|
|
@@ -218,6 +228,43 @@ const registryEntries = [
|
|
|
218
228
|
serverNames: ['git'],
|
|
219
229
|
},
|
|
220
230
|
],
|
|
231
|
+
// ── Google Workspace roles ──────────────────────────────────────
|
|
232
|
+
[
|
|
233
|
+
'email-address',
|
|
234
|
+
{
|
|
235
|
+
description: 'Email address (recipient, attendee, share target)',
|
|
236
|
+
isResourceIdentifier: false,
|
|
237
|
+
category: 'opaque',
|
|
238
|
+
canonicalize: identity,
|
|
239
|
+
annotationGuidance: 'Assign to arguments that are email addresses (recipients, attendees, share targets). ' +
|
|
240
|
+
'Includes the "to" field on send/draft, "attendees" on calendar events, "email" on file sharing.',
|
|
241
|
+
serverNames: ['google-workspace'],
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
[
|
|
245
|
+
'email-body',
|
|
246
|
+
{
|
|
247
|
+
description: 'Email message body content',
|
|
248
|
+
isResourceIdentifier: false,
|
|
249
|
+
category: 'opaque',
|
|
250
|
+
canonicalize: identity,
|
|
251
|
+
annotationGuidance: 'Assign to arguments that contain email body text or rich content. ' +
|
|
252
|
+
'Includes the "body" field on send/draft message tools.',
|
|
253
|
+
serverNames: ['google-workspace'],
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
[
|
|
257
|
+
'share-permission',
|
|
258
|
+
{
|
|
259
|
+
description: 'Sharing permission level (viewer, commenter, editor, organizer)',
|
|
260
|
+
isResourceIdentifier: false,
|
|
261
|
+
category: 'opaque',
|
|
262
|
+
canonicalize: lowercase,
|
|
263
|
+
annotationGuidance: 'Assign to arguments that specify a sharing or permission level on shared resources ' +
|
|
264
|
+
'(e.g., the role parameter on Drive file sharing).',
|
|
265
|
+
serverNames: ['google-workspace'],
|
|
266
|
+
},
|
|
267
|
+
],
|
|
221
268
|
[
|
|
222
269
|
'none',
|
|
223
270
|
{
|
|
@@ -247,6 +294,9 @@ const _ROLE_COMPLETENESS_CHECK = {
|
|
|
247
294
|
'github-repo': true,
|
|
248
295
|
'branch-name': true,
|
|
249
296
|
'commit-message': true,
|
|
297
|
+
'email-address': true,
|
|
298
|
+
'email-body': true,
|
|
299
|
+
'share-permission': true,
|
|
250
300
|
none: true,
|
|
251
301
|
};
|
|
252
302
|
// ---------------------------------------------------------------------------
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"argument-roles.js","sourceRoot":"","sources":["../../src/types/argument-roles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"argument-roles.js","sourceRoot":"","sources":["../../src/types/argument-roles.ts"],"names":[],"mappings":"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"}
|
package/dist/types/audit.d.ts
CHANGED
|
@@ -20,4 +20,15 @@ export interface AuditEntry {
|
|
|
20
20
|
* rather than a human. Only present when escalationResult is 'approved'.
|
|
21
21
|
*/
|
|
22
22
|
autoApproved?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* When true, the escalation was bypassed because a whitelist
|
|
25
|
+
* pattern matched. The whitelistPatternId links to the original
|
|
26
|
+
* approval that created the pattern.
|
|
27
|
+
*/
|
|
28
|
+
whitelistApproved?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* ID of the whitelist pattern that matched, linking back to the
|
|
31
|
+
* original escalation approval. Only present when whitelistApproved is true.
|
|
32
|
+
*/
|
|
33
|
+
whitelistPatternId?: string;
|
|
23
34
|
}
|
package/docker/Dockerfile.base
CHANGED
|
@@ -10,8 +10,30 @@ RUN apt-get update && apt-get install -y --no-install-recommends socat && rm -rf
|
|
|
10
10
|
COPY ironcurtain-ca-cert.pem /usr/local/share/ca-certificates/ironcurtain-ca.crt
|
|
11
11
|
RUN update-ca-certificates
|
|
12
12
|
|
|
13
|
+
# Python tooling: uv (fast package manager) and ruff (linter)
|
|
14
|
+
RUN curl -LsSf https://astral.sh/uv/install.sh | sh && \
|
|
15
|
+
curl -LsSf https://astral.sh/ruff/install.sh | sh && \
|
|
16
|
+
mv /root/.local/bin/uv /usr/local/bin/uv && \
|
|
17
|
+
mv /root/.local/bin/ruff /usr/local/bin/ruff && \
|
|
18
|
+
rm -rf /root/.local
|
|
19
|
+
|
|
20
|
+
# Pre-install Python 3.12 so uv never needs to download it at runtime.
|
|
21
|
+
# Containers run with --network=none, so runtime downloads would fail.
|
|
22
|
+
# Install to a shared location so the codespace user can find it.
|
|
23
|
+
# uv uses rustls by default, which doesn't read system CA certs.
|
|
24
|
+
# UV_NATIVE_TLS makes it use the system TLS stack (OpenSSL) instead,
|
|
25
|
+
# so it trusts the IronCurtain MITM CA installed above.
|
|
26
|
+
ENV UV_NATIVE_TLS=1
|
|
27
|
+
ENV UV_PYTHON_INSTALL_DIR=/opt/uv-python
|
|
28
|
+
RUN uv python install 3.12
|
|
29
|
+
|
|
13
30
|
RUN mkdir -p /workspace /etc/ironcurtain /run/ironcurtain && \
|
|
14
31
|
chown codespace:codespace /workspace /etc/ironcurtain /run/ironcurtain
|
|
15
32
|
|
|
16
33
|
WORKDIR /workspace
|
|
17
34
|
USER codespace
|
|
35
|
+
|
|
36
|
+
# Node.js headers for native addon compilation (node-gyp).
|
|
37
|
+
# Must run as codespace — node-gyp caches headers in ~/.cache/node-gyp/
|
|
38
|
+
# and the runtime user is codespace, not root.
|
|
39
|
+
RUN node-gyp install
|
|
@@ -1,23 +1,63 @@
|
|
|
1
|
-
FROM node:22-
|
|
1
|
+
FROM node:22-trixie
|
|
2
2
|
|
|
3
3
|
# Replicate the 'codespace' user (uid 1000) from the devcontainers/universal
|
|
4
4
|
# image so Dockerfile.claude-code works unchanged on both platforms.
|
|
5
|
-
# node
|
|
5
|
+
# The node base image ships node:node at uid/gid 1000 — rename it.
|
|
6
6
|
RUN usermod -l codespace -d /home/codespace -m node && \
|
|
7
7
|
groupmod -n codespace node
|
|
8
8
|
|
|
9
9
|
USER root
|
|
10
10
|
RUN apt-get update && \
|
|
11
|
-
apt-get install -y --no-install-recommends
|
|
12
|
-
|
|
11
|
+
apt-get install -y --no-install-recommends \
|
|
12
|
+
# Existing
|
|
13
|
+
git socat ca-certificates \
|
|
14
|
+
# Build tools for native extensions
|
|
15
|
+
build-essential cmake pkg-config \
|
|
16
|
+
# Graphics/Qt runtime + dev
|
|
17
|
+
libegl1 libegl-dev libgl1 libgl-dev \
|
|
18
|
+
libxkbcommon0 libxkbcommon-dev libdbus-1-3 libdbus-1-dev \
|
|
19
|
+
# X11/XCB (Qt offscreen mode)
|
|
20
|
+
libx11-6 libxext6 libxrender1 libxcb1 \
|
|
21
|
+
libxcb-cursor0 libxcb-icccm4 libxcb-keysyms1 \
|
|
22
|
+
libxcb-shape0 libxcb-xfixes0 libxcb-xkb1 libxkbcommon-x11-0 \
|
|
23
|
+
# Common native Python deps
|
|
24
|
+
libffi-dev libssl-dev zlib1g-dev libxml2-dev libxslt1-dev \
|
|
25
|
+
# Fonts (Qt needs at least one font)
|
|
26
|
+
fontconfig fonts-dejavu-core \
|
|
27
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
13
28
|
|
|
14
29
|
# IronCurtain CA (for MITM proxy trust)
|
|
15
30
|
# This file is copied into a temporary build context by ensureImage().
|
|
16
31
|
COPY ironcurtain-ca-cert.pem /usr/local/share/ca-certificates/ironcurtain-ca.crt
|
|
17
32
|
RUN update-ca-certificates
|
|
18
33
|
|
|
34
|
+
# Python tooling: uv (fast package manager) and ruff (linter)
|
|
35
|
+
# curl is available from the apt-get install above.
|
|
36
|
+
RUN curl -LsSf https://astral.sh/uv/install.sh | sh && \
|
|
37
|
+
curl -LsSf https://astral.sh/ruff/install.sh | sh && \
|
|
38
|
+
mv /root/.local/bin/uv /usr/local/bin/uv && \
|
|
39
|
+
mv /root/.local/bin/ruff /usr/local/bin/ruff && \
|
|
40
|
+
rm -rf /root/.local
|
|
41
|
+
|
|
42
|
+
# Pre-install Python 3.12 so uv never needs to download it at runtime.
|
|
43
|
+
# Containers run with --network=none, so runtime downloads would fail.
|
|
44
|
+
# Install to a shared location so the codespace user can find it.
|
|
45
|
+
# uv uses rustls by default, which doesn't read system CA certs.
|
|
46
|
+
# UV_NATIVE_TLS makes it use the system TLS stack (OpenSSL) instead,
|
|
47
|
+
# so it trusts the IronCurtain MITM CA installed above.
|
|
48
|
+
ENV UV_NATIVE_TLS=1
|
|
49
|
+
ENV UV_PYTHON_INSTALL_DIR=/opt/uv-python
|
|
50
|
+
RUN uv python install 3.12
|
|
51
|
+
|
|
52
|
+
RUN npm install -g node-gyp
|
|
53
|
+
|
|
19
54
|
RUN mkdir -p /workspace /etc/ironcurtain /run/ironcurtain && \
|
|
20
55
|
chown codespace:codespace /workspace /etc/ironcurtain /run/ironcurtain
|
|
21
56
|
|
|
22
57
|
WORKDIR /workspace
|
|
23
58
|
USER codespace
|
|
59
|
+
|
|
60
|
+
# Node.js headers for native addon compilation (node-gyp).
|
|
61
|
+
# Must run as codespace — node-gyp caches headers in ~/.cache/node-gyp/
|
|
62
|
+
# and the runtime user is codespace, not root.
|
|
63
|
+
RUN node-gyp install
|