fase(5): findings module complete
Some checks failed
ABE Exploratory Testing / explore (push) Has been cancelled
Some checks failed
ABE Exploratory Testing / explore (push) Has been cancelled
This commit is contained in:
94
dist/modules/findings/infrastructure/exporters/JSONExporter.js
vendored
Normal file
94
dist/modules/findings/infrastructure/exporters/JSONExporter.js
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.JSONExporter = void 0;
|
||||
const fs = __importStar(require("fs"));
|
||||
const path = __importStar(require("path"));
|
||||
const os = __importStar(require("os"));
|
||||
class JSONExporter {
|
||||
constructor(targetUrl = '', abeVersion = '0.1.0') {
|
||||
this.targetUrl = targetUrl;
|
||||
this.abeVersion = abeVersion;
|
||||
}
|
||||
async export(finding, outputDir) {
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
const report = {
|
||||
version: '1.0',
|
||||
generated_at: finding.createdAt.toISOString(),
|
||||
environment: {
|
||||
target_url: this.targetUrl,
|
||||
abe_version: this.abeVersion,
|
||||
os: os.platform(),
|
||||
node_version: process.version,
|
||||
},
|
||||
finding: {
|
||||
id: finding.id.toString(),
|
||||
type: finding.type.value,
|
||||
severity: finding.severity.value,
|
||||
status: finding.status.value,
|
||||
description: finding.description,
|
||||
browser: finding.browser,
|
||||
browser_version: finding.browserVersion,
|
||||
},
|
||||
reproduction: {
|
||||
seed: finding.actionTrace[0]?.seed ?? null,
|
||||
steps: finding.actionTrace.map((action, index) => ({
|
||||
step: index + 1,
|
||||
action_type: action.type,
|
||||
selector: action.selector,
|
||||
value: action.value,
|
||||
url: action.url,
|
||||
timestamp: action.timestamp,
|
||||
})),
|
||||
},
|
||||
evidence: {
|
||||
screenshot: finding.evidence.screenshotPath ?? null,
|
||||
dom_snapshot: finding.evidence.domSnapshotPath ?? null,
|
||||
http_log: finding.evidence.httpLog.map((r) => ({
|
||||
url: r.url,
|
||||
method: r.method,
|
||||
status: r.status,
|
||||
duration_ms: r.durationMs,
|
||||
})),
|
||||
raw_errors: finding.evidence.rawErrors,
|
||||
},
|
||||
ai_enrichment: finding.aiEnrichment ?? null,
|
||||
};
|
||||
const filePath = path.join(outputDir, 'report.json');
|
||||
fs.writeFileSync(filePath, JSON.stringify(report, null, 2), 'utf8');
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
exports.JSONExporter = JSONExporter;
|
||||
109
dist/modules/findings/infrastructure/exporters/MarkdownExporter.js
vendored
Normal file
109
dist/modules/findings/infrastructure/exporters/MarkdownExporter.js
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.MarkdownExporter = void 0;
|
||||
const fs = __importStar(require("fs"));
|
||||
const path = __importStar(require("path"));
|
||||
class MarkdownExporter {
|
||||
async export(finding, outputDir) {
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
const date = finding.createdAt.toISOString().split('T')[0];
|
||||
const seed = finding.actionTrace[0]?.seed ?? 'N/A';
|
||||
const replayCmd = `npm run replay -- --report ${outputDir}/report.json`;
|
||||
const steps = finding.actionTrace
|
||||
.map((action, i) => {
|
||||
switch (action.type) {
|
||||
case 'navigate':
|
||||
return `${i + 1}. Navigate to \`${action.url}\``;
|
||||
case 'click':
|
||||
return `${i + 1}. Click element \`${action.selector}\``;
|
||||
case 'fill':
|
||||
return `${i + 1}. Fill \`${action.selector}\` with \`${JSON.stringify(action.value ?? '')}\``;
|
||||
case 'select':
|
||||
return `${i + 1}. Select \`${action.value}\` in \`${action.selector}\``;
|
||||
case 'submit':
|
||||
return `${i + 1}. Submit form \`${action.selector}\``;
|
||||
default:
|
||||
return `${i + 1}. ${action.type}`;
|
||||
}
|
||||
})
|
||||
.join('\n');
|
||||
const httpTable = finding.evidence.httpLog.length > 0
|
||||
? [
|
||||
'| Method | URL | Status | Duration |',
|
||||
'|--------|-----|--------|----------|',
|
||||
...finding.evidence.httpLog.map((r) => `| ${r.method} | ${r.url} | ${r.status} | ${r.durationMs}ms |`),
|
||||
].join('\n')
|
||||
: '_No HTTP log available._';
|
||||
const rawErrors = finding.evidence.rawErrors.length > 0
|
||||
? '```\n' + finding.evidence.rawErrors.join('\n') + '\n```'
|
||||
: '_No raw errors recorded._';
|
||||
const md = `# Bug Report — ${finding.type.value} — ${date}
|
||||
|
||||
## Summary
|
||||
${finding.description}
|
||||
|
||||
## Severity
|
||||
**${finding.severity.value}** — detected by ABE heuristic rule \`${finding.type.value}\`
|
||||
|
||||
## Status
|
||||
**${finding.status.value}**
|
||||
|
||||
## Reproduction Steps
|
||||
|
||||
${steps.length > 0 ? steps : '_No steps recorded._'}
|
||||
|
||||
**Seed used**: \`${seed}\`
|
||||
**Replay command**: \`${replayCmd}\`
|
||||
|
||||
## Observed Behavior
|
||||
${finding.description}
|
||||
|
||||
## Evidence
|
||||
- Screenshot: \`${finding.evidence.screenshotPath ?? 'N/A'}\`
|
||||
- DOM Snapshot: \`${finding.evidence.domSnapshotPath ?? 'N/A'}\`
|
||||
- HTTP Log:
|
||||
|
||||
${httpTable}
|
||||
|
||||
## Raw Errors
|
||||
${rawErrors}
|
||||
`;
|
||||
const filePath = path.join(outputDir, 'report.md');
|
||||
fs.writeFileSync(filePath, md, 'utf8');
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
exports.MarkdownExporter = MarkdownExporter;
|
||||
48
dist/modules/findings/infrastructure/exporters/PlaywrightScriptExporter.js
vendored
Normal file
48
dist/modules/findings/infrastructure/exporters/PlaywrightScriptExporter.js
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PlaywrightScriptExporter = void 0;
|
||||
class PlaywrightScriptExporter {
|
||||
generate(finding) {
|
||||
const trace = finding.actionTrace;
|
||||
const lines = [
|
||||
'// Auto-generated replay script by ABE (Autonomous Bug Explorer)',
|
||||
`// Generated at: ${new Date().toISOString()}`,
|
||||
`// Finding ID: ${finding.id.toString()}`,
|
||||
`// Type: ${finding.type.value} | Severity: ${finding.severity.value}`,
|
||||
`// Steps: ${trace.length}`,
|
||||
'',
|
||||
"const { chromium } = require('playwright');",
|
||||
'',
|
||||
'(async () => {',
|
||||
' const browser = await chromium.launch({ headless: true });',
|
||||
' const context = await browser.newContext();',
|
||||
' const page = await context.newPage();',
|
||||
'',
|
||||
];
|
||||
for (let i = 0; i < trace.length; i++) {
|
||||
const action = trace[i];
|
||||
lines.push(` // Step ${i + 1}: ${action.type} (seed=${action.seed})`);
|
||||
switch (action.type) {
|
||||
case 'navigate':
|
||||
lines.push(` await page.goto(${JSON.stringify(action.url)});`);
|
||||
break;
|
||||
case 'click':
|
||||
lines.push(` await page.locator(${JSON.stringify(action.selector)}).first().click();`);
|
||||
break;
|
||||
case 'fill':
|
||||
lines.push(` await page.locator(${JSON.stringify(action.selector)}).first().fill(${JSON.stringify(action.value ?? '')});`);
|
||||
break;
|
||||
case 'select':
|
||||
lines.push(` await page.locator(${JSON.stringify(action.selector)}).first().selectOption(${JSON.stringify(action.value ?? '')});`);
|
||||
break;
|
||||
case 'submit':
|
||||
lines.push(` await page.locator(${JSON.stringify(action.selector)}).first().dispatchEvent('submit');`);
|
||||
break;
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
lines.push(" console.log('Replay complete');", ' await browser.close();', '})();');
|
||||
return lines.join('\n');
|
||||
}
|
||||
}
|
||||
exports.PlaywrightScriptExporter = PlaywrightScriptExporter;
|
||||
Reference in New Issue
Block a user