create github issue with a formatted body
Co-authored-by: Harry Hogg <hhogg@spotify.com> Signed-off-by: Himanshu Mishra <himanshu@orkohunter.net>
This commit is contained in:
@@ -15,15 +15,22 @@
|
||||
*/
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { Octokit } from '@octokit/rest';
|
||||
// The GitHub workflow .github/workflows/
|
||||
import syncJsonOutput from '../snyk.json';
|
||||
// Generated by GitHub workflow .github/workflows/snyk-github-issue-creator
|
||||
import synkJsonOutput from '../snyk.json';
|
||||
|
||||
// Pattern for a GitHub Issue title
|
||||
// Snyk vulnerability [Vulnerability ID]
|
||||
|
||||
type Vulnerability = {
|
||||
description: string;
|
||||
id: string;
|
||||
snykId: string;
|
||||
packages: Set<string>;
|
||||
};
|
||||
|
||||
// Remember to fix me!
|
||||
const GH_OWNER = 'orkohunter';
|
||||
const GH_REPO = 'backstage';
|
||||
|
||||
const octokit = new Octokit({
|
||||
auth: process.env.GITHUB_TOKEN,
|
||||
});
|
||||
@@ -32,14 +39,16 @@ const fetchSnykGithubIssueMap = async (): Promise<Record<string, number>> => {
|
||||
const snykGithubIssueMap: Record<string, number> = {};
|
||||
|
||||
const iterator = octokit.paginate.iterator(octokit.rest.issues.listForRepo, {
|
||||
owner: 'backstage',
|
||||
repo: 'backstage',
|
||||
// TODO(Harry/Himanshu): Use a CLI flag for these values.
|
||||
owner: GH_OWNER,
|
||||
repo: GH_REPO,
|
||||
per_page: 100,
|
||||
labels: 'snyk',
|
||||
labels: 'snyk-vulnerability',
|
||||
});
|
||||
|
||||
for await (const { data: issues } of iterator) {
|
||||
for (const issue of issues) {
|
||||
// Gets the Vulnerability ID from square braces
|
||||
const match = /\([([A-Z0-9-]+)\])/.exec(issue.title);
|
||||
|
||||
if (match && match[1]) {
|
||||
@@ -51,13 +60,31 @@ const fetchSnykGithubIssueMap = async (): Promise<Record<string, number>> => {
|
||||
return snykGithubIssueMap;
|
||||
};
|
||||
|
||||
const generateIssueBody = (vulnerability: Vulnerability) => {
|
||||
let issueBody = '';
|
||||
issueBody += '## Affecting Packages/Plugins\n';
|
||||
vulnerability.packages.forEach(pkgName => {
|
||||
issueBody += `* ${pkgName}\n`;
|
||||
});
|
||||
// TODO: Use displayTargetFile in snyk.json to create hyperlinks
|
||||
issueBody += '\n';
|
||||
issueBody += vulnerability.description;
|
||||
return issueBody;
|
||||
};
|
||||
|
||||
const createGithubIssue = (vulnerability: Vulnerability) => {
|
||||
console.log(
|
||||
`Create issue for vulnerability ${
|
||||
vulnerability.id
|
||||
vulnerability.snykId
|
||||
} affecting packages ${Array.from(vulnerability.packages)}`,
|
||||
);
|
||||
// TODO(hhogg): Create github issue with the contents from a Snyk issue.
|
||||
octokit.issues.create({
|
||||
owner: GH_OWNER,
|
||||
repo: GH_REPO,
|
||||
title: `Snyk vulnerability [${vulnerability.snykId}]`,
|
||||
labels: ['snyk-vulnerability', 'help wanted'],
|
||||
body: generateIssueBody(vulnerability),
|
||||
});
|
||||
};
|
||||
|
||||
const updateGithubIssue = (
|
||||
@@ -65,7 +92,7 @@ const updateGithubIssue = (
|
||||
vulnerability: Vulnerability,
|
||||
) => {
|
||||
console.log(
|
||||
`Update issue ${githubIssueId} for vulnerability ${vulnerability.id}`,
|
||||
`Update issue ${githubIssueId} for vulnerability ${vulnerability.snykId}`,
|
||||
);
|
||||
// TODO(hhogg): Update github issue with the contents from a Snyk issue.
|
||||
};
|
||||
@@ -75,12 +102,12 @@ const closeGithubIssue = (githubIssueId: number) => {
|
||||
// TODO(hhogg): Delete a github issue
|
||||
};
|
||||
|
||||
(async () => {
|
||||
async function main() {
|
||||
const snykGithubIssueMap = await fetchSnykGithubIssueMap();
|
||||
const vulnerabilityStore: Record<string, Vulnerability> = {};
|
||||
|
||||
// Group the Snyk vulnerabilities, and aggregate the affecting packages.
|
||||
syncJsonOutput.forEach(({ projectName, vulnerabilities }) => {
|
||||
synkJsonOutput.forEach(({ projectName, vulnerabilities }) => {
|
||||
vulnerabilities.forEach(
|
||||
({ id, description }: { id: string; description: string }) => {
|
||||
if (id !== undefined && description !== undefined) {
|
||||
@@ -89,7 +116,7 @@ const closeGithubIssue = (githubIssueId: number) => {
|
||||
} else {
|
||||
vulnerabilityStore[id] = {
|
||||
description,
|
||||
id,
|
||||
snykId: id,
|
||||
packages: new Set([projectName]),
|
||||
};
|
||||
}
|
||||
@@ -113,4 +140,9 @@ const closeGithubIssue = (githubIssueId: number) => {
|
||||
closeGithubIssue(githubIssueId);
|
||||
}
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
main().catch(error => {
|
||||
console.error(error.stack);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user