micro-models-agent 0.52.0 → 0.52.1

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 (231) hide show
  1. package/README.md +358 -358
  2. package/dist/main.js +244 -122
  3. package/dist/modules/browser/bridge-server.mjs +202 -202
  4. package/dist/skills/builtin/git.md +36 -36
  5. package/dist/skills/builtin/typescript.md +35 -35
  6. package/package.json +1 -1
  7. package/dist/cli/commands.js +0 -447
  8. package/dist/cli/completer.js +0 -167
  9. package/dist/cli/index.js +0 -2
  10. package/dist/cli/main.js +0 -153
  11. package/dist/cli/plugin-commands.js +0 -36
  12. package/dist/cli/repl-commands.js +0 -761
  13. package/dist/cli/repl.js +0 -702
  14. package/dist/cli/run-result.js +0 -33
  15. package/dist/cli/security-commands.js +0 -164
  16. package/dist/cli/setup.js +0 -237
  17. package/dist/config/config.js +0 -276
  18. package/dist/config/defaults.js +0 -141
  19. package/dist/config/domains.js +0 -179
  20. package/dist/config/experts.js +0 -15
  21. package/dist/config/index.js +0 -4
  22. package/dist/config/security.js +0 -213
  23. package/dist/config/types.js +0 -1
  24. package/dist/core/agent-moe.js +0 -102
  25. package/dist/core/agent.js +0 -1018
  26. package/dist/core/bootstrap.js +0 -481
  27. package/dist/core/crash-handler.js +0 -51
  28. package/dist/core/environment.js +0 -199
  29. package/dist/core/index.js +0 -2
  30. package/dist/core/prompt-builder.js +0 -76
  31. package/dist/core/session-logger.js +0 -251
  32. package/dist/core/types.js +0 -1
  33. package/dist/core/version.js +0 -26
  34. package/dist/core/workspace.js +0 -76
  35. package/dist/i18n/en.json +0 -679
  36. package/dist/i18n/index.js +0 -46
  37. package/dist/i18n/ru.json +0 -679
  38. package/dist/index.js +0 -22
  39. package/dist/llm/image-utils.js +0 -143
  40. package/dist/llm/index.js +0 -4
  41. package/dist/llm/model-loader.js +0 -78
  42. package/dist/llm/openai-compat.js +0 -497
  43. package/dist/llm/orchestrator.js +0 -200
  44. package/dist/llm/provider.js +0 -10
  45. package/dist/llm/response.js +0 -39
  46. package/dist/llm/token-counter.js +0 -39
  47. package/dist/llm/types.js +0 -1
  48. package/dist/logger/app-logger.js +0 -189
  49. package/dist/logger/file-log.js +0 -151
  50. package/dist/logger/index.js +0 -1
  51. package/dist/migration/backup.js +0 -45
  52. package/dist/migration/detect.js +0 -50
  53. package/dist/migration/index.js +0 -2
  54. package/dist/modules/artifacts/store.js +0 -61
  55. package/dist/modules/browser/actions.js +0 -76
  56. package/dist/modules/browser/bridge-client.js +0 -199
  57. package/dist/modules/browser/bridge-path.js +0 -10
  58. package/dist/modules/browser/cookie-store.js +0 -24
  59. package/dist/modules/browser/driver.js +0 -136
  60. package/dist/modules/browser/index.js +0 -7
  61. package/dist/modules/browser/module.js +0 -29
  62. package/dist/modules/browser/session.js +0 -342
  63. package/dist/modules/browser/snapshot.js +0 -148
  64. package/dist/modules/browser/types.js +0 -12
  65. package/dist/modules/certification/cli.js +0 -213
  66. package/dist/modules/certification/fact-checker.js +0 -82
  67. package/dist/modules/certification/loader.js +0 -106
  68. package/dist/modules/certification/manifest.js +0 -58
  69. package/dist/modules/certification/runner.js +0 -245
  70. package/dist/modules/certification/scenarios.js +0 -407
  71. package/dist/modules/certification/types.js +0 -1
  72. package/dist/modules/context/chunk-query.js +0 -100
  73. package/dist/modules/context/fact-extractor.js +0 -168
  74. package/dist/modules/context/history.js +0 -15
  75. package/dist/modules/context/index.js +0 -1
  76. package/dist/modules/context/manager.js +0 -440
  77. package/dist/modules/execution/audit-runners.js +0 -206
  78. package/dist/modules/execution/auditor.js +0 -218
  79. package/dist/modules/execution/execution-plugin.js +0 -431
  80. package/dist/modules/execution/index.js +0 -8
  81. package/dist/modules/execution/module.js +0 -625
  82. package/dist/modules/execution/moe-executor.js +0 -304
  83. package/dist/modules/execution/plan-coverage.js +0 -68
  84. package/dist/modules/execution/plan-persister.js +0 -46
  85. package/dist/modules/execution/plan-store.js +0 -196
  86. package/dist/modules/execution/plan-tool.js +0 -677
  87. package/dist/modules/execution/plan-validator.js +0 -153
  88. package/dist/modules/execution/planner.js +0 -94
  89. package/dist/modules/execution/stuck-detector.js +0 -746
  90. package/dist/modules/execution/tracker.js +0 -69
  91. package/dist/modules/execution/types.js +0 -1
  92. package/dist/modules/execution/verifier.js +0 -235
  93. package/dist/modules/execution/windows-commands.js +0 -41
  94. package/dist/modules/hallucination/confidence.js +0 -66
  95. package/dist/modules/hallucination/consistency.js +0 -26
  96. package/dist/modules/hallucination/detector.js +0 -47
  97. package/dist/modules/hallucination/factual.js +0 -169
  98. package/dist/modules/hallucination/index.js +0 -5
  99. package/dist/modules/hallucination/js-identifiers.js +0 -262
  100. package/dist/modules/hallucination/llm-judge.js +0 -101
  101. package/dist/modules/index.js +0 -5
  102. package/dist/modules/indexer/cache.js +0 -40
  103. package/dist/modules/indexer/index.js +0 -3
  104. package/dist/modules/indexer/module.js +0 -246
  105. package/dist/modules/indexer/project-profile.js +0 -183
  106. package/dist/modules/indexer/walker.js +0 -101
  107. package/dist/modules/lsp/check-tool.js +0 -58
  108. package/dist/modules/lsp/client.js +0 -389
  109. package/dist/modules/lsp/command.js +0 -60
  110. package/dist/modules/lsp/config.js +0 -135
  111. package/dist/modules/lsp/index.js +0 -3
  112. package/dist/modules/lsp/module.js +0 -260
  113. package/dist/modules/lsp/probe.js +0 -86
  114. package/dist/modules/lsp/project-root.js +0 -32
  115. package/dist/modules/lsp/startup-check.js +0 -144
  116. package/dist/modules/lsp/types.js +0 -1
  117. package/dist/modules/mcp/client.js +0 -399
  118. package/dist/modules/mcp/index.js +0 -3
  119. package/dist/modules/mcp/module.js +0 -142
  120. package/dist/modules/mcp/registry.js +0 -15
  121. package/dist/modules/memory/index.js +0 -1
  122. package/dist/modules/memory/module.js +0 -96
  123. package/dist/modules/memory/search.js +0 -42
  124. package/dist/modules/memory/store.js +0 -69
  125. package/dist/modules/pipelines/engine.js +0 -60
  126. package/dist/modules/pipelines/index.js +0 -3
  127. package/dist/modules/pipelines/parser.js +0 -56
  128. package/dist/modules/pipelines/template.js +0 -14
  129. package/dist/modules/plugins/builtin/lint-on-write.js +0 -334
  130. package/dist/modules/plugins/builtin/notify.js +0 -9
  131. package/dist/modules/plugins/index.js +0 -1
  132. package/dist/modules/plugins/loader.js +0 -70
  133. package/dist/modules/plugins/manager.js +0 -261
  134. package/dist/modules/plugins/types.js +0 -1
  135. package/dist/modules/pricing/index.js +0 -61
  136. package/dist/modules/pricing/prices.js +0 -129
  137. package/dist/modules/processes/detect.js +0 -34
  138. package/dist/modules/processes/index.js +0 -2
  139. package/dist/modules/processes/registry.js +0 -327
  140. package/dist/modules/processes/runner.js +0 -23
  141. package/dist/modules/providers/create.js +0 -22
  142. package/dist/modules/providers/fallback.js +0 -79
  143. package/dist/modules/providers/health.js +0 -46
  144. package/dist/modules/providers/index.js +0 -5
  145. package/dist/modules/providers/manager.js +0 -161
  146. package/dist/modules/providers/presets.js +0 -128
  147. package/dist/modules/providers/registry.js +0 -22
  148. package/dist/modules/providers/types.js +0 -1
  149. package/dist/modules/registry.js +0 -48
  150. package/dist/modules/security/audit-log.js +0 -136
  151. package/dist/modules/security/audit-notifier.js +0 -292
  152. package/dist/modules/security/command-validator.js +0 -219
  153. package/dist/modules/security/content-scanner.js +0 -53
  154. package/dist/modules/security/data-sanitizer.js +0 -89
  155. package/dist/modules/security/encryption.js +0 -242
  156. package/dist/modules/security/index.js +0 -14
  157. package/dist/modules/security/network-validator.js +0 -88
  158. package/dist/modules/security/path-validator.js +0 -203
  159. package/dist/modules/security/rate-limiter.js +0 -119
  160. package/dist/modules/security/security-policies.js +0 -531
  161. package/dist/modules/security/session-encryption.js +0 -210
  162. package/dist/modules/security/session-isolation.js +0 -95
  163. package/dist/modules/session/index.js +0 -3
  164. package/dist/modules/session/manager.js +0 -172
  165. package/dist/modules/session/module.js +0 -24
  166. package/dist/modules/session/store.js +0 -222
  167. package/dist/modules/session/types.js +0 -1
  168. package/dist/modules/skills/index.js +0 -2
  169. package/dist/modules/skills/loader.js +0 -72
  170. package/dist/modules/skills/matcher.js +0 -27
  171. package/dist/modules/skills/module.js +0 -129
  172. package/dist/modules/types.js +0 -1
  173. package/dist/modules/updater/checker.js +0 -96
  174. package/dist/modules/updater/index.js +0 -2
  175. package/dist/modules/updater/module.js +0 -116
  176. package/dist/modules/user-profile/compressor.js +0 -16
  177. package/dist/modules/user-profile/index.js +0 -1
  178. package/dist/modules/user-profile/profile.js +0 -68
  179. package/dist/tools/approve.js +0 -33
  180. package/dist/tools/attach-image.js +0 -101
  181. package/dist/tools/bash.js +0 -519
  182. package/dist/tools/browser.js +0 -115
  183. package/dist/tools/chunk-query.js +0 -100
  184. package/dist/tools/create-dir.js +0 -56
  185. package/dist/tools/delete-file.js +0 -63
  186. package/dist/tools/download-file.js +0 -117
  187. package/dist/tools/edit-file.js +0 -80
  188. package/dist/tools/enable-tools.js +0 -59
  189. package/dist/tools/executor.js +0 -154
  190. package/dist/tools/file-info.js +0 -47
  191. package/dist/tools/filter-tools.js +0 -17
  192. package/dist/tools/glob-tool.js +0 -27
  193. package/dist/tools/grep-tool.js +0 -125
  194. package/dist/tools/hidden-tools-block.js +0 -37
  195. package/dist/tools/index.js +0 -78
  196. package/dist/tools/list-dir.js +0 -49
  197. package/dist/tools/load-skill.js +0 -43
  198. package/dist/tools/mcp-call.js +0 -69
  199. package/dist/tools/move-file.js +0 -86
  200. package/dist/tools/path-utils.js +0 -101
  201. package/dist/tools/pipeline-run.js +0 -145
  202. package/dist/tools/preview.js +0 -2
  203. package/dist/tools/process-kill.js +0 -40
  204. package/dist/tools/process-list.js +0 -37
  205. package/dist/tools/process-log.js +0 -54
  206. package/dist/tools/question.js +0 -141
  207. package/dist/tools/read-file.js +0 -179
  208. package/dist/tools/recall.js +0 -118
  209. package/dist/tools/registry.js +0 -47
  210. package/dist/tools/remember.js +0 -68
  211. package/dist/tools/scope-check.js +0 -32
  212. package/dist/tools/search-history.js +0 -85
  213. package/dist/tools/subagent.js +0 -196
  214. package/dist/tools/types.js +0 -1
  215. package/dist/tools/user-input.js +0 -123
  216. package/dist/tools/web-browse.js +0 -87
  217. package/dist/tools/web-fetch.js +0 -119
  218. package/dist/tools/web-search.js +0 -105
  219. package/dist/tools/write-file.js +0 -82
  220. package/dist/ui/box.js +0 -77
  221. package/dist/ui/colors.js +0 -4
  222. package/dist/ui/diff.js +0 -178
  223. package/dist/ui/index.js +0 -6
  224. package/dist/ui/line-editor.js +0 -822
  225. package/dist/ui/line-math.js +0 -73
  226. package/dist/ui/md-formatter.js +0 -212
  227. package/dist/ui/output.js +0 -13
  228. package/dist/ui/plan-view.js +0 -103
  229. package/dist/ui/renderer.js +0 -259
  230. package/dist/ui/spinner.js +0 -70
  231. package/dist/ui/table.js +0 -144
