mstro-app 0.4.20 → 0.4.22

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 (177) hide show
  1. package/README.md +66 -0
  2. package/dist/server/cli/headless/claude-invoker-process.js +1 -1
  3. package/dist/server/cli/headless/claude-invoker-process.js.map +1 -1
  4. package/dist/server/cli/headless/headless-logger.js +1 -1
  5. package/dist/server/cli/headless/headless-logger.js.map +1 -1
  6. package/dist/server/cli/headless/mcp-config.d.ts +1 -1
  7. package/dist/server/cli/headless/mcp-config.d.ts.map +1 -1
  8. package/dist/server/cli/headless/mcp-config.js +4 -1
  9. package/dist/server/cli/headless/mcp-config.js.map +1 -1
  10. package/dist/server/cli/headless/runner.d.ts.map +1 -1
  11. package/dist/server/cli/headless/runner.js +1 -0
  12. package/dist/server/cli/headless/runner.js.map +1 -1
  13. package/dist/server/cli/headless/types.d.ts +4 -1
  14. package/dist/server/cli/headless/types.d.ts.map +1 -1
  15. package/dist/server/index.js +9 -1
  16. package/dist/server/index.js.map +1 -1
  17. package/dist/server/mcp/bouncer-integration.d.ts +2 -2
  18. package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
  19. package/dist/server/mcp/bouncer-integration.js +20 -20
  20. package/dist/server/mcp/bouncer-integration.js.map +1 -1
  21. package/dist/server/mcp/security-analysis.d.ts +6 -0
  22. package/dist/server/mcp/security-analysis.d.ts.map +1 -1
  23. package/dist/server/mcp/security-analysis.js +16 -1
  24. package/dist/server/mcp/security-analysis.js.map +1 -1
  25. package/dist/server/mcp/security-patterns.d.ts +8 -0
  26. package/dist/server/mcp/security-patterns.d.ts.map +1 -1
  27. package/dist/server/mcp/security-patterns.js +47 -2
  28. package/dist/server/mcp/security-patterns.js.map +1 -1
  29. package/dist/server/services/deploy/ai-broker.d.ts +63 -0
  30. package/dist/server/services/deploy/ai-broker.d.ts.map +1 -0
  31. package/dist/server/services/deploy/ai-broker.js +360 -0
  32. package/dist/server/services/deploy/ai-broker.js.map +1 -0
  33. package/dist/server/services/deploy/board-execution-handler.d.ts +114 -0
  34. package/dist/server/services/deploy/board-execution-handler.d.ts.map +1 -0
  35. package/dist/server/services/deploy/board-execution-handler.js +621 -0
  36. package/dist/server/services/deploy/board-execution-handler.js.map +1 -0
  37. package/dist/server/services/deploy/credentials.d.ts +35 -0
  38. package/dist/server/services/deploy/credentials.d.ts.map +1 -0
  39. package/dist/server/services/deploy/credentials.js +177 -0
  40. package/dist/server/services/deploy/credentials.js.map +1 -0
  41. package/dist/server/services/deploy/deploy-ai-service.d.ts +107 -0
  42. package/dist/server/services/deploy/deploy-ai-service.d.ts.map +1 -0
  43. package/dist/server/services/deploy/deploy-ai-service.js +294 -0
  44. package/dist/server/services/deploy/deploy-ai-service.js.map +1 -0
  45. package/dist/server/services/deploy/headless-session-handler.d.ts +94 -0
  46. package/dist/server/services/deploy/headless-session-handler.d.ts.map +1 -0
  47. package/dist/server/services/deploy/headless-session-handler.js +274 -0
  48. package/dist/server/services/deploy/headless-session-handler.js.map +1 -0
  49. package/dist/server/services/pathUtils.d.ts.map +1 -1
  50. package/dist/server/services/pathUtils.js +33 -1
  51. package/dist/server/services/pathUtils.js.map +1 -1
  52. package/dist/server/services/plan/agent-loader.d.ts +10 -0
  53. package/dist/server/services/plan/agent-loader.d.ts.map +1 -0
  54. package/dist/server/services/plan/agent-loader.js +65 -0
  55. package/dist/server/services/plan/agent-loader.js.map +1 -0
  56. package/dist/server/services/plan/composer.d.ts.map +1 -1
  57. package/dist/server/services/plan/composer.js +5 -1
  58. package/dist/server/services/plan/composer.js.map +1 -1
  59. package/dist/server/services/plan/dependency-resolver.d.ts +1 -1
  60. package/dist/server/services/plan/dependency-resolver.js +2 -2
  61. package/dist/server/services/plan/dependency-resolver.js.map +1 -1
  62. package/dist/server/services/plan/executor.d.ts +7 -3
  63. package/dist/server/services/plan/executor.d.ts.map +1 -1
  64. package/dist/server/services/plan/executor.js +27 -14
  65. package/dist/server/services/plan/executor.js.map +1 -1
  66. package/dist/server/services/plan/front-matter.d.ts +5 -0
  67. package/dist/server/services/plan/front-matter.d.ts.map +1 -1
  68. package/dist/server/services/plan/front-matter.js +19 -0
  69. package/dist/server/services/plan/front-matter.js.map +1 -1
  70. package/dist/server/services/plan/issue-prompt-builder.d.ts +1 -1
  71. package/dist/server/services/plan/issue-prompt-builder.d.ts.map +1 -1
  72. package/dist/server/services/plan/issue-prompt-builder.js +1 -1
  73. package/dist/server/services/plan/issue-retry.d.ts +25 -0
  74. package/dist/server/services/plan/issue-retry.d.ts.map +1 -0
  75. package/dist/server/services/plan/issue-retry.js +216 -0
  76. package/dist/server/services/plan/issue-retry.js.map +1 -0
  77. package/dist/server/services/plan/output-manager.d.ts +2 -2
  78. package/dist/server/services/plan/output-manager.js +2 -2
  79. package/dist/server/services/plan/parser-core.d.ts +1 -1
  80. package/dist/server/services/plan/parser-core.js +1 -1
  81. package/dist/server/services/plan/parser-core.js.map +1 -1
  82. package/dist/server/services/plan/parser-migration.d.ts +2 -2
  83. package/dist/server/services/plan/parser-migration.d.ts.map +1 -1
  84. package/dist/server/services/plan/parser-migration.js +5 -5
  85. package/dist/server/services/plan/parser-migration.js.map +1 -1
  86. package/dist/server/services/plan/parser.d.ts.map +1 -1
  87. package/dist/server/services/plan/parser.js +4 -7
  88. package/dist/server/services/plan/parser.js.map +1 -1
  89. package/dist/server/services/plan/prompt-builder.d.ts +1 -1
  90. package/dist/server/services/plan/prompt-builder.d.ts.map +1 -1
  91. package/dist/server/services/plan/review-gate.d.ts +4 -0
  92. package/dist/server/services/plan/review-gate.d.ts.map +1 -1
  93. package/dist/server/services/plan/review-gate.js +90 -35
  94. package/dist/server/services/plan/review-gate.js.map +1 -1
  95. package/dist/server/services/plan/state-reconciler.d.ts.map +1 -1
  96. package/dist/server/services/plan/state-reconciler.js +21 -11
  97. package/dist/server/services/plan/state-reconciler.js.map +1 -1
  98. package/dist/server/services/plan/types.d.ts +2 -2
  99. package/dist/server/services/plan/types.d.ts.map +1 -1
  100. package/dist/server/services/plan/watcher.js +1 -1
  101. package/dist/server/services/sentry.d.ts.map +1 -1
  102. package/dist/server/services/sentry.js +8 -4
  103. package/dist/server/services/sentry.js.map +1 -1
  104. package/dist/server/services/websocket/deploy-handlers.d.ts +14 -0
  105. package/dist/server/services/websocket/deploy-handlers.d.ts.map +1 -0
  106. package/dist/server/services/websocket/deploy-handlers.js +409 -0
  107. package/dist/server/services/websocket/deploy-handlers.js.map +1 -0
  108. package/dist/server/services/websocket/handler.d.ts.map +1 -1
  109. package/dist/server/services/websocket/handler.js +12 -0
  110. package/dist/server/services/websocket/handler.js.map +1 -1
  111. package/dist/server/services/websocket/handlers/deploy-handlers.d.ts +11 -0
  112. package/dist/server/services/websocket/handlers/deploy-handlers.d.ts.map +1 -0
  113. package/dist/server/services/websocket/handlers/deploy-handlers.js +180 -0
  114. package/dist/server/services/websocket/handlers/deploy-handlers.js.map +1 -0
  115. package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -1
  116. package/dist/server/services/websocket/plan-board-handlers.js +54 -1
  117. package/dist/server/services/websocket/plan-board-handlers.js.map +1 -1
  118. package/dist/server/services/websocket/plan-helpers.d.ts +1 -1
  119. package/dist/server/services/websocket/plan-helpers.d.ts.map +1 -1
  120. package/dist/server/services/websocket/plan-helpers.js +3 -4
  121. package/dist/server/services/websocket/plan-helpers.js.map +1 -1
  122. package/dist/server/services/websocket/plan-issue-handlers.d.ts.map +1 -1
  123. package/dist/server/services/websocket/plan-issue-handlers.js +5 -1
  124. package/dist/server/services/websocket/plan-issue-handlers.js.map +1 -1
  125. package/dist/server/services/websocket/plan-sprint-handlers.d.ts.map +1 -1
  126. package/dist/server/services/websocket/plan-sprint-handlers.js +3 -11
  127. package/dist/server/services/websocket/plan-sprint-handlers.js.map +1 -1
  128. package/dist/server/services/websocket/settings-handlers.d.ts.map +1 -1
  129. package/dist/server/services/websocket/settings-handlers.js +17 -21
  130. package/dist/server/services/websocket/settings-handlers.js.map +1 -1
  131. package/dist/server/services/websocket/types.d.ts +264 -2
  132. package/dist/server/services/websocket/types.d.ts.map +1 -1
  133. package/package.json +1 -1
  134. package/server/cli/headless/claude-invoker-process.ts +1 -1
  135. package/server/cli/headless/headless-logger.ts +1 -1
  136. package/server/cli/headless/mcp-config.ts +4 -1
  137. package/server/cli/headless/runner.ts +1 -0
  138. package/server/cli/headless/types.ts +4 -1
  139. package/server/index.ts +9 -1
  140. package/server/mcp/bouncer-integration.ts +19 -17
  141. package/server/mcp/security-analysis.ts +19 -0
  142. package/server/mcp/security-patterns.ts +53 -2
  143. package/server/services/deploy/ai-broker.ts +512 -0
  144. package/server/services/deploy/board-execution-handler.ts +847 -0
  145. package/server/services/deploy/credentials.ts +200 -0
  146. package/server/services/deploy/deploy-ai-service.ts +401 -0
  147. package/server/services/deploy/headless-session-handler.ts +415 -0
  148. package/server/services/pathUtils.ts +35 -1
  149. package/server/services/plan/agent-loader.ts +73 -0
  150. package/server/services/plan/agents/review-code.md +28 -0
  151. package/server/services/plan/agents/review-custom.md +27 -0
  152. package/server/services/plan/agents/review-quality.md +42 -0
  153. package/server/services/plan/composer.ts +5 -1
  154. package/server/services/plan/dependency-resolver.ts +2 -2
  155. package/server/services/plan/executor.ts +27 -15
  156. package/server/services/plan/front-matter.ts +23 -0
  157. package/server/services/plan/issue-prompt-builder.ts +2 -2
  158. package/server/services/plan/issue-retry.ts +297 -0
  159. package/server/services/plan/output-manager.ts +2 -2
  160. package/server/services/plan/parser-core.ts +2 -2
  161. package/server/services/plan/parser-migration.ts +5 -5
  162. package/server/services/plan/parser.ts +4 -5
  163. package/server/services/plan/prompt-builder.ts +1 -1
  164. package/server/services/plan/review-gate.ts +105 -34
  165. package/server/services/plan/state-reconciler.ts +21 -11
  166. package/server/services/plan/types.ts +3 -3
  167. package/server/services/plan/watcher.ts +1 -1
  168. package/server/services/sentry.ts +8 -4
  169. package/server/services/websocket/deploy-handlers.ts +544 -0
  170. package/server/services/websocket/handler.ts +11 -1
  171. package/server/services/websocket/handlers/deploy-handlers.ts +230 -0
  172. package/server/services/websocket/plan-board-handlers.ts +53 -1
  173. package/server/services/websocket/plan-helpers.ts +3 -4
  174. package/server/services/websocket/plan-issue-handlers.ts +6 -1
  175. package/server/services/websocket/plan-sprint-handlers.ts +3 -9
  176. package/server/services/websocket/settings-handlers.ts +18 -22
  177. package/server/services/websocket/types.ts +333 -2
