@goodandready/dsh-moa 0.2.74 → 0.2.76

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.
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Stack-Aware Dynamic Persona Evolution from Project Manifests (#308)
3
+ *
4
+ * Scans project manifests (package.json, Cargo.toml, pyproject.toml, requirements.txt, go.mod)
5
+ * in the workspace root to infer primary programming languages, frameworks, ORMs,
6
+ * and test suites. Evolves candidate proposers into specialized domain experts
7
+ * (e.g. React Optimization, TypeScript Strict Safety, Accessibility, FastAPI Async)
8
+ * to maximize architectural hypothesis diversity.
9
+ */
10
+
11
+ import fs from 'node:fs'
12
+ import path from 'node:path'
13
+
14
+ /**
15
+ * Scans workspace root manifests to detect project languages and dependencies.
16
+ *
17
+ * @param {string} cwd - Workspace root directory
18
+ * @returns {object} Detected stack information
19
+ */
20
+ export function detectProjectStack(cwd = process.cwd()) {
21
+ const stack = {
22
+ primaryLanguage: 'unknown',
23
+ frameworks: [],
24
+ libraries: [],
25
+ manifestFound: false,
26
+ stackSummary: '',
27
+ }
28
+
29
+ if (!cwd || typeof cwd !== 'string') return stack
30
+
31
+ // 1. Node / JavaScript / TypeScript (package.json)
32
+ const pkgPath = path.join(cwd, 'package.json')
33
+ if (fs.existsSync(pkgPath)) {
34
+ try {
35
+ const raw = fs.readFileSync(pkgPath, 'utf8')
36
+ const pkg = JSON.parse(raw)
37
+ stack.manifestFound = true
38
+ stack.primaryLanguage = 'javascript'
39
+
40
+ const allDeps = {
41
+ ...(pkg.dependencies || {}),
42
+ ...(pkg.devDependencies || {}),
43
+ ...(pkg.peerDependencies || {}),
44
+ }
45
+
46
+ if (allDeps.typescript || fs.existsSync(path.join(cwd, 'tsconfig.json'))) {
47
+ stack.primaryLanguage = 'typescript'
48
+ stack.libraries.push('typescript')
49
+ }
50
+
51
+ // Frameworks
52
+ if (allDeps.next) stack.frameworks.push('next.js')
53
+ else if (allDeps.react) stack.frameworks.push('react')
54
+
55
+ if (allDeps.nuxt) stack.frameworks.push('nuxt')
56
+ else if (allDeps.vue) stack.frameworks.push('vue')
57
+
58
+ if (allDeps['@sveltejs/kit']) stack.frameworks.push('sveltekit')
59
+ else if (allDeps.svelte) stack.frameworks.push('svelte')
60
+
61
+ if (allDeps['@angular/core']) stack.frameworks.push('angular')
62
+ if (allDeps['@nestjs/core']) stack.frameworks.push('nestjs')
63
+ if (allDeps.fastify) stack.frameworks.push('fastify')
64
+ if (allDeps.express) stack.frameworks.push('express')
65
+
66
+ // Styling & UI
67
+ if (allDeps.tailwindcss) stack.libraries.push('tailwindcss')
68
+
69
+ // ORM & Data
70
+ if (allDeps.prisma || allDeps['@prisma/client']) stack.libraries.push('prisma')
71
+ if (allDeps['drizzle-orm']) stack.libraries.push('drizzle')
72
+ if (allDeps.typeorm) stack.libraries.push('typeorm')
73
+ if (allDeps.mongoose) stack.libraries.push('mongoose')
74
+
75
+ // Validation
76
+ if (allDeps.zod) stack.libraries.push('zod')
77
+ if (allDeps.valibot) stack.libraries.push('valibot')
78
+
79
+ // Testing
80
+ if (allDeps.vitest) stack.libraries.push('vitest')
81
+ if (allDeps.jest) stack.libraries.push('jest')
82
+ if (allDeps.playwright || allDeps['@playwright/test']) stack.libraries.push('playwright')
83
+ } catch {
84
+ // safe fallback on corrupted package.json
85
+ }
86
+ }
87
+
88
+ // 2. Rust (Cargo.toml)
89
+ const cargoPath = path.join(cwd, 'Cargo.toml')
90
+ if (fs.existsSync(cargoPath)) {
91
+ try {
92
+ const content = fs.readFileSync(cargoPath, 'utf8')
93
+ stack.manifestFound = true
94
+ stack.primaryLanguage = 'rust'
95
+
96
+ if (content.includes('axum')) stack.frameworks.push('axum')
97
+ if (content.includes('actix-web')) stack.frameworks.push('actix-web')
98
+ if (content.includes('tokio')) stack.libraries.push('tokio')
99
+ if (content.includes('serde')) stack.libraries.push('serde')
100
+ if (content.includes('sqlx')) stack.libraries.push('sqlx')
101
+ if (content.includes('diesel')) stack.libraries.push('diesel')
102
+ } catch {
103
+ // safe fallback
104
+ }
105
+ }
106
+
107
+ // 3. Python (pyproject.toml, requirements.txt)
108
+ const pyprojectPath = path.join(cwd, 'pyproject.toml')
109
+ const reqPath = path.join(cwd, 'requirements.txt')
110
+ if (fs.existsSync(pyprojectPath) || fs.existsSync(reqPath)) {
111
+ try {
112
+ const pyContent = (fs.existsSync(pyprojectPath) ? fs.readFileSync(pyprojectPath, 'utf8') : '') +
113
+ '\n' + (fs.existsSync(reqPath) ? fs.readFileSync(reqPath, 'utf8') : '')
114
+ stack.manifestFound = true
115
+ if (stack.primaryLanguage === 'unknown') stack.primaryLanguage = 'python'
116
+
117
+ if (pyContent.includes('fastapi')) stack.frameworks.push('fastapi')
118
+ if (pyContent.includes('django')) stack.frameworks.push('django')
119
+ if (pyContent.includes('flask')) stack.frameworks.push('flask')
120
+ if (pyContent.includes('pydantic')) stack.libraries.push('pydantic')
121
+ if (pyContent.includes('sqlalchemy')) stack.libraries.push('sqlalchemy')
122
+ if (pyContent.includes('pytest')) stack.libraries.push('pytest')
123
+ if (pyContent.includes('torch')) stack.libraries.push('pytorch')
124
+ if (pyContent.includes('pandas')) stack.libraries.push('pandas')
125
+ } catch {
126
+ // safe fallback
127
+ }
128
+ }
129
+
130
+ // 4. Go (go.mod)
131
+ const goModPath = path.join(cwd, 'go.mod')
132
+ if (fs.existsSync(goModPath)) {
133
+ try {
134
+ const goContent = fs.readFileSync(goModPath, 'utf8')
135
+ stack.manifestFound = true
136
+ if (stack.primaryLanguage === 'unknown') stack.primaryLanguage = 'go'
137
+
138
+ if (goContent.includes('gin-gonic/gin')) stack.frameworks.push('gin')
139
+ if (goContent.includes('gofiber/fiber')) stack.frameworks.push('fiber')
140
+ if (goContent.includes('labstack/echo')) stack.frameworks.push('echo')
141
+ if (goContent.includes('gorm.io/gorm')) stack.libraries.push('gorm')
142
+ if (goContent.includes('stretchr/testify')) stack.libraries.push('testify')
143
+ } catch {
144
+ // safe fallback
145
+ }
146
+ }
147
+
148
+ // Build summary string
149
+ const parts = []
150
+ if (stack.primaryLanguage !== 'unknown') parts.push(stack.primaryLanguage)
151
+ if (stack.frameworks.length > 0) parts.push(`framework: ${stack.frameworks.join(', ')}`)
152
+ if (stack.libraries.length > 0) parts.push(`libs: ${stack.libraries.slice(0, 4).join(', ')}`)
153
+ stack.stackSummary = parts.join(' | ')
154
+
155
+ return stack
156
+ }
157
+
158
+ /**
159
+ * Returns specialized domain personas based on detected stack.
160
+ *
161
+ * @param {object} stackInfo
162
+ * @returns {Array<string>} Array of specialized persona role descriptions
163
+ */
164
+ export function getStackPersonaSpecialties(stackInfo = {}) {
165
+ const lang = stackInfo.primaryLanguage || 'unknown'
166
+ const frameworks = Array.isArray(stackInfo.frameworks) ? stackInfo.frameworks : []
167
+ const libs = Array.isArray(stackInfo.libraries) ? stackInfo.libraries : []
168
+
169
+ // React / Next.js / Frontend
170
+ if (frameworks.includes('react') || frameworks.includes('next.js') || frameworks.includes('vue') || frameworks.includes('svelte')) {
171
+ return [
172
+ 'Component Architecture, Hooks & Re-render Optimization Specialist',
173
+ libs.includes('typescript') || lang === 'typescript'
174
+ ? 'TypeScript Strict Typing, Generic Invariants & Defensive Schema Expert'
175
+ : 'State Management, Data Flow & Edge-Case Specialist',
176
+ 'Accessibility (a11y), Semantic UI & Modern CSS Performance Reviewer',
177
+ ]
178
+ }
179
+
180
+ // Python / FastAPI / Django
181
+ if (lang === 'python') {
182
+ return [
183
+ frameworks.includes('fastapi')
184
+ ? 'FastAPI Async Concurrency & High-Throughput REST Architect'
185
+ : 'Pythonic Clean Architecture & Idiomatic Object Design Specialist',
186
+ libs.includes('pydantic')
187
+ ? 'Pydantic V2 Schema Validation & Type-Safe Domain Modeler'
188
+ : 'Defensive Data Integrity & Error Boundary Engineer',
189
+ libs.includes('pytest')
190
+ ? 'Pytest Fixtures, Mocking & Comprehensive Edge-Case Test Engineer'
191
+ : 'Performance Profiling & Memory Leak Auditor',
192
+ ]
193
+ }
194
+
195
+ // Rust
196
+ if (lang === 'rust') {
197
+ return [
198
+ 'Rust Zero-Cost Abstractions & Concurrency Architect',
199
+ 'Rust Memory Safety, Error Handling & Lifetime Specialist',
200
+ 'Rust Idiomatic API & Performance Specialist',
201
+ ]
202
+ }
203
+
204
+ // Go
205
+ if (lang === 'go') {
206
+ return [
207
+ 'Go Idiomatic Concurrency & Channel Synchronization Architect',
208
+ 'Go Interface Design, Error Wrapping & Zero-Allocation Specialist',
209
+ 'Go Production Reliability & Table-Driven Unit Testing Specialist',
210
+ ]
211
+ }
212
+
213
+ // General TypeScript / Node
214
+ if (lang === 'typescript') {
215
+ return [
216
+ 'TypeScript Strict Type Safety & Clean Architecture Specialist',
217
+ 'Async Flow, Micro-Optimization & Error Boundary Engineer',
218
+ 'Maintainability, Modularity & Test Coverage Auditor',
219
+ ]
220
+ }
221
+
222
+ // Universal Default
223
+ return [
224
+ 'System Architecture & Core Correctness Engineer',
225
+ 'Edge-Case Analysis & Defensive Error Handling Specialist',
226
+ 'Clean Code, Maintainability & Documentation Specialist',
227
+ ]
228
+ }
229
+
230
+ /**
231
+ * Assigns stack-aware specialized personas to candidate proposer slots.
232
+ *
233
+ * @param {Array<object>} references - Proposer slots
234
+ * @param {object} stackInfo - Output of detectProjectStack
235
+ * @param {object} [options]
236
+ * @param {boolean} [options.enabled=true] - Whether stack-aware personas are enabled
237
+ * @returns {{ references: Array<object>, isSpecialized: boolean, stackSummary: string }}
238
+ */
239
+ export function assignStackAwarePersonas(references = [], stackInfo = {}, options = {}) {
240
+ const { enabled = true } = options
241
+
242
+ if (!enabled || !Array.isArray(references) || references.length === 0) {
243
+ return {
244
+ references: Array.isArray(references) ? references : [],
245
+ isSpecialized: false,
246
+ stackSummary: stackInfo.stackSummary || '',
247
+ }
248
+ }
249
+
250
+ const specialties = getStackPersonaSpecialties(stackInfo)
251
+ const evolved = references.map((slot, idx) => {
252
+ // If user already specified a custom non-default persona, preserve it
253
+ const hasCustom = slot.role_persona && slot.role_persona !== 'general' && slot.role_persona !== 'proposer'
254
+ if (hasCustom) {
255
+ return { ...slot }
256
+ }
257
+
258
+ const specialty = specialties[idx % specialties.length]
259
+ return {
260
+ ...slot,
261
+ role_persona: specialty,
262
+ stackSpecialization: specialty,
263
+ }
264
+ })
265
+
266
+ return {
267
+ references: evolved,
268
+ isSpecialized: Boolean(stackInfo.manifestFound),
269
+ stackSummary: stackInfo.stackSummary || '',
270
+ }
271
+ }
272
+
273
+ /**
274
+ * Formats a directive summarizing the project stack for injection into judge or synthesis prompts.
275
+ *
276
+ * @param {object} stackInfo
277
+ * @returns {string|null}
278
+ */
279
+ export function formatStackAwareDirective(stackInfo = {}) {
280
+ if (!stackInfo || !stackInfo.manifestFound || !stackInfo.stackSummary) {
281
+ return null
282
+ }
283
+
284
+ return `### Project Stack & Architecture Context
285
+ - Detected Environment: ${stackInfo.stackSummary}
286
+ - Verification Requirement: All proposals must adhere to the conventions and idiomatic idioms of this technology stack.`
287
+ }
@@ -18,6 +18,8 @@ import { stageSynthesis } from './synthesis.js'
18
18
  import { stagePromotion } from './promotion.js'
19
19
  import { applySyntaxFilter, formatSyntaxDirective } from './syntax-filter.js'
20
20
  import { stageEarlyConsensus } from './early-consensus.js'
21
+ import { runSecurityAuditGate } from './security-fuzzer.js'
22
+ import { runCoveVerificationGate } from './cove-verifier.js'
21
23
  import { emitEvent, MOA_EVENTS } from '../events.js'
22
24
 
23
25
  export async function runMoAPipeline({
@@ -199,6 +201,39 @@ export async function runMoAPipeline({
199
201
  return { error: new Error('Turn aborted') }
200
202
  }
201
203
 
204
+ // Pre-Stage 5.8: Chain-of-Verification (CoVe) Fact-Checking Gate (#314)
205
+ let coveDirective = null
206
+ let coveGateResult = null
207
+ if (preset?.cove_verification_enabled) {
208
+ coveGateResult = runCoveVerificationGate(
209
+ syntaxResult.validCandidates.length > 0 ? syntaxResult.validCandidates : successfulRefs,
210
+ ctxStage,
211
+ {
212
+ ctx,
213
+ runId,
214
+ onProgress,
215
+ maxQuestions: preset.cove_max_questions || 5,
216
+ }
217
+ )
218
+ coveDirective = coveGateResult.coveDirective
219
+ }
220
+
221
+ // Pre-Stage 5.9: Adversarial White-Hat Security Fuzzing Gate (#302)
222
+ let securityDirective = null
223
+ let securityGateResult = null
224
+ if (preset?.security_gate_enabled) {
225
+ securityGateResult = runSecurityAuditGate(
226
+ syntaxResult.validCandidates.length > 0 ? syntaxResult.validCandidates : successfulRefs,
227
+ {
228
+ ctx,
229
+ runId,
230
+ onProgress,
231
+ strictVeto: preset.security_gate_strict_veto !== false,
232
+ }
233
+ )
234
+ securityDirective = securityGateResult.securityDirective
235
+ }
236
+
202
237
  // Pre-Stage 6: Dynamic Consensus Threshold & Multi-Judge Escalation (#300)
203
238
  const escalationResult = evaluateJudgeEscalation({
204
239
  candidateOutputs: syntaxResult.validCandidates.length > 0 ? syntaxResult.validCandidates : successfulRefs,
@@ -249,7 +284,7 @@ export async function runMoAPipeline({
249
284
  preset: effectivePreset,
250
285
  successfulRefs: syntaxResult.validCandidates.length > 0 ? syntaxResult.validCandidates : successfulRefs,
251
286
  referenceOutputs, primaryJudge: effectivePrimaryJudge,
252
- userPrompt, judgeCriteria: ctxStage.judgeCriteria, prices, maxTokens: ctxStage.maxTokens,
287
+ userPrompt, judgeCriteria: [ctxStage.judgeCriteria, coveDirective, securityDirective].filter(Boolean).join('\n\n'), prices, maxTokens: ctxStage.maxTokens,
253
288
  callLlm, signal, onProgress, cwd, runId, isRefinement: ctxStage.isRefinement,
254
289
  isFastMode: ctxStage.isFastMode, collectedCtx: ctxStage.collectedCtx, startTime,
255
290
  })
@@ -307,7 +342,7 @@ export async function runMoAPipeline({
307
342
  }
308
343
  }
309
344
 
310
- const fileScoringDirective = [rawFileDirective, visualResult?.directive, adversarialTddResult?.directive, syntaxDirective, pruningDirective].filter(Boolean).join("\n\n") || null
345
+ const fileScoringDirective = [rawFileDirective, visualResult?.directive, adversarialTddResult?.directive, syntaxDirective, coveDirective, securityDirective, pruningDirective, ctxStage.stackAwareDirective, ctxStage.developerPreferencesDirective].filter(Boolean).join("\n\n") || null
311
346
 
312
347
  // Stage 7: Synthesis Phase
313
348
  const synthRes = await stageSynthesis({
@@ -0,0 +1,290 @@
1
+ /**
2
+ * DeepSeek Harness Mixture of Agents (MoA) — Adversarial Security Fuzzing Gate (#302)
3
+ *
4
+ * White-Hat Red Team security gate that audits candidate code proposals for critical
5
+ * vulnerabilities, injection vectors, memory exhaustion, prototype pollution, and CWE patterns
6
+ * before final Judge arbitration.
7
+ */
8
+
9
+ import { MOA_EVENTS, emitEvent } from '../events.js'
10
+
11
+ /**
12
+ * Known vulnerability rule signatures with CWE classifications.
13
+ */
14
+ export const SECURITY_RULES = [
15
+ {
16
+ cwe: 'CWE-89',
17
+ title: 'SQL Injection Risk',
18
+ severity: 'critical',
19
+ regex: /(?:SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|EXEC)\s+[^;`'"]*?(\$\{[^}]+\}|['"`]\s*\+\s*[a-zA-Z0-9_]+)/i,
20
+ detail: 'Unsanitized query construction using string interpolation or concatenation instead of parameterized bindings.',
21
+ },
22
+ {
23
+ cwe: 'CWE-78',
24
+ title: 'OS Command Injection',
25
+ severity: 'critical',
26
+ regex: /(?:child_process\.)?(?:exec|execSync)\s*\(\s*(?:`[^`]*\$\{[^}]+\}[^`]*`|['"][^'"]*['"]\s*\+)/i,
27
+ detail: 'Executing shell commands with interpolated or concatenated untrusted input.',
28
+ },
29
+ {
30
+ cwe: 'CWE-78',
31
+ title: 'Shell Invocation with Dynamic Arguments',
32
+ severity: 'critical',
33
+ regex: /spawn\s*\([^,]+,\s*\{[^}]*shell\s*:\s*true/i,
34
+ detail: 'Invoking child_process.spawn with shell: true exposes process to command injection.',
35
+ },
36
+ {
37
+ cwe: 'CWE-22',
38
+ title: 'Path Traversal Vulnerability',
39
+ severity: 'high',
40
+ regex: /(?:readFile|writeFile|createReadStream|createWriteStream|unlink|stat)\s*\([^)]*?(?:\.\.\/|\.\.\\)/i,
41
+ detail: 'File system operation contains unconstrained relative path traversal sequences (../).',
42
+ },
43
+ {
44
+ cwe: 'CWE-79',
45
+ title: 'Cross-Site Scripting (DOM XSS)',
46
+ severity: 'high',
47
+ regex: /(?:\.innerHTML\s*=|document\.write\s*\(|dangerouslySetInnerHTML\s*=\s*\{\s*\{\s*__html\s*:\s*(?!DOMPurify|sanitize))/i,
48
+ detail: 'Unescaped HTML or DOM insertion allows arbitrary script execution in browser contexts.',
49
+ },
50
+ {
51
+ cwe: 'CWE-1321',
52
+ title: 'Prototype Pollution',
53
+ severity: 'critical',
54
+ regex: /(?:__proto__|constructor\s*\[\s*['"`]prototype['"`]\s*\]|prototype\s*\[\s*['"`]\w+['"`]\s*\]\s*=)/i,
55
+ detail: 'Direct modification of object prototype chain may lead to remote code execution or privilege escalation.',
56
+ },
57
+ {
58
+ cwe: 'CWE-400',
59
+ title: 'Regular Expression Denial of Service (ReDoS)',
60
+ severity: 'high',
61
+ regex: /\/(?:[^\/\\]|\\.)*(?:\([^\)]*[\+\*]\)[^\)]*[\+\*]|\([^\)]*\|[^\)]*\)[\+\*])(?:[^\/\\]|\\.)*\//,
62
+ detail: 'Regular expression pattern contains nested quantifiers with catastrophic polynomial/exponential backtracking.',
63
+ },
64
+ {
65
+ cwe: 'CWE-798',
66
+ title: 'Hardcoded Cryptographic Secret / Credential',
67
+ severity: 'high',
68
+ regex: /(?:api_?key|auth_?token|secret_?key|private_?key|bearer_?token)\s*[:=]\s*['"`](?:sk_live_[0-9a-zA-Z]{16,}|ghp_[0-9a-zA-Z]{20,}|ey[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,})['"`]/i,
69
+ detail: 'Production-like API token, private key, or credential embedded directly in source code.',
70
+ },
71
+ {
72
+ cwe: 'CWE-362',
73
+ title: 'TOCTOU Concurrency Race Condition',
74
+ severity: 'medium',
75
+ regex: /fs\.existsSync\s*\([^)]+\)[\s\S]{1,80}?fs\.(?:writeFileSync|appendFileSync)\s*\(/i,
76
+ detail: 'Non-atomic check-then-act pattern creates file race condition under concurrent operations.',
77
+ },
78
+ ]
79
+
80
+ /**
81
+ * Audits a code snippet or model response for security vulnerabilities.
82
+ *
83
+ * @param {string} code - Candidate response text or extracted code
84
+ * @param {object} [options]
85
+ * @returns {object} Audit report with score, findings, and veto flag
86
+ */
87
+ export function auditCodeSecurity(code, options = {}) {
88
+ if (!code || typeof code !== 'string') {
89
+ return {
90
+ veto: false,
91
+ score: 100,
92
+ findings: [],
93
+ summary: 'Clean: No executable code provided for security audit.',
94
+ }
95
+ }
96
+
97
+ const findings = []
98
+ const lines = code.split('\n')
99
+
100
+ for (const rule of SECURITY_RULES) {
101
+ if (rule.regex.test(code)) {
102
+ // Pinpoint line number if possible
103
+ let matchedLine = null
104
+ let matchedSnippet = ''
105
+ for (let i = 0; i < lines.length; i++) {
106
+ if (rule.regex.test(lines[i])) {
107
+ matchedLine = i + 1
108
+ matchedSnippet = lines[i].trim().slice(0, 120)
109
+ break
110
+ }
111
+ }
112
+
113
+ findings.push({
114
+ cwe: rule.cwe,
115
+ title: rule.title,
116
+ severity: rule.severity,
117
+ detail: rule.detail,
118
+ line: matchedLine,
119
+ snippet: matchedSnippet || null,
120
+ })
121
+ }
122
+ }
123
+
124
+ let penalty = 0
125
+ let hasCriticalOrHigh = false
126
+ for (const f of findings) {
127
+ if (f.severity === 'critical') {
128
+ penalty += 45
129
+ hasCriticalOrHigh = true
130
+ } else if (f.severity === 'high') {
131
+ penalty += 25
132
+ hasCriticalOrHigh = true
133
+ } else if (f.severity === 'medium') {
134
+ penalty += 15
135
+ } else {
136
+ penalty += 5
137
+ }
138
+ }
139
+
140
+ const score = Math.max(0, Math.min(100, 100 - penalty))
141
+ const strictVeto = options.strictVeto !== false
142
+ const veto = strictVeto ? hasCriticalOrHigh || score < 60 : score < 40
143
+
144
+ let summary = ''
145
+ if (findings.length === 0) {
146
+ summary = '🛡️ Red Team Security Audit: PASSED (Score 100/100). No known CWE vulnerabilities detected.'
147
+ } else if (veto) {
148
+ summary = `⛔ SECURITY_VETO (Score ${score}/100): Found ${findings.length} security violation(s) (${findings.map((f) => f.cwe).join(', ')}).`
149
+ } else {
150
+ summary = `⚠️ Security Warning (Score ${score}/100): ${findings.length} minor/medium issue(s) identified.`
151
+ }
152
+
153
+ return {
154
+ veto,
155
+ score,
156
+ findings,
157
+ summary,
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Executes the Adversarial Security Fuzzing Gate across all candidate outputs.
163
+ *
164
+ * @param {Array<object>} candidates - List of candidate references with output/text
165
+ * @param {object} [options]
166
+ * @returns {object} Gate execution results with directive and veto counters
167
+ */
168
+ export function runSecurityAuditGate(candidates, options = {}) {
169
+ const { ctx, runId, onProgress, strictVeto = true } = options
170
+ const results = []
171
+ let vetoCount = 0
172
+
173
+ if (!Array.isArray(candidates) || candidates.length === 0) {
174
+ return {
175
+ results: [],
176
+ vetoCount: 0,
177
+ cleanCount: 0,
178
+ allPassed: true,
179
+ securityDirective: null,
180
+ }
181
+ }
182
+
183
+ for (let i = 0; i < candidates.length; i++) {
184
+ const cand = candidates[i]
185
+ const text = typeof cand === 'string' ? cand : cand.output || cand.text || cand.code || ''
186
+ const audit = auditCodeSecurity(text, { strictVeto })
187
+
188
+ if (typeof cand === 'object' && cand !== null) {
189
+ cand.securityAudit = audit
190
+ cand.securityVeto = audit.veto
191
+ }
192
+
193
+ if (audit.veto) {
194
+ vetoCount++
195
+ }
196
+
197
+ results.push({
198
+ candidateIndex: i,
199
+ model: cand?.model || `Candidate ${i + 1}`,
200
+ audit,
201
+ veto: audit.veto,
202
+ })
203
+
204
+ if (ctx) {
205
+ emitEvent(ctx, MOA_EVENTS.SECURITY_AUDIT, {
206
+ runId,
207
+ candidateIndex: i,
208
+ score: audit.score,
209
+ veto: audit.veto,
210
+ findingsCount: audit.findings.length,
211
+ cwes: audit.findings.map((f) => f.cwe),
212
+ })
213
+ }
214
+ }
215
+
216
+ const cleanCount = candidates.length - vetoCount
217
+ const allPassed = vetoCount === 0
218
+
219
+ if (typeof onProgress === 'function') {
220
+ if (allPassed) {
221
+ onProgress(`🛡️ *Security Gate Passed*: All ${candidates.length} candidate solutions cleared Red Team audit.\n`)
222
+ } else {
223
+ onProgress(
224
+ `🚨 *Security Gate Alert*: ${vetoCount}/${candidates.length} candidates triggered SECURITY_VETO (${results
225
+ .filter((r) => r.veto)
226
+ .map((r) => `Ref ${r.candidateIndex + 1}`)
227
+ .join(', ')}).\n`
228
+ )
229
+ }
230
+ }
231
+
232
+ const securityDirective = formatSecurityAuditDirective(results, { strictVeto })
233
+
234
+ return {
235
+ results,
236
+ vetoCount,
237
+ cleanCount,
238
+ allPassed,
239
+ securityDirective,
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Formats Red Team audit findings into a high-priority prompt directive for Stage 6/7.
245
+ *
246
+ * @param {Array<object>} results
247
+ * @param {object} [options]
248
+ * @returns {string|null} Directive text
249
+ */
250
+ export function formatSecurityAuditDirective(results, options = {}) {
251
+ if (!Array.isArray(results) || results.length === 0) return null
252
+
253
+ const hasAnyFindings = results.some((r) => r.audit && r.audit.findings.length > 0)
254
+ if (!hasAnyFindings) {
255
+ return '### 🛡️ RED TEAM SECURITY AUDIT: ALL CANDIDATES VERIFIED SECURE\nNo injection, XSS, ReDoS, path traversal, or credential exposure detected.'
256
+ }
257
+
258
+ const lines = [
259
+ '### 🛡️ ADVERSARIAL RED TEAM SECURITY AUDIT DIRECTIVE',
260
+ 'Strict security evaluation of candidate proposals has been completed:',
261
+ ]
262
+
263
+ for (const r of results) {
264
+ const label = `Candidate ${r.candidateIndex + 1}`
265
+ const a = r.audit || {}
266
+ if (a.veto) {
267
+ lines.push(
268
+ `- **${label}**: ⛔ **SECURITY_VETO** (Score ${a.score}/100) — DO NOT adopt this solution without removing critical flaws:`
269
+ )
270
+ for (const f of a.findings || []) {
271
+ lines.push(
272
+ ` * [${f.cwe}] ${f.title} (${f.severity.toUpperCase()}): ${f.detail}${f.line ? ` (at line ${f.line})` : ''}`
273
+ )
274
+ }
275
+ } else if (a.findings && a.findings.length > 0) {
276
+ lines.push(`- **${label}**: ⚠️ Warning (Score ${a.score}/100):`)
277
+ for (const f of a.findings) {
278
+ lines.push(` * [${f.cwe}] ${f.title}: ${f.detail}`)
279
+ }
280
+ } else {
281
+ lines.push(`- **${label}**: ✅ PASSED (Score 100/100) — Free of detectable vulnerabilities.`)
282
+ }
283
+ }
284
+
285
+ lines.push(
286
+ '\n**Judge Mandate**: Solutions marked with SECURITY_VETO must be heavily penalized or rejected. The final synthesized code MUST NOT contain any of the flagged CWE patterns.'
287
+ )
288
+
289
+ return lines.join('\n')
290
+ }