agent-master-devsecops 0.0.0-stage → 5.1.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 (61) hide show
  1. package/README.md +204 -2
  2. package/agents/AGENT_DEVSECOPS.md +32 -0
  3. package/agents/AGENT_INFRA.md +31 -0
  4. package/agents/AGENT_ORCHESTRATOR.md +39 -0
  5. package/agents/AGENT_QA.md +58 -0
  6. package/agents/AGENT_SCRUM.md +23 -0
  7. package/agents/AGENT_SRE.md +22 -0
  8. package/agents/AGENT_UIUX.md +26 -0
  9. package/docs/ARCHITECTURE.md +152 -0
  10. package/docs/CALCULATIONS.md +17 -0
  11. package/docs/CHANGELOG.md +112 -0
  12. package/docs/ENGINEERING_RULES.md +56 -0
  13. package/docs/IDEAS.md +17 -0
  14. package/docs/LOCAL_BACKLOG.md +20 -0
  15. package/docs/STATE.md +111 -0
  16. package/docs/playbooks/PLAYBOOK_CIRCUIT_BREAKER_LLM.md +58 -0
  17. package/docs/playbooks/PLAYBOOK_OPENTELEMETRY_TRACING.md +58 -0
  18. package/package.json +57 -4
  19. package/scripts/auditors/a11y_auditor.js +462 -0
  20. package/scripts/auditors/code_quality_auditor.js +444 -0
  21. package/scripts/auditors/contract_test_validator.js +396 -0
  22. package/scripts/auditors/eval_harness.js +213 -0
  23. package/scripts/auditors/git_hygiene_linter.js +391 -0
  24. package/scripts/auditors/pr_reviewer.js +627 -0
  25. package/scripts/auditors/sast_scanner.js +442 -0
  26. package/scripts/auditors/sca_dependency_auditor.js +673 -0
  27. package/scripts/bin/bootstrap_cli.js +597 -0
  28. package/scripts/bin/domain_idea_miner.js +658 -0
  29. package/scripts/bin/smart_onboarding.js +905 -0
  30. package/scripts/bin/web_inspector.js +578 -0
  31. package/scripts/core/architecture_advisor.js +378 -0
  32. package/scripts/core/ast_skeletonizer.js +413 -0
  33. package/scripts/core/autonomous_remediation_engine.js +305 -0
  34. package/scripts/core/circuit_breaker.js +546 -0
  35. package/scripts/core/context_compressor.js +237 -0
  36. package/scripts/core/fast_feature_scaffold.js +840 -0
  37. package/scripts/core/hot_state_cache.js +238 -0
  38. package/scripts/core/knowledge_gateway.js +888 -0
  39. package/scripts/core/magic_prompt_generator.js +250 -0
  40. package/scripts/core/multi_agent_orchestrator.js +421 -0
  41. package/scripts/core/otel_tracer.js +335 -0
  42. package/scripts/core/perf_benchmark.js +212 -0
  43. package/scripts/core/sarif_engine.js +299 -0
  44. package/scripts/core/sre_remediation_engine.js +236 -0
  45. package/scripts/core/universal_packager.js +357 -0
  46. package/scripts/integrations/atlassian_client.js +600 -0
  47. package/scripts/integrations/atlassian_sync_action.js +576 -0
  48. package/scripts/integrations/confluence_sync.js +684 -0
  49. package/scripts/integrations/credentials_guard.js +500 -0
  50. package/scripts/integrations/jira_manager.js +722 -0
  51. package/scripts/mcp/handlers/atlassian_handlers.js +300 -0
  52. package/scripts/mcp/handlers/core_handlers.js +419 -0
  53. package/scripts/mcp/handlers/qa_handlers.js +502 -0
  54. package/scripts/mcp/handlers/rules_handlers.js +379 -0
  55. package/scripts/mcp/handlers/scaffold_handlers.js +334 -0
  56. package/scripts/mcp/handlers/sre_handlers.js +443 -0
  57. package/scripts/mcp/resources_registry.js +453 -0
  58. package/scripts/mcp/server.js +408 -0
  59. package/scripts/mcp/tool_handlers.js +444 -0
  60. package/scripts/mcp/tools_registry.js +1123 -0
  61. package/scripts/mcp_server.js +236 -0
