@provos/ironcurtain 0.1.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.
Files changed (160) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +311 -0
  3. package/dist/agent/index.d.ts +10 -0
  4. package/dist/agent/index.js +71 -0
  5. package/dist/agent/index.js.map +1 -0
  6. package/dist/agent/prompts.d.ts +5 -0
  7. package/dist/agent/prompts.js +26 -0
  8. package/dist/agent/prompts.js.map +1 -0
  9. package/dist/agent/tools.d.ts +13 -0
  10. package/dist/agent/tools.js +51 -0
  11. package/dist/agent/tools.js.map +1 -0
  12. package/dist/cli.d.ts +2 -0
  13. package/dist/cli.js +78 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/config/constitution.md +16 -0
  16. package/dist/config/generated/compiled-policy.json +236 -0
  17. package/dist/config/generated/test-scenarios.json +765 -0
  18. package/dist/config/generated/tool-annotations.json +955 -0
  19. package/dist/config/index.d.ts +25 -0
  20. package/dist/config/index.js +151 -0
  21. package/dist/config/index.js.map +1 -0
  22. package/dist/config/mcp-servers.json +22 -0
  23. package/dist/config/model-provider.d.ts +49 -0
  24. package/dist/config/model-provider.js +78 -0
  25. package/dist/config/model-provider.js.map +1 -0
  26. package/dist/config/paths.d.ts +59 -0
  27. package/dist/config/paths.js +96 -0
  28. package/dist/config/paths.js.map +1 -0
  29. package/dist/config/types.d.ts +89 -0
  30. package/dist/config/types.js +2 -0
  31. package/dist/config/types.js.map +1 -0
  32. package/dist/config/user-config.d.ts +93 -0
  33. package/dist/config/user-config.js +309 -0
  34. package/dist/config/user-config.js.map +1 -0
  35. package/dist/hash.d.ts +17 -0
  36. package/dist/hash.js +34 -0
  37. package/dist/hash.js.map +1 -0
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.js +61 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/logger.d.ts +11 -0
  42. package/dist/logger.js +93 -0
  43. package/dist/logger.js.map +1 -0
  44. package/dist/pipeline/annotate.d.ts +9 -0
  45. package/dist/pipeline/annotate.js +136 -0
  46. package/dist/pipeline/annotate.js.map +1 -0
  47. package/dist/pipeline/compile.d.ts +23 -0
  48. package/dist/pipeline/compile.js +386 -0
  49. package/dist/pipeline/compile.js.map +1 -0
  50. package/dist/pipeline/constitution-compiler.d.ts +22 -0
  51. package/dist/pipeline/constitution-compiler.js +197 -0
  52. package/dist/pipeline/constitution-compiler.js.map +1 -0
  53. package/dist/pipeline/generate-with-repair.d.ts +22 -0
  54. package/dist/pipeline/generate-with-repair.js +64 -0
  55. package/dist/pipeline/generate-with-repair.js.map +1 -0
  56. package/dist/pipeline/handwritten-scenarios.d.ts +9 -0
  57. package/dist/pipeline/handwritten-scenarios.js +321 -0
  58. package/dist/pipeline/handwritten-scenarios.js.map +1 -0
  59. package/dist/pipeline/llm-logger.d.ts +42 -0
  60. package/dist/pipeline/llm-logger.js +78 -0
  61. package/dist/pipeline/llm-logger.js.map +1 -0
  62. package/dist/pipeline/pipeline-shared.d.ts +47 -0
  63. package/dist/pipeline/pipeline-shared.js +145 -0
  64. package/dist/pipeline/pipeline-shared.js.map +1 -0
  65. package/dist/pipeline/policy-verifier.d.ts +46 -0
  66. package/dist/pipeline/policy-verifier.js +277 -0
  67. package/dist/pipeline/policy-verifier.js.map +1 -0
  68. package/dist/pipeline/scenario-generator.d.ts +11 -0
  69. package/dist/pipeline/scenario-generator.js +128 -0
  70. package/dist/pipeline/scenario-generator.js.map +1 -0
  71. package/dist/pipeline/tool-annotator.d.ts +24 -0
  72. package/dist/pipeline/tool-annotator.js +201 -0
  73. package/dist/pipeline/tool-annotator.js.map +1 -0
  74. package/dist/pipeline/types.d.ts +122 -0
  75. package/dist/pipeline/types.js +10 -0
  76. package/dist/pipeline/types.js.map +1 -0
  77. package/dist/sandbox/index.d.ts +39 -0
  78. package/dist/sandbox/index.js +178 -0
  79. package/dist/sandbox/index.js.map +1 -0
  80. package/dist/session/agent-session.d.ts +83 -0
  81. package/dist/session/agent-session.js +382 -0
  82. package/dist/session/agent-session.js.map +1 -0
  83. package/dist/session/cli-transport.d.ts +61 -0
  84. package/dist/session/cli-transport.js +320 -0
  85. package/dist/session/cli-transport.js.map +1 -0
  86. package/dist/session/errors.d.ts +19 -0
  87. package/dist/session/errors.js +33 -0
  88. package/dist/session/errors.js.map +1 -0
  89. package/dist/session/index.d.ts +29 -0
  90. package/dist/session/index.js +104 -0
  91. package/dist/session/index.js.map +1 -0
  92. package/dist/session/message-compactor.d.ts +32 -0
  93. package/dist/session/message-compactor.js +81 -0
  94. package/dist/session/message-compactor.js.map +1 -0
  95. package/dist/session/prompts.d.ts +5 -0
  96. package/dist/session/prompts.js +62 -0
  97. package/dist/session/prompts.js.map +1 -0
  98. package/dist/session/resource-budget-tracker.d.ts +124 -0
  99. package/dist/session/resource-budget-tracker.js +327 -0
  100. package/dist/session/resource-budget-tracker.js.map +1 -0
  101. package/dist/session/step-loop-detector.d.ts +63 -0
  102. package/dist/session/step-loop-detector.js +136 -0
  103. package/dist/session/step-loop-detector.js.map +1 -0
  104. package/dist/session/transport.d.ts +24 -0
  105. package/dist/session/transport.js +2 -0
  106. package/dist/session/transport.js.map +1 -0
  107. package/dist/session/truncate-result.d.ts +35 -0
  108. package/dist/session/truncate-result.js +71 -0
  109. package/dist/session/truncate-result.js.map +1 -0
  110. package/dist/session/types.d.ts +220 -0
  111. package/dist/session/types.js +6 -0
  112. package/dist/session/types.js.map +1 -0
  113. package/dist/trusted-process/audit-log.d.ts +7 -0
  114. package/dist/trusted-process/audit-log.js +21 -0
  115. package/dist/trusted-process/audit-log.js.map +1 -0
  116. package/dist/trusted-process/call-circuit-breaker.d.ts +33 -0
  117. package/dist/trusted-process/call-circuit-breaker.js +61 -0
  118. package/dist/trusted-process/call-circuit-breaker.js.map +1 -0
  119. package/dist/trusted-process/escalation.d.ts +7 -0
  120. package/dist/trusted-process/escalation.js +38 -0
  121. package/dist/trusted-process/escalation.js.map +1 -0
  122. package/dist/trusted-process/index.d.ts +32 -0
  123. package/dist/trusted-process/index.js +151 -0
  124. package/dist/trusted-process/index.js.map +1 -0
  125. package/dist/trusted-process/mcp-client-manager.d.ts +25 -0
  126. package/dist/trusted-process/mcp-client-manager.js +90 -0
  127. package/dist/trusted-process/mcp-client-manager.js.map +1 -0
  128. package/dist/trusted-process/mcp-proxy-server.d.ts +24 -0
  129. package/dist/trusted-process/mcp-proxy-server.js +451 -0
  130. package/dist/trusted-process/mcp-proxy-server.js.map +1 -0
  131. package/dist/trusted-process/path-utils.d.ts +50 -0
  132. package/dist/trusted-process/path-utils.js +158 -0
  133. package/dist/trusted-process/path-utils.js.map +1 -0
  134. package/dist/trusted-process/policy-engine.d.ts +88 -0
  135. package/dist/trusted-process/policy-engine.js +523 -0
  136. package/dist/trusted-process/policy-engine.js.map +1 -0
  137. package/dist/trusted-process/policy-roots.d.ts +50 -0
  138. package/dist/trusted-process/policy-roots.js +67 -0
  139. package/dist/trusted-process/policy-roots.js.map +1 -0
  140. package/dist/trusted-process/policy-types.d.ts +6 -0
  141. package/dist/trusted-process/policy-types.js +2 -0
  142. package/dist/trusted-process/policy-types.js.map +1 -0
  143. package/dist/trusted-process/sandbox-integration.d.ts +92 -0
  144. package/dist/trusted-process/sandbox-integration.js +184 -0
  145. package/dist/trusted-process/sandbox-integration.js.map +1 -0
  146. package/dist/types/argument-roles.d.ts +112 -0
  147. package/dist/types/argument-roles.js +344 -0
  148. package/dist/types/argument-roles.js.map +1 -0
  149. package/dist/types/audit.d.ts +18 -0
  150. package/dist/types/audit.js +2 -0
  151. package/dist/types/audit.js.map +1 -0
  152. package/dist/types/mcp.d.ts +20 -0
  153. package/dist/types/mcp.js +2 -0
  154. package/dist/types/mcp.js.map +1 -0
  155. package/package.json +83 -0
  156. package/src/config/constitution.md +16 -0
  157. package/src/config/generated/compiled-policy.json +236 -0
  158. package/src/config/generated/test-scenarios.json +765 -0
  159. package/src/config/generated/tool-annotations.json +955 -0
  160. package/src/config/mcp-servers.json +22 -0