@@ -123,6 +123,8 @@ export interface HeadlessConfig {
123
123
  extraEnv?: Record<string, string>;
124
124
  /** Tools to disallow in the spawned Claude session (passed as --disallowedTools) */
125
125
  disallowedTools?: string[];
126
+ /** Enable deploy-mode patterns in the bouncer (stricter rules for end-user-driven sessions) */
127
+ deployMode?: boolean;
126
128
  }
127
129
 
128
130
  export interface SessionState {
@@ -209,7 +211,7 @@ export interface ExecutionResult {
209
211
  }
210
212
 
211
213
  /** Resolved config with all defaults applied */
212
- export type ResolvedHeadlessConfig = Omit<Required<HeadlessConfig>, 'outputCallback' | 'thinkingCallback' | 'toolUseCallback' | 'tokenUsageCallback' | 'continueSession' | 'claudeSessionId' | 'imageAttachments' | 'model' | 'toolTimeoutProfiles' | 'onToolTimeout' | 'extraEnv' | 'disallowedTools'> & {
214
+ export type ResolvedHeadlessConfig = Omit<Required<HeadlessConfig>, 'outputCallback' | 'thinkingCallback' | 'toolUseCallback' | 'tokenUsageCallback' | 'continueSession' | 'claudeSessionId' | 'imageAttachments' | 'model' | 'toolTimeoutProfiles' | 'onToolTimeout' | 'extraEnv' | 'disallowedTools' | 'deployMode'> & {
213
215
  outputCallback?: (text: string) => void;
214
216
  thinkingCallback?: (text: string) => void;
215
217
  toolUseCallback?: (event: ToolUseEvent) => void;
@@ -222,6 +224,7 @@ export type ResolvedHeadlessConfig = Omit<Required<HeadlessConfig>, 'outputCallb
222
224
  onToolTimeout?: (checkpoint: ExecutionCheckpoint) => void;
223
225
  extraEnv?: Record<string, string>;
224
226
  disallowedTools?: string[];
227
+ deployMode?: boolean;
225
228
  };
226
229
 
227
230
 
package/server/index.ts CHANGED
@@ -27,6 +27,7 @@ import {
27
27
  import { createPlatformRelayContext, ensureClaudeSettings, setTerminalTitle, wrapWebSocket } from './server-setup.js'
28
28
  import { AnalyticsEvents, initAnalytics, shutdownAnalytics, trackEvent } from './services/analytics.js'
29
29
  import { AuthService } from './services/auth.js'
30
+ import { createAiBrokerRoutes, setDeployHealthUpdateListener, setDeployUsageReportListener } from './services/deploy/ai-broker.js'
30
31
  import { FileService } from './services/files.js'
31
32
  import { InstanceRegistry, type MstroInstance } from './services/instances.js'
32
33
  import { PlatformConnection } from './services/platform.js'
@@ -81,7 +82,7 @@ app.use('*', cors({
81
82
  app.use('*', logger())
82
83
 
83
84
  const authMiddleware = async (c: Context, next: Next) => {
84
- const publicPaths = ['/health', '/api/config']
85
+ const publicPaths = ['/health', '/api/config', '/api/deploy/ai']
85
86
  if (publicPaths.some(path => c.req.path.startsWith(path))) {
86
87
  return next()
87
88
  }
@@ -104,6 +105,7 @@ app.route('/api/shutdown', createShutdownRoute(instanceRegistry))
104
105
  app.route('/api/improvise', createImproviseRoutes(WORKING_DIR))
105
106
  app.route('/api/files', createFileRoutes(fileService))
106
107
  app.route('/api/notifications', createNotificationRoutes(WORKING_DIR))
108
+ app.route('/api/deploy/ai', createAiBrokerRoutes())
107
109
 
108
110
  app.post('/api/reload-pty', async (c) => {
109
111
  const success = await reloadPty()
@@ -193,6 +195,12 @@ async function startServer() {
193
195
  wsHandler.setUsageReporter((report) => {
194
196
  platformConnection.send({ type: 'reportUsage', data: report })
195
197
  })
198
+ setDeployUsageReportListener((report) => {
199
+ platformConnection.send({ type: 'deployUsageReport', data: report })
200
+ })
201
+ setDeployHealthUpdateListener((update) => {
202
+ platformConnection.send({ type: 'deployAiHealthUpdate', data: update })
203
+ })
196
204
  },
197
205
  onDisconnected: () => {
198
206
  if (platformRelayContext) {
@@ -19,6 +19,13 @@
19
19
  * │ - Defaults to ALLOW - user is actively working with Claude │
20
20
  * └─────────────────────────────────────────────────────────────┘
21
21
  *
22
+ * SECURITY BOUNDARY: Layer 1 is a performance optimization, NOT a
23
+ * security boundary. Haiku (Layer 2) is the security boundary.
24
+ * Layer 1 patterns are public (open-source repo) and should be
25
+ * treated as a fast-path filter only. Never expand SAFE_OPERATIONS
26
+ * to include operations with side effects beyond the user's
27
+ * working directory.
28
+ *
22
29
  * Haiku AI analysis lives in bouncer-haiku.ts.
23
30
  * Pattern definitions live in security-patterns.ts.
24
31
  * Analysis logic lives in security-analysis.ts.
@@ -168,8 +175,9 @@ async function runHaikuAnalysis(
168
175
  startTime: number,
169
176
  fin: (d: BouncerDecision, layer: string, opts?: Parameters<typeof finalizeDecision>[6]) => BouncerDecision,
170
177
  ): Promise<BouncerDecision> {
171
- if (process.env.BOUNCER_USE_AI === 'false') {
172
- console.error('[Bouncer] AI analysis disabled (BOUNCER_USE_AI=false)');
178
+ const aiDisabledByEnv = process.env.BOUNCER_USE_AI === 'false' && process.env.NODE_ENV !== 'production';
179
+ if (aiDisabledByEnv || request.context?._skipAI === true) {
180
+ console.error('[Bouncer] AI analysis disabled');
173
181
  return fin({ decision: 'warn_allow', confidence: 60, reasoning: 'Operation requires review but AI analysis is disabled. Proceeding with caution.', threatLevel: 'medium' }, 'ai-disabled', { skipCache: true, skipAnalytics: true });
174
182
  }
175
183
 
@@ -263,26 +271,20 @@ export { classifyRisk as classifyOperationRisk } from './security-patterns.js';
263
271
 
264
272
  /**
265
273
  * Legacy compatibility — redirects to reviewOperation.
266
- * When useAI=false, temporarily sets BOUNCER_USE_AI env var.
267
- * Uses a saved/restored pattern to avoid race conditions with concurrent calls.
274
+ * When useAI=false, skips AI analysis by injecting a context flag
275
+ * that runHaikuAnalysis checks (avoids racy process.env mutation).
268
276
  */
269
277
  export async function launchBouncerAgent(
270
278
  request: BouncerReviewRequest,
271
279
  useAI: boolean = true
272
280
  ): Promise<BouncerDecision> {
273
- const prevValue = process.env.BOUNCER_USE_AI;
274
281
  if (!useAI) {
275
- process.env.BOUNCER_USE_AI = 'false';
276
- }
277
- try {
278
- return await reviewOperation(request);
279
- } finally {
280
- if (!useAI) {
281
- if (prevValue !== undefined) {
282
- process.env.BOUNCER_USE_AI = prevValue;
283
- } else {
284
- delete process.env.BOUNCER_USE_AI;
285
- }
286
- }
282
+ // Inject skipAI flag into the request context so runHaikuAnalysis
283
+ // can check it without mutating process.env (which races under concurrency).
284
+ request = {
285
+ ...request,
286
+ context: { ...request.context, _skipAI: true },
287
+ };
287
288
  }
289
+ return reviewOperation(request);
288
290
  }
@@ -10,6 +10,7 @@
10
10
 
11
11
  import {
12
12
  CRITICAL_THREATS,
13
+ DEPLOY_PATTERNS,
13
14
  matchesPattern,
14
15
  NEEDS_AI_REVIEW,
15
16
  normalizeOperation,
@@ -62,6 +63,17 @@ function isSafeExpansionUse(operation: string): boolean {
62
63
  return safePrefix.test(cmd);
63
64
  }
64
65
 
66
+ // ── Deploy Mode Detection ────────────────────────────────────
67
+
68
+ /**
69
+ * Check if the bouncer is running in deploy mode.
70
+ * Set by the MCP config when spawned for deploy (board/headless) executions.
71
+ * Deploy mode activates additional security patterns for end-user-driven sessions.
72
+ */
73
+ export function isDeployMode(): boolean {
74
+ return process.env.BOUNCER_DEPLOY_MODE === 'true';
75
+ }
76
+
65
77
  // ── Public API ────────────────────────────────────────────────
66
78
 
67
79
  /**
@@ -104,6 +116,13 @@ export function requiresAIReview(operation: string): boolean {
104
116
  return true;
105
117
  }
106
118
 
119
+ // Deploy-specific patterns: when running in deploy mode (end-user driven),
120
+ // additional operations are flagged for AI review. These take precedence
121
+ // over safe operations because deploy context has stricter requirements.
122
+ if (isDeployMode() && matchesPattern(op, DEPLOY_PATTERNS)) {
123
+ return true;
124
+ }
125
+
107
126
  if (matchesPattern(op, SAFE_OPERATIONS)) {
108
127
  // Safe bash commands must not contain chain operators, dangerous pipes,
109
128
  // or subshell/backtick expansion that could hide dangerous operations.
@@ -13,6 +13,12 @@
13
13
  * - Sensitive operations (system paths, credentials) get AI review with context
14
14
  * - The question is: "Does this operation make sense given user intent?"
15
15
  *
16
+ * SECURITY NOTE: These patterns are public (open-source repo). Pattern
17
+ * visibility is intentional and follows industry practice (OWASP CRS,
18
+ * Snort, ModSecurity all publish rules publicly). The Haiku AI layer
19
+ * in bouncer-integration.ts is the actual security boundary — these
20
+ * patterns are a performance optimization for the fast path only.
21
+ *
16
22
  * Analysis logic (requiresAIReview, classifyRisk) lives in security-analysis.ts
17
23
  * and is re-exported here for backward compatibility.
18
24
  */
@@ -34,7 +40,7 @@ export interface SecurityPattern {
34
40
  export const SENSITIVE_PATHS: SecurityPattern[] = [
35
41
  // System directories - might be legitimate (e.g., user asked to configure something)
36
42
  { pattern: /^(Write|Edit):\s*\/etc\//i, reason: 'System configuration - verify user intent' },
37
- { pattern: /^(Write|Edit):\s*\/(bin|sbin|usr\/bin|usr\/sbin)\//i, reason: 'System binaries - verify user intent' },
43
+ { pattern: /^(Write|Edit):\s*\/(bin|sbin|usr\/bin|usr\/sbin|usr\/local\/bin|usr\/local\/sbin)\//i, reason: 'System binaries - verify user intent' },
38
44
  { pattern: /^(Write|Edit):\s*\/boot\//i, reason: 'Boot directory - verify user intent' },
39
45
  { pattern: /^(Write|Edit):\s*\/root\//i, reason: 'Root home - verify user intent' },
40
46
  { pattern: /^(Write|Edit):\s*\/System\//i, reason: 'macOS system - verify user intent' },
@@ -63,7 +69,7 @@ export const SENSITIVE_PATHS: SecurityPattern[] = [
63
69
  */
64
70
  export const CRITICAL_THREATS: SecurityPattern[] = [
65
71
  {
66
- pattern: /rm\s+-rf\s+(\/|~)($|\s)/i,
72
+ pattern: /rm\s+-rf\s+(\/|~)($|\s|;|&&|\|\|)/i,
67
73
  reason: 'Deleting root (/) or home (~) directory is never a legitimate dev task'
68
74
  },
69
75
  {
@@ -239,6 +245,51 @@ export const NEEDS_AI_REVIEW: SecurityPattern[] = [
239
245
  { pattern: /\bclaude\b.*\bmcp\b.*\badd\b/i, reason: 'Adding MCP server - verify source is trusted' },
240
246
  ];
241
247
 
248
+ /**
249
+ * Deploy-specific patterns — additional restrictions for board/headless executions
250
+ * triggered by end-user prompts (untrusted input from deployed app users).
251
+ *
252
+ * These catch operations that are unusual in an automated board execution context
253
+ * and should be routed to AI review. They supplement NEEDS_AI_REVIEW above.
254
+ */
255
+ export const DEPLOY_PATTERNS: SecurityPattern[] = [
256
+ // Credential access from deploy context is suspicious
257
+ {
258
+ pattern: /\b(cat|head|tail|less|more)\b.*\.(env|pem|key|crt|p12|pfx|jks)\b/i,
259
+ reason: 'Deploy execution reading credential/certificate files — verify intent'
260
+ },
261
+
262
+ // Git push from deploy context — end-user code should not push upstream
263
+ {
264
+ pattern: /\bgit\b.*\bpush\b/i,
265
+ reason: 'Deploy execution attempting git push — verify this is intended'
266
+ },
267
+
268
+ // Network listeners — deploy executions should not open ports
269
+ {
270
+ pattern: /\b(nc|netcat|ncat|socat)\b.*(\blisten\b|\s-l\b)/i,
271
+ reason: 'Deploy execution opening network listener — potential backdoor'
272
+ },
273
+
274
+ // Process manipulation from deploy context
275
+ {
276
+ pattern: /\b(kill|killall|pkill)\b/i,
277
+ reason: 'Deploy execution attempting process termination — verify intent'
278
+ },
279
+
280
+ // SSH/SCP from deploy context
281
+ {
282
+ pattern: /\b(ssh|scp|sftp)\b.*@/i,
283
+ reason: 'Deploy execution initiating SSH/SCP connection — verify intent'
284
+ },
285
+
286
+ // Cron/systemd manipulation
287
+ {
288
+ pattern: /\b(crontab|systemctl|launchctl)\b/i,
289
+ reason: 'Deploy execution manipulating scheduled tasks — verify intent'
290
+ },
291
+ ];
292
+
242
293
  // ── Utility functions ─────────────────────────────────────────
243
294
 
244
295
  /**