Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/crazy-experts-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"devprod-status-bot": patch
---

fix security alerts to avoid being in the same notification thread
65 changes: 38 additions & 27 deletions packages/devprod-status-bot/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { IssuesOpenedEvent, WebhookEvent } from "@octokit/webhooks-types";
import type {
IssueCommentEvent,
IssuesEvent,
Schema,
WebhookEvent,
} from "@octokit/webhooks-types";

async function getBotMessage(ai: Ai, prompt: string) {
const chat = {
Expand All @@ -21,16 +26,20 @@ async function getBotMessage(ai: Ai, prompt: string) {
return message.response;
}

async function analyzeIssueSecurity(
async function checkForSecurityIssue(
ai: Ai,
issueTitle: string,
issueBody: string
): Promise<boolean> {
message: Schema
): Promise<IssuesEvent | IssueCommentEvent | null> {
if (!isIssueEvent(message)) {
return null;
}
const prompt = `Analyze this GitHub issue to determine if it's likely reporting a security vulnerability or security concern.

Issue Title: ${issueTitle}
Issue Title: ${message.issue.title}

Issue Body: ${message.issue.body || ""}

Issue Body: ${issueBody}
Changed Comment: ${"comment" in message ? message.comment.body : "N/A"}

Look for keywords and patterns that suggest this is a security report, such as:
- Vulnerability, exploit, security flaw, CVE
Expand All @@ -55,12 +64,8 @@ Respond with only "YES" if this appears to be a security-related issue, or "NO"
] as RoleScopedChatInput[],
};

const message = await ai.run("@cf/meta/llama-2-7b-chat-int8", chat);
if (!("response" in message) || !message.response) {
return false;
}

return message.response.trim().toUpperCase() === "YES";
const aiMessage = await ai.run("@cf/meta/llama-2-7b-chat-int8", chat);
return aiMessage.response?.trim().toUpperCase() === "YES" ? message : null;
}

type ProjectGQLResponse = {
Expand Down Expand Up @@ -139,6 +144,7 @@ async function addPRToProject(pat: string, repo: string, number: string) {
}),
});
}

function getThreadID(date?: string | Date, label = "-pull-requests") {
// Apply an offset so we rollover days at around 10am UTC
return (
Expand Down Expand Up @@ -172,13 +178,24 @@ async function sendMessage(
console.log(await response.json());
}

function isIssueOpenedEvent(
function isIssueEvent(
message: WebhookEvent
): message is IssuesOpenedEvent {
return "issue" in message && message.action === "opened";
): message is IssuesEvent | IssueCommentEvent {
if (
"issue" in message &&
(message.action === "opened" ||
message.action === "reopened" ||
message.action === "edited")
) {
return true;
}
return false;
}

async function sendSecurityAlert(webhookUrl: string, issue: IssuesOpenedEvent) {
async function sendSecurityAlert(
webhookUrl: string,
issue: IssuesEvent | IssueCommentEvent
) {
return sendMessage(
webhookUrl,
{
Expand Down Expand Up @@ -234,7 +251,7 @@ async function sendSecurityAlert(webhookUrl: string, issue: IssuesOpenedEvent) {
},
],
},
"security-alerts"
"-security-alert-" + issue.issue.number
);
}

Expand Down Expand Up @@ -399,15 +416,9 @@ export default {
if (url.pathname === "/github") {
const body = await request.json<WebhookEvent>();

if (isIssueOpenedEvent(body)) {
const isSecurityIssue = await analyzeIssueSecurity(
env.AI,
body.issue.title,
body.issue.body || ""
);
if (isSecurityIssue) {
await sendSecurityAlert(env.ALERTS_WEBHOOK, body);
}
const maybeSecurityIssue = await checkForSecurityIssue(env.AI, body);
if (maybeSecurityIssue) {
await sendSecurityAlert(env.ALERTS_WEBHOOK, maybeSecurityIssue);
}
}

Expand Down
Loading