@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.
Files changed (259) hide show
  1. package/README.md +29 -100
  2. package/dist/auth/auth-command.d.ts +15 -0
  3. package/dist/auth/auth-command.js +424 -0
  4. package/dist/auth/auth-command.js.map +1 -0
  5. package/dist/auth/oauth-flow.d.ts +46 -0
  6. package/dist/auth/oauth-flow.js +279 -0
  7. package/dist/auth/oauth-flow.js.map +1 -0
  8. package/dist/auth/oauth-provider.d.ts +55 -0
  9. package/dist/auth/oauth-provider.js +73 -0
  10. package/dist/auth/oauth-provider.js.map +1 -0
  11. package/dist/auth/oauth-registry.d.ts +34 -0
  12. package/dist/auth/oauth-registry.js +69 -0
  13. package/dist/auth/oauth-registry.js.map +1 -0
  14. package/dist/auth/oauth-token-provider.d.ts +52 -0
  15. package/dist/auth/oauth-token-provider.js +159 -0
  16. package/dist/auth/oauth-token-provider.js.map +1 -0
  17. package/dist/auth/oauth-token-store.d.ts +30 -0
  18. package/dist/auth/oauth-token-store.js +93 -0
  19. package/dist/auth/oauth-token-store.js.map +1 -0
  20. package/dist/auth/providers/google-scopes.d.ts +35 -0
  21. package/dist/auth/providers/google-scopes.js +183 -0
  22. package/dist/auth/providers/google-scopes.js.map +1 -0
  23. package/dist/auth/providers/google.d.ts +2 -0
  24. package/dist/auth/providers/google.js +28 -0
  25. package/dist/auth/providers/google.js.map +1 -0
  26. package/dist/cli.js +6 -0
  27. package/dist/cli.js.map +1 -1
  28. package/dist/config/config-command.js +39 -1
  29. package/dist/config/config-command.js.map +1 -1
  30. package/dist/config/constitution-readonly.md +14 -11
  31. package/dist/config/constitution-user-base.md +15 -0
  32. package/dist/config/first-start.js +4 -1
  33. package/dist/config/first-start.js.map +1 -1
  34. package/dist/config/generated/test-scenarios.json +1 -1
  35. package/dist/config/generated/tool-annotations.json +10617 -296
  36. package/dist/config/generated-readonly/compiled-policy.json +787 -244
  37. package/dist/config/index.d.ts +2 -2
  38. package/dist/config/index.js +8 -0
  39. package/dist/config/index.js.map +1 -1
  40. package/dist/config/mcp-servers.json +31 -2
  41. package/dist/config/paths.d.ts +20 -0
  42. package/dist/config/paths.js +43 -0
  43. package/dist/config/paths.js.map +1 -1
  44. package/dist/config/types.d.ts +8 -0
  45. package/dist/config/user-config.d.ts +29 -0
  46. package/dist/config/user-config.js +30 -0
  47. package/dist/config/user-config.js.map +1 -1
  48. package/dist/cron/constitution-generator.d.ts +2 -1
  49. package/dist/cron/constitution-generator.js +35 -36
  50. package/dist/cron/constitution-generator.js.map +1 -1
  51. package/dist/cron/headless-transport.d.ts +4 -0
  52. package/dist/cron/headless-transport.js +1 -1
  53. package/dist/cron/headless-transport.js.map +1 -1
  54. package/dist/daemon/ironcurtain-daemon.js +7 -1
  55. package/dist/daemon/ironcurtain-daemon.js.map +1 -1
  56. package/dist/docker/adapters/claude-code.js +32 -5
  57. package/dist/docker/adapters/claude-code.js.map +1 -1
  58. package/dist/docker/agent-adapter.d.ts +40 -0
  59. package/dist/docker/claude-md-seed.d.ts +27 -0
  60. package/dist/docker/claude-md-seed.js +42 -0
  61. package/dist/docker/claude-md-seed.js.map +1 -0
  62. package/dist/docker/docker-agent-session.d.ts +3 -1
  63. package/dist/docker/docker-agent-session.js +51 -28
  64. package/dist/docker/docker-agent-session.js.map +1 -1
  65. package/dist/docker/docker-infrastructure.d.ts +15 -1
  66. package/dist/docker/docker-infrastructure.js +105 -9
  67. package/dist/docker/docker-infrastructure.js.map +1 -1
  68. package/dist/docker/docker-manager.d.ts +2 -0
  69. package/dist/docker/docker-manager.js +9 -1
  70. package/dist/docker/docker-manager.js.map +1 -1
  71. package/dist/docker/mitm-proxy.d.ts +65 -0
  72. package/dist/docker/mitm-proxy.js +288 -31
  73. package/dist/docker/mitm-proxy.js.map +1 -1
  74. package/dist/docker/package-types.d.ts +127 -0
  75. package/dist/docker/package-types.js +8 -0
  76. package/dist/docker/package-types.js.map +1 -0
  77. package/dist/docker/package-validator.d.ts +41 -0
  78. package/dist/docker/package-validator.js +90 -0
  79. package/dist/docker/package-validator.js.map +1 -0
  80. package/dist/docker/platform.d.ts +6 -6
  81. package/dist/docker/platform.js +8 -6
  82. package/dist/docker/platform.js.map +1 -1
  83. package/dist/docker/proxy-tools.d.ts +80 -0
  84. package/dist/docker/proxy-tools.js +248 -0
  85. package/dist/docker/proxy-tools.js.map +1 -0
  86. package/dist/docker/pty-session.d.ts +15 -0
  87. package/dist/docker/pty-session.js +253 -73
  88. package/dist/docker/pty-session.js.map +1 -1
  89. package/dist/docker/pty-types.d.ts +28 -0
  90. package/dist/docker/pty-types.js +2 -0
  91. package/dist/docker/pty-types.js.map +1 -1
  92. package/dist/docker/registry-proxy.d.ts +142 -0
  93. package/dist/docker/registry-proxy.js +856 -0
  94. package/dist/docker/registry-proxy.js.map +1 -0
  95. package/dist/escalation/escalation-watcher.d.ts +3 -1
  96. package/dist/escalation/escalation-watcher.js +6 -2
  97. package/dist/escalation/escalation-watcher.js.map +1 -1
  98. package/dist/escalation/listener-command.js +24 -10
  99. package/dist/escalation/listener-command.js.map +1 -1
  100. package/dist/escalation/listener-lock.d.ts +5 -0
  101. package/dist/escalation/listener-lock.js +14 -0
  102. package/dist/escalation/listener-lock.js.map +1 -1
  103. package/dist/index.js +16 -3
  104. package/dist/index.js.map +1 -1
  105. package/dist/memory/auto-save.d.ts +25 -0
  106. package/dist/memory/auto-save.js +89 -0
  107. package/dist/memory/auto-save.js.map +1 -0
  108. package/dist/memory/memory-annotations.d.ts +47 -0
  109. package/dist/memory/memory-annotations.js +87 -0
  110. package/dist/memory/memory-annotations.js.map +1 -0
  111. package/dist/memory/memory-prompt.d.ts +12 -0
  112. package/dist/memory/memory-prompt.js +20 -0
  113. package/dist/memory/memory-prompt.js.map +1 -0
  114. package/dist/memory/resolve-memory-path.d.ts +20 -0
  115. package/dist/memory/resolve-memory-path.js +30 -0
  116. package/dist/memory/resolve-memory-path.js.map +1 -0
  117. package/dist/mux/mux-app.d.ts +4 -0
  118. package/dist/mux/mux-app.js +246 -28
  119. package/dist/mux/mux-app.js.map +1 -1
  120. package/dist/mux/mux-command.d.ts +2 -2
  121. package/dist/mux/mux-command.js +14 -22
  122. package/dist/mux/mux-command.js.map +1 -1
  123. package/dist/mux/mux-escalation-manager.d.ts +9 -3
  124. package/dist/mux/mux-escalation-manager.js +69 -19
  125. package/dist/mux/mux-escalation-manager.js.map +1 -1
  126. package/dist/mux/mux-input-handler.d.ts +59 -3
  127. package/dist/mux/mux-input-handler.js +270 -32
  128. package/dist/mux/mux-input-handler.js.map +1 -1
  129. package/dist/mux/mux-renderer.d.ts +19 -1
  130. package/dist/mux/mux-renderer.js +466 -11
  131. package/dist/mux/mux-renderer.js.map +1 -1
  132. package/dist/mux/persona-scanner.d.ts +19 -0
  133. package/dist/mux/persona-scanner.js +53 -0
  134. package/dist/mux/persona-scanner.js.map +1 -0
  135. package/dist/mux/pty-bridge.d.ts +8 -0
  136. package/dist/mux/pty-bridge.js +19 -1
  137. package/dist/mux/pty-bridge.js.map +1 -1
  138. package/dist/mux/session-scanner.d.ts +18 -0
  139. package/dist/mux/session-scanner.js +65 -0
  140. package/dist/mux/session-scanner.js.map +1 -0
  141. package/dist/mux/types.d.ts +36 -1
  142. package/dist/mux/types.js +14 -1
  143. package/dist/mux/types.js.map +1 -1
  144. package/dist/persona/persona-command.js +130 -93
  145. package/dist/persona/persona-command.js.map +1 -1
  146. package/dist/persona/persona-prompt.d.ts +7 -7
  147. package/dist/persona/persona-prompt.js +14 -29
  148. package/dist/persona/persona-prompt.js.map +1 -1
  149. package/dist/persona/resolve.js +5 -2
  150. package/dist/persona/resolve.js.map +1 -1
  151. package/dist/pipeline/annotate.js +1 -7
  152. package/dist/pipeline/annotate.js.map +1 -1
  153. package/dist/pipeline/compile.d.ts +5 -2
  154. package/dist/pipeline/compile.js +23 -11
  155. package/dist/pipeline/compile.js.map +1 -1
  156. package/dist/pipeline/constitution-compiler.d.ts +302 -3
  157. package/dist/pipeline/constitution-compiler.js +285 -23
  158. package/dist/pipeline/constitution-compiler.js.map +1 -1
  159. package/dist/pipeline/generate-with-repair.d.ts +2 -2
  160. package/dist/pipeline/generate-with-repair.js +2 -2
  161. package/dist/pipeline/handwritten-scenarios.d.ts +20 -7
  162. package/dist/pipeline/handwritten-scenarios.js +20 -41
  163. package/dist/pipeline/handwritten-scenarios.js.map +1 -1
  164. package/dist/pipeline/list-resolver.d.ts +18 -20
  165. package/dist/pipeline/list-resolver.js +28 -36
  166. package/dist/pipeline/list-resolver.js.map +1 -1
  167. package/dist/pipeline/pipeline-runner.d.ts +102 -13
  168. package/dist/pipeline/pipeline-runner.js +497 -237
  169. package/dist/pipeline/pipeline-runner.js.map +1 -1
  170. package/dist/pipeline/pipeline-shared.d.ts +7 -9
  171. package/dist/pipeline/pipeline-shared.js +8 -18
  172. package/dist/pipeline/pipeline-shared.js.map +1 -1
  173. package/dist/pipeline/policy-verifier.d.ts +32 -5
  174. package/dist/pipeline/policy-verifier.js +137 -8
  175. package/dist/pipeline/policy-verifier.js.map +1 -1
  176. package/dist/pipeline/proxy-mcp-connections.d.ts +25 -0
  177. package/dist/pipeline/proxy-mcp-connections.js +121 -0
  178. package/dist/pipeline/proxy-mcp-connections.js.map +1 -0
  179. package/dist/pipeline/refresh-lists.js +21 -13
  180. package/dist/pipeline/refresh-lists.js.map +1 -1
  181. package/dist/pipeline/scenario-generator.d.ts +29 -49
  182. package/dist/pipeline/scenario-generator.js +180 -143
  183. package/dist/pipeline/scenario-generator.js.map +1 -1
  184. package/dist/pipeline/scenario-schema-validator.d.ts +51 -0
  185. package/dist/pipeline/scenario-schema-validator.js +132 -0
  186. package/dist/pipeline/scenario-schema-validator.js.map +1 -0
  187. package/dist/pipeline/tool-annotator.d.ts +9 -8
  188. package/dist/pipeline/tool-annotator.js +48 -95
  189. package/dist/pipeline/tool-annotator.js.map +1 -1
  190. package/dist/pipeline/types.d.ts +31 -24
  191. package/dist/sandbox/index.d.ts +26 -10
  192. package/dist/sandbox/index.js +151 -40
  193. package/dist/sandbox/index.js.map +1 -1
  194. package/dist/servers/fetch-server.js +10 -5
  195. package/dist/servers/fetch-server.js.map +1 -1
  196. package/dist/session/agent-session.d.ts +8 -20
  197. package/dist/session/agent-session.js +22 -70
  198. package/dist/session/agent-session.js.map +1 -1
  199. package/dist/session/base-transport.d.ts +17 -1
  200. package/dist/session/base-transport.js +25 -1
  201. package/dist/session/base-transport.js.map +1 -1
  202. package/dist/session/cli-transport.d.ts +5 -0
  203. package/dist/session/cli-transport.js +48 -25
  204. package/dist/session/cli-transport.js.map +1 -1
  205. package/dist/session/index.d.ts +25 -1
  206. package/dist/session/index.js +57 -8
  207. package/dist/session/index.js.map +1 -1
  208. package/dist/session/prompts.js +8 -9
  209. package/dist/session/prompts.js.map +1 -1
  210. package/dist/session/session-manager.d.ts +6 -0
  211. package/dist/session/session-manager.js +12 -0
  212. package/dist/session/session-manager.js.map +1 -1
  213. package/dist/session/types.d.ts +11 -1
  214. package/dist/session/types.js.map +1 -1
  215. package/dist/session/workspace-validation.js +37 -6
  216. package/dist/session/workspace-validation.js.map +1 -1
  217. package/dist/signal/signal-bot-daemon.js +24 -8
  218. package/dist/signal/signal-bot-daemon.js.map +1 -1
  219. package/dist/signal/signal-transport.d.ts +5 -2
  220. package/dist/signal/signal-transport.js +3 -3
  221. package/dist/signal/signal-transport.js.map +1 -1
  222. package/dist/trusted-process/approval-whitelist.d.ts +117 -0
  223. package/dist/trusted-process/approval-whitelist.js +237 -0
  224. package/dist/trusted-process/approval-whitelist.js.map +1 -0
  225. package/dist/trusted-process/gworkspace-credentials.d.ts +40 -0
  226. package/dist/trusted-process/gworkspace-credentials.js +45 -0
  227. package/dist/trusted-process/gworkspace-credentials.js.map +1 -0
  228. package/dist/trusted-process/index.d.ts +11 -1
  229. package/dist/trusted-process/index.js +83 -53
  230. package/dist/trusted-process/index.js.map +1 -1
  231. package/dist/trusted-process/mcp-proxy-server.d.ts +23 -0
  232. package/dist/trusted-process/mcp-proxy-server.js +409 -94
  233. package/dist/trusted-process/mcp-proxy-server.js.map +1 -1
  234. package/dist/trusted-process/policy-engine.d.ts +12 -3
  235. package/dist/trusted-process/policy-engine.js +33 -23
  236. package/dist/trusted-process/policy-engine.js.map +1 -1
  237. package/dist/trusted-process/policy-types.d.ts +17 -0
  238. package/dist/trusted-process/sandbox-integration.d.ts +23 -0
  239. package/dist/trusted-process/sandbox-integration.js +115 -3
  240. package/dist/trusted-process/sandbox-integration.js.map +1 -1
  241. package/dist/trusted-process/token-file-refresher.d.ts +69 -0
  242. package/dist/trusted-process/token-file-refresher.js +120 -0
  243. package/dist/trusted-process/token-file-refresher.js.map +1 -0
  244. package/dist/types/argument-roles.d.ts +7 -1
  245. package/dist/types/argument-roles.js +50 -0
  246. package/dist/types/argument-roles.js.map +1 -1
  247. package/dist/types/audit.d.ts +11 -0
  248. package/docker/Dockerfile.base +22 -0
  249. package/docker/Dockerfile.base.arm64 +44 -4
  250. package/docker/Dockerfile.claude-code +2 -2
  251. package/docker/entrypoint-claude-code.sh +24 -6
  252. package/package.json +8 -2
  253. package/src/config/constitution-user-base.md +15 -0
  254. package/src/config/generated/test-scenarios.json +1 -1
  255. package/src/config/generated/tool-annotations.json +10617 -296
  256. package/src/config/mcp-servers.json +31 -2
  257. package/dist/pipeline/mcp-connections.d.ts +0 -16
  258. package/dist/pipeline/mcp-connections.js +0 -61
  259. package/dist/pipeline/mcp-connections.js.map +0 -1
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Type definitions for the secure package installation proxy.
3
+ *
4
+ * These types are shared across the package validator, registry proxy,
5
+ * and MITM proxy integration layers.
6
+ */
7
+ /**
8
+ * Supported package registry types.
9
+ * Each type determines how package names and versions are extracted
10
+ * from HTTP request paths, and how metadata responses are filtered.
11
+ */
12
+ export type RegistryType = 'npm' | 'pypi' | 'debian';
13
+ /**
14
+ * Configuration for a package registry host.
15
+ *
16
+ * Unlike ProviderConfig (which handles credential swap and endpoint
17
+ * filtering for LLM APIs), RegistryConfig handles package-level
18
+ * validation for software registries.
19
+ *
20
+ * No key injection is needed -- package registries are public.
21
+ */
22
+ export interface RegistryConfig {
23
+ /** Registry hostname (e.g., 'registry.npmjs.org'). */
24
+ readonly host: string;
25
+ /** Human-readable name for logging. */
26
+ readonly displayName: string;
27
+ /** Registry type, determines URL parsing and metadata filtering strategy. */
28
+ readonly type: RegistryType;
29
+ /**
30
+ * Additional hosts that serve package tarballs for this registry.
31
+ * For PyPI, this includes 'files.pythonhosted.org'.
32
+ * These hosts are added to the MITM proxy's allowlist and their
33
+ * requests are validated using the same rules as the main host.
34
+ */
35
+ readonly mirrorHosts?: readonly string[];
36
+ }
37
+ /**
38
+ * Parsed package identity extracted from a registry HTTP request.
39
+ *
40
+ * Invariant: scope is only present for npm scoped packages
41
+ * (e.g., @types/node). PyPI packages never have a scope.
42
+ */
43
+ export interface PackageIdentity {
44
+ /** Registry type this package belongs to. */
45
+ readonly registry: RegistryType;
46
+ /** Package name (e.g., 'express', 'numpy'). */
47
+ readonly name: string;
48
+ /** npm scope without @, if scoped (e.g., 'types' for @types/node). */
49
+ readonly scope?: string;
50
+ /** Package version, if parseable from the URL or metadata. */
51
+ readonly version?: string;
52
+ }
53
+ /**
54
+ * Result of a package validation check.
55
+ * Binary: allow or deny. No escalation.
56
+ */
57
+ export type PackageDecision = {
58
+ readonly status: 'allow';
59
+ readonly reason: string;
60
+ } | {
61
+ readonly status: 'deny';
62
+ readonly reason: string;
63
+ };
64
+ /**
65
+ * Per-version metadata from the registry, focused on the fields
66
+ * needed for security validation.
67
+ *
68
+ * Intentionally minimal -- we only extract what we check.
69
+ */
70
+ export interface VersionMetadata {
71
+ /** When this specific version was published. */
72
+ readonly publishedAt?: Date;
73
+ /** Whether this version has been deprecated. */
74
+ readonly deprecated?: boolean;
75
+ }
76
+ /**
77
+ * Validates whether a package version should be allowed.
78
+ *
79
+ * Used in two contexts:
80
+ * 1. Metadata filtering: called per-version to decide which versions
81
+ * to include in the filtered metadata response.
82
+ * 2. Tarball backstop: called when a tarball download is requested,
83
+ * as a defense-in-depth check.
84
+ */
85
+ export interface PackageValidator {
86
+ /**
87
+ * Validates a package version against configured rules.
88
+ *
89
+ * @param pkg - Parsed package identity (name, version, scope).
90
+ * @param metadata - Per-version metadata from the registry, if available.
91
+ * Undefined when metadata could not be fetched (treated as deny).
92
+ * @returns Decision: allow or deny.
93
+ */
94
+ validate(pkg: PackageIdentity, metadata: VersionMetadata | undefined): PackageDecision;
95
+ }
96
+ /**
97
+ * In-memory cache of allowed versions per package.
98
+ * Populated during metadata filtering, consulted during tarball downloads.
99
+ *
100
+ * Keyed by canonical package identifier: 'npm:express', 'npm:@types/node',
101
+ * 'pypi:numpy'.
102
+ */
103
+ export type AllowedVersionCache = Map<string, {
104
+ /** Set of version strings that passed validation. */
105
+ readonly allowedVersions: ReadonlySet<string>;
106
+ /** When this cache entry was populated. */
107
+ readonly cachedAt: Date;
108
+ }>;
109
+ /**
110
+ * Audit log entry for package installation decisions.
111
+ * Written to package-audit.jsonl in the session directory.
112
+ */
113
+ export interface PackageAuditEntry {
114
+ readonly timestamp: string;
115
+ /** Package identity. */
116
+ readonly registry: RegistryType;
117
+ readonly packageName: string;
118
+ readonly packageVersion?: string;
119
+ readonly packageScope?: string;
120
+ /** Decision made by the validator. */
121
+ readonly decision: 'allow' | 'deny';
122
+ readonly reason: string;
123
+ /** Whether this was a metadata filter or tarball backstop decision. */
124
+ readonly source: 'metadata-filter' | 'tarball-backstop' | 'deb-backstop';
125
+ /** The HTTP request path that triggered this check. */
126
+ readonly requestPath: string;
127
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Type definitions for the secure package installation proxy.
3
+ *
4
+ * These types are shared across the package validator, registry proxy,
5
+ * and MITM proxy integration layers.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=package-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-types.js","sourceRoot":"","sources":["../../src/docker/package-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Package validation logic for the registry proxy.
3
+ *
4
+ * Evaluates packages against allowlist, denylist, and age gate rules.
5
+ * Decisions are binary: allow or deny. No escalation.
6
+ *
7
+ * Validation order (first match wins):
8
+ * 1. Denylist match -> DENY
9
+ * 2. Allowlist match -> ALLOW (bypasses age gate)
10
+ * 3. Version too new -> DENY
11
+ * 4. No metadata -> DENY (fail-closed)
12
+ * 5. Default -> ALLOW
13
+ */
14
+ import type { PackageIdentity, PackageValidator } from './package-types.js';
15
+ /** Fallback validator that denies all packages. Used when no validator is configured. */
16
+ export declare const DENY_ALL_VALIDATOR: PackageValidator;
17
+ export interface PackageValidatorConfig {
18
+ /** Packages always allowed (bypass age gate). Supports glob patterns. */
19
+ readonly allowedPackages?: readonly string[];
20
+ /** Packages always denied. Takes precedence over allowedPackages. Supports glob patterns. */
21
+ readonly deniedPackages?: readonly string[];
22
+ /** Days a version must age before auto-allow. 0 disables age gate. */
23
+ readonly quarantineDays?: number;
24
+ }
25
+ /**
26
+ * Returns the canonical display name for a package.
27
+ * Scoped npm packages use '@scope/name' format.
28
+ */
29
+ export declare function canonicalPackageName(pkg: PackageIdentity): string;
30
+ /**
31
+ * Returns the canonical cache key for a package.
32
+ * Format: 'npm:express', 'npm:@types/node', 'pypi:numpy'.
33
+ */
34
+ export declare function packageCacheKey(pkg: PackageIdentity): string;
35
+ /**
36
+ * Creates a PackageValidator from configuration.
37
+ *
38
+ * The validator is stateless -- all configuration is captured at
39
+ * construction time. Thread-safe for concurrent use.
40
+ */
41
+ export declare function createPackageValidator(config?: PackageValidatorConfig): PackageValidator;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Package validation logic for the registry proxy.
3
+ *
4
+ * Evaluates packages against allowlist, denylist, and age gate rules.
5
+ * Decisions are binary: allow or deny. No escalation.
6
+ *
7
+ * Validation order (first match wins):
8
+ * 1. Denylist match -> DENY
9
+ * 2. Allowlist match -> ALLOW (bypasses age gate)
10
+ * 3. Version too new -> DENY
11
+ * 4. No metadata -> DENY (fail-closed)
12
+ * 5. Default -> ALLOW
13
+ */
14
+ import { minimatch } from 'minimatch';
15
+ /** Fallback validator that denies all packages. Used when no validator is configured. */
16
+ export const DENY_ALL_VALIDATOR = {
17
+ validate: () => ({ status: 'deny', reason: 'No validator configured' }),
18
+ };
19
+ /** Default quarantine period in days. */
20
+ const DEFAULT_QUARANTINE_DAYS = 2;
21
+ /** Milliseconds per day, used for age calculations. */
22
+ const MS_PER_DAY = 24 * 60 * 60 * 1000;
23
+ /**
24
+ * Returns the canonical display name for a package.
25
+ * Scoped npm packages use '@scope/name' format.
26
+ */
27
+ export function canonicalPackageName(pkg) {
28
+ return pkg.scope ? `@${pkg.scope}/${pkg.name}` : pkg.name;
29
+ }
30
+ /**
31
+ * Returns the canonical cache key for a package.
32
+ * Format: 'npm:express', 'npm:@types/node', 'pypi:numpy'.
33
+ */
34
+ export function packageCacheKey(pkg) {
35
+ return `${pkg.registry}:${canonicalPackageName(pkg)}`;
36
+ }
37
+ /**
38
+ * Checks if a package name matches any pattern in the given list.
39
+ * Supports glob patterns via minimatch.
40
+ */
41
+ function matchesPatternList(packageName, patterns) {
42
+ return patterns.some((pattern) => minimatch(packageName, pattern, { nocase: true }));
43
+ }
44
+ /**
45
+ * Creates a PackageValidator from configuration.
46
+ *
47
+ * The validator is stateless -- all configuration is captured at
48
+ * construction time. Thread-safe for concurrent use.
49
+ */
50
+ export function createPackageValidator(config = {}) {
51
+ const allowedPackages = config.allowedPackages ?? [];
52
+ const deniedPackages = config.deniedPackages ?? [];
53
+ const quarantineDays = config.quarantineDays ?? DEFAULT_QUARANTINE_DAYS;
54
+ return {
55
+ validate(pkg, metadata) {
56
+ const name = canonicalPackageName(pkg);
57
+ // 1. Denylist (takes precedence over everything)
58
+ if (deniedPackages.length > 0 && matchesPatternList(name, deniedPackages)) {
59
+ return { status: 'deny', reason: `Package "${name}" is on the deny list` };
60
+ }
61
+ // 2. Allowlist (bypasses age gate)
62
+ if (allowedPackages.length > 0 && matchesPatternList(name, allowedPackages)) {
63
+ return { status: 'allow', reason: `Package "${name}" is on the allow list` };
64
+ }
65
+ // 3. Age gate (only when quarantineDays > 0)
66
+ if (quarantineDays > 0) {
67
+ if (!metadata) {
68
+ // 4. No metadata -> fail-closed
69
+ return { status: 'deny', reason: `No metadata available for "${name}" (fail-closed)` };
70
+ }
71
+ if (!metadata.publishedAt) {
72
+ // No publish timestamp -> fail-closed
73
+ return { status: 'deny', reason: `No publish timestamp for "${name}" (fail-closed)` };
74
+ }
75
+ const ageMs = Math.max(0, Date.now() - metadata.publishedAt.getTime());
76
+ const ageDays = ageMs / MS_PER_DAY;
77
+ if (ageDays < quarantineDays) {
78
+ const daysOld = Math.floor(ageDays);
79
+ return {
80
+ status: 'deny',
81
+ reason: `Version "${pkg.version ?? 'unknown'}" of "${name}" is only ${daysOld} day(s) old (quarantine: ${quarantineDays} days)`,
82
+ };
83
+ }
84
+ }
85
+ // 5. Default -> allow
86
+ return { status: 'allow', reason: 'Passed all validation checks' };
87
+ },
88
+ };
89
+ }
90
+ //# sourceMappingURL=package-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-validator.js","sourceRoot":"","sources":["../../src/docker/package-validator.ts"],"names":[],"mappings":"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"}
@@ -12,9 +12,9 @@
12
12
  * Docker Desktop's VirtioFS does not support UDS in bind mounts.
13
13
  */
14
14
  export declare function useTcpTransport(): boolean;
15
- /** Docker network name for the internal (no-egress) bridge used in TCP mode. */
16
- export declare const INTERNAL_NETWORK_NAME = "ironcurtain-internal";
17
- /** Subnet for the internal bridge network. */
18
- export declare const INTERNAL_NETWORK_SUBNET = "172.30.0.0/24";
19
- /** Gateway IP for the internal bridge network (host-side). */
20
- export declare const INTERNAL_NETWORK_GATEWAY = "172.30.0.1";
15
+ /**
16
+ * Returns a per-session Docker network name for the internal (no-egress)
17
+ * bridge used in TCP mode. Each session gets its own network to avoid
18
+ * conflicts when multiple sessions run concurrently.
19
+ */
20
+ export declare function getInternalNetworkName(shortId: string): string;
@@ -15,10 +15,12 @@ import { platform } from 'node:os';
15
15
  export function useTcpTransport() {
16
16
  return platform() === 'darwin';
17
17
  }
18
- /** Docker network name for the internal (no-egress) bridge used in TCP mode. */
19
- export const INTERNAL_NETWORK_NAME = 'ironcurtain-internal';
20
- /** Subnet for the internal bridge network. */
21
- export const INTERNAL_NETWORK_SUBNET = '172.30.0.0/24';
22
- /** Gateway IP for the internal bridge network (host-side). */
23
- export const INTERNAL_NETWORK_GATEWAY = '172.30.0.1';
18
+ /**
19
+ * Returns a per-session Docker network name for the internal (no-egress)
20
+ * bridge used in TCP mode. Each session gets its own network to avoid
21
+ * conflicts when multiple sessions run concurrently.
22
+ */
23
+ export function getInternalNetworkName(shortId) {
24
+ return `ironcurtain-${shortId}`;
25
+ }
24
26
  //# sourceMappingURL=platform.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/docker/platform.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,QAAQ,EAAE,KAAK,QAAQ,CAAC;AACjC,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAE5D,8CAA8C;AAC9C,MAAM,CAAC,MAAM,uBAAuB,GAAG,eAAe,CAAC;AAEvD,8DAA8D;AAC9D,MAAM,CAAC,MAAM,wBAAwB,GAAG,YAAY,CAAC"}
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/docker/platform.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,QAAQ,EAAE,KAAK,QAAQ,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,OAAO,eAAe,OAAO,EAAE,CAAC;AAClC,CAAC"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Proxy MCP Server tool definitions, annotations, and policy rules.
3
+ *
4
+ * These are hardcoded (not generated by the LLM pipeline) because the
5
+ * proxy tools have known, fixed semantics. The annotations and rules
6
+ * are injected into the PolicyEngine at startup so that domain
7
+ * management calls go through normal policy evaluation and audit logging.
8
+ */
9
+ import type { CompiledRule, StoredToolAnnotation } from '../pipeline/types.js';
10
+ /** Validates a domain string for use as a passthrough host. */
11
+ export declare function validateDomain(domain: string): void;
12
+ export interface DomainListing {
13
+ /** Statically configured LLM provider hosts (with key swap). */
14
+ readonly providers: readonly string[];
15
+ /** Dynamically added passthrough hosts (no key swap). */
16
+ readonly dynamic: readonly string[];
17
+ }
18
+ /** MCP tool definitions for the proxy server. */
19
+ export declare const proxyToolDefinitions: readonly [{
20
+ readonly name: "add_proxy_domain";
21
+ readonly description: string;
22
+ readonly inputSchema: {
23
+ readonly type: "object";
24
+ readonly properties: {
25
+ readonly domain: {
26
+ readonly type: "string";
27
+ readonly description: "The exact domain name to allow (e.g., \"api.example.com\"). No wildcards.";
28
+ };
29
+ readonly justification: {
30
+ readonly type: "string";
31
+ readonly description: string;
32
+ };
33
+ };
34
+ readonly required: readonly ["domain", "justification"];
35
+ };
36
+ }, {
37
+ readonly name: "remove_proxy_domain";
38
+ readonly description: string;
39
+ readonly inputSchema: {
40
+ readonly type: "object";
41
+ readonly properties: {
42
+ readonly domain: {
43
+ readonly type: "string";
44
+ readonly description: "The domain name to remove.";
45
+ };
46
+ };
47
+ readonly required: readonly ["domain"];
48
+ };
49
+ }, {
50
+ readonly name: "list_proxy_domains";
51
+ readonly description: string;
52
+ readonly inputSchema: {
53
+ readonly type: "object";
54
+ readonly properties: {};
55
+ };
56
+ }];
57
+ export declare const proxyAnnotations: StoredToolAnnotation[];
58
+ export declare const proxyPolicyRules: CompiledRule[];
59
+ export interface ControlApiClient {
60
+ addDomain(domain: string): Promise<{
61
+ added: boolean;
62
+ }>;
63
+ removeDomain(domain: string): Promise<{
64
+ removed: boolean;
65
+ }>;
66
+ listDomains(): Promise<DomainListing>;
67
+ }
68
+ /**
69
+ * Creates an HTTP client for the MITM proxy's domain control API.
70
+ *
71
+ * @param controlAddr - "unix:///path/to/socket" or "http://127.0.0.1:PORT"
72
+ */
73
+ export declare function createControlApiClient(controlAddr: string): ControlApiClient;
74
+ /**
75
+ * Dispatches a virtual proxy tool call to the control API.
76
+ * Called by mcp-proxy-server.ts when the tool belongs to the 'proxy' server.
77
+ */
78
+ export declare function handleVirtualProxyTool(toolName: string, args: Record<string, unknown>, client: ControlApiClient): Promise<unknown>;
79
+ /** Server names reserved for internal use that cannot be used in mcp-servers.json. */
80
+ export declare const RESERVED_SERVER_NAMES: Set<string>;
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Proxy MCP Server tool definitions, annotations, and policy rules.
3
+ *
4
+ * These are hardcoded (not generated by the LLM pipeline) because the
5
+ * proxy tools have known, fixed semantics. The annotations and rules
6
+ * are injected into the PolicyEngine at startup so that domain
7
+ * management calls go through normal policy evaluation and audit logging.
8
+ */
9
+ import * as http from 'node:http';
10
+ // ---------------------------------------------------------------------------
11
+ // Domain validation
12
+ // ---------------------------------------------------------------------------
13
+ const DOMAIN_RE = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/i;
14
+ const IP_RE = /^\d{1,3}(\.\d{1,3}){3}$/;
15
+ const DOCKER_INTERNAL_SUFFIX = '.docker.internal';
16
+ /** Validates a domain string for use as a passthrough host. */
17
+ export function validateDomain(domain) {
18
+ if (domain.length > 253)
19
+ throw new Error(`Domain too long (${domain.length} > 253)`);
20
+ if (domain.toLowerCase() === 'localhost') {
21
+ throw new Error(`Blocked host: "${domain}"`);
22
+ }
23
+ if (!DOMAIN_RE.test(domain))
24
+ throw new Error(`Invalid domain format: "${domain}"`);
25
+ if (IP_RE.test(domain))
26
+ throw new Error(`IP addresses are not allowed: "${domain}"`);
27
+ if (domain.toLowerCase().endsWith(DOCKER_INTERNAL_SUFFIX)) {
28
+ throw new Error(`Blocked host: "${domain}" (*.docker.internal is not allowed)`);
29
+ }
30
+ }
31
+ // ---------------------------------------------------------------------------
32
+ // MCP tool schemas
33
+ // ---------------------------------------------------------------------------
34
+ /** MCP tool definitions for the proxy server. */
35
+ export const proxyToolDefinitions = [
36
+ {
37
+ name: 'add_proxy_domain',
38
+ description: 'Request access to an additional internet domain through the network proxy. ' +
39
+ 'This will be reviewed by a human before being granted. ' +
40
+ 'Provide a clear justification for why the domain is needed.',
41
+ inputSchema: {
42
+ type: 'object',
43
+ properties: {
44
+ domain: {
45
+ type: 'string',
46
+ description: 'The exact domain name to allow (e.g., "api.example.com"). No wildcards.',
47
+ },
48
+ justification: {
49
+ type: 'string',
50
+ description: 'Explanation of why this domain is needed for the current task. ' +
51
+ 'This text is shown to the human reviewer.',
52
+ },
53
+ },
54
+ required: ['domain', 'justification'],
55
+ },
56
+ },
57
+ {
58
+ name: 'remove_proxy_domain',
59
+ description: 'Remove a previously approved domain from the proxy allowlist. ' +
60
+ 'Only dynamically added domains can be removed; built-in provider domains cannot.',
61
+ inputSchema: {
62
+ type: 'object',
63
+ properties: {
64
+ domain: {
65
+ type: 'string',
66
+ description: 'The domain name to remove.',
67
+ },
68
+ },
69
+ required: ['domain'],
70
+ },
71
+ },
72
+ {
73
+ name: 'list_proxy_domains',
74
+ description: 'List all domains currently accessible through the network proxy. ' +
75
+ 'Includes both built-in provider domains and dynamically added domains.',
76
+ inputSchema: {
77
+ type: 'object',
78
+ properties: {},
79
+ },
80
+ },
81
+ ];
82
+ // ---------------------------------------------------------------------------
83
+ // Tool annotations (hardcoded, not LLM-generated)
84
+ // ---------------------------------------------------------------------------
85
+ const schemaByName = Object.fromEntries(proxyToolDefinitions.map((t) => [t.name, t.inputSchema]));
86
+ export const proxyAnnotations = [
87
+ {
88
+ toolName: 'add_proxy_domain',
89
+ serverName: 'proxy',
90
+ comment: 'Add a domain to the MITM proxy allowlist',
91
+ args: {
92
+ domain: ['none'],
93
+ justification: ['none'],
94
+ },
95
+ inputSchema: schemaByName.add_proxy_domain,
96
+ },
97
+ {
98
+ toolName: 'remove_proxy_domain',
99
+ serverName: 'proxy',
100
+ comment: 'Remove a domain from the MITM proxy allowlist',
101
+ args: {
102
+ domain: ['none'],
103
+ },
104
+ inputSchema: schemaByName.remove_proxy_domain,
105
+ },
106
+ {
107
+ toolName: 'list_proxy_domains',
108
+ serverName: 'proxy',
109
+ comment: 'List currently allowed proxy domains',
110
+ args: {},
111
+ inputSchema: schemaByName.list_proxy_domains,
112
+ },
113
+ ];
114
+ // ---------------------------------------------------------------------------
115
+ // Compiled policy rules (hardcoded)
116
+ // ---------------------------------------------------------------------------
117
+ export const proxyPolicyRules = [
118
+ {
119
+ name: 'proxy-add-domain-escalate',
120
+ description: 'Adding network domains requires human review',
121
+ principle: 'Human oversight',
122
+ if: { server: ['proxy'], tool: ['add_proxy_domain'] },
123
+ then: 'escalate',
124
+ reason: 'Adding network domains expands the container attack surface and requires human review',
125
+ },
126
+ {
127
+ name: 'proxy-remove-domain-allow',
128
+ description: 'Removing domains reduces attack surface',
129
+ principle: 'Least privilege',
130
+ if: { server: ['proxy'], tool: ['remove_proxy_domain'] },
131
+ then: 'allow',
132
+ reason: 'Removing domains reduces the attack surface',
133
+ },
134
+ {
135
+ name: 'proxy-list-domains-allow',
136
+ description: 'Listing domains is a read-only operation',
137
+ principle: 'Least privilege',
138
+ if: { server: ['proxy'], tool: ['list_proxy_domains'] },
139
+ then: 'allow',
140
+ reason: 'Read-only operation with no side effects',
141
+ },
142
+ ];
143
+ /**
144
+ * Creates an HTTP client for the MITM proxy's domain control API.
145
+ *
146
+ * @param controlAddr - "unix:///path/to/socket" or "http://127.0.0.1:PORT"
147
+ */
148
+ export function createControlApiClient(controlAddr) {
149
+ const isUnix = controlAddr.startsWith('unix://');
150
+ const socketPath = isUnix ? controlAddr.slice('unix://'.length) : undefined;
151
+ const baseUrl = isUnix ? 'http://localhost' : controlAddr;
152
+ function request(method, path, body) {
153
+ return new Promise((resolve, reject) => {
154
+ const url = new URL(path, baseUrl);
155
+ const opts = {
156
+ method,
157
+ hostname: url.hostname,
158
+ port: url.port || undefined,
159
+ path: url.pathname,
160
+ headers: { 'Content-Type': 'application/json' },
161
+ ...(socketPath ? { socketPath } : {}),
162
+ };
163
+ const req = http.request(opts, (res) => {
164
+ const chunks = [];
165
+ res.on('data', (chunk) => chunks.push(chunk));
166
+ res.on('end', () => {
167
+ const text = Buffer.concat(chunks).toString();
168
+ if (res.statusCode && res.statusCode >= 400) {
169
+ reject(new Error(`Control API ${res.statusCode}: ${text}`));
170
+ return;
171
+ }
172
+ try {
173
+ resolve(JSON.parse(text));
174
+ }
175
+ catch {
176
+ resolve(text);
177
+ }
178
+ });
179
+ res.on('error', reject);
180
+ });
181
+ req.on('error', reject);
182
+ if (body !== undefined) {
183
+ req.end(JSON.stringify(body));
184
+ }
185
+ else {
186
+ req.end();
187
+ }
188
+ });
189
+ }
190
+ return {
191
+ async addDomain(domain) {
192
+ return (await request('POST', '/__ironcurtain/domains/add', { domain }));
193
+ },
194
+ async removeDomain(domain) {
195
+ return (await request('POST', '/__ironcurtain/domains/remove', { domain }));
196
+ },
197
+ async listDomains() {
198
+ return (await request('GET', '/__ironcurtain/domains'));
199
+ },
200
+ };
201
+ }
202
+ // ---------------------------------------------------------------------------
203
+ // Argument validation
204
+ // ---------------------------------------------------------------------------
205
+ /** Extracts a required string argument, throwing if missing or wrong type. */
206
+ function requireStringArg(args, name) {
207
+ const value = args[name];
208
+ if (typeof value !== 'string' || value.length === 0) {
209
+ throw new Error(`Missing or invalid required argument: ${name}`);
210
+ }
211
+ return value;
212
+ }
213
+ // ---------------------------------------------------------------------------
214
+ // Virtual tool handler
215
+ // ---------------------------------------------------------------------------
216
+ /**
217
+ * Dispatches a virtual proxy tool call to the control API.
218
+ * Called by mcp-proxy-server.ts when the tool belongs to the 'proxy' server.
219
+ */
220
+ export async function handleVirtualProxyTool(toolName, args, client) {
221
+ switch (toolName) {
222
+ case 'add_proxy_domain': {
223
+ const domain = requireStringArg(args, 'domain');
224
+ requireStringArg(args, 'justification');
225
+ validateDomain(domain);
226
+ const result = await client.addDomain(domain);
227
+ if (!result.added) {
228
+ return { status: 'already_accessible', message: 'Domain is already accessible (built-in provider)' };
229
+ }
230
+ return { status: 'added', domain };
231
+ }
232
+ case 'remove_proxy_domain': {
233
+ const domain = requireStringArg(args, 'domain');
234
+ const result = await client.removeDomain(domain);
235
+ return { status: result.removed ? 'removed' : 'not_found', domain };
236
+ }
237
+ case 'list_proxy_domains':
238
+ return client.listDomains();
239
+ default:
240
+ throw new Error(`Unknown virtual proxy tool: ${toolName}`);
241
+ }
242
+ }
243
+ // ---------------------------------------------------------------------------
244
+ // Reserved server names
245
+ // ---------------------------------------------------------------------------
246
+ /** Server names reserved for internal use that cannot be used in mcp-servers.json. */
247
+ export const RESERVED_SERVER_NAMES = new Set(['proxy']);
248
+ //# sourceMappingURL=proxy-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-tools.js","sourceRoot":"","sources":["../../src/docker/proxy-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,MAAM,SAAS,GAAG,oEAAoE,CAAC;AACvF,MAAM,KAAK,GAAG,yBAAyB,CAAC;AACxC,MAAM,sBAAsB,GAAG,kBAAkB,CAAC;AAElD,+DAA+D;AAC/D,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC;IACrF,IAAI,MAAM,CAAC,WAAW,EAAE,KAAK,WAAW,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,kBAAkB,MAAM,GAAG,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,GAAG,CAAC,CAAC;IACnF,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,MAAM,GAAG,CAAC,CAAC;IACrF,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,kBAAkB,MAAM,sCAAsC,CAAC,CAAC;IAClF,CAAC;AACH,CAAC;AAaD,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,iDAAiD;AACjD,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC;QACE,IAAI,EAAE,kBAAkB;QACxB,WAAW,EACT,6EAA6E;YAC7E,yDAAyD;YACzD,6DAA6D;QAC/D,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE;gBACV,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,yEAAyE;iBACvF;gBACD,aAAa,EAAE;oBACb,IAAI,EAAE,QAAQ;oBACd,WAAW,EACT,iEAAiE;wBACjE,2CAA2C;iBAC9C;aACF;YACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,eAAe,CAAC;SACtC;KACF;IACD;QACE,IAAI,EAAE,qBAAqB;QAC3B,WAAW,EACT,gEAAgE;YAChE,kFAAkF;QACpF,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE;gBACV,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,4BAA4B;iBAC1C;aACF;YACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;SACrB;KACF;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EACT,mEAAmE;YACnE,wEAAwE;QAC1E,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,UAAU,EAAE,EAAE;SACf;KACF;CACO,CAAC;AAEX,8EAA8E;AAC9E,kDAAkD;AAClD,8EAA8E;AAE9E,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CACrC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAsC,CAAC,CAAC,CACF,CAAC;AAEpF,MAAM,CAAC,MAAM,gBAAgB,GAA2B;IACtD;QACE,QAAQ,EAAE,kBAAkB;QAC5B,UAAU,EAAE,OAAO;QACnB,OAAO,EAAE,0CAA0C;QACnD,IAAI,EAAE;YACJ,MAAM,EAAE,CAAC,MAAM,CAAC;YAChB,aAAa,EAAE,CAAC,MAAM,CAAC;SACxB;QACD,WAAW,EAAE,YAAY,CAAC,gBAAgB;KAC3C;IACD;QACE,QAAQ,EAAE,qBAAqB;QAC/B,UAAU,EAAE,OAAO;QACnB,OAAO,EAAE,+CAA+C;QACxD,IAAI,EAAE;YACJ,MAAM,EAAE,CAAC,MAAM,CAAC;SACjB;QACD,WAAW,EAAE,YAAY,CAAC,mBAAmB;KAC9C;IACD;QACE,QAAQ,EAAE,oBAAoB;QAC9B,UAAU,EAAE,OAAO;QACnB,OAAO,EAAE,sCAAsC;QAC/C,IAAI,EAAE,EAAE;QACR,WAAW,EAAE,YAAY,CAAC,kBAAkB;KAC7C;CACF,CAAC;AAEF,8EAA8E;AAC9E,oCAAoC;AACpC,8EAA8E;AAE9E,MAAM,CAAC,MAAM,gBAAgB,GAAmB;IAC9C;QACE,IAAI,EAAE,2BAA2B;QACjC,WAAW,EAAE,8CAA8C;QAC3D,SAAS,EAAE,iBAAiB;QAC5B,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,kBAAkB,CAAC,EAAE;QACrD,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,uFAAuF;KAChG;IACD;QACE,IAAI,EAAE,2BAA2B;QACjC,WAAW,EAAE,yCAAyC;QACtD,SAAS,EAAE,iBAAiB;QAC5B,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,qBAAqB,CAAC,EAAE;QACxD,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,6CAA6C;KACtD;IACD;QACE,IAAI,EAAE,0BAA0B;QAChC,WAAW,EAAE,0CAA0C;QACvD,SAAS,EAAE,iBAAiB;QAC5B,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,oBAAoB,CAAC,EAAE;QACvD,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,0CAA0C;KACnD;CACF,CAAC;AAYF;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,WAAmB;IACxD,MAAM,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5E,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,WAAW,CAAC;IAE1D,SAAS,OAAO,CAAC,MAAc,EAAE,IAAY,EAAE,IAAc;QAC3D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACnC,MAAM,IAAI,GAAwB;gBAChC,MAAM;gBACN,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,SAAS;gBAC3B,IAAI,EAAE,GAAG,CAAC,QAAQ;gBAClB,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtC,CAAC;YAEF,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE;gBACrC,MAAM,MAAM,GAAa,EAAE,CAAC;gBAC5B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;gBACtD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBACjB,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;oBAC9C,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;wBAC5C,MAAM,CAAC,IAAI,KAAK,CAAC,eAAe,GAAG,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;wBAC5D,OAAO;oBACT,CAAC;oBACD,IAAI,CAAC;wBACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;oBAC5B,CAAC;oBAAC,MAAM,CAAC;wBACP,OAAO,CAAC,IAAI,CAAC,CAAC;oBAChB,CAAC;gBACH,CAAC,CAAC,CAAC;gBACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC1B,CAAC,CAAC,CAAC;YAEH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACxB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,KAAK,CAAC,SAAS,CAAC,MAAc;YAC5B,OAAO,CAAC,MAAM,OAAO,CAAC,MAAM,EAAE,4BAA4B,EAAE,EAAE,MAAM,EAAE,CAAC,CAAuB,CAAC;QACjG,CAAC;QACD,KAAK,CAAC,YAAY,CAAC,MAAc;YAC/B,OAAO,CAAC,MAAM,OAAO,CAAC,MAAM,EAAE,+BAA+B,EAAE,EAAE,MAAM,EAAE,CAAC,CAAyB,CAAC;QACtG,CAAC;QACD,KAAK,CAAC,WAAW;YACf,OAAO,CAAC,MAAM,OAAO,CAAC,KAAK,EAAE,wBAAwB,CAAC,CAAkB,CAAC;QAC3E,CAAC;KACF,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E,8EAA8E;AAC9E,SAAS,gBAAgB,CAAC,IAA6B,EAAE,IAAY;IACnE,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,yCAAyC,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,QAAgB,EAChB,IAA6B,EAC7B,MAAwB;IAExB,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,kBAAkB,CAAC,CAAC,CAAC;YACxB,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAChD,gBAAgB,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;YACxC,cAAc,CAAC,MAAM,CAAC,CAAC;YACvB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAC9C,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBAClB,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,OAAO,EAAE,kDAAkD,EAAE,CAAC;YACvG,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QACrC,CAAC;QACD,KAAK,qBAAqB,CAAC,CAAC,CAAC;YAC3B,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAChD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YACjD,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;QACtE,CAAC;QACD,KAAK,oBAAoB;YACvB,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC;QAC9B;YACE,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,EAAE,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E,sFAAsF;AACtF,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC"}