@@ -0,0 +1,305 @@
1
+ /**
2
+ * scripts/core/autonomous_remediation_engine.js
3
+ * Motor Autônomo de Autocura DevSecOps em Ciclo OODA (Observe-Orient-Decide-Act-Verify)
4
+ *
5
+ * Executa o loop de remediação adaptativa sobre repositórios ou arquivos reais:
6
+ * 1. OBSERVE: Varredura SARIF v2.1.0 e checagem de suíte de testes do host.
7
+ * 2. ORIENT: Análise sintática e semântica do finding (CWE/CVE, linha, contexto).
8
+ * 3. DECIDE: Síntese de estratégia de patch cirúrgico anti-regressão.
9
+ * 4. ACT: Aplicação física do patch no disco com salvaguarda de rollback atômico.
10
+ * 5. VERIFY: Re-execução da auditoria de segurança E dos testes do projeto alvo.
11
+ * 6. LOOP/ROLLBACK: Re-planejamento em caso de falha ou restauração do estado original.
12
+ */
13
+ 'use strict';
14
+
15
+ const fs = require('node:fs');
16
+ const path = require('node:path');
17
+ const { spawnSync } = require('node:child_process');
18
+ const { SastScanner } = require('../auditors/sast_scanner.js');
19
+ const { parseSarifReport, validateSarif } = require('./sarif_engine.js');
20
+
21
+ class AutonomousRemediationEngine {
22
+ constructor(options = {}) {
23
+ this.sastScanner = options.sastScanner || new SastScanner();
24
+ this.maxIterations = options.maxIterations || 3;
25
+ this.timeoutMs = options.timeoutMs || 30000;
26
+ }
27
+
28
+ /**
29
+ * Executa comandos da toolchain de forma segura e síncrona.
30
+ */
31
+ _runCommand(cmd, args = [], cwd = process.cwd()) {
32
+ try {
33
+ if (process.platform === 'win32') {
34
+ return spawnSync(process.env.ComSpec || 'cmd.exe', ['/d', '/s', '/c', cmd, ...args], {
35
+ encoding: 'utf8',
36
+ timeout: this.timeoutMs,
37
+ cwd
38
+ });
39
+ }
40
+ return spawnSync(cmd, args, {
41
+ encoding: 'utf8',
42
+ timeout: this.timeoutMs,
43
+ cwd
44
+ });
45
+ } catch (err) {
46
+ return { status: -1, stdout: '', stderr: err.message, error: err };
47
+ }
48
+ }
49
+
50
+ runProjectTests(testCommand, cwd) {
51
+ if (!testCommand) return { passed: true, output: 'Nenhum comando de teste fornecido (verificação ignorada).', exitCode: 0 };
52
+
53
+ try {
54
+ const cleanEnv = { ...process.env };
55
+ delete cleanEnv.NODE_TEST_CONTEXT;
56
+
57
+ const res = spawnSync(testCommand, {
58
+ shell: true,
59
+ encoding: 'utf8',
60
+ cwd: cwd || process.cwd(),
61
+ timeout: this.timeoutMs,
62
+ env: cleanEnv
63
+ });
64
+ const passed = res.status === 0;
65
+ const output = (res.stdout || '') + (res.stderr || '');
66
+
67
+ return {
68
+ passed,
69
+ output: output.trim(),
70
+ exitCode: res.status
71
+ };
72
+ } catch (err) {
73
+ return {
74
+ passed: false,
75
+ output: err.message,
76
+ exitCode: -1
77
+ };
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Sintetiza uma correção cirúrgica baseada na taxonomia da vulnerabilidade.
83
+ * @param {object} finding Finding normalizado (SARIF ou scanCode)
84
+ * @param {string} currentContent Conteúdo atual do arquivo
85
+ * @returns {{ patchedContent: string, strategy: string } | null}
86
+ */
87
+ synthesizePatch(finding, currentContent) {
88
+ const lines = currentContent.split('\n');
89
+ const targetLineIdx = Math.max(0, (finding.line || 1) - 1);
90
+ const targetLine = lines[targetLineIdx] || '';
91
+
92
+ // Estratégia 1: Command Injection (CWE-78)
93
+ // Converte exec(`...${var}`) ou exec(cmd) em spawnSync seguro ou execFile seguro
94
+ if (finding.cwe === 'CWE-78' || finding.ruleId?.includes('CWE-78')) {
95
+ if (/child_process\s*\.\s*exec\s*\(|(?<![\w$.])exec\s*\(/.test(targetLine)) {
96
+ let patchedLine = targetLine;
97
+ if (/(?:child_process\s*\.\s*)?exec\s*\(\s*`\s*([a-zA-Z0-9_\-\.]+)\s+\$\{([^}]+)\}`(?:\s*,\s*([\s\S]+?))?\s*\)/.test(targetLine)) {
98
+ patchedLine = targetLine.replace(
99
+ /(?:child_process\s*\.\s*)?exec\s*\(\s*`\s*([a-zA-Z0-9_\-\.]+)\s+\$\{([^}]+)\}`(?:\s*,\s*([\s\S]+?))?\s*\)/,
100
+ (m, bin, param, cb) => cb ? `execFile('${bin}', [${param}], ${cb})` : `execFile('${bin}', [${param}])`
101
+ );
102
+ } else if (/(?:child_process\s*\.\s*)?exec\s*\(([^,)]+)(?:\s*,\s*([\s\S]+?))?\s*\)/.test(targetLine)) {
103
+ patchedLine = targetLine.replace(
104
+ /(?:child_process\s*\.\s*)?exec\s*\(([^,)]+)(?:\s*,\s*([\s\S]+?))?\s*\)/,
105
+ (m, cmd, cb) => cb ? `execFile('sh', ['-c', ${cmd}], ${cb})` : `execFile('sh', ['-c', ${cmd}])`
106
+ );
107
+ }
108
+
109
+ // Garante que execFile esteja importado se child_process estiver na página
110
+ lines[targetLineIdx] = patchedLine;
111
+ let newContent = lines.join('\n');
112
+ if (!newContent.includes('execFile') && newContent.includes("require('child_process')")) {
113
+ newContent = newContent.replace("require('child_process')", "require('child_process'); const { execFile } = require('child_process')");
114
+ }
115
+ return {
116
+ patchedContent: newContent,
117
+ strategy: 'Substituição de invocação de shell por execFile() com argumentos em array sanitizados contra CWE-78'
118
+ };
119
+ }
120
+ }
121
+
122
+ // Estratégia 2: SQL Injection (CWE-89)
123
+ // Converte query concatenada para query parametrizada
124
+ if (finding.cwe === 'CWE-89' || finding.ruleId?.includes('CWE-89')) {
125
+ if (/SELECT|INSERT|UPDATE|DELETE/i.test(targetLine) && /\+|\$\{/.test(targetLine)) {
126
+ let patchedLine = targetLine;
127
+ // Ex: `SELECT * FROM users WHERE id = ${userId}` -> 'SELECT * FROM users WHERE id = ?', [userId]
128
+ if (/`\s*(SELECT\b[\s\S]*?WHERE\s+[a-zA-Z0-9_]+\s*=)\s*\$\{([^}]+)\}`/.test(targetLine)) {
129
+ patchedLine = targetLine.replace(
130
+ /`\s*(SELECT\b[\s\S]*?WHERE\s+[a-zA-Z0-9_]+\s*=)\s*\$\{([^}]+)\}`/,
131
+ "'$1 ?', [$2]"
132
+ );
133
+ } else if (/['"]\s*(SELECT\b[\s\S]*?WHERE\s+[a-zA-Z0-9_]+\s*=\s*)['"]\s*\+\s*([a-zA-Z0-9_$]+)/.test(targetLine)) {
134
+ patchedLine = targetLine.replace(
135
+ /['"]\s*(SELECT\b[\s\S]*?WHERE\s+[a-zA-Z0-9_]+\s*=\s*)['"]\s*\+\s*([a-zA-Z0-9_$]+)/,
136
+ "'$1 ?', [$2]"
137
+ );
138
+ }
139
+ lines[targetLineIdx] = patchedLine;
140
+ return {
141
+ patchedContent: lines.join('\n'),
142
+ strategy: 'Conversão de interpolação SQL em Prepared Statement parametrizado com placeholders contra CWE-89'
143
+ };
144
+ }
145
+ }
146
+
147
+ // Estratégia 3: Hardcoded Credentials / Segredos (CWE-798)
148
+ // Converte segredo em texto plano para process.env
149
+ if (finding.cwe === 'CWE-798' || finding.ruleId?.includes('CWE-798')) {
150
+ if (/(?:api[_-]?key|secret|password|token)\s*[:=]\s*['"][^'"]{8,}['"]/i.test(targetLine)) {
151
+ const envVarName = 'APP_SECRET_' + Math.floor(Math.random() * 1000);
152
+ const patchedLine = targetLine.replace(
153
+ /((?:api[_-]?key|secret|password|token)\s*[:=]\s*)['"][^'"]+['"]/i,
154
+ `$1process.env.${envVarName}`
155
+ );
156
+ lines[targetLineIdx] = patchedLine;
157
+ return {
158
+ patchedContent: lines.join('\n'),
159
+ strategy: 'Remoção de credencial em texto plano e injeção de variável de ambiente segura (process.env) contra CWE-798'
160
+ };
161
+ }
162
+ }
163
+
164
+ // Estratégia 4: XSS (CWE-79)
165
+ if (finding.cwe === 'CWE-79' || finding.ruleId?.includes('CWE-79')) {
166
+ if (/innerHTML\s*=/.test(targetLine)) {
167
+ const patchedLine = targetLine.replace(/innerHTML\s*=/, 'textContent =');
168
+ lines[targetLineIdx] = patchedLine;
169
+ return {
170
+ patchedContent: lines.join('\n'),
171
+ strategy: 'Substituição de innerHTML por textContent para mitigar XSS refletido (CWE-79)'
172
+ };
173
+ }
174
+ }
175
+
176
+ return null;
177
+ }
178
+
179
+ /**
180
+ * Executa o Loop Autônomo de Remediação (OODA) sobre um arquivo alvo.
181
+ * @param {object} params
182
+ * @param {string} params.targetFile Caminho do arquivo a ser remediado
183
+ * @param {string} [params.testCommand] Comando para rodar testes (ex: "node --test")
184
+ * @param {string} [params.projectRoot] Diretório raiz do projeto
185
+ * @returns {Promise<object>} Relatório final da autocura
186
+ */
187
+ async remediateFile({ targetFile, testCommand, projectRoot }) {
188
+ if (!fs.existsSync(targetFile)) {
189
+ throw new Error(`Arquivo alvo não encontrado: ${targetFile}`);
190
+ }
191
+
192
+ const cwd = projectRoot || path.dirname(targetFile);
193
+ const originalContent = fs.readFileSync(targetFile, 'utf8');
194
+ const snapshotPath = targetFile + '.pre_remediation.bak';
195
+ fs.writeFileSync(snapshotPath, originalContent, 'utf8');
196
+
197
+ let currentContent = originalContent;
198
+ let iteration = 0;
199
+ const history = [];
200
+
201
+ try {
202
+ while (iteration < this.maxIterations) {
203
+ iteration++;
204
+
205
+ // 1. OBSERVE: Scan SARIF
206
+ const sarifReport = this.sastScanner.scanCodeToSarif(currentContent, path.basename(targetFile));
207
+ const parsed = parseSarifReport(sarifReport);
208
+ const activeFindings = parsed.findings.filter(f => f.level === 'error' || f.severity === 'HIGH' || f.severity === 'CRITICAL');
209
+
210
+ if (activeFindings.length === 0) {
211
+ // Sem vulnerabilidades de segurança. Agora verifica não-regressão funcional
212
+ const testRes = this.runProjectTests(testCommand, cwd);
213
+ if (testRes.passed) {
214
+ // Sucesso absoluto! Código seguro e testes verdes
215
+ if (fs.existsSync(snapshotPath)) fs.unlinkSync(snapshotPath);
216
+ return {
217
+ status: 'REMEDIATION_CONFIRMED_GREEN',
218
+ success: true,
219
+ iterationsNeeded: iteration,
220
+ targetFile,
221
+ findingsResolved: originalContent !== currentContent,
222
+ testValidation: testRes,
223
+ history
224
+ };
225
+ } else {
226
+ // Regressão nos testes! Rollback imediato
227
+ fs.writeFileSync(targetFile, originalContent, 'utf8');
228
+ if (fs.existsSync(snapshotPath)) fs.unlinkSync(snapshotPath);
229
+ return {
230
+ status: 'REGRESSION_DETECTED_ROLLED_BACK',
231
+ success: false,
232
+ targetFile,
233
+ error: 'O patch introduziu falha nos testes automatizados do projeto alvo.',
234
+ testOutput: testRes.output,
235
+ history
236
+ };
237
+ }
238
+ }
239
+
240
+ // 2. ORIENT & DECIDE
241
+ const primaryFinding = activeFindings[0];
242
+ const patchResult = this.synthesizePatch(primaryFinding, currentContent);
243
+
244
+ if (!patchResult) {
245
+ // Não foi possível deduzir estratégia segura
246
+ fs.writeFileSync(targetFile, originalContent, 'utf8');
247
+ if (fs.existsSync(snapshotPath)) fs.unlinkSync(snapshotPath);
248
+ return {
249
+ status: 'UNRESOLVED_NO_SAFE_STRATEGY',
250
+ success: false,
251
+ targetFile,
252
+ unresolvedFinding: primaryFinding,
253
+ history
254
+ };
255
+ }
256
+
257
+ // 3. ACT: Aplica patch no arquivo
258
+ currentContent = patchResult.patchedContent;
259
+ fs.writeFileSync(targetFile, currentContent, 'utf8');
260
+
261
+ // 4. VERIFY: Roda testes para checagem imediata
262
+ const stepTest = this.runProjectTests(testCommand, cwd);
263
+ history.push({
264
+ iteration,
265
+ findingTargeted: primaryFinding.ruleId,
266
+ strategy: patchResult.strategy,
267
+ testPassed: stepTest.passed
268
+ });
269
+
270
+ if (!stepTest.passed) {
271
+ // O patch quebrou a sintaxe ou quebrou os testes! Restaura e tenta abortar
272
+ fs.writeFileSync(targetFile, originalContent, 'utf8');
273
+ if (fs.existsSync(snapshotPath)) fs.unlinkSync(snapshotPath);
274
+ return {
275
+ status: 'REMEDIATION_FAILED_TEST_BROKEN',
276
+ success: false,
277
+ targetFile,
278
+ failedStrategy: patchResult.strategy,
279
+ testOutput: stepTest.output,
280
+ history
281
+ };
282
+ }
283
+ }
284
+
285
+ // Se estourou as iterações sem zerar os findings
286
+ fs.writeFileSync(targetFile, originalContent, 'utf8');
287
+ if (fs.existsSync(snapshotPath)) fs.unlinkSync(snapshotPath);
288
+ return {
289
+ status: 'MAX_ITERATIONS_EXCEEDED_ROLLED_BACK',
290
+ success: false,
291
+ targetFile,
292
+ history
293
+ };
294
+ } catch (err) {
295
+ // Falha inesperada: rollback garantido
296
+ fs.writeFileSync(targetFile, originalContent, 'utf8');
297
+ if (fs.existsSync(snapshotPath)) fs.unlinkSync(snapshotPath);
298
+ throw err;
299
+ }
300
+ }
301
+ }
302
+
303
+ module.exports = {
304
+ AutonomousRemediationEngine
305
+ };