@phuetz/code-buddy 0.1.24 → 0.1.26

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 (258) hide show
  1. package/README.md +1049 -741
  2. package/dist/agent/codebuddy-agent.d.ts +5 -0
  3. package/dist/agent/codebuddy-agent.js +46 -1
  4. package/dist/agent/codebuddy-agent.js.map +1 -1
  5. package/dist/agent/execution/agent-executor.d.ts +12 -0
  6. package/dist/agent/execution/agent-executor.js +147 -6
  7. package/dist/agent/execution/agent-executor.js.map +1 -1
  8. package/dist/agent/lessons-tracker.d.ts +50 -0
  9. package/dist/agent/lessons-tracker.js +234 -0
  10. package/dist/agent/lessons-tracker.js.map +1 -0
  11. package/dist/agent/message-queue.d.ts +39 -2
  12. package/dist/agent/message-queue.js +67 -2
  13. package/dist/agent/message-queue.js.map +1 -1
  14. package/dist/agent/middleware/index.d.ts +1 -0
  15. package/dist/agent/middleware/index.js +1 -0
  16. package/dist/agent/middleware/index.js.map +1 -1
  17. package/dist/agent/middleware/workflow-guard.d.ts +21 -0
  18. package/dist/agent/middleware/workflow-guard.js +94 -0
  19. package/dist/agent/middleware/workflow-guard.js.map +1 -0
  20. package/dist/agent/repo-profiler.d.ts +61 -0
  21. package/dist/agent/repo-profiler.js +295 -0
  22. package/dist/agent/repo-profiler.js.map +1 -0
  23. package/dist/agent/response-constraint.d.ts +61 -0
  24. package/dist/agent/response-constraint.js +91 -0
  25. package/dist/agent/response-constraint.js.map +1 -0
  26. package/dist/agent/todo-tracker.d.ts +67 -0
  27. package/dist/agent/todo-tracker.js +245 -0
  28. package/dist/agent/todo-tracker.js.map +1 -0
  29. package/dist/agent/tool-handler.d.ts +11 -0
  30. package/dist/agent/tool-handler.js +79 -1
  31. package/dist/agent/tool-handler.js.map +1 -1
  32. package/dist/agent/types.d.ts +20 -2
  33. package/dist/agent/wide-research.d.ts +93 -0
  34. package/dist/agent/wide-research.js +232 -0
  35. package/dist/agent/wide-research.js.map +1 -0
  36. package/dist/channels/index.d.ts +2 -0
  37. package/dist/channels/index.js +2 -0
  38. package/dist/channels/index.js.map +1 -1
  39. package/dist/channels/pro/callback-router.d.ts +54 -0
  40. package/dist/channels/pro/callback-router.js +178 -0
  41. package/dist/channels/pro/callback-router.js.map +1 -0
  42. package/dist/channels/pro/ci-watcher.d.ts +86 -0
  43. package/dist/channels/pro/ci-watcher.js +343 -0
  44. package/dist/channels/pro/ci-watcher.js.map +1 -0
  45. package/dist/channels/pro/diff-first.d.ts +63 -0
  46. package/dist/channels/pro/diff-first.js +187 -0
  47. package/dist/channels/pro/diff-first.js.map +1 -0
  48. package/dist/channels/pro/enhanced-commands.d.ts +83 -0
  49. package/dist/channels/pro/enhanced-commands.js +218 -0
  50. package/dist/channels/pro/enhanced-commands.js.map +1 -0
  51. package/dist/channels/pro/index.d.ts +19 -0
  52. package/dist/channels/pro/index.js +21 -0
  53. package/dist/channels/pro/index.js.map +1 -0
  54. package/dist/channels/pro/pro-features.d.ts +79 -0
  55. package/dist/channels/pro/pro-features.js +203 -0
  56. package/dist/channels/pro/pro-features.js.map +1 -0
  57. package/dist/channels/pro/run-commands.d.ts +59 -0
  58. package/dist/channels/pro/run-commands.js +122 -0
  59. package/dist/channels/pro/run-commands.js.map +1 -0
  60. package/dist/channels/pro/run-tracker.d.ts +74 -0
  61. package/dist/channels/pro/run-tracker.js +252 -0
  62. package/dist/channels/pro/run-tracker.js.map +1 -0
  63. package/dist/channels/pro/scoped-auth.d.ts +97 -0
  64. package/dist/channels/pro/scoped-auth.js +340 -0
  65. package/dist/channels/pro/scoped-auth.js.map +1 -0
  66. package/dist/channels/pro/text-formatter.d.ts +27 -0
  67. package/dist/channels/pro/text-formatter.js +269 -0
  68. package/dist/channels/pro/text-formatter.js.map +1 -0
  69. package/dist/channels/pro/types.d.ts +242 -0
  70. package/dist/channels/pro/types.js +14 -0
  71. package/dist/channels/pro/types.js.map +1 -0
  72. package/dist/channels/streaming-policy.d.ts +66 -0
  73. package/dist/channels/streaming-policy.js +266 -0
  74. package/dist/channels/streaming-policy.js.map +1 -0
  75. package/dist/channels/telegram/ci-watcher.d.ts +5 -0
  76. package/dist/channels/telegram/ci-watcher.js +5 -0
  77. package/dist/channels/telegram/ci-watcher.js.map +1 -0
  78. package/dist/channels/telegram/client.d.ts +28 -0
  79. package/dist/channels/telegram/client.js +147 -1
  80. package/dist/channels/telegram/client.js.map +1 -1
  81. package/dist/channels/telegram/diff-first.d.ts +5 -0
  82. package/dist/channels/telegram/diff-first.js +5 -0
  83. package/dist/channels/telegram/diff-first.js.map +1 -0
  84. package/dist/channels/telegram/enhanced-commands.d.ts +6 -0
  85. package/dist/channels/telegram/enhanced-commands.js +6 -0
  86. package/dist/channels/telegram/enhanced-commands.js.map +1 -0
  87. package/dist/channels/telegram/index.d.ts +6 -0
  88. package/dist/channels/telegram/index.js +6 -0
  89. package/dist/channels/telegram/index.js.map +1 -1
  90. package/dist/channels/telegram/pro-formatter.d.ts +30 -0
  91. package/dist/channels/telegram/pro-formatter.js +276 -0
  92. package/dist/channels/telegram/pro-formatter.js.map +1 -0
  93. package/dist/channels/telegram/run-commands.d.ts +5 -0
  94. package/dist/channels/telegram/run-commands.js +6 -0
  95. package/dist/channels/telegram/run-commands.js.map +1 -0
  96. package/dist/channels/telegram/run-tracker.d.ts +5 -0
  97. package/dist/channels/telegram/run-tracker.js +5 -0
  98. package/dist/channels/telegram/run-tracker.js.map +1 -0
  99. package/dist/channels/telegram/scoped-auth.d.ts +6 -0
  100. package/dist/channels/telegram/scoped-auth.js +5 -0
  101. package/dist/channels/telegram/scoped-auth.js.map +1 -0
  102. package/dist/channels/telegram/types.d.ts +34 -0
  103. package/dist/codebuddy/client.js +14 -1
  104. package/dist/codebuddy/client.js.map +1 -1
  105. package/dist/commands/dev/index.d.ts +12 -0
  106. package/dist/commands/dev/index.js +231 -0
  107. package/dist/commands/dev/index.js.map +1 -0
  108. package/dist/commands/dev/workflows.d.ts +31 -0
  109. package/dist/commands/dev/workflows.js +214 -0
  110. package/dist/commands/dev/workflows.js.map +1 -0
  111. package/dist/commands/execpolicy.d.ts +17 -0
  112. package/dist/commands/execpolicy.js +155 -0
  113. package/dist/commands/execpolicy.js.map +1 -0
  114. package/dist/commands/knowledge.d.ts +13 -0
  115. package/dist/commands/knowledge.js +142 -0
  116. package/dist/commands/knowledge.js.map +1 -0
  117. package/dist/commands/lessons.d.ts +11 -0
  118. package/dist/commands/lessons.js +129 -0
  119. package/dist/commands/lessons.js.map +1 -0
  120. package/dist/commands/pairing.d.ts +14 -0
  121. package/dist/commands/pairing.js +132 -0
  122. package/dist/commands/pairing.js.map +1 -0
  123. package/dist/commands/research/index.d.ts +13 -0
  124. package/dist/commands/research/index.js +91 -0
  125. package/dist/commands/research/index.js.map +1 -0
  126. package/dist/commands/run-cli/index.d.ts +11 -0
  127. package/dist/commands/run-cli/index.js +49 -0
  128. package/dist/commands/run-cli/index.js.map +1 -0
  129. package/dist/commands/todos.d.ts +9 -0
  130. package/dist/commands/todos.js +119 -0
  131. package/dist/commands/todos.js.map +1 -0
  132. package/dist/config/toml-config.d.ts +21 -0
  133. package/dist/config/toml-config.js +15 -0
  134. package/dist/config/toml-config.js.map +1 -1
  135. package/dist/context/enhanced-compression.js +12 -1
  136. package/dist/context/enhanced-compression.js.map +1 -1
  137. package/dist/context/observation-variator.d.ts +44 -0
  138. package/dist/context/observation-variator.js +83 -0
  139. package/dist/context/observation-variator.js.map +1 -0
  140. package/dist/context/precompaction-flush.d.ts +40 -0
  141. package/dist/context/precompaction-flush.js +134 -0
  142. package/dist/context/precompaction-flush.js.map +1 -0
  143. package/dist/context/restorable-compression.d.ts +80 -0
  144. package/dist/context/restorable-compression.js +228 -0
  145. package/dist/context/restorable-compression.js.map +1 -0
  146. package/dist/daemon/daily-reset.d.ts +77 -0
  147. package/dist/daemon/daily-reset.js +175 -0
  148. package/dist/daemon/daily-reset.js.map +1 -0
  149. package/dist/daemon/index.d.ts +1 -0
  150. package/dist/daemon/index.js +1 -0
  151. package/dist/daemon/index.js.map +1 -1
  152. package/dist/index.js +53 -0
  153. package/dist/index.js.map +1 -1
  154. package/dist/knowledge/knowledge-manager.d.ts +77 -0
  155. package/dist/knowledge/knowledge-manager.js +244 -0
  156. package/dist/knowledge/knowledge-manager.js.map +1 -0
  157. package/dist/observability/run-store.d.ts +133 -0
  158. package/dist/observability/run-store.js +419 -0
  159. package/dist/observability/run-store.js.map +1 -0
  160. package/dist/observability/run-viewer.d.ts +33 -0
  161. package/dist/observability/run-viewer.js +254 -0
  162. package/dist/observability/run-viewer.js.map +1 -0
  163. package/dist/optimization/cache-breakpoints.d.ts +52 -0
  164. package/dist/optimization/cache-breakpoints.js +97 -0
  165. package/dist/optimization/cache-breakpoints.js.map +1 -0
  166. package/dist/persistence/session-store.d.ts +3 -1
  167. package/dist/persistence/session-store.js +1 -1
  168. package/dist/persistence/session-store.js.map +1 -1
  169. package/dist/prompts/system-base.js +51 -7
  170. package/dist/prompts/system-base.js.map +1 -1
  171. package/dist/prompts/variation-injector.d.ts +55 -0
  172. package/dist/prompts/variation-injector.js +171 -0
  173. package/dist/prompts/variation-injector.js.map +1 -0
  174. package/dist/prompts/workflow-rules.d.ts +10 -0
  175. package/dist/prompts/workflow-rules.js +79 -0
  176. package/dist/prompts/workflow-rules.js.map +1 -0
  177. package/dist/sandbox/execpolicy.d.ts +45 -0
  178. package/dist/sandbox/execpolicy.js +80 -0
  179. package/dist/sandbox/execpolicy.js.map +1 -1
  180. package/dist/sandbox/os-sandbox.d.ts +25 -0
  181. package/dist/sandbox/os-sandbox.js +73 -0
  182. package/dist/sandbox/os-sandbox.js.map +1 -1
  183. package/dist/security/security-audit.d.ts +10 -0
  184. package/dist/security/security-audit.js +116 -0
  185. package/dist/security/security-audit.js.map +1 -1
  186. package/dist/security/shell-env-policy.d.ts +45 -0
  187. package/dist/security/shell-env-policy.js +141 -0
  188. package/dist/security/shell-env-policy.js.map +1 -0
  189. package/dist/security/ssrf-guard.d.ts +61 -0
  190. package/dist/security/ssrf-guard.js +382 -0
  191. package/dist/security/ssrf-guard.js.map +1 -0
  192. package/dist/security/write-policy.d.ts +57 -0
  193. package/dist/security/write-policy.js +117 -0
  194. package/dist/security/write-policy.js.map +1 -0
  195. package/dist/services/prompt-builder.js +37 -0
  196. package/dist/services/prompt-builder.js.map +1 -1
  197. package/dist/themes/theme-schema.d.ts +10 -10
  198. package/dist/tools/ask-human-tool.d.ts +62 -0
  199. package/dist/tools/ask-human-tool.js +112 -0
  200. package/dist/tools/ask-human-tool.js.map +1 -0
  201. package/dist/tools/bash/bash-tool.d.ts +15 -0
  202. package/dist/tools/bash/bash-tool.js +62 -0
  203. package/dist/tools/bash/bash-tool.js.map +1 -1
  204. package/dist/tools/bash/command-validator.d.ts +1 -0
  205. package/dist/tools/bash/command-validator.js +5 -0
  206. package/dist/tools/bash/command-validator.js.map +1 -1
  207. package/dist/tools/create-skill-tool.d.ts +87 -0
  208. package/dist/tools/create-skill-tool.js +142 -0
  209. package/dist/tools/create-skill-tool.js.map +1 -0
  210. package/dist/tools/fetch-tool.js +5 -3
  211. package/dist/tools/fetch-tool.js.map +1 -1
  212. package/dist/tools/hooks/default-hooks.js +24 -23
  213. package/dist/tools/hooks/default-hooks.js.map +1 -1
  214. package/dist/tools/index.d.ts +1 -0
  215. package/dist/tools/index.js +1 -0
  216. package/dist/tools/index.js.map +1 -1
  217. package/dist/tools/plan-tool.d.ts +22 -0
  218. package/dist/tools/plan-tool.js +128 -0
  219. package/dist/tools/plan-tool.js.map +1 -0
  220. package/dist/tools/registry/attention-tools.d.ts +32 -0
  221. package/dist/tools/registry/attention-tools.js +225 -0
  222. package/dist/tools/registry/attention-tools.js.map +1 -0
  223. package/dist/tools/registry/index.d.ts +9 -1
  224. package/dist/tools/registry/index.js +30 -2
  225. package/dist/tools/registry/index.js.map +1 -1
  226. package/dist/tools/registry/knowledge-tools.d.ts +46 -0
  227. package/dist/tools/registry/knowledge-tools.js +293 -0
  228. package/dist/tools/registry/knowledge-tools.js.map +1 -0
  229. package/dist/tools/registry/lessons-tools.d.ts +48 -0
  230. package/dist/tools/registry/lessons-tools.js +359 -0
  231. package/dist/tools/registry/lessons-tools.js.map +1 -0
  232. package/dist/tools/registry/plan-tools.d.ts +2 -0
  233. package/dist/tools/registry/plan-tools.js +7 -0
  234. package/dist/tools/registry/plan-tools.js.map +1 -0
  235. package/dist/tools/registry/script-tools.d.ts +2 -0
  236. package/dist/tools/registry/script-tools.js +7 -0
  237. package/dist/tools/registry/script-tools.js.map +1 -0
  238. package/dist/tools/registry/tool-aliases.d.ts +44 -0
  239. package/dist/tools/registry/tool-aliases.js +130 -0
  240. package/dist/tools/registry/tool-aliases.js.map +1 -0
  241. package/dist/tools/run-script-tool.d.ts +13 -0
  242. package/dist/tools/run-script-tool.js +146 -0
  243. package/dist/tools/run-script-tool.js.map +1 -0
  244. package/dist/tools/web-search.d.ts +25 -0
  245. package/dist/tools/web-search.js +68 -6
  246. package/dist/tools/web-search.js.map +1 -1
  247. package/dist/utils/config-validation/schema.d.ts +2 -2
  248. package/dist/utils/debug-logger.d.ts +1 -1
  249. package/dist/utils/rtk-compressor.d.ts +13 -10
  250. package/dist/utils/rtk-compressor.js +83 -34
  251. package/dist/utils/rtk-compressor.js.map +1 -1
  252. package/dist/utils/stable-json.d.ts +27 -0
  253. package/dist/utils/stable-json.js +50 -0
  254. package/dist/utils/stable-json.js.map +1 -0
  255. package/dist/webhooks/webhook-manager.d.ts +7 -0
  256. package/dist/webhooks/webhook-manager.js +29 -0
  257. package/dist/webhooks/webhook-manager.js.map +1 -1
  258. package/package.json +1 -1
@@ -0,0 +1,61 @@
1
+ /**
2
+ * SSRF Guard — OpenClaw-inspired server-side request forgery protection
3
+ *
4
+ * Applied to all outbound HTTP calls made by the agent (web_fetch, media
5
+ * download, webhook delivery). Blocks all private/loopback/link-local
6
+ * addresses including advanced bypass vectors:
7
+ *
8
+ * - RFC 1918 / loopback / link-local IPv4
9
+ * - IPv4-mapped IPv6 (::ffff:127.0.0.1), full-form variants
10
+ * - NAT64 prefix (64:ff9b::/96, 64:ff9b:1::/48)
11
+ * - 6to4 (2002::/16)
12
+ * - Teredo (2001:0000::/32)
13
+ * - Octal, hex, short, packed IPv4 literals (0177.0.0.1, 127.1, 2130706433)
14
+ * - Sensitive headers stripped on cross-origin redirects
15
+ *
16
+ * Fails **closed** on parse errors (unknown format → blocked).
17
+ */
18
+ export interface SSRFCheckResult {
19
+ safe: boolean;
20
+ reason?: string;
21
+ }
22
+ export interface SSRFGuardConfig {
23
+ /** Additional allowed hosts (exact hostname or *.domain.com wildcard) */
24
+ allowedHosts?: string[];
25
+ /** Additional blocked CIDR-like ranges (for extension) */
26
+ extraBlockedHosts?: string[];
27
+ /** Resolve DNS and check each returned IP (default: true) */
28
+ resolveDns?: boolean;
29
+ }
30
+ export declare class SSRFGuard {
31
+ private config;
32
+ constructor(config?: SSRFGuardConfig);
33
+ /**
34
+ * Check if a URL is safe to fetch.
35
+ * Resolves the hostname to IP(s) and validates each one.
36
+ *
37
+ * @returns `{safe: true}` if the URL is safe, or `{safe: false, reason}` otherwise.
38
+ */
39
+ isSafeUrl(rawUrl: string): Promise<SSRFCheckResult>;
40
+ /**
41
+ * Synchronous check for IP literals only (no DNS).
42
+ * Use for fast path when URL is already an IP literal.
43
+ */
44
+ isSafeUrlSync(rawUrl: string): SSRFCheckResult;
45
+ private isAllowedHost;
46
+ /** Returns null if not an IP literal */
47
+ private checkIpLiteral;
48
+ private checkIPv4String;
49
+ private checkIPv4Uint32;
50
+ private checkIPv6;
51
+ }
52
+ export declare function getSSRFGuard(config?: SSRFGuardConfig): SSRFGuard;
53
+ export declare function resetSSRFGuard(): void;
54
+ /**
55
+ * Convenience wrapper — use in web_fetch, webhook delivery, media download.
56
+ *
57
+ * @example
58
+ * const check = await assertSafeUrl(url);
59
+ * if (!check.safe) throw new Error(`SSRF blocked: ${check.reason}`);
60
+ */
61
+ export declare function assertSafeUrl(url: string): Promise<SSRFCheckResult>;
@@ -0,0 +1,382 @@
1
+ /**
2
+ * SSRF Guard — OpenClaw-inspired server-side request forgery protection
3
+ *
4
+ * Applied to all outbound HTTP calls made by the agent (web_fetch, media
5
+ * download, webhook delivery). Blocks all private/loopback/link-local
6
+ * addresses including advanced bypass vectors:
7
+ *
8
+ * - RFC 1918 / loopback / link-local IPv4
9
+ * - IPv4-mapped IPv6 (::ffff:127.0.0.1), full-form variants
10
+ * - NAT64 prefix (64:ff9b::/96, 64:ff9b:1::/48)
11
+ * - 6to4 (2002::/16)
12
+ * - Teredo (2001:0000::/32)
13
+ * - Octal, hex, short, packed IPv4 literals (0177.0.0.1, 127.1, 2130706433)
14
+ * - Sensitive headers stripped on cross-origin redirects
15
+ *
16
+ * Fails **closed** on parse errors (unknown format → blocked).
17
+ */
18
+ import * as dns from 'dns/promises';
19
+ import { logger } from '../utils/logger.js';
20
+ // ============================================================================
21
+ // Private IP range matchers (IPv4)
22
+ // ============================================================================
23
+ /** Parse decimal, octal (0177.0.0.1), hex (0x7f000001), short forms (127.1) to uint32 */
24
+ function parseIPv4ToUint32(host) {
25
+ // Hex: 0x7f000001
26
+ if (/^0x[0-9a-f]+$/i.test(host)) {
27
+ const n = parseInt(host, 16);
28
+ return isNaN(n) ? null : n >>> 0;
29
+ }
30
+ // Pure decimal integer: 2130706433
31
+ if (/^\d+$/.test(host)) {
32
+ const n = parseInt(host, 10);
33
+ return isNaN(n) ? null : n >>> 0;
34
+ }
35
+ // Dotted notation: handles decimal, octal, hex per-octet and short forms
36
+ const parts = host.split('.');
37
+ if (parts.length < 1 || parts.length > 4)
38
+ return null;
39
+ const octets = [];
40
+ for (const part of parts) {
41
+ let val;
42
+ if (/^0x[0-9a-f]+$/i.test(part)) {
43
+ val = parseInt(part, 16);
44
+ }
45
+ else if (/^0[0-7]+$/.test(part)) {
46
+ val = parseInt(part, 8); // octal
47
+ }
48
+ else if (/^\d+$/.test(part)) {
49
+ val = parseInt(part, 10);
50
+ }
51
+ else {
52
+ return null;
53
+ }
54
+ if (isNaN(val) || val < 0)
55
+ return null;
56
+ octets.push(val);
57
+ }
58
+ // Short-form expansion: 127.1 → 127.0.0.1, 10.1.2 → 10.1.0.2
59
+ while (octets.length < 4) {
60
+ const last = octets.pop();
61
+ // last octet expands into remaining spots (like inet_aton)
62
+ octets.push(0);
63
+ octets.push(last);
64
+ }
65
+ if (octets.some(o => o > 255))
66
+ return null;
67
+ return ((octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3]) >>> 0;
68
+ }
69
+ function isPrivateIPv4(uint32) {
70
+ // 0.0.0.0/8 — This network
71
+ if ((uint32 & 0xff000000) === 0x00000000)
72
+ return true;
73
+ // 10.0.0.0/8
74
+ if ((uint32 & 0xff000000) === 0x0a000000)
75
+ return true;
76
+ // 100.64.0.0/10 — Shared address space (RFC 6598)
77
+ if ((uint32 & 0xffc00000) === 0x64400000)
78
+ return true;
79
+ // 127.0.0.0/8 — Loopback
80
+ if ((uint32 & 0xff000000) === 0x7f000000)
81
+ return true;
82
+ // 169.254.0.0/16 — Link-local / AWS metadata
83
+ if ((uint32 & 0xffff0000) === 0xa9fe0000)
84
+ return true;
85
+ // 172.16.0.0/12
86
+ if ((uint32 & 0xfff00000) === 0xac100000)
87
+ return true;
88
+ // 192.0.0.0/24 — IETF protocol assignments
89
+ if ((uint32 & 0xffffff00) === 0xc0000000)
90
+ return true;
91
+ // 192.168.0.0/16
92
+ if ((uint32 & 0xffff0000) === 0xc0a80000)
93
+ return true;
94
+ // 198.18.0.0/15 — Benchmark testing
95
+ if ((uint32 & 0xfffe0000) === 0xc6120000)
96
+ return true;
97
+ // 198.51.100.0/24 — TEST-NET-2
98
+ if ((uint32 & 0xffffff00) === 0xc6336400)
99
+ return true;
100
+ // 203.0.113.0/24 — TEST-NET-3
101
+ if ((uint32 & 0xffffff00) === 0xcb007100)
102
+ return true;
103
+ // 224.0.0.0/4 — Multicast
104
+ if ((uint32 & 0xf0000000) === 0xe0000000)
105
+ return true;
106
+ // 240.0.0.0/4 — Reserved
107
+ if ((uint32 & 0xf0000000) === 0xf0000000)
108
+ return true;
109
+ // 255.255.255.255
110
+ if (uint32 === 0xffffffff)
111
+ return true;
112
+ return false;
113
+ }
114
+ // ============================================================================
115
+ // IPv6 private range detection
116
+ // ============================================================================
117
+ /** Expand a possibly compressed IPv6 address to 8 groups of uint16 */
118
+ function expandIPv6(address) {
119
+ try {
120
+ // Handle IPv4-mapped: ::ffff:1.2.3.4
121
+ const v4mapped = address.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i);
122
+ if (v4mapped) {
123
+ const v4 = parseIPv4ToUint32(v4mapped[1]);
124
+ if (v4 === null)
125
+ return null;
126
+ return [0, 0, 0, 0, 0, 0xffff, (v4 >>> 16) & 0xffff, v4 & 0xffff];
127
+ }
128
+ if (!address.includes(':'))
129
+ return null;
130
+ // Split on ::
131
+ const halves = address.split('::');
132
+ if (halves.length > 2)
133
+ return null;
134
+ const parseGroups = (s) => {
135
+ if (s === '')
136
+ return [];
137
+ return s.split(':').map(g => {
138
+ // Handle embedded IPv4 in last two groups
139
+ if (g.includes('.')) {
140
+ const v4 = parseIPv4ToUint32(g);
141
+ return v4 !== null ? [((v4 >>> 16) & 0xffff), v4 & 0xffff] : null;
142
+ }
143
+ const n = parseInt(g, 16);
144
+ return isNaN(n) ? null : [n];
145
+ }).reduce((acc, val) => {
146
+ if (acc === null || val === null)
147
+ return null;
148
+ return [...acc, ...(Array.isArray(val[0]) ? val[0] : val)];
149
+ }, []);
150
+ };
151
+ if (halves.length === 1) {
152
+ const groups = parseGroups(halves[0]);
153
+ if (!groups || groups.length !== 8)
154
+ return null;
155
+ return groups;
156
+ }
157
+ const left = parseGroups(halves[0]) ?? [];
158
+ const right = parseGroups(halves[1]) ?? [];
159
+ const fill = new Array(8 - left.length - right.length).fill(0);
160
+ const groups = [...left, ...fill, ...right];
161
+ if (groups.length !== 8)
162
+ return null;
163
+ return groups;
164
+ }
165
+ catch {
166
+ return null;
167
+ }
168
+ }
169
+ function isPrivateIPv6(address) {
170
+ const addr = address.toLowerCase().replace(/^\[|\]$/g, ''); // strip brackets
171
+ // ::1 — loopback
172
+ if (addr === '::1')
173
+ return true;
174
+ // :: — unspecified
175
+ if (addr === '::')
176
+ return true;
177
+ const groups = expandIPv6(addr);
178
+ if (!groups)
179
+ return false; // parse error → caller should handle
180
+ const g = groups;
181
+ // ::ffff:0:0/96 — IPv4-mapped
182
+ if (g[0] === 0 && g[1] === 0 && g[2] === 0 && g[3] === 0 && g[4] === 0 && g[5] === 0xffff) {
183
+ const v4 = (g[6] << 16) | g[7];
184
+ return isPrivateIPv4(v4 >>> 0);
185
+ }
186
+ // 0:0:0:0:0:0::/96 — IPv4-compatible (deprecated but still mapped)
187
+ if (g[0] === 0 && g[1] === 0 && g[2] === 0 && g[3] === 0 && g[4] === 0 && g[5] === 0) {
188
+ const v4 = (g[6] << 16) | g[7];
189
+ if (v4 !== 0 && v4 !== 1)
190
+ return isPrivateIPv4(v4 >>> 0);
191
+ }
192
+ // 64:ff9b::/96 — NAT64 (RFC 6052)
193
+ if (g[0] === 0x0064 && g[1] === 0xff9b && g[2] === 0 && g[3] === 0 && g[4] === 0 && g[5] === 0) {
194
+ const v4 = (g[6] << 16) | g[7];
195
+ return isPrivateIPv4(v4 >>> 0);
196
+ }
197
+ // 64:ff9b:1::/48 — NAT64 (RFC 8215)
198
+ if (g[0] === 0x0064 && g[1] === 0xff9b && g[2] === 0x0001)
199
+ return true;
200
+ // 2002::/16 — 6to4 (RFC 3056): embedded IPv4 is in groups [1] and [2]
201
+ if (g[0] === 0x2002) {
202
+ const v4 = (g[1] << 16) | g[2];
203
+ return isPrivateIPv4(v4 >>> 0);
204
+ }
205
+ // 2001:0000::/32 — Teredo (RFC 4380)
206
+ if (g[0] === 0x2001 && g[1] === 0x0000)
207
+ return true;
208
+ // fc00::/7 — Unique local
209
+ if ((g[0] & 0xfe00) === 0xfc00)
210
+ return true;
211
+ // fe80::/10 — Link-local
212
+ if ((g[0] & 0xffc0) === 0xfe80)
213
+ return true;
214
+ // ff00::/8 — Multicast
215
+ if ((g[0] & 0xff00) === 0xff00)
216
+ return true;
217
+ return false;
218
+ }
219
+ // ============================================================================
220
+ // SSRFGuard
221
+ // ============================================================================
222
+ export class SSRFGuard {
223
+ config;
224
+ constructor(config = {}) {
225
+ this.config = {
226
+ allowedHosts: config.allowedHosts ?? [],
227
+ extraBlockedHosts: config.extraBlockedHosts ?? [],
228
+ resolveDns: config.resolveDns ?? true,
229
+ };
230
+ }
231
+ /**
232
+ * Check if a URL is safe to fetch.
233
+ * Resolves the hostname to IP(s) and validates each one.
234
+ *
235
+ * @returns `{safe: true}` if the URL is safe, or `{safe: false, reason}` otherwise.
236
+ */
237
+ async isSafeUrl(rawUrl) {
238
+ let parsed;
239
+ try {
240
+ parsed = new URL(rawUrl);
241
+ }
242
+ catch {
243
+ return { safe: false, reason: 'Invalid URL (parse error)' };
244
+ }
245
+ // Only allow http/https
246
+ if (!['http:', 'https:'].includes(parsed.protocol)) {
247
+ return { safe: false, reason: `Blocked protocol: ${parsed.protocol}` };
248
+ }
249
+ const host = parsed.hostname.toLowerCase();
250
+ // Check allowlist first
251
+ if (this.isAllowedHost(host)) {
252
+ return { safe: true };
253
+ }
254
+ // Check extra blocked hosts
255
+ if (this.config.extraBlockedHosts.some(h => host === h || host.endsWith('.' + h))) {
256
+ return { safe: false, reason: `Host on blocked list: ${host}` };
257
+ }
258
+ // Check if host is an IP literal
259
+ const ipCheck = this.checkIpLiteral(host);
260
+ if (ipCheck !== null)
261
+ return ipCheck;
262
+ // Resolve DNS and check each returned address
263
+ if (this.config.resolveDns) {
264
+ try {
265
+ const addresses = await dns.lookup(host, { all: true });
266
+ for (const { address, family } of addresses) {
267
+ const result = family === 6
268
+ ? this.checkIPv6(address)
269
+ : this.checkIPv4String(address);
270
+ if (!result.safe) {
271
+ return { safe: false, reason: `Host ${host} resolves to private IP: ${address} — ${result.reason}` };
272
+ }
273
+ }
274
+ }
275
+ catch (err) {
276
+ // DNS resolution failure → fail closed
277
+ return { safe: false, reason: `DNS resolution failed for ${host}: ${err}` };
278
+ }
279
+ }
280
+ return { safe: true };
281
+ }
282
+ /**
283
+ * Synchronous check for IP literals only (no DNS).
284
+ * Use for fast path when URL is already an IP literal.
285
+ */
286
+ isSafeUrlSync(rawUrl) {
287
+ let parsed;
288
+ try {
289
+ parsed = new URL(rawUrl);
290
+ }
291
+ catch {
292
+ return { safe: false, reason: 'Invalid URL' };
293
+ }
294
+ if (!['http:', 'https:'].includes(parsed.protocol)) {
295
+ return { safe: false, reason: `Blocked protocol: ${parsed.protocol}` };
296
+ }
297
+ const host = parsed.hostname;
298
+ const ipCheck = this.checkIpLiteral(host);
299
+ if (ipCheck !== null)
300
+ return ipCheck;
301
+ // Cannot verify hostname without DNS — return safe (async version required)
302
+ return { safe: true };
303
+ }
304
+ isAllowedHost(host) {
305
+ return this.config.allowedHosts.some(allowed => {
306
+ if (allowed.startsWith('*.')) {
307
+ return host.endsWith(allowed.slice(1));
308
+ }
309
+ return host === allowed;
310
+ });
311
+ }
312
+ /** Returns null if not an IP literal */
313
+ checkIpLiteral(host) {
314
+ // IPv6 literal in brackets [::1]
315
+ if (host.startsWith('[') && host.endsWith(']')) {
316
+ return this.checkIPv6(host.slice(1, -1));
317
+ }
318
+ // Try parsing as IPv4 (handles octal/hex/short forms)
319
+ const v4 = parseIPv4ToUint32(host);
320
+ if (v4 !== null) {
321
+ return this.checkIPv4Uint32(v4);
322
+ }
323
+ // Try parsing as plain IPv6 (no brackets)
324
+ if (host.includes(':')) {
325
+ return this.checkIPv6(host);
326
+ }
327
+ return null; // Not an IP literal
328
+ }
329
+ checkIPv4String(address) {
330
+ const v4 = parseIPv4ToUint32(address);
331
+ if (v4 === null)
332
+ return { safe: false, reason: `Could not parse IPv4 address: ${address}` };
333
+ return this.checkIPv4Uint32(v4);
334
+ }
335
+ checkIPv4Uint32(uint32) {
336
+ if (isPrivateIPv4(uint32)) {
337
+ const a = [(uint32 >>> 24) & 0xff, (uint32 >>> 16) & 0xff, (uint32 >>> 8) & 0xff, uint32 & 0xff];
338
+ return { safe: false, reason: `Private/reserved IPv4: ${a.join('.')}` };
339
+ }
340
+ return { safe: true };
341
+ }
342
+ checkIPv6(address) {
343
+ if (isPrivateIPv6(address)) {
344
+ return { safe: false, reason: `Private/reserved IPv6: ${address}` };
345
+ }
346
+ // Expand to verify parse succeeded
347
+ const groups = expandIPv6(address.toLowerCase());
348
+ if (groups === null) {
349
+ return { safe: false, reason: `Could not parse IPv6 address: ${address}` };
350
+ }
351
+ return { safe: true };
352
+ }
353
+ }
354
+ // ============================================================================
355
+ // Singleton
356
+ // ============================================================================
357
+ let _guard = null;
358
+ export function getSSRFGuard(config) {
359
+ if (!_guard)
360
+ _guard = new SSRFGuard(config);
361
+ return _guard;
362
+ }
363
+ export function resetSSRFGuard() {
364
+ _guard = null;
365
+ }
366
+ /**
367
+ * Convenience wrapper — use in web_fetch, webhook delivery, media download.
368
+ *
369
+ * @example
370
+ * const check = await assertSafeUrl(url);
371
+ * if (!check.safe) throw new Error(`SSRF blocked: ${check.reason}`);
372
+ */
373
+ export async function assertSafeUrl(url) {
374
+ try {
375
+ return await getSSRFGuard().isSafeUrl(url);
376
+ }
377
+ catch (err) {
378
+ logger.warn('SSRFGuard check failed', { url, err });
379
+ return { safe: false, reason: `SSRF guard error: ${err}` };
380
+ }
381
+ }
382
+ //# sourceMappingURL=ssrf-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssrf-guard.js","sourceRoot":"","sources":["../../src/security/ssrf-guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * WritePolicy — enforces diff-first writes at the tool-handler level.
3
+ *
4
+ * Modes:
5
+ * strict — blocks any direct file write; the caller must use applyPatch()
6
+ * confirm — allows writes but records a decision event in RunStore (existing confirmation UX)
7
+ * off — no restriction (current default behaviour)
8
+ *
9
+ * The singleton is injectable for tests via WritePolicy.setInstance().
10
+ */
11
+ export type WritePolicyMode = 'strict' | 'confirm' | 'off';
12
+ export interface WriteOperation {
13
+ /** Tool name triggering the write */
14
+ toolName: string;
15
+ /** File path(s) being written */
16
+ paths: string[];
17
+ /** Patch content if already prepared */
18
+ patch?: string;
19
+ /** Short description for decision log */
20
+ description?: string;
21
+ }
22
+ export interface GateResult {
23
+ allowed: boolean;
24
+ /** True if the caller must route through applyPatch() */
25
+ requiresPatch: boolean;
26
+ reason?: string;
27
+ }
28
+ export declare const WRITE_TOOL_NAMES: Set<string>;
29
+ export declare class WritePolicy {
30
+ private static _instance;
31
+ private mode;
32
+ private listeners;
33
+ static getInstance(): WritePolicy;
34
+ /** Replace the singleton (for testing). */
35
+ static setInstance(instance: WritePolicy): void;
36
+ static resetInstance(): void;
37
+ setMode(mode: WritePolicyMode): void;
38
+ getMode(): WritePolicyMode;
39
+ /**
40
+ * Check whether the operation is allowed under the current policy.
41
+ *
42
+ * Called by tool-handler before executing str_replace_editor / create_file / multi_edit.
43
+ *
44
+ * @param operation - The write operation being attempted
45
+ * @param runId - Active run ID for decision logging (optional)
46
+ */
47
+ gate(operation: WriteOperation, _runId?: string): Promise<GateResult>;
48
+ /**
49
+ * Returns true if the tool name is subject to write-policy gating.
50
+ */
51
+ isWriteTool(toolName: string): boolean;
52
+ /**
53
+ * Subscribe to gate decisions (for RunStore integration).
54
+ */
55
+ onGate(listener: (op: WriteOperation, result: GateResult) => void): void;
56
+ private notifyListeners;
57
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * WritePolicy — enforces diff-first writes at the tool-handler level.
3
+ *
4
+ * Modes:
5
+ * strict — blocks any direct file write; the caller must use applyPatch()
6
+ * confirm — allows writes but records a decision event in RunStore (existing confirmation UX)
7
+ * off — no restriction (current default behaviour)
8
+ *
9
+ * The singleton is injectable for tests via WritePolicy.setInstance().
10
+ */
11
+ import { logger } from '../utils/logger.js';
12
+ // ──────────────────────────────────────────────────────────────────
13
+ // Tool names that trigger write-policy gating
14
+ // ──────────────────────────────────────────────────────────────────
15
+ export const WRITE_TOOL_NAMES = new Set([
16
+ 'str_replace_editor',
17
+ 'create_file',
18
+ 'multi_edit',
19
+ 'apply_patch',
20
+ 'edit_file', // Morph Fast Apply
21
+ 'write_file',
22
+ ]);
23
+ // ──────────────────────────────────────────────────────────────────
24
+ // WritePolicy
25
+ // ──────────────────────────────────────────────────────────────────
26
+ export class WritePolicy {
27
+ static _instance = null;
28
+ mode = 'confirm';
29
+ listeners = [];
30
+ // ── Singleton ────────────────────────────────────────────────
31
+ static getInstance() {
32
+ if (!WritePolicy._instance) {
33
+ WritePolicy._instance = new WritePolicy();
34
+ }
35
+ return WritePolicy._instance;
36
+ }
37
+ /** Replace the singleton (for testing). */
38
+ static setInstance(instance) {
39
+ WritePolicy._instance = instance;
40
+ }
41
+ static resetInstance() {
42
+ WritePolicy._instance = null;
43
+ }
44
+ // ── Configuration ─────────────────────────────────────────────
45
+ setMode(mode) {
46
+ this.mode = mode;
47
+ logger.debug(`WritePolicy: mode set to ${mode}`);
48
+ }
49
+ getMode() {
50
+ return this.mode;
51
+ }
52
+ // ── Gating ────────────────────────────────────────────────────
53
+ /**
54
+ * Check whether the operation is allowed under the current policy.
55
+ *
56
+ * Called by tool-handler before executing str_replace_editor / create_file / multi_edit.
57
+ *
58
+ * @param operation - The write operation being attempted
59
+ * @param runId - Active run ID for decision logging (optional)
60
+ */
61
+ async gate(operation, _runId) {
62
+ const { toolName } = operation;
63
+ // apply_patch is always allowed — it IS the diff-first path
64
+ if (toolName === 'apply_patch') {
65
+ return { allowed: true, requiresPatch: false };
66
+ }
67
+ switch (this.mode) {
68
+ case 'off':
69
+ return { allowed: true, requiresPatch: false };
70
+ case 'confirm': {
71
+ // In confirm mode, direct writes are allowed but we log the decision
72
+ const result = { allowed: true, requiresPatch: false };
73
+ this.notifyListeners(operation, result);
74
+ return result;
75
+ }
76
+ case 'strict': {
77
+ // In strict mode, block direct writes if no patch is provided
78
+ if (operation.patch) {
79
+ // Caller has already produced a patch — allow it
80
+ return { allowed: true, requiresPatch: false };
81
+ }
82
+ const result = {
83
+ allowed: false,
84
+ requiresPatch: true,
85
+ reason: `WritePolicy (strict): tool "${toolName}" attempted a direct file write. Use apply_patch with a unified diff instead.`,
86
+ };
87
+ this.notifyListeners(operation, result);
88
+ logger.info(`WritePolicy blocked: ${toolName}`, { paths: operation.paths });
89
+ return result;
90
+ }
91
+ }
92
+ }
93
+ /**
94
+ * Returns true if the tool name is subject to write-policy gating.
95
+ */
96
+ isWriteTool(toolName) {
97
+ return WRITE_TOOL_NAMES.has(toolName);
98
+ }
99
+ // ── Observability ─────────────────────────────────────────────
100
+ /**
101
+ * Subscribe to gate decisions (for RunStore integration).
102
+ */
103
+ onGate(listener) {
104
+ this.listeners.push(listener);
105
+ }
106
+ notifyListeners(op, result) {
107
+ for (const l of this.listeners) {
108
+ try {
109
+ l(op, result);
110
+ }
111
+ catch {
112
+ // Ignore listener errors
113
+ }
114
+ }
115
+ }
116
+ }
117
+ //# sourceMappingURL=write-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-policy.js","sourceRoot":"","sources":["../../src/security/write-policy.ts"],"names":[],"mappings":"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"}