@phuetz/code-buddy 0.1.25 → 0.2.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 (264) 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/orchestrator/supervisor-agent.d.ts +9 -0
  21. package/dist/agent/orchestrator/supervisor-agent.js +21 -1
  22. package/dist/agent/orchestrator/supervisor-agent.js.map +1 -1
  23. package/dist/agent/repo-profiler.d.ts +61 -0
  24. package/dist/agent/repo-profiler.js +295 -0
  25. package/dist/agent/repo-profiler.js.map +1 -0
  26. package/dist/agent/response-constraint.d.ts +61 -0
  27. package/dist/agent/response-constraint.js +91 -0
  28. package/dist/agent/response-constraint.js.map +1 -0
  29. package/dist/agent/todo-tracker.d.ts +67 -0
  30. package/dist/agent/todo-tracker.js +245 -0
  31. package/dist/agent/todo-tracker.js.map +1 -0
  32. package/dist/agent/tool-handler.d.ts +11 -0
  33. package/dist/agent/tool-handler.js +79 -1
  34. package/dist/agent/tool-handler.js.map +1 -1
  35. package/dist/agent/types.d.ts +20 -2
  36. package/dist/agent/wide-research.d.ts +93 -0
  37. package/dist/agent/wide-research.js +232 -0
  38. package/dist/agent/wide-research.js.map +1 -0
  39. package/dist/channels/index.d.ts +2 -0
  40. package/dist/channels/index.js +2 -0
  41. package/dist/channels/index.js.map +1 -1
  42. package/dist/channels/pro/callback-router.d.ts +54 -0
  43. package/dist/channels/pro/callback-router.js +178 -0
  44. package/dist/channels/pro/callback-router.js.map +1 -0
  45. package/dist/channels/pro/ci-watcher.d.ts +86 -0
  46. package/dist/channels/pro/ci-watcher.js +343 -0
  47. package/dist/channels/pro/ci-watcher.js.map +1 -0
  48. package/dist/channels/pro/diff-first.d.ts +63 -0
  49. package/dist/channels/pro/diff-first.js +187 -0
  50. package/dist/channels/pro/diff-first.js.map +1 -0
  51. package/dist/channels/pro/enhanced-commands.d.ts +83 -0
  52. package/dist/channels/pro/enhanced-commands.js +218 -0
  53. package/dist/channels/pro/enhanced-commands.js.map +1 -0
  54. package/dist/channels/pro/index.d.ts +19 -0
  55. package/dist/channels/pro/index.js +21 -0
  56. package/dist/channels/pro/index.js.map +1 -0
  57. package/dist/channels/pro/pro-features.d.ts +79 -0
  58. package/dist/channels/pro/pro-features.js +203 -0
  59. package/dist/channels/pro/pro-features.js.map +1 -0
  60. package/dist/channels/pro/run-commands.d.ts +59 -0
  61. package/dist/channels/pro/run-commands.js +122 -0
  62. package/dist/channels/pro/run-commands.js.map +1 -0
  63. package/dist/channels/pro/run-tracker.d.ts +74 -0
  64. package/dist/channels/pro/run-tracker.js +252 -0
  65. package/dist/channels/pro/run-tracker.js.map +1 -0
  66. package/dist/channels/pro/scoped-auth.d.ts +97 -0
  67. package/dist/channels/pro/scoped-auth.js +340 -0
  68. package/dist/channels/pro/scoped-auth.js.map +1 -0
  69. package/dist/channels/pro/text-formatter.d.ts +27 -0
  70. package/dist/channels/pro/text-formatter.js +269 -0
  71. package/dist/channels/pro/text-formatter.js.map +1 -0
  72. package/dist/channels/pro/types.d.ts +242 -0
  73. package/dist/channels/pro/types.js +14 -0
  74. package/dist/channels/pro/types.js.map +1 -0
  75. package/dist/channels/streaming-policy.d.ts +66 -0
  76. package/dist/channels/streaming-policy.js +266 -0
  77. package/dist/channels/streaming-policy.js.map +1 -0
  78. package/dist/channels/telegram/ci-watcher.d.ts +5 -0
  79. package/dist/channels/telegram/ci-watcher.js +5 -0
  80. package/dist/channels/telegram/ci-watcher.js.map +1 -0
  81. package/dist/channels/telegram/client.d.ts +28 -0
  82. package/dist/channels/telegram/client.js +147 -1
  83. package/dist/channels/telegram/client.js.map +1 -1
  84. package/dist/channels/telegram/diff-first.d.ts +5 -0
  85. package/dist/channels/telegram/diff-first.js +5 -0
  86. package/dist/channels/telegram/diff-first.js.map +1 -0
  87. package/dist/channels/telegram/enhanced-commands.d.ts +6 -0
  88. package/dist/channels/telegram/enhanced-commands.js +6 -0
  89. package/dist/channels/telegram/enhanced-commands.js.map +1 -0
  90. package/dist/channels/telegram/index.d.ts +6 -0
  91. package/dist/channels/telegram/index.js +6 -0
  92. package/dist/channels/telegram/index.js.map +1 -1
  93. package/dist/channels/telegram/pro-formatter.d.ts +30 -0
  94. package/dist/channels/telegram/pro-formatter.js +276 -0
  95. package/dist/channels/telegram/pro-formatter.js.map +1 -0
  96. package/dist/channels/telegram/run-commands.d.ts +5 -0
  97. package/dist/channels/telegram/run-commands.js +6 -0
  98. package/dist/channels/telegram/run-commands.js.map +1 -0
  99. package/dist/channels/telegram/run-tracker.d.ts +5 -0
  100. package/dist/channels/telegram/run-tracker.js +5 -0
  101. package/dist/channels/telegram/run-tracker.js.map +1 -0
  102. package/dist/channels/telegram/scoped-auth.d.ts +6 -0
  103. package/dist/channels/telegram/scoped-auth.js +5 -0
  104. package/dist/channels/telegram/scoped-auth.js.map +1 -0
  105. package/dist/channels/telegram/types.d.ts +34 -0
  106. package/dist/codebuddy/client.js +14 -1
  107. package/dist/codebuddy/client.js.map +1 -1
  108. package/dist/commands/dev/index.d.ts +12 -0
  109. package/dist/commands/dev/index.js +231 -0
  110. package/dist/commands/dev/index.js.map +1 -0
  111. package/dist/commands/dev/workflows.d.ts +31 -0
  112. package/dist/commands/dev/workflows.js +214 -0
  113. package/dist/commands/dev/workflows.js.map +1 -0
  114. package/dist/commands/execpolicy.d.ts +17 -0
  115. package/dist/commands/execpolicy.js +155 -0
  116. package/dist/commands/execpolicy.js.map +1 -0
  117. package/dist/commands/knowledge.d.ts +13 -0
  118. package/dist/commands/knowledge.js +142 -0
  119. package/dist/commands/knowledge.js.map +1 -0
  120. package/dist/commands/lessons.d.ts +11 -0
  121. package/dist/commands/lessons.js +129 -0
  122. package/dist/commands/lessons.js.map +1 -0
  123. package/dist/commands/pairing.d.ts +14 -0
  124. package/dist/commands/pairing.js +132 -0
  125. package/dist/commands/pairing.js.map +1 -0
  126. package/dist/commands/research/index.d.ts +13 -0
  127. package/dist/commands/research/index.js +91 -0
  128. package/dist/commands/research/index.js.map +1 -0
  129. package/dist/commands/run-cli/index.d.ts +11 -0
  130. package/dist/commands/run-cli/index.js +49 -0
  131. package/dist/commands/run-cli/index.js.map +1 -0
  132. package/dist/commands/slash/builtin-commands.js +70 -2
  133. package/dist/commands/slash/builtin-commands.js.map +1 -1
  134. package/dist/commands/todos.d.ts +9 -0
  135. package/dist/commands/todos.js +119 -0
  136. package/dist/commands/todos.js.map +1 -0
  137. package/dist/config/toml-config.d.ts +21 -0
  138. package/dist/config/toml-config.js +15 -0
  139. package/dist/config/toml-config.js.map +1 -1
  140. package/dist/context/enhanced-compression.js +12 -1
  141. package/dist/context/enhanced-compression.js.map +1 -1
  142. package/dist/context/observation-variator.d.ts +44 -0
  143. package/dist/context/observation-variator.js +83 -0
  144. package/dist/context/observation-variator.js.map +1 -0
  145. package/dist/context/precompaction-flush.d.ts +40 -0
  146. package/dist/context/precompaction-flush.js +134 -0
  147. package/dist/context/precompaction-flush.js.map +1 -0
  148. package/dist/context/restorable-compression.d.ts +80 -0
  149. package/dist/context/restorable-compression.js +228 -0
  150. package/dist/context/restorable-compression.js.map +1 -0
  151. package/dist/daemon/daily-reset.d.ts +77 -0
  152. package/dist/daemon/daily-reset.js +175 -0
  153. package/dist/daemon/daily-reset.js.map +1 -0
  154. package/dist/daemon/index.d.ts +1 -0
  155. package/dist/daemon/index.js +1 -0
  156. package/dist/daemon/index.js.map +1 -1
  157. package/dist/index.js +53 -0
  158. package/dist/index.js.map +1 -1
  159. package/dist/knowledge/knowledge-manager.d.ts +77 -0
  160. package/dist/knowledge/knowledge-manager.js +244 -0
  161. package/dist/knowledge/knowledge-manager.js.map +1 -0
  162. package/dist/memory/semantic-memory-search.d.ts +7 -0
  163. package/dist/memory/semantic-memory-search.js +49 -5
  164. package/dist/memory/semantic-memory-search.js.map +1 -1
  165. package/dist/observability/run-store.d.ts +133 -0
  166. package/dist/observability/run-store.js +419 -0
  167. package/dist/observability/run-store.js.map +1 -0
  168. package/dist/observability/run-viewer.d.ts +33 -0
  169. package/dist/observability/run-viewer.js +254 -0
  170. package/dist/observability/run-viewer.js.map +1 -0
  171. package/dist/optimization/cache-breakpoints.d.ts +52 -0
  172. package/dist/optimization/cache-breakpoints.js +97 -0
  173. package/dist/optimization/cache-breakpoints.js.map +1 -0
  174. package/dist/persistence/session-store.d.ts +3 -1
  175. package/dist/persistence/session-store.js +1 -1
  176. package/dist/persistence/session-store.js.map +1 -1
  177. package/dist/prompts/system-base.js +51 -7
  178. package/dist/prompts/system-base.js.map +1 -1
  179. package/dist/prompts/variation-injector.d.ts +55 -0
  180. package/dist/prompts/variation-injector.js +171 -0
  181. package/dist/prompts/variation-injector.js.map +1 -0
  182. package/dist/prompts/workflow-rules.d.ts +10 -0
  183. package/dist/prompts/workflow-rules.js +79 -0
  184. package/dist/prompts/workflow-rules.js.map +1 -0
  185. package/dist/sandbox/execpolicy.d.ts +45 -0
  186. package/dist/sandbox/execpolicy.js +80 -0
  187. package/dist/sandbox/execpolicy.js.map +1 -1
  188. package/dist/sandbox/os-sandbox.d.ts +25 -0
  189. package/dist/sandbox/os-sandbox.js +73 -0
  190. package/dist/sandbox/os-sandbox.js.map +1 -1
  191. package/dist/scheduler/cron-scheduler.d.ts +9 -0
  192. package/dist/scheduler/cron-scheduler.js +17 -1
  193. package/dist/scheduler/cron-scheduler.js.map +1 -1
  194. package/dist/security/security-audit.d.ts +10 -0
  195. package/dist/security/security-audit.js +116 -0
  196. package/dist/security/security-audit.js.map +1 -1
  197. package/dist/security/shell-env-policy.d.ts +45 -0
  198. package/dist/security/shell-env-policy.js +141 -0
  199. package/dist/security/shell-env-policy.js.map +1 -0
  200. package/dist/security/ssrf-guard.d.ts +61 -0
  201. package/dist/security/ssrf-guard.js +382 -0
  202. package/dist/security/ssrf-guard.js.map +1 -0
  203. package/dist/security/write-policy.d.ts +57 -0
  204. package/dist/security/write-policy.js +117 -0
  205. package/dist/security/write-policy.js.map +1 -0
  206. package/dist/services/prompt-builder.js +37 -0
  207. package/dist/services/prompt-builder.js.map +1 -1
  208. package/dist/themes/theme-schema.d.ts +10 -10
  209. package/dist/tools/ask-human-tool.d.ts +62 -0
  210. package/dist/tools/ask-human-tool.js +112 -0
  211. package/dist/tools/ask-human-tool.js.map +1 -0
  212. package/dist/tools/bash/bash-tool.d.ts +15 -0
  213. package/dist/tools/bash/bash-tool.js +62 -0
  214. package/dist/tools/bash/bash-tool.js.map +1 -1
  215. package/dist/tools/bash/command-validator.d.ts +1 -0
  216. package/dist/tools/bash/command-validator.js +5 -0
  217. package/dist/tools/bash/command-validator.js.map +1 -1
  218. package/dist/tools/create-skill-tool.d.ts +87 -0
  219. package/dist/tools/create-skill-tool.js +142 -0
  220. package/dist/tools/create-skill-tool.js.map +1 -0
  221. package/dist/tools/fetch-tool.js +5 -3
  222. package/dist/tools/fetch-tool.js.map +1 -1
  223. package/dist/tools/index.d.ts +1 -0
  224. package/dist/tools/index.js +1 -0
  225. package/dist/tools/index.js.map +1 -1
  226. package/dist/tools/plan-tool.d.ts +22 -0
  227. package/dist/tools/plan-tool.js +128 -0
  228. package/dist/tools/plan-tool.js.map +1 -0
  229. package/dist/tools/registry/attention-tools.d.ts +32 -0
  230. package/dist/tools/registry/attention-tools.js +225 -0
  231. package/dist/tools/registry/attention-tools.js.map +1 -0
  232. package/dist/tools/registry/index.d.ts +9 -1
  233. package/dist/tools/registry/index.js +30 -2
  234. package/dist/tools/registry/index.js.map +1 -1
  235. package/dist/tools/registry/knowledge-tools.d.ts +46 -0
  236. package/dist/tools/registry/knowledge-tools.js +293 -0
  237. package/dist/tools/registry/knowledge-tools.js.map +1 -0
  238. package/dist/tools/registry/lessons-tools.d.ts +48 -0
  239. package/dist/tools/registry/lessons-tools.js +359 -0
  240. package/dist/tools/registry/lessons-tools.js.map +1 -0
  241. package/dist/tools/registry/plan-tools.d.ts +2 -0
  242. package/dist/tools/registry/plan-tools.js +7 -0
  243. package/dist/tools/registry/plan-tools.js.map +1 -0
  244. package/dist/tools/registry/script-tools.d.ts +2 -0
  245. package/dist/tools/registry/script-tools.js +7 -0
  246. package/dist/tools/registry/script-tools.js.map +1 -0
  247. package/dist/tools/registry/tool-aliases.d.ts +44 -0
  248. package/dist/tools/registry/tool-aliases.js +130 -0
  249. package/dist/tools/registry/tool-aliases.js.map +1 -0
  250. package/dist/tools/run-script-tool.d.ts +13 -0
  251. package/dist/tools/run-script-tool.js +146 -0
  252. package/dist/tools/run-script-tool.js.map +1 -0
  253. package/dist/tools/web-search.d.ts +25 -0
  254. package/dist/tools/web-search.js +68 -6
  255. package/dist/tools/web-search.js.map +1 -1
  256. package/dist/utils/config-validation/schema.d.ts +2 -2
  257. package/dist/utils/debug-logger.d.ts +1 -1
  258. package/dist/utils/stable-json.d.ts +27 -0
  259. package/dist/utils/stable-json.js +50 -0
  260. package/dist/utils/stable-json.js.map +1 -0
  261. package/dist/webhooks/webhook-manager.d.ts +7 -0
  262. package/dist/webhooks/webhook-manager.js +29 -0
  263. package/dist/webhooks/webhook-manager.js.map +1 -1
  264. package/package.json +1 -1
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Shell Environment Policy — Codex-inspired subprocess env control
3
+ *
4
+ * Controls which environment variables are passed to every subprocess
5
+ * the agent spawns. Prevents accidental leakage of API keys and
6
+ * credentials to untrusted subprocess environments.
7
+ *
8
+ * Config (via [shell_env] in .codebuddy/config.toml):
9
+ *
10
+ * [shell_env]
11
+ * inherit = "all" # all | core | none
12
+ * exclude = ["*SECRET*", "*TOKEN*", "*KEY*", "*PASSWORD*"]
13
+ * include_only = [] # if set, only these vars pass (overrides exclude)
14
+ * # set = { NODE_ENV = "production" } # always-injected overrides
15
+ *
16
+ * Defaults strip variables matching common credential patterns while
17
+ * preserving PATH, HOME, USER, SHELL, TERM, LANG, etc.
18
+ */
19
+ /** Baseline inheritance mode */
20
+ export type EnvInheritMode = 'all' | 'core' | 'none';
21
+ export interface ShellEnvPolicyConfig {
22
+ /** How many env vars to start with */
23
+ inherit?: EnvInheritMode;
24
+ /** Glob-style patterns to strip from inherited env */
25
+ exclude?: string[];
26
+ /** If non-empty, ONLY these vars are passed (overrides exclude) */
27
+ include_only?: string[];
28
+ /** Key/value pairs always injected into every subprocess env */
29
+ set?: Record<string, string>;
30
+ }
31
+ export declare class ShellEnvPolicy {
32
+ private config;
33
+ constructor(config?: ShellEnvPolicyConfig);
34
+ /**
35
+ * Build a filtered environment object for subprocess spawning.
36
+ * Returns a new object — never mutates process.env.
37
+ */
38
+ buildEnv(source?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
39
+ /**
40
+ * Check if a specific env var would be passed through.
41
+ */
42
+ wouldPass(key: string): boolean;
43
+ }
44
+ export declare function getShellEnvPolicy(config?: ShellEnvPolicyConfig): ShellEnvPolicy;
45
+ export declare function resetShellEnvPolicy(): void;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Shell Environment Policy — Codex-inspired subprocess env control
3
+ *
4
+ * Controls which environment variables are passed to every subprocess
5
+ * the agent spawns. Prevents accidental leakage of API keys and
6
+ * credentials to untrusted subprocess environments.
7
+ *
8
+ * Config (via [shell_env] in .codebuddy/config.toml):
9
+ *
10
+ * [shell_env]
11
+ * inherit = "all" # all | core | none
12
+ * exclude = ["*SECRET*", "*TOKEN*", "*KEY*", "*PASSWORD*"]
13
+ * include_only = [] # if set, only these vars pass (overrides exclude)
14
+ * # set = { NODE_ENV = "production" } # always-injected overrides
15
+ *
16
+ * Defaults strip variables matching common credential patterns while
17
+ * preserving PATH, HOME, USER, SHELL, TERM, LANG, etc.
18
+ */
19
+ import { logger } from '../utils/logger.js';
20
+ // ============================================================================
21
+ // Core variable sets
22
+ // ============================================================================
23
+ /** Always-safe variables for 'core' mode */
24
+ const CORE_VARS = new Set([
25
+ 'PATH', 'HOME', 'USER', 'LOGNAME', 'SHELL', 'TERM', 'TERM_PROGRAM',
26
+ 'LANG', 'LC_ALL', 'LC_CTYPE', 'TZ', 'TMPDIR', 'TEMP', 'TMP',
27
+ 'PWD', 'OLDPWD', 'SHLVL', 'COLORTERM', 'CLICOLOR',
28
+ // Node.js / npm
29
+ 'NODE_ENV', 'NODE_PATH', 'NPM_CONFIG_PREFIX',
30
+ // Common CI vars (non-sensitive)
31
+ 'CI', 'GITHUB_ACTIONS', 'GITLAB_CI',
32
+ ]);
33
+ /** Default exclusion glob patterns (credential-like names) */
34
+ const DEFAULT_EXCLUDE_PATTERNS = [
35
+ '*_KEY', '*_SECRET', '*_TOKEN', '*_PASSWORD', '*_PASSWD',
36
+ '*_CREDENTIAL', '*_CREDENTIALS', '*_CERT', '*_PRIVATE*',
37
+ 'AWS_*', 'OPENAI_*', 'ANTHROPIC_*', 'GOOGLE_*API*',
38
+ 'GROK_API*', 'MORPH_API*', 'EXA_API*', 'BRAVE_API*',
39
+ 'PERPLEXITY_API*', 'OPENROUTER_API*', 'PICOVOICE_*',
40
+ 'DATABASE_URL', 'MONGO_*', 'REDIS_*', 'POSTGRES_*', 'MYSQL_*',
41
+ 'JWT_SECRET', 'SESSION_SECRET', 'COOKIE_SECRET',
42
+ 'SLACK_*TOKEN*', 'TELEGRAM_*TOKEN*', 'DISCORD_*TOKEN*',
43
+ 'STRIPE_*', 'TWILIO_*', 'SENDGRID_*',
44
+ ];
45
+ // ============================================================================
46
+ // Glob-style pattern matching (lightweight, no deps)
47
+ // ============================================================================
48
+ function globMatch(pattern, str) {
49
+ // Convert glob to regex: * → [^_]* within a word segment, handle leading/trailing *
50
+ const regexStr = pattern
51
+ .toUpperCase()
52
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&') // escape regex special chars
53
+ .replace(/\*/g, '.*');
54
+ try {
55
+ return new RegExp(`^${regexStr}$`).test(str.toUpperCase());
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ }
61
+ function matchesAny(patterns, key) {
62
+ return patterns.some(p => globMatch(p, key));
63
+ }
64
+ // ============================================================================
65
+ // ShellEnvPolicy
66
+ // ============================================================================
67
+ export class ShellEnvPolicy {
68
+ config;
69
+ constructor(config = {}) {
70
+ this.config = {
71
+ inherit: config.inherit ?? 'all',
72
+ exclude: config.exclude ?? DEFAULT_EXCLUDE_PATTERNS,
73
+ include_only: config.include_only ?? [],
74
+ set: config.set ?? {},
75
+ };
76
+ }
77
+ /**
78
+ * Build a filtered environment object for subprocess spawning.
79
+ * Returns a new object — never mutates process.env.
80
+ */
81
+ buildEnv(source = process.env) {
82
+ let env = {};
83
+ // Step 1: baseline from inherit mode
84
+ if (this.config.inherit === 'all') {
85
+ env = { ...source };
86
+ }
87
+ else if (this.config.inherit === 'core') {
88
+ for (const key of Object.keys(source)) {
89
+ if (CORE_VARS.has(key)) {
90
+ env[key] = source[key];
91
+ }
92
+ }
93
+ }
94
+ // 'none' starts with empty {}
95
+ // Step 2: apply include_only whitelist (takes priority over exclude)
96
+ if (this.config.include_only.length > 0) {
97
+ const whitelisted = {};
98
+ for (const key of Object.keys(env)) {
99
+ if (matchesAny(this.config.include_only, key)) {
100
+ whitelisted[key] = env[key];
101
+ }
102
+ }
103
+ env = whitelisted;
104
+ }
105
+ else {
106
+ // Step 3: apply exclude patterns
107
+ for (const key of Object.keys(env)) {
108
+ if (matchesAny(this.config.exclude, key)) {
109
+ delete env[key];
110
+ logger.debug(`ShellEnvPolicy: stripped env var ${key}`);
111
+ }
112
+ }
113
+ }
114
+ // Step 4: inject forced overrides
115
+ for (const [key, value] of Object.entries(this.config.set)) {
116
+ env[key] = value;
117
+ }
118
+ return env;
119
+ }
120
+ /**
121
+ * Check if a specific env var would be passed through.
122
+ */
123
+ wouldPass(key) {
124
+ const built = this.buildEnv({ [key]: 'test' });
125
+ return key in built;
126
+ }
127
+ }
128
+ // ============================================================================
129
+ // Singleton
130
+ // ============================================================================
131
+ let _policy = null;
132
+ export function getShellEnvPolicy(config) {
133
+ if (!_policy) {
134
+ _policy = new ShellEnvPolicy(config);
135
+ }
136
+ return _policy;
137
+ }
138
+ export function resetShellEnvPolicy() {
139
+ _policy = null;
140
+ }
141
+ //# sourceMappingURL=shell-env-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-env-policy.js","sourceRoot":"","sources":["../../src/security/shell-env-policy.ts"],"names":[],"mappings":"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"}
@@ -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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"}