@@ -1,219 +0,0 @@
1
- import { DEFAULT_SECURITY_CONFIG } from "../../config/security";
2
- // Fallback in case DEFAULT_SECURITY_CONFIG is not available
3
- const FALLBACK_BASH_CONFIG = {
4
- enabled: false,
5
- blacklist: [
6
- "rm",
7
- "dd",
8
- "chmod",
9
- "wget",
10
- "curl",
11
- "scp",
12
- "ssh",
13
- "nc",
14
- "netcat",
15
- "powershell",
16
- "pwsh",
17
- "cmd",
18
- ],
19
- whitelist: [],
20
- blockDangerousFlags: false,
21
- dangerousFlags: ["--force", "-rf", "--no-preserve-root"],
22
- dangerousOperators: [">", ">>", "2>", "2>>", "|", "&&", "||", ";", "`"],
23
- logCommands: true,
24
- };
25
- export const DEFAULT_BASH_CONFIG = DEFAULT_SECURITY_CONFIG?.bash || FALLBACK_BASH_CONFIG;
26
- /**
27
- * Extract the actual base command from a shell command string.
28
- * Handles path prefixes, env assignments, and sudo.
29
- *
30
- * Examples:
31
- * "/usr/bin/rm -rf /" → "rm"
32
- * "sudo /usr/bin/rm file" → "rm"
33
- * "NODE_ENV=prod node app.js" → "node"
34
- * "env PATH=/x rm -rf /" → "rm"
35
- * "cmd=rm; $cmd -rf /" → "cmd" (variable indirection — not expanded)
36
- * "powershell Remove-Item x" → "Remove-Item"
37
- * "cmd /c del /s /q" → "del"
38
- */
39
- function extractBaseCommand(trimmed) {
40
- const tokens = trimmed.split(/\s+/);
41
- let i = 0;
42
- // Skip env assignments (KEY=val, KEY="val", etc.) and prefixed commands
43
- while (i < tokens.length) {
44
- const tok = tokens[i];
45
- if (/^[a-zA-Z_][a-zA-Z0-9_]*=/.test(tok)) {
46
- i++;
47
- continue;
48
- }
49
- if (tok === "sudo" || tok === "env" || tok === "command" || tok === "exec" || tok === "nohup") {
50
- i++;
51
- continue;
52
- }
53
- break;
54
- }
55
- if (i >= tokens.length)
56
- return tokens[0] ?? "";
57
- // Extract basename from path (e.g. /usr/bin/rm → rm)
58
- const raw = tokens[i];
59
- const parts = raw.split(/[\\/]/);
60
- const basename = parts[parts.length - 1] || raw;
61
- // Strip .exe/.cmd/.bat extensions for blacklist matching (e.g. powershell.exe → powershell)
62
- return basename.replace(/\.(exe|cmd|bat)$/i, "") || basename;
63
- }
64
- /**
65
- * Check if a shell operator appears as a standalone token in the command.
66
- * Uses regex with lookbehind/lookahead so that:
67
- * "&" does NOT match "&&" (AND operator)
68
- * "|" does NOT match "||" (OR operator)
69
- * ">" does NOT match ">>" (append)
70
- * "2>" does NOT match "2>>" (append stderr)
71
- */
72
- function containsOperator(command, op) {
73
- const escaped = op.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
74
- // For single-char operators that are prefixes of multi-char ones,
75
- // ensure they don't match when part of a longer sequence.
76
- // Note: "&" is no longer in dangerousOperators (&& is legitimate),
77
- // but keep the special case for defense-in-depth if manually added.
78
- if (op === "&")
79
- return /(?<!&)&(?!&)/.test(command);
80
- if (op === "|")
81
- return /(?<!\|)\|(?!\|)/.test(command);
82
- if (op === ">")
83
- return /(?<!>)>(?!>)/.test(command);
84
- // For everything else (including multi-char like ">>", "2>", "2>>", ";", "`"),
85
- // match literally.
86
- return new RegExp(escaped).test(command);
87
- }
88
- /**
89
- * Check if a command is allowed based on security configuration
90
- */
91
- export function isCommandAllowed(command, securityConfig) {
92
- // If security is disabled, allow everything
93
- if (!securityConfig?.enabled) {
94
- return { allowed: true, sanitizedCommand: command };
95
- }
96
- // Ensure config has all required fields
97
- let config = securityConfig;
98
- if (!config.blacklist || !Array.isArray(config.blacklist)) {
99
- config = {
100
- ...FALLBACK_BASH_CONFIG,
101
- enabled: config.enabled ?? FALLBACK_BASH_CONFIG.enabled,
102
- };
103
- }
104
- const trimmedCommand = command.trim();
105
- if (!trimmedCommand) {
106
- return { allowed: false, reason: "Empty command" };
107
- }
108
- // Shell wrappers are always blocked — they bypass all command validation.
109
- // The agent should use the bash tool directly, not shell interpreters.
110
- const ALWAYS_BLOCKED = ["powershell", "pwsh", "cmd"];
111
- const baseForShellCheck = extractBaseCommand(trimmedCommand);
112
- if (ALWAYS_BLOCKED.includes(baseForShellCheck)) {
113
- return {
114
- allowed: false,
115
- reason: `Shell wrapper "${baseForShellCheck}" is blocked — use the bash tool directly`,
116
- };
117
- }
118
- // Interpreters with -c/-e execute arbitrary code and bypass the blacklist.
119
- const INTERPRETER_FLAGS = /(?:^|\s)(?:bash|sh|zsh|dash|python|python3|node|bun|perl|ruby)\s+(?:-c|-e|--command|--eval)\b/;
120
- if (INTERPRETER_FLAGS.test(trimmedCommand)) {
121
- return { allowed: false, reason: "Interpreter -c/-e invocation is blocked" };
122
- }
123
- // Multi-line commands can hide blacklisted commands after a newline.
124
- if (/\r?\n/.test(trimmedCommand)) {
125
- return { allowed: false, reason: "Multi-line commands are blocked" };
126
- }
127
- // Chained commands bypass the base-command check (e.g. "echo hi; rm -rf /").
128
- if (/[;&|]/.test(trimmedCommand) &&
129
- /(^|[;&|\s])(rm|del|rd|dd|chmod|chown|wget|curl|nc|netcat|shutdown|reboot|mkfs|fdisk)\b/.test(trimmedCommand)) {
130
- return { allowed: false, reason: "Command chaining to a dangerous command is blocked" };
131
- }
132
- // Check dangerous operators FIRST — before parsing the base command.
133
- // e.g. "curl http://x | bash" must be caught even though curl isn't blacklisted.
134
- if (config.blockDangerousFlags) {
135
- for (const op of config.dangerousOperators || []) {
136
- if (containsOperator(trimmedCommand, op)) {
137
- return {
138
- allowed: false,
139
- reason: `Operator "${op}" is not allowed`,
140
- };
141
- }
142
- }
143
- }
144
- // Extract actual base command (handles paths, env vars, sudo)
145
- const baseCommand = extractBaseCommand(trimmedCommand);
146
- // Check whitelist first (if non-empty, only whitelisted commands are allowed)
147
- if (config.whitelist.length > 0) {
148
- if (!config.whitelist.includes(baseCommand)) {
149
- return {
150
- allowed: false,
151
- reason: `Command "${baseCommand}" is not in the whitelist`,
152
- };
153
- }
154
- }
155
- // Check blacklist (against the extracted basename, not the raw token)
156
- if (config.blacklist.includes(baseCommand)) {
157
- return {
158
- allowed: false,
159
- reason: `Command "${baseCommand}" is blacklisted`,
160
- };
161
- }
162
- // Also check the raw first token in case it's a simple name
163
- const rawFirst = trimmedCommand.split(/\s+/)[0].replace(/\.(exe|cmd|bat)$/i, "");
164
- if (rawFirst !== baseCommand && config.blacklist.includes(rawFirst)) {
165
- return {
166
- allowed: false,
167
- reason: `Command "${rawFirst}" is blacklisted`,
168
- };
169
- }
170
- // Check for dangerous flags
171
- if (config.blockDangerousFlags) {
172
- for (const flag of config.dangerousFlags || []) {
173
- // Check for flag as whole word or with equals
174
- const flagPattern = new RegExp(`(?:^|\\s)${flag}(?:\\s|$|=)`);
175
- if (flagPattern.test(trimmedCommand)) {
176
- return {
177
- allowed: false,
178
- reason: `Dangerous flag "${flag}" is not allowed`,
179
- };
180
- }
181
- }
182
- }
183
- // Command is allowed
184
- return { allowed: true, sanitizedCommand: command };
185
- }
186
- /**
187
- * Sanitize command for logging (remove sensitive information)
188
- * Uses the same patterns as sanitizeLogMessage for consistency
189
- */
190
- export function sanitizeCommandForLog(command) {
191
- // Import patterns from data-sanitizer to maintain consistency
192
- const patterns = [
193
- /(api[_-]?key|apikey|api_key)\s*[=:\s]\s*["']?([a-zA-Z0-9_-]{10,})["']?/gi,
194
- /(token|access[_-]?token|auth[_-]?token)\s*[=:\s]\s*["']?([a-zA-Z0-9_-]{10,})["']?/gi,
195
- /(password|passwd|pwd|pass)\s*[=:\s]\s*["']?([^\s"'&]+)["']?/gi,
196
- /(secret|private[_-]?key|secret[_-]?key)\s*[=:\s]\s*["']?([^\s"'&]+)["']?/gi,
197
- /\bsk-[a-zA-Z0-9_-]{20,}\b/gi,
198
- /\bctx7sk-[a-zA-Z0-9_-]{10,}\b/gi,
199
- /\bghp_[a-zA-Z0-9]{30,}\b/gi,
200
- /\bgithub_pat_[a-zA-Z0-9]{20,}\b/gi,
201
- /\bAKIA[0-9A-Z]{15,}\b/gi,
202
- /Bearer\s+[a-zA-Z0-9_-]{20,}/gi,
203
- /\b([a-zA-Z0-9_-]{30,})\b/g,
204
- ];
205
- let sanitized = command;
206
- for (const pattern of patterns) {
207
- if (pattern.toString().includes("($1")) {
208
- // For patterns with capture groups, use the group in replacement
209
- sanitized = sanitized.replace(pattern, (match, p1) => {
210
- return `${p1}=[REDACTED]`;
211
- });
212
- }
213
- else {
214
- // For simple patterns, just replace with [REDACTED]
215
- sanitized = sanitized.replace(pattern, "[REDACTED]");
216
- }
217
- }
218
- return sanitized;
219
- }
@@ -1,53 +0,0 @@
1
- /**
2
- * Default dangerous patterns to scan for in file content.
3
- * NOTE: only genuinely dangerous constructs are listed. Legitimate runtime
4
- * APIs (process.exit, setTimeout/setInterval, template literals `${}`,
5
- * backtick strings) are NOT scanned — they are valid JS/TS and blocking
6
- * them breaks ordinary CLI code (false positives).
7
- */
8
- const DEFAULT_DANGEROUS_PATTERNS = [
9
- /eval\(/gi,
10
- /new Function\(/gi,
11
- /child_process\.exec\(/gi,
12
- /child_process\.spawn\(/gi,
13
- /require\('child_process'\)/gi,
14
- /require\('http'\).createServer/gi,
15
- /require\('net'\).createServer/gi,
16
- /require\('fs'\).writeFileSync/gi,
17
- /require\('fs'\).unlinkSync/gi,
18
- /while\(true\)/gi,
19
- /for\(;;\)/gi,
20
- /rm -rf/gi,
21
- /dd if=/gi,
22
- /chmod 777/gi,
23
- /wget.*\|.*sh/gi,
24
- /curl.*\|.*sh/gi,
25
- ];
26
- /**
27
- * Scan file content for dangerous patterns
28
- */
29
- export function scanContent(content, filePath, config) {
30
- // If scanning is disabled, allow everything
31
- if (!config?.enabled) {
32
- return { allowed: true };
33
- }
34
- // Use default patterns if none provided
35
- const patterns = config.dangerousPatterns?.length
36
- ? config.dangerousPatterns
37
- : DEFAULT_DANGEROUS_PATTERNS;
38
- const matches = [];
39
- for (const pattern of patterns) {
40
- const match = content.match(pattern);
41
- if (match) {
42
- matches.push(...match);
43
- }
44
- }
45
- if (matches.length > 0) {
46
- return {
47
- allowed: false,
48
- reason: `Content contains dangerous patterns in ${filePath}: ${matches.slice(0, 3).join(", ")}`,
49
- matches,
50
- };
51
- }
52
- return { allowed: true };
53
- }
@@ -1,89 +0,0 @@
1
- /**
2
- * Patterns for sensitive data that should be redacted from logs
3
- */
4
- const SENSITIVE_PATTERNS = [
5
- // API keys and tokens in key=value format
6
- {
7
- pattern: /(api[_-]?key|apikey|api_key)\s*[=:\s]\s*["']?([a-zA-Z0-9_-]{10,})["']?/gi,
8
- replacement: "$1=[REDACTED]",
9
- },
10
- {
11
- pattern: /(token|access[_-]?token|auth[_-]?token)\s*[=:\s]\s*["']?([a-zA-Z0-9_-]{10,})["']?/gi,
12
- replacement: "$1=[REDACTED]",
13
- },
14
- {
15
- pattern: /(password|passwd|pwd|pass)\s*[=:\s]\s*["']?([^\s"'&]+)["']?/gi,
16
- replacement: "$1=[REDACTED]",
17
- },
18
- {
19
- pattern: /(secret|private[_-]?key|secret[_-]?key)\s*[=:\s]\s*["']?([^\s"'&]+)["']?/gi,
20
- replacement: "$1=[REDACTED]",
21
- },
22
- // Standalone API keys (not in key=value format)
23
- {
24
- pattern: /\bsk-[a-zA-Z0-9_-]{20,}\b/gi,
25
- replacement: "sk-[REDACTED]",
26
- },
27
- {
28
- pattern: /\bctx7sk-[a-zA-Z0-9_-]{10,}\b/gi,
29
- replacement: "ctx7sk-[REDACTED]",
30
- },
31
- {
32
- pattern: /\bghp_[a-zA-Z0-9]{30,}\b/gi,
33
- replacement: "ghp_[REDACTED]",
34
- },
35
- {
36
- pattern: /\bgithub_pat_[a-zA-Z0-9]{20,}\b/gi,
37
- replacement: "github_pat_[REDACTED]",
38
- },
39
- {
40
- pattern: /\bAKIA[0-9A-Z]{15,}\b/gi,
41
- replacement: "AKIA[REDACTED]",
42
- },
43
- // Bearer tokens in headers
44
- {
45
- pattern: /Bearer\s+[a-zA-Z0-9_-]{20,}/gi,
46
- replacement: "Bearer [REDACTED]",
47
- },
48
- // Generic high-entropy strings that look like secrets (30+ chars, mixed case and numbers)
49
- {
50
- pattern: /\b([a-zA-Z0-9_-]{30,})\b/g,
51
- replacement: "[REDACTED]",
52
- },
53
- ];
54
- /**
55
- * Sanitize a log message by removing sensitive information
56
- */
57
- export function sanitizeLogMessage(message) {
58
- let sanitized = message;
59
- for (const { pattern, replacement } of SENSITIVE_PATTERNS) {
60
- sanitized = sanitized.replace(pattern, replacement);
61
- }
62
- return sanitized;
63
- }
64
- /**
65
- * Sanitize a command string by removing sensitive information
66
- */
67
- export function sanitizeCommand(command) {
68
- return sanitizeLogMessage(command);
69
- }
70
- /**
71
- * Sanitize a URL by removing sensitive query parameters
72
- */
73
- export function sanitizeUrl(url) {
74
- try {
75
- const urlObj = new URL(url);
76
- const sensitiveKeys = ["api_key", "token", "password", "secret", "access_token", "auth", "key"];
77
- const sanitizedParams = new URLSearchParams(urlObj.search);
78
- for (const key of sensitiveKeys) {
79
- if (sanitizedParams.has(key)) {
80
- sanitizedParams.set(key, "[REDACTED]");
81
- }
82
- }
83
- urlObj.search = sanitizedParams.toString();
84
- return urlObj.toString();
85
- }
86
- catch {
87
- return sanitizeLogMessage(url);
88
- }
89
- }
@@ -1,242 +0,0 @@
1
- import { createCipheriv, createDecipheriv, randomBytes, scryptSync, timingSafeEqual } from "node:crypto";
2
- import { homedir } from "os";
3
- import { join } from "path";
4
- import { readFileSync, writeFileSync, existsSync, copyFileSync } from "fs";
5
- const DEFAULT_CONFIG = {
6
- keyPath: join(homedir(), ".mma", ".encryption-key"),
7
- algorithm: "aes-256-gcm",
8
- };
9
- const IV_LENGTH = 16;
10
- const SALT_LENGTH = 16;
11
- const KEY_LENGTH = 32;
12
- const AUTH_TAG_LENGTH = 16;
13
- /**
14
- * Generate a new encryption key
15
- */
16
- export function generateEncryptionKey() {
17
- return randomBytes(KEY_LENGTH);
18
- }
19
- /**
20
- * Get or create encryption key from file
21
- */
22
- export function getOrCreateEncryptionKey(config) {
23
- const { keyPath } = { ...DEFAULT_CONFIG, ...config };
24
- // Ensure directory exists
25
- const dir = join(keyPath, "..");
26
- if (!existsSync(dir)) {
27
- // Note: We can't use mkdirSync here because we're in a pure function
28
- // This will be handled by the caller
29
- }
30
- if (!existsSync(keyPath)) {
31
- const key = generateEncryptionKey();
32
- try {
33
- writeFileSync(keyPath, key.toString("base64"), { mode: 0o600 });
34
- return key;
35
- }
36
- catch (e) {
37
- // If we can't persist the key, encrypted data would be unrecoverable
38
- // on the next run — fail loudly instead of silently degrading.
39
- throw new Error(`Cannot write encryption key to ${keyPath}: ${e instanceof Error ? e.message : String(e)}`);
40
- }
41
- }
42
- try {
43
- const keyBase64 = readFileSync(keyPath, "utf8");
44
- return Buffer.from(keyBase64, "base64");
45
- }
46
- catch {
47
- // Backup the corrupted key file before throwing
48
- try {
49
- const backupPath = `${keyPath}.corrupted.${Date.now()}`;
50
- copyFileSync(keyPath, backupPath);
51
- }
52
- catch {
53
- /* backup failed, continue */
54
- }
55
- throw new Error(`Encryption key file is corrupted or unreadable: ${keyPath}. ` +
56
- `All previously encrypted data will be unrecoverable. ` +
57
- `Delete the key file to generate a new one.`);
58
- }
59
- }
60
- /**
61
- * Encrypt a string using AES-256-GCM
62
- * Note: Bun's crypto module doesn't support getAuthTag/setAuthTag directly,
63
- * so we use a simpler approach with AES-256-CBC + HMAC for authentication
64
- */
65
- export function encryptString(plaintext, key) {
66
- const iv = randomBytes(IV_LENGTH);
67
- const salt = randomBytes(SALT_LENGTH);
68
- // Derive encryption key and HMAC key from the main key
69
- const encKey = scryptSync(key, salt, KEY_LENGTH);
70
- const hmacSalt = Buffer.concat([salt, Buffer.from([1, 2, 3, 4])]);
71
- const hmacKey = scryptSync(key, hmacSalt, KEY_LENGTH);
72
- // Encrypt with AES-256-CBC
73
- const cipher = createCipheriv("aes-256-cbc", encKey, iv);
74
- let encrypted = cipher.update(plaintext, "utf8", "base64");
75
- encrypted += cipher.final("base64");
76
- // Create HMAC for authentication
77
- const hmac = createHmac("sha256", hmacKey);
78
- hmac.update(iv);
79
- hmac.update(Buffer.from(encrypted, "base64"));
80
- const authTag = hmac.digest();
81
- // Format: salt:iv:authTag:encrypted
82
- return `${salt.toString("base64")}:${iv.toString("base64")}:${authTag.toString("base64")}:${encrypted}`;
83
- }
84
- /**
85
- * Decrypt a string using AES-256-CBC + HMAC
86
- */
87
- export function decryptString(encryptedText, key) {
88
- const parts = encryptedText.split(":");
89
- if (parts.length !== 4) {
90
- throw new Error("Invalid encrypted format");
91
- }
92
- const salt = Buffer.from(parts[0], "base64");
93
- const iv = Buffer.from(parts[1], "base64");
94
- const authTag = Buffer.from(parts[2], "base64");
95
- const encrypted = parts[3];
96
- // Derive encryption key and HMAC key from the main key
97
- const encKey = scryptSync(key, salt, KEY_LENGTH);
98
- const hmacSalt = Buffer.concat([salt, Buffer.from([1, 2, 3, 4])]);
99
- const hmacKey = scryptSync(key, hmacSalt, KEY_LENGTH);
100
- // Verify HMAC
101
- const hmac = createHmac("sha256", hmacKey);
102
- hmac.update(iv);
103
- hmac.update(Buffer.from(encrypted, "base64"));
104
- const computedTag = hmac.digest();
105
- if (computedTag.length !== authTag.length || !timingSafeEqual(computedTag, authTag)) {
106
- throw new Error("Authentication failed: invalid tag");
107
- }
108
- // Decrypt with AES-256-CBC
109
- const decipher = createDecipheriv("aes-256-cbc", encKey, iv);
110
- let decrypted = decipher.update(encrypted, "base64", "utf8");
111
- decrypted += decipher.final("utf8");
112
- return decrypted;
113
- }
114
- import { createHmac } from "node:crypto";
115
- /**
116
- * Check if a string looks like it's encrypted
117
- */
118
- export function isEncryptedString(value) {
119
- // Encrypted strings have the format: salt:iv:authTag:encrypted
120
- // Each part is base64 encoded and separated by colons
121
- const parts = value.split(":");
122
- if (parts.length !== 4)
123
- return false;
124
- // Check if all parts are valid base64
125
- try {
126
- Buffer.from(parts[0], "base64");
127
- Buffer.from(parts[1], "base64");
128
- Buffer.from(parts[2], "base64");
129
- Buffer.from(parts[3], "base64");
130
- return true;
131
- }
132
- catch {
133
- return false;
134
- }
135
- }
136
- /**
137
- * Sensitive field names that should be encrypted
138
- */
139
- export const SENSITIVE_FIELD_NAMES = [
140
- "api_key",
141
- "apikey",
142
- "apiKey",
143
- "token",
144
- "access_token",
145
- "accessToken",
146
- "password",
147
- "passwd",
148
- "pwd",
149
- "secret",
150
- "private_key",
151
- "privateKey",
152
- "auth",
153
- "authorization",
154
- "key",
155
- ];
156
- /**
157
- * Check if a field name indicates sensitive data
158
- */
159
- export function isSensitiveFieldName(fieldName) {
160
- const lowerFieldName = fieldName.toLowerCase();
161
- return SENSITIVE_FIELD_NAMES.some((name) => lowerFieldName.includes(name));
162
- }
163
- /**
164
- * Encrypt sensitive fields in an object
165
- */
166
- export function encryptSensitiveFields(obj, key) {
167
- const result = {};
168
- for (const [fieldName, value] of Object.entries(obj)) {
169
- if (isSensitiveFieldName(fieldName) && typeof value === "string" && !isEncryptedString(value)) {
170
- result[fieldName] = encryptString(value, key);
171
- }
172
- else if (typeof value === "object" && value !== null) {
173
- if (Array.isArray(value)) {
174
- result[fieldName] = value.map((item) => typeof item === "object" && item !== null && !(item instanceof RegExp)
175
- ? encryptSensitiveFields(item, key)
176
- : item);
177
- }
178
- else if (value instanceof RegExp) {
179
- result[fieldName] = value;
180
- }
181
- else {
182
- result[fieldName] = encryptSensitiveFields(value, key);
183
- }
184
- }
185
- else {
186
- result[fieldName] = value;
187
- }
188
- }
189
- return result;
190
- }
191
- /**
192
- * Decrypt sensitive fields in an object
193
- */
194
- export function decryptSensitiveFields(obj, key) {
195
- const result = {};
196
- for (const [fieldName, value] of Object.entries(obj)) {
197
- if (isSensitiveFieldName(fieldName) && typeof value === "string" && isEncryptedString(value)) {
198
- try {
199
- result[fieldName] = decryptString(value, key);
200
- }
201
- catch {
202
- // If decryption fails, keep the encrypted value
203
- result[fieldName] = value;
204
- }
205
- }
206
- else if (typeof value === "object" && value !== null) {
207
- if (Array.isArray(value)) {
208
- result[fieldName] = value.map((item) => typeof item === "object" && item !== null && !(item instanceof RegExp)
209
- ? decryptSensitiveFields(item, key)
210
- : item);
211
- }
212
- else if (value instanceof RegExp) {
213
- result[fieldName] = value;
214
- }
215
- else {
216
- result[fieldName] = decryptSensitiveFields(value, key);
217
- }
218
- }
219
- else {
220
- result[fieldName] = value;
221
- }
222
- }
223
- return result;
224
- }
225
- /**
226
- * Create a wrapper for encrypting/decrypting config values
227
- */
228
- export class ConfigEncryptor {
229
- key;
230
- constructor(config) {
231
- this.key = getOrCreateEncryptionKey(config);
232
- }
233
- encrypt(config) {
234
- return encryptSensitiveFields(config, this.key);
235
- }
236
- decrypt(config) {
237
- return decryptSensitiveFields(config, this.key);
238
- }
239
- getKey() {
240
- return this.key;
241
- }
242
- }
@@ -1,14 +0,0 @@
1
- export * from "./command-validator";
2
- export * from "./path-validator";
3
- export * from "./network-validator";
4
- export * from "./content-scanner";
5
- export * from "./data-sanitizer";
6
- export * from "./audit-log";
7
- export * from "./rate-limiter";
8
- export * from "./encryption";
9
- export * from "./session-isolation";
10
- export * from "./session-encryption";
11
- export * from "./audit-notifier";
12
- export * from "./security-policies";
13
- // Re-export sanitizeUrl from network-validator to avoid conflicts
14
- export { sanitizeUrl } from "./network-validator";