@@ -0,0 +1,344 @@
1
+ /**
2
+ * ArgumentRole Registry -- Central definition of argument role semantics.
3
+ *
4
+ * Each role is paired with metadata describing its security semantics
5
+ * and a normalizer function for canonicalizing argument values. This
6
+ * eliminates scattered hardcoded role strings and enables annotation-driven
7
+ * normalization instead of fragile heuristics.
8
+ *
9
+ * Roles are organized into categories that determine which structural
10
+ * invariant applies in the policy engine:
11
+ * - path: filesystem path containment checks
12
+ * - url: domain allowlist checks
13
+ * - opaque: no structural invariant (semantic meaning only)
14
+ */
15
+ import { execFileSync } from 'node:child_process';
16
+ import { realpathSync } from 'node:fs';
17
+ import { homedir } from 'node:os';
18
+ import { resolve, dirname, basename, join } from 'node:path';
19
+ // ---------------------------------------------------------------------------
20
+ // Normalizer functions
21
+ // ---------------------------------------------------------------------------
22
+ /** Expands a leading `~` or `~/` to the current user's home directory. */
23
+ export function expandTilde(filePath) {
24
+ if (filePath === '~')
25
+ return homedir();
26
+ if (filePath.startsWith('~/'))
27
+ return homedir() + filePath.slice(1);
28
+ return filePath;
29
+ }
30
+ /**
31
+ * Resolves a filesystem path to its canonical real path, following symlinks.
32
+ *
33
+ * Tries three strategies in order:
34
+ * 1. `realpathSync(path)` — works for existing paths, follows all symlinks
35
+ * 2. `realpathSync(parent) + basename` — works for new files in existing dirs
36
+ * 3. `path.resolve(path)` — fallback for entirely new paths
37
+ *
38
+ * This is security-critical: without symlink resolution, a symlinked
39
+ * directory inside the sandbox could escape containment checks.
40
+ */
41
+ export function resolveRealPath(filePath) {
42
+ const absolute = resolve(filePath);
43
+ try {
44
+ return realpathSync(absolute);
45
+ }
46
+ catch {
47
+ try {
48
+ return join(realpathSync(dirname(absolute)), basename(absolute));
49
+ }
50
+ catch {
51
+ return absolute;
52
+ }
53
+ }
54
+ }
55
+ /** Tilde expansion + symlink resolution to produce a canonical real path. */
56
+ export function normalizePath(value) {
57
+ return resolveRealPath(expandTilde(value));
58
+ }
59
+ /** Identity function -- returns the value unchanged. */
60
+ function identity(value) {
61
+ return value;
62
+ }
63
+ // ---------------------------------------------------------------------------
64
+ // URL normalizers and domain extractors
65
+ // ---------------------------------------------------------------------------
66
+ /** Normalizes an HTTP(S) URL to a canonical form. Returns value as-is on parse failure. */
67
+ export function normalizeUrl(value) {
68
+ try {
69
+ const url = new URL(value);
70
+ if (url.pathname === '/')
71
+ url.pathname = '';
72
+ return url.toString().replace(/\/$/, '');
73
+ }
74
+ catch {
75
+ return value;
76
+ }
77
+ }
78
+ /** Extracts the hostname from an HTTP(S) URL. Returns value as-is on parse failure. */
79
+ export function extractDomain(value) {
80
+ try {
81
+ return new URL(value).hostname;
82
+ }
83
+ catch {
84
+ return value;
85
+ }
86
+ }
87
+ /** Normalizes a git URL (HTTP or SSH format). SSH URLs are returned as-is. */
88
+ export function normalizeGitUrl(value) {
89
+ // SSH format: git@host:path -- no further normalization needed
90
+ const sshMatch = value.match(/^(?:[\w.+-]+@)?([^:]+):/);
91
+ if (sshMatch && !value.includes('://'))
92
+ return value;
93
+ return normalizeUrl(value);
94
+ }
95
+ /** Extracts the domain from a git URL (HTTP or SSH format). */
96
+ export function extractGitDomain(value) {
97
+ // SSH format: git@host:path
98
+ const sshMatch = value.match(/^(?:[\w.+-]+@)?([^:]+):/);
99
+ if (sshMatch && !value.includes('://'))
100
+ return sshMatch[1];
101
+ return extractDomain(value);
102
+ }
103
+ /**
104
+ * Resolves a git remote value to a URL for policy evaluation.
105
+ *
106
+ * If the value is already a URL (contains :// or matches SSH pattern),
107
+ * returns it as-is. Otherwise, treats it as a named remote and runs
108
+ * `git remote get-url <name>` in the repository directory (found via
109
+ * the `path` sibling argument).
110
+ *
111
+ * Uses execFileSync (not execSync) to avoid command injection --
112
+ * the value comes from agent-controlled tool call arguments.
113
+ *
114
+ * When resolution fails (repo doesn't exist, remote not found, git
115
+ * not installed), returns the original value. This causes the domain
116
+ * check to escalate (the value won't match any allowed domain),
117
+ * which is the correct behavior -- escalate when we can't verify.
118
+ */
119
+ export function resolveGitRemote(value, allArgs) {
120
+ // Already a URL -- return as-is
121
+ if (value.includes('://') || /^[\w.+-]+@[^:]+:/.test(value)) {
122
+ return value;
123
+ }
124
+ // Named remote -- resolve via git (no shell, no injection risk)
125
+ const rawPath = typeof allArgs.path === 'string' ? allArgs.path : '.';
126
+ const repoPath = resolve(rawPath);
127
+ try {
128
+ return execFileSync('git', ['remote', 'get-url', value], {
129
+ cwd: repoPath,
130
+ encoding: 'utf-8',
131
+ timeout: 5000,
132
+ stdio: ['pipe', 'pipe', 'pipe'],
133
+ }).trim();
134
+ }
135
+ catch {
136
+ return value; // Resolution failed -- escalation will catch it
137
+ }
138
+ }
139
+ // ---------------------------------------------------------------------------
140
+ // Registry
141
+ // ---------------------------------------------------------------------------
142
+ const registryEntries = [
143
+ [
144
+ 'read-path',
145
+ {
146
+ description: 'Filesystem path that will be read',
147
+ isResourceIdentifier: true,
148
+ category: 'path',
149
+ normalize: normalizePath,
150
+ annotationGuidance: 'Assign to arguments that are filesystem paths the tool will read from. ' +
151
+ 'Includes file and directory paths used for input.',
152
+ },
153
+ ],
154
+ [
155
+ 'write-path',
156
+ {
157
+ description: 'Filesystem path that will be written to',
158
+ isResourceIdentifier: true,
159
+ category: 'path',
160
+ normalize: normalizePath,
161
+ annotationGuidance: 'Assign to arguments that are filesystem paths the tool will write or create. ' +
162
+ 'Includes destination paths for file creation and modification.',
163
+ },
164
+ ],
165
+ [
166
+ 'delete-path',
167
+ {
168
+ description: 'Filesystem path that will be deleted',
169
+ isResourceIdentifier: true,
170
+ category: 'path',
171
+ normalize: normalizePath,
172
+ annotationGuidance: 'Assign to arguments that are filesystem paths the tool will delete or remove. ' +
173
+ 'Also assign to the source argument of move operations (source is deleted after copy).',
174
+ },
175
+ ],
176
+ [
177
+ 'write-history',
178
+ {
179
+ description: 'Filesystem path where git history will be rewritten',
180
+ isResourceIdentifier: true,
181
+ category: 'path',
182
+ normalize: normalizePath,
183
+ annotationGuidance: 'Assign to the repository path argument of git operations that rewrite history or modify refs. ' +
184
+ 'Includes git_reset, git_rebase, git_merge, git_cherry_pick, and similar operations. ' +
185
+ 'These operations are dangerous even within the sandbox and require human oversight.',
186
+ serverNames: ['git'],
187
+ },
188
+ ],
189
+ [
190
+ 'delete-history',
191
+ {
192
+ description: 'Filesystem path where git refs or history will be deleted',
193
+ isResourceIdentifier: true,
194
+ category: 'path',
195
+ normalize: normalizePath,
196
+ annotationGuidance: 'Assign to the repository path argument of git operations that delete refs (branches, tags). ' +
197
+ 'Includes git_branch (delete mode), git_tag (delete mode), and similar operations. ' +
198
+ 'These operations are dangerous even within the sandbox and require human oversight.',
199
+ serverNames: ['git'],
200
+ },
201
+ ],
202
+ [
203
+ 'fetch-url',
204
+ {
205
+ description: 'URL that will be fetched via HTTP(S)',
206
+ isResourceIdentifier: true,
207
+ category: 'url',
208
+ normalize: normalizeUrl,
209
+ prepareForPolicy: extractDomain,
210
+ annotationGuidance: 'Assign to arguments that are HTTP(S) URLs the tool will fetch. ' +
211
+ 'Typically applies to web-fetch server tools.',
212
+ },
213
+ ],
214
+ [
215
+ 'git-remote-url',
216
+ {
217
+ description: 'Git remote URL or named remote for network operations',
218
+ isResourceIdentifier: true,
219
+ category: 'url',
220
+ normalize: normalizeGitUrl,
221
+ prepareForPolicy: extractGitDomain,
222
+ resolveForPolicy: resolveGitRemote,
223
+ annotationGuidance: 'Assign to arguments that identify a git remote (URL or named remote like "origin"). ' +
224
+ 'Typically applies to git server tools like git_clone, git_push, git_pull, git_fetch, git_remote.',
225
+ serverNames: ['git'],
226
+ },
227
+ ],
228
+ [
229
+ 'branch-name',
230
+ {
231
+ description: 'Git branch name',
232
+ isResourceIdentifier: false,
233
+ category: 'opaque',
234
+ normalize: identity,
235
+ annotationGuidance: 'Assign to arguments that are git branch names. ' +
236
+ 'Typically applies to git server tools like git_branch, git_checkout, git_merge, git_push.',
237
+ serverNames: ['git'],
238
+ },
239
+ ],
240
+ [
241
+ 'commit-message',
242
+ {
243
+ description: 'Git commit message text',
244
+ isResourceIdentifier: false,
245
+ category: 'opaque',
246
+ normalize: identity,
247
+ annotationGuidance: 'Assign to arguments that are git commit messages. ' +
248
+ 'Typically applies to git_commit.',
249
+ serverNames: ['git'],
250
+ },
251
+ ],
252
+ [
253
+ 'none',
254
+ {
255
+ description: 'Argument carries no resource-identifier semantics',
256
+ isResourceIdentifier: false,
257
+ category: 'opaque',
258
+ normalize: identity,
259
+ annotationGuidance: 'Assign to arguments that have no resource-identifier semantics. ' +
260
+ 'Use for flags, counts, patterns, messages, and other non-path, non-URL values.',
261
+ },
262
+ ],
263
+ ];
264
+ export const ARGUMENT_ROLE_REGISTRY = new Map(registryEntries);
265
+ // ---------------------------------------------------------------------------
266
+ // Compile-time completeness check
267
+ // ---------------------------------------------------------------------------
268
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
269
+ const _ROLE_COMPLETENESS_CHECK = {
270
+ 'read-path': true,
271
+ 'write-path': true,
272
+ 'delete-path': true,
273
+ 'write-history': true,
274
+ 'delete-history': true,
275
+ 'fetch-url': true,
276
+ 'git-remote-url': true,
277
+ 'branch-name': true,
278
+ 'commit-message': true,
279
+ 'none': true,
280
+ };
281
+ // ---------------------------------------------------------------------------
282
+ // Convenience accessors
283
+ // ---------------------------------------------------------------------------
284
+ /** Returns the RoleDefinition for a role. Throws if not registered. */
285
+ export function getRoleDefinition(role) {
286
+ const def = ARGUMENT_ROLE_REGISTRY.get(role);
287
+ if (!def) {
288
+ throw new Error(`No registry entry for role: ${role}`);
289
+ }
290
+ return def;
291
+ }
292
+ /** Returns all roles where isResourceIdentifier is true. */
293
+ export function getResourceRoles() {
294
+ return Array.from(ARGUMENT_ROLE_REGISTRY)
295
+ .filter(([, def]) => def.isResourceIdentifier)
296
+ .map(([role]) => role);
297
+ }
298
+ /** Type guard: returns true if the value is a valid ArgumentRole string. */
299
+ export function isArgumentRole(value) {
300
+ return ARGUMENT_ROLE_REGISTRY.has(value);
301
+ }
302
+ /** All role values as a tuple for z.enum() compatibility. */
303
+ export function getArgumentRoleValues() {
304
+ const roles = [...ARGUMENT_ROLE_REGISTRY.keys()];
305
+ return roles;
306
+ }
307
+ /**
308
+ * Returns roles relevant to a specific MCP server.
309
+ * Universal roles (no serverNames) are always included.
310
+ * Server-specific roles are included only when the server matches.
311
+ */
312
+ export function getRolesForServer(serverName) {
313
+ return Array.from(ARGUMENT_ROLE_REGISTRY)
314
+ .filter(([, def]) => !def.serverNames || def.serverNames.includes(serverName));
315
+ }
316
+ /** Returns all roles with the given category. */
317
+ export function getRolesByCategory(category) {
318
+ return Array.from(ARGUMENT_ROLE_REGISTRY)
319
+ .filter(([, def]) => def.category === category)
320
+ .map(([role]) => role);
321
+ }
322
+ /** Returns path-category roles only. Used by Phase 1a/1b structural invariants. */
323
+ export function getPathRoles() {
324
+ return getRolesByCategory('path');
325
+ }
326
+ /** Returns url-category roles only. Used by Phase 1c domain checks. */
327
+ export function getUrlRoles() {
328
+ return getRolesByCategory('url');
329
+ }
330
+ /**
331
+ * Path roles that Phase 1b sandbox containment is allowed to auto-resolve.
332
+ *
333
+ * Basic filesystem operations (read, write, delete) are safe within the
334
+ * sandbox boundary. Higher-risk path roles like `write-history` and
335
+ * `delete-history` are NOT sandbox-safe: even when the repo path is inside
336
+ * the sandbox, these operations require Phase 2 policy evaluation (and
337
+ * typically human approval) because they can destroy git history.
338
+ */
339
+ export const SANDBOX_SAFE_PATH_ROLES = new Set([
340
+ 'read-path',
341
+ 'write-path',
342
+ 'delete-path',
343
+ ]);
344
+ //# sourceMappingURL=argument-roles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"argument-roles.js","sourceRoot":"","sources":["../../src/types/argument-roles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { PolicyDecision } from './mcp.js';
2
+ export interface AuditEntry {
3
+ timestamp: string;
4
+ requestId: string;
5
+ serverName: string;
6
+ toolName: string;
7
+ arguments: Record<string, unknown>;
8
+ policyDecision: PolicyDecision;
9
+ escalationResult?: 'approved' | 'denied';
10
+ result: {
11
+ status: 'success' | 'denied' | 'error';
12
+ content?: unknown;
13
+ error?: string;
14
+ };
15
+ durationMs: number;
16
+ /** Whether the MCP server process was running inside an OS-level sandbox. */
17
+ sandboxed?: boolean;
18
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/types/audit.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ export interface ToolCallRequest {
2
+ requestId: string;
3
+ serverName: string;
4
+ toolName: string;
5
+ arguments: Record<string, unknown>;
6
+ timestamp: string;
7
+ }
8
+ export type PolicyDecisionStatus = 'allow' | 'deny' | 'escalate';
9
+ export interface PolicyDecision {
10
+ status: PolicyDecisionStatus;
11
+ rule: string;
12
+ reason: string;
13
+ }
14
+ export interface ToolCallResult {
15
+ requestId: string;
16
+ status: 'success' | 'denied' | 'error';
17
+ content: unknown;
18
+ policyDecision: PolicyDecision;
19
+ durationMs: number;
20
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/types/mcp.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@provos/ironcurtain",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Secure agent runtime with trusted process mediation",
6
+ "license": "Apache-2.0",
7
+ "author": "Niels Provos",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/provos/ironcurtain.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/provos/ironcurtain/issues"
14
+ },
15
+ "homepage": "https://github.com/provos/ironcurtain#readme",
16
+ "keywords": [
17
+ "mcp",
18
+ "agent",
19
+ "security",
20
+ "sandbox",
21
+ "policy",
22
+ "trusted-process",
23
+ "model-context-protocol"
24
+ ],
25
+ "engines": {
26
+ "node": ">=18.3.0"
27
+ },
28
+ "bin": {
29
+ "ironcurtain": "dist/cli.js"
30
+ },
31
+ "main": "dist/index.js",
32
+ "files": [
33
+ "dist/",
34
+ "src/config/constitution.md",
35
+ "src/config/mcp-servers.json",
36
+ "src/config/generated/compiled-policy.json",
37
+ "src/config/generated/tool-annotations.json",
38
+ "src/config/generated/test-scenarios.json",
39
+ "README.md",
40
+ "LICENSE"
41
+ ],
42
+ "scripts": {
43
+ "build": "tsc && node scripts/copy-assets.mjs",
44
+ "start": "tsx src/cli.ts start",
45
+ "annotate-tools": "tsx src/cli.ts annotate-tools",
46
+ "compile-policy": "tsx src/cli.ts compile-policy",
47
+ "prepublishOnly": "npm run build",
48
+ "test": "vitest run",
49
+ "test:watch": "vitest",
50
+ "lint": "eslint src/ test/"
51
+ },
52
+ "dependencies": {
53
+ "@ai-sdk/anthropic": "^3.0.44",
54
+ "@ai-sdk/google": "^3.0.30",
55
+ "@ai-sdk/openai": "^3.0.30",
56
+ "@anthropic-ai/sandbox-runtime": "^0.0.37",
57
+ "@modelcontextprotocol/sdk": "^1.26.0",
58
+ "@utcp/code-mode": "^1.2.11",
59
+ "@utcp/mcp": "^1.1.1",
60
+ "ai": "^6.0.86",
61
+ "chalk": "^5.6.2",
62
+ "cli-highlight": "^2.1.11",
63
+ "dotenv": "^17.3.1",
64
+ "marked": "^15.0.12",
65
+ "marked-terminal": "^7.3.0",
66
+ "ora": "^9.3.0",
67
+ "@cyanheads/git-mcp-server": "^2.8.4",
68
+ "shell-quote": "^1.8.3",
69
+ "uuid": "^13.0.0",
70
+ "zod": "^4.3.6"
71
+ },
72
+ "devDependencies": {
73
+ "@eslint/js": "^9.39.2",
74
+ "@types/node": "^22.0.0",
75
+ "@types/shell-quote": "^1.7.5",
76
+ "@types/uuid": "^10.0.0",
77
+ "eslint": "^9.39.2",
78
+ "tsx": "^4.19.0",
79
+ "typescript": "^5.7.0",
80
+ "typescript-eslint": "^8.56.0",
81
+ "vitest": "^3.0.0"
82
+ }
83
+ }
@@ -0,0 +1,16 @@
1
+ # IronCurtain Constitution
2
+
3
+ ## Guiding Principles
4
+
5
+ 1. **Least privilege**: The agent may only access resources explicitly permitted by policy.
6
+ 2. **No destruction**: Delete operations outside the sandbox are never permitted.
7
+ 3. **Human oversight**: Operations outside the sandbox require explicit human approval.
8
+
9
+ ## Concrete Guidance which supersedes the guiding principles
10
+ - The agent is allowed to read, write and delete content in the Downloads folder
11
+ - The agent is allowed to read documents in the Users document folder.
12
+ - The agent may perform read-only git operations (status, diff, log, show, blame) within the sandbox without approval.
13
+ - The agent may stage files (git add) and commit within the sandbox without approval.
14
+ - The agent must receive human approval before git push, git pull, git fetch, or any remote-contacting operation.
15
+ - The agent must receive human approval before git reset, git rebase, git merge, or any history-rewriting operation.
16
+ - The agent must receive human approval before git branch deletion or force operations.