fase(16): integrations module
This commit is contained in:
36
dist/modules/integrations/infrastructure/providers/GitHubIssuesProvider.js
vendored
Normal file
36
dist/modules/integrations/infrastructure/providers/GitHubIssuesProvider.js
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.GitHubIssuesProvider = void 0;
|
||||
const rest_1 = require("@octokit/rest");
|
||||
class GitHubIssuesProvider {
|
||||
constructor(token, repo) {
|
||||
this.octokit = new rest_1.Octokit({ auth: token });
|
||||
const [owner, repoName] = repo.split('/');
|
||||
this.owner = owner;
|
||||
this.repo = repoName;
|
||||
}
|
||||
async sendFinding(finding) {
|
||||
const stepsSection = finding.steps && finding.steps.length > 0
|
||||
? `\n\n## Reproduction Steps\n${finding.steps.map((s, i) => `${i + 1}. ${s}`).join('\n')}`
|
||||
: '';
|
||||
const body = `## ABE Security Finding
|
||||
|
||||
**Severity:** ${finding.severity.toUpperCase()}
|
||||
**Type:** ${finding.type}
|
||||
**Session:** ${finding.sessionId}
|
||||
|
||||
## Description
|
||||
${finding.description}${stepsSection}
|
||||
|
||||
---
|
||||
*Generated by [ABE — Autonomous Bug Explorer](https://github.com/your-org/abe)*`;
|
||||
await this.octokit.issues.create({
|
||||
owner: this.owner,
|
||||
repo: this.repo,
|
||||
title: `[ABE] [${finding.severity.toUpperCase()}] ${finding.title}`,
|
||||
body,
|
||||
labels: ['bug', 'abe-finding', `severity:${finding.severity}`],
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.GitHubIssuesProvider = GitHubIssuesProvider;
|
||||
57
dist/modules/integrations/infrastructure/providers/JiraProvider.js
vendored
Normal file
57
dist/modules/integrations/infrastructure/providers/JiraProvider.js
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.JiraProvider = void 0;
|
||||
const PRIORITY_MAP = {
|
||||
critical: 'Highest',
|
||||
high: 'High',
|
||||
medium: 'Medium',
|
||||
low: 'Low',
|
||||
};
|
||||
class JiraProvider {
|
||||
constructor(host, token, username, projectKey) {
|
||||
this.host = host;
|
||||
this.token = token;
|
||||
this.username = username;
|
||||
this.projectKey = projectKey;
|
||||
}
|
||||
async sendFinding(finding) {
|
||||
const stepsSection = finding.steps && finding.steps.length > 0
|
||||
? `\n\nReproduction Steps:\n${finding.steps.map((s, i) => `${i + 1}. ${s}`).join('\n')}`
|
||||
: '';
|
||||
const body = {
|
||||
fields: {
|
||||
project: { key: this.projectKey },
|
||||
summary: `[ABE] [${finding.severity.toUpperCase()}] ${finding.title}`,
|
||||
description: {
|
||||
type: 'doc',
|
||||
version: 1,
|
||||
content: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
content: [{ type: 'text', text: `${finding.description}${stepsSection}` }],
|
||||
},
|
||||
],
|
||||
},
|
||||
issuetype: { name: 'Bug' },
|
||||
priority: { name: PRIORITY_MAP[finding.severity] ?? 'Medium' },
|
||||
labels: ['abe-finding', `severity-${finding.severity}`],
|
||||
},
|
||||
};
|
||||
const auth = Buffer.from(`${this.username}:${this.token}`).toString('base64');
|
||||
const url = `${this.host.replace(/\/$/, '')}/rest/api/3/issue`;
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Basic ${auth}`,
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
signal: AbortSignal.timeout(15000),
|
||||
});
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(`Jira API error ${res.status}: ${text}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.JiraProvider = JiraProvider;
|
||||
53
dist/modules/integrations/infrastructure/providers/SlackProvider.js
vendored
Normal file
53
dist/modules/integrations/infrastructure/providers/SlackProvider.js
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SlackProvider = void 0;
|
||||
const SEVERITY_COLORS = {
|
||||
critical: '#dc2626',
|
||||
high: '#ea580c',
|
||||
medium: '#ca8a04',
|
||||
low: '#2563eb',
|
||||
};
|
||||
class SlackProvider {
|
||||
constructor(webhookUrl) {
|
||||
this.webhookUrl = webhookUrl;
|
||||
}
|
||||
async sendFinding(finding) {
|
||||
const color = SEVERITY_COLORS[finding.severity] ?? '#6b7280';
|
||||
const payload = {
|
||||
blocks: [
|
||||
{
|
||||
type: 'header',
|
||||
text: { type: 'plain_text', text: `ABE Finding: ${finding.title}`, emoji: true },
|
||||
},
|
||||
{
|
||||
type: 'section',
|
||||
fields: [
|
||||
{ type: 'mrkdwn', text: `*Severity:*\n${finding.severity.toUpperCase()}` },
|
||||
{ type: 'mrkdwn', text: `*Type:*\n${finding.type}` },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'section',
|
||||
text: { type: 'mrkdwn', text: `*Description:*\n${finding.description}` },
|
||||
},
|
||||
{
|
||||
type: 'context',
|
||||
elements: [
|
||||
{ type: 'mrkdwn', text: `Session: ${finding.sessionId}` },
|
||||
],
|
||||
},
|
||||
],
|
||||
attachments: [{ color, fallback: `${finding.severity.toUpperCase()} finding: ${finding.description}` }],
|
||||
};
|
||||
const res = await fetch(this.webhookUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
signal: AbortSignal.timeout(10000),
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error(`Slack webhook failed: ${res.status} ${await res.text()}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.SlackProvider = SlackProvider;
|
||||
Reference in New Issue
Block a user