diff --git a/.github/actions/check/action.yml b/.github/actions/check/action.yml deleted file mode 100644 index 941ff80..0000000 --- a/.github/actions/check/action.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: 'check-replication-action' -description: 'Checks that all external bounties are replicated internally' -author: 'xcorail' -inputs: - internal_repo: - description: 'The destination repo for the internal issue' - default: 'github/securitylab-bounties' -runs: - using: 'node12' - main: './check-replication.js' \ No newline at end of file diff --git a/.github/actions/check/check-replication.js b/.github/actions/check/check-replication.js deleted file mode 100644 index 476311d..0000000 --- a/.github/actions/check/check-replication.js +++ /dev/null @@ -1,57 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (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 (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const core = __importStar(require("@actions/core")); -const github = __importStar(require("@actions/github")); -const issues_1 = require("../replicate/issues"); -const run = async () => { - const internalRepoAccessToken = process.env['INT_REPO_TOKEN']; - const internalRepo = core.getInput('internal_repo') || '/'; - const [owner, repo] = internalRepo.split('/'); - const internalIssues = await issues_1.getIssueList(owner, repo, internalRepoAccessToken, false, false); - if (!internalIssues) { - core.setFailed(`Internal error. Cannot access the internal repo ${internalRepo}. Aborting`); - return; - } - else { - core.debug(`Retrieved ${internalIssues === null || internalIssues === void 0 ? void 0 : internalIssues.length} internal issues`); - const externalIssues = await issues_1.getIssueList(github.context.repo.owner, github.context.repo.repo, process.env['GITHUB_TOKEN'], true, true); - if (!externalIssues) { - core.setFailed(`Internal error when retrieving all issues.`); - return; - } - core.debug(`Retrieved ${externalIssues === null || externalIssues === void 0 ? void 0 : externalIssues.length} external issues`); - let failed = false; - externalIssues.forEach(issue => { - const ref = issues_1.internalIssueAlreadyCreated(issue === null || issue === void 0 ? void 0 : issue.html_url, internalIssues); - if (!ref) { - core.debug(`External issue ${issue === null || issue === void 0 ? void 0 : issue.number} is not replicated internally.`); - failed = true; - } - }); - if (failed) { - core.setFailed("Some submissions are not replicated internally, see execution logs."); - } - } - return; -}; -run(); -//# sourceMappingURL=check-replication.js.map \ No newline at end of file diff --git a/.github/actions/check/check-replication.ts b/.github/actions/check/check-replication.ts deleted file mode 100644 index 7dbb23b..0000000 --- a/.github/actions/check/check-replication.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as core from '@actions/core' -import * as github from '@actions/github' -import { getIssueList, internalIssueAlreadyCreated } from '../replicate/issues' - -const run = async (): Promise => { - const internalRepoAccessToken: string | undefined = process.env['INT_REPO_TOKEN'] - const internalRepo = core.getInput('internal_repo') || '/' - const [owner, repo] = internalRepo.split('/') - const internalIssues = await getIssueList(owner, repo, internalRepoAccessToken, false, false) - if(!internalIssues) { - core.setFailed(`Internal error. Cannot access the internal repo ${internalRepo}. Aborting`) - return - } else { - core.debug(`Retrieved ${internalIssues?.length} internal issues`) - const externalIssues = await getIssueList(github.context.repo.owner, github.context.repo.repo, process.env['GITHUB_TOKEN'], true, true) - if(!externalIssues) { - core.setFailed(`Internal error when retrieving all issues.`) - return - } - core.debug(`Retrieved ${externalIssues?.length} external issues`) - let failed = false - externalIssues.forEach( issue => { - const ref = internalIssueAlreadyCreated(issue?.html_url, internalIssues) - if(!ref) { - core.debug(`External issue ${issue?.number} is not replicated internally.`) - failed = true - } - }) - if(failed) { - core.setFailed("Some submissions are not replicated internally, see execution logs.") - } - } - return -} - -run() - diff --git a/.github/actions/replicate/__tests__/replicate.test.js b/.github/actions/replicate/__tests__/replicate.test.js deleted file mode 100644 index c341579..0000000 --- a/.github/actions/replicate/__tests__/replicate.test.js +++ /dev/null @@ -1,143 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (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 (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const core = __importStar(require("@actions/core")); -const replicate = __importStar(require("../replicate")); -const issues = __importStar(require("../issues")); -const TEST_ISSUE_1 = 1; -const TEST_REPOSITORY = { - full_name: 'myuser/myrepo', - name: 'myrepo', - owner: { - login: 'myuser', - name: 'My User' - } -}; -const TEST_INVALID_PAYLOAD_NOUSER = { - repository: TEST_REPOSITORY, - issue: { - number: TEST_ISSUE_1, - html_url: 'https://github.com/test_owner/test_repo/issues/1', - } -}; -const TEST_INVALID_PAYLOAD_NOURL = { - repository: TEST_REPOSITORY, - issue: { - number: TEST_ISSUE_1, - user: { - login: 'issue_user', - html_url: 'https://github.com/users/issue_user' - } - } -}; -const TEST_INVALID_PAYLOAD_NOISSUE = { - repository: TEST_REPOSITORY, -}; -const TEST_LABEL_ALLFORONE = { name: 'All For One' }; -const TEST_LABEL_NOTBOUNTY_1 = { name: 'not-a-bounty-label' }; -const TEST_LABEL_NOTBOUNTY_2 = { name: 'not-a-bounty-label-either' }; -const TEST_PAYLOAD_NOTBOUNTY = { - repository: TEST_REPOSITORY, - issue: { - number: TEST_ISSUE_1, - html_url: 'https://github.com/test_owner/test_repo/issues/1', - user: { - login: 'issue_user', - html_url: 'https://github.com/users/issue_user' - }, - labels: [TEST_LABEL_NOTBOUNTY_1, TEST_LABEL_NOTBOUNTY_2], - } -}; -const TEST_PAYLOAD = { - repository: TEST_REPOSITORY, - issue: { - number: TEST_ISSUE_1, - html_url: 'https://github.com/test_owner/test_repo/issues/1', - user: { - login: 'ghsecuritylab', - html_url: 'https://github.com/ghsecuritylab' - }, - title: 'Issue Title', - labels: [TEST_LABEL_ALLFORONE, TEST_LABEL_NOTBOUNTY_1], - body: `# This is the issue title -This is the issue body first line -This is the issue body second line -` - } -}; -const TEST_GENERATED_ISSUE = { - title: '[All For One] Issue Title', - labels: ['All For One', 'not-a-bounty-label'], - bountyType: 'All For One', - body: `Original external [issue](https://github.com/test_owner/test_repo/issues/1) - -Submitted by [ghsecuritylab](https://github.com/ghsecuritylab) - -# This is the issue title -This is the issue body first line -This is the issue body second line -` -}; -describe('log errors when generating issue content', () => { - it('outputs a message for invalid issue in payload', async () => { - const debugMock = jest.spyOn(core, 'debug'); - const issue = await replicate.generateInternalIssueContentFromPayload(TEST_INVALID_PAYLOAD_NOURL); - expect(debugMock).toHaveBeenCalledWith('Invalid issue payload'); - expect(issue).toBeUndefined(); - const issue2 = await replicate.generateInternalIssueContentFromPayload(TEST_INVALID_PAYLOAD_NOUSER); - expect(debugMock).toHaveBeenCalledWith('Invalid issue payload'); - expect(issue2).toBeUndefined(); - const issue3 = await replicate.generateInternalIssueContentFromPayload(TEST_INVALID_PAYLOAD_NOISSUE); - expect(debugMock).toHaveBeenCalledWith('Invalid issue payload'); - expect(issue3).toBeUndefined(); - }); -}); -describe('excludes non bounty issues', () => { - it('creates the proper issue', async () => { - const debugMock = jest.spyOn(core, 'debug'); - const issue = await replicate.generateInternalIssueContentFromPayload(TEST_PAYLOAD_NOTBOUNTY); - expect(debugMock).toHaveBeenCalledWith('Not a bounty'); - expect(issue).toBeUndefined(); - }); -}); -describe('generates proper content', () => { - it('creates the proper issue', async () => { - const issue = await replicate.generateInternalIssueContentFromPayload(TEST_PAYLOAD); - expect(issue).toBeDefined(); - expect(issue).toEqual(TEST_GENERATED_ISSUE); - }); -}); -describe('check for duplicates', () => { - it('can find duplicates', async () => { - const TEST_REF = 31; - const TEST_BODY1 = `Original external [issue](https://github.com/owner/repo/issues/1)\n\nThen there is some text`; - const TEST_BODY2 = `Original external [issue](https://github.com/owner/repo/issues/2)\n\nThen there is some text`; - const TEST_INTERNAL_ISSUES = [ - { title: 'issue 1', author: 'author1', body: TEST_BODY1, number: 31 }, - { title: 'issue 2', author: 'author2', body: TEST_BODY2, number: 33 } - ]; - let foundRef = issues.internalIssueAlreadyCreated('https://github.com/owner/repo/issues/1', TEST_INTERNAL_ISSUES); - expect(foundRef).toEqual(TEST_REF); - foundRef = issues.internalIssueAlreadyCreated('https://github.com/owner/repo/issues/3', TEST_INTERNAL_ISSUES); - expect(foundRef).toBeUndefined(); - }); -}); -//# sourceMappingURL=replicate.test.js.map \ No newline at end of file diff --git a/.github/actions/replicate/__tests__/replicate.test.ts b/.github/actions/replicate/__tests__/replicate.test.ts deleted file mode 100644 index cdd2c2b..0000000 --- a/.github/actions/replicate/__tests__/replicate.test.ts +++ /dev/null @@ -1,139 +0,0 @@ -import * as core from '@actions/core' -import * as replicate from '../replicate' -import * as issues from '../issues' -import { WebhookPayload, PayloadRepository } from '@actions/github/lib/interfaces' - -const TEST_ISSUE_1 = 1 -const TEST_REPOSITORY: PayloadRepository = { - full_name: 'myuser/myrepo', - name: 'myrepo', - owner: { - login: 'myuser', - name: 'My User' - } -} - -const TEST_INVALID_PAYLOAD_NOUSER: WebhookPayload = { - repository: TEST_REPOSITORY, - issue: { - number: TEST_ISSUE_1, - html_url: 'https://github.com/test_owner/test_repo/issues/1', - } -} - -const TEST_INVALID_PAYLOAD_NOURL: WebhookPayload = { - repository: TEST_REPOSITORY, - issue: { - number: TEST_ISSUE_1, - user: { - login: 'issue_user', - html_url: 'https://github.com/users/issue_user' - } - } -} - -const TEST_INVALID_PAYLOAD_NOISSUE: WebhookPayload = { - repository: TEST_REPOSITORY, -} - -const TEST_LABEL_ALLFORONE = { name: 'All For One' } -const TEST_LABEL_NOTBOUNTY_1 = { name: 'not-a-bounty-label' } -const TEST_LABEL_NOTBOUNTY_2 = { name: 'not-a-bounty-label-either' } - -const TEST_PAYLOAD_NOTBOUNTY: WebhookPayload = { - repository: TEST_REPOSITORY, - issue: { - number: TEST_ISSUE_1, - html_url: 'https://github.com/test_owner/test_repo/issues/1', - user: { - login: 'issue_user', - html_url: 'https://github.com/users/issue_user' - }, - labels: [TEST_LABEL_NOTBOUNTY_1,TEST_LABEL_NOTBOUNTY_2], - } -} - -const TEST_PAYLOAD: WebhookPayload = { - repository: TEST_REPOSITORY, - issue: { - number: TEST_ISSUE_1, - html_url: 'https://github.com/test_owner/test_repo/issues/1', - user: { - login: 'ghsecuritylab', - html_url: 'https://github.com/ghsecuritylab' - }, - title: 'Issue Title', - labels: [TEST_LABEL_ALLFORONE,TEST_LABEL_NOTBOUNTY_1], - body: `# This is the issue title -This is the issue body first line -This is the issue body second line -` - } -} - -const TEST_GENERATED_ISSUE: replicate.Issue = { - title: '[All For One] Issue Title', - labels: ['All For One','not-a-bounty-label'], - bountyType: 'All For One', - body: `Original external [issue](https://github.com/test_owner/test_repo/issues/1) - -Submitted by [ghsecuritylab](https://github.com/ghsecuritylab) - -# This is the issue title -This is the issue body first line -This is the issue body second line -` -} - -describe('log errors when generating issue content', () => { - it('outputs a message for invalid issue in payload', async () => { - const debugMock = jest.spyOn(core, 'debug') - const issue = await replicate.generateInternalIssueContentFromPayload(TEST_INVALID_PAYLOAD_NOURL) - expect(debugMock).toHaveBeenCalledWith('Invalid issue payload') - expect(issue).toBeUndefined() - - const issue2 = await replicate.generateInternalIssueContentFromPayload(TEST_INVALID_PAYLOAD_NOUSER) - expect(debugMock).toHaveBeenCalledWith('Invalid issue payload') - expect(issue2).toBeUndefined() - - const issue3 = await replicate.generateInternalIssueContentFromPayload(TEST_INVALID_PAYLOAD_NOISSUE) - expect(debugMock).toHaveBeenCalledWith('Invalid issue payload') - expect(issue3).toBeUndefined() - - }) -}) - -describe('excludes non bounty issues', () => { - it('creates the proper issue', async () => { - const debugMock = jest.spyOn(core, 'debug') - const issue = await replicate.generateInternalIssueContentFromPayload(TEST_PAYLOAD_NOTBOUNTY) - expect(debugMock).toHaveBeenCalledWith('Not a bounty') - expect(issue).toBeUndefined() - }) -}) - -describe('generates proper content', () => { - it('creates the proper issue', async () => { - const issue = await replicate.generateInternalIssueContentFromPayload(TEST_PAYLOAD) - expect(issue).toBeDefined() - expect(issue).toEqual(TEST_GENERATED_ISSUE) - }) -}) - -describe('check for duplicates', () => { - it('can find duplicates', async () => { - const TEST_REF: number = 31 - const TEST_BODY1 = `Original external [issue](https://github.com/owner/repo/issues/1)\n\nThen there is some text` - const TEST_BODY2 = `Original external [issue](https://github.com/owner/repo/issues/2)\n\nThen there is some text` - const TEST_INTERNAL_ISSUES: issues.Issue_info[] = [ - {title: 'issue 1', author: 'author1', body: TEST_BODY1, number: 31}, - {title: 'issue 2', author: 'author2', body: TEST_BODY2, number: 33} - ] - let foundRef: number | undefined = issues.internalIssueAlreadyCreated('https://github.com/owner/repo/issues/1', TEST_INTERNAL_ISSUES) - expect(foundRef).toEqual(TEST_REF) - foundRef = issues.internalIssueAlreadyCreated('https://github.com/owner/repo/issues/3', TEST_INTERNAL_ISSUES) - expect(foundRef).toBeUndefined() - }) -}) - - diff --git a/.github/actions/replicate/action.yml b/.github/actions/replicate/action.yml deleted file mode 100644 index 8860a2b..0000000 --- a/.github/actions/replicate/action.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: 'replicate-action' -description: 'Replicates bounty internal' -author: 'xcorail' -inputs: - internal_repo: - description: 'The destination repo for the internal issue' - default: 'github/securitylab-bounties' - existing_issue: - description: 'Launching on existing issues: we check duplicates, and we do not comment the original issue' - default: false - specific_issue: - description: 'Specific issue to replicate, in case of manual trigger' - default: '' -runs: - using: 'node12' - main: './replicate.js' \ No newline at end of file diff --git a/.github/actions/replicate/issues.js b/.github/actions/replicate/issues.js deleted file mode 100644 index 2afb124..0000000 --- a/.github/actions/replicate/issues.js +++ /dev/null @@ -1,94 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (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 (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.internalIssueAlreadyCreated = exports.isUserAlreadyParticipant = exports.getIssueList = void 0; -const core = __importStar(require("@actions/core")); -const github = __importStar(require("@actions/github")); -const replicate = __importStar(require("./replicate")); -exports.getIssueList = async (owner, repo, token, open, checkBountyLabels, per_page) => { - if (!token) { - core.debug("No valid token for creating issues on the internal repo"); - return; - } - try { - let result = []; - const octokit = new github.GitHub(token); - const issueState = open ? 'open' : 'all'; - // const labelFilter: string = replicate.BOUNTY_LABELS.join(',') - const issuesPerPage = per_page ? per_page : 50; - let pageNb = 0; - do { - const issues = await octokit.issues.listForRepo({ - owner, - repo, - state: issueState, - per_page: issuesPerPage, - page: pageNb - // labels: labelFilter -- Does not work properly - }); - issues.data.forEach(issue => { - var _a; - const bountyLabel = checkBountyLabels ? issue.labels.some(label => { - return replicate.BOUNTY_LABELS.includes(label.name); - }) : undefined; - if (!checkBountyLabels || bountyLabel) { - let item = { - title: issue.title, - author: (_a = issue.user) === null || _a === void 0 ? void 0 : _a.login, - body: issue.body ? issue.body : '', - number: issue.number, - html_url: issue.html_url - }; - result.push(item); - } - }); - pageNb = (issues.data.length < issuesPerPage) ? -1 : pageNb + 1; - } while (pageNb >= 0); - return result; - } - catch (error) { - core.debug(error.message); - return undefined; - } -}; -exports.isUserAlreadyParticipant = (user, externalSubmissions) => { - if (!externalSubmissions) - return false; - const check = externalSubmissions.some(element => { - return (element.author === user); - }); - return check; -}; -function escapeRegExp(text) { - return text.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); -} -exports.internalIssueAlreadyCreated = (externalSubmissionUrl, internalIssues) => { - const searchString = new RegExp(escapeRegExp(`Original external [issue](${externalSubmissionUrl})`)); - let ref = undefined; - internalIssues.some(element => { - if (element.body.search(searchString) != -1) { - ref = element.number; - return true; - } - }); - return ref; -}; -//# sourceMappingURL=issues.js.map \ No newline at end of file diff --git a/.github/actions/replicate/issues.ts b/.github/actions/replicate/issues.ts deleted file mode 100644 index de5d6ba..0000000 --- a/.github/actions/replicate/issues.ts +++ /dev/null @@ -1,77 +0,0 @@ -import * as core from '@actions/core' -import * as github from '@actions/github' -import * as replicate from './replicate' - -export type Issue_info = {title: string, author: string, body: string, number: number, html_url?: string} -type Issue_state = 'open' | 'all' | 'closed' | undefined - -export const getIssueList = async (owner: string, repo: string, token: string | undefined, open: boolean, checkBountyLabels: boolean, per_page?: number) : Promise => { - if(!token) { - core.debug("No valid token for creating issues on the internal repo") - return - } - try { - let result: Issue_info[] = [] - const octokit = new github.GitHub(token) - const issueState: Issue_state = open? 'open' : 'all' - // const labelFilter: string = replicate.BOUNTY_LABELS.join(',') - const issuesPerPage = per_page? per_page : 50 - let pageNb = 0 - do { - const issues = await octokit.issues.listForRepo({ - owner, - repo, - state: issueState, - per_page: issuesPerPage, - page: pageNb - // labels: labelFilter -- Does not work properly - }) - - issues.data.forEach(issue => { - const bountyLabel = checkBountyLabels? issue.labels.some(label => { - return replicate.BOUNTY_LABELS.includes(label.name as replicate.BountyType) - }) : undefined - if(!checkBountyLabels || bountyLabel){ - let item: Issue_info = { - title: issue.title, - author: issue.user?.login, - body: issue.body? issue.body : '', - number: issue.number, - html_url: issue.html_url - } - result.push(item) - } - }); - pageNb = (issues.data.length < issuesPerPage)? -1 : pageNb + 1 - } while (pageNb >= 0) - return result - } catch(error) { - core.debug(error.message) - return undefined - } -} - -export const isUserAlreadyParticipant = (user: string, externalSubmissions: Issue_info[] | undefined) : boolean => { - if(!externalSubmissions) - return false - const check = externalSubmissions.some( element => { - return (element.author === user) - }) - return check -} - -function escapeRegExp(text: string) { - return text.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') -} - -export const internalIssueAlreadyCreated = (externalSubmissionUrl: string | undefined, internalIssues: Issue_info[]) : number | undefined => { - const searchString = new RegExp(escapeRegExp(`Original external [issue](${externalSubmissionUrl})`)) - let ref: number | undefined = undefined - internalIssues.some( element => { - if(element.body.search(searchString) != -1) { - ref = element.number - return true - } - }) - return ref -} diff --git a/.github/actions/replicate/replicate.js b/.github/actions/replicate/replicate.js deleted file mode 100644 index 42cee35..0000000 --- a/.github/actions/replicate/replicate.js +++ /dev/null @@ -1,204 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (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 (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createInternalIssue = exports.generateInternalIssueContentFromPayload = exports.BOUNTY_LABELS = void 0; -const core = __importStar(require("@actions/core")); -const github = __importStar(require("@actions/github")); -const issues_1 = require("./issues"); -exports.BOUNTY_LABELS = ['All For One', 'The Bug Slayer']; -const COMMENT_TASK_LIST_AFO = `## Task List - -- **If this is your first time in this process, have a look at that [5 min video](https://drive.google.com/file/d/1Uy3JukURoSk-2Bq7EjyagVdpsyvKI67E)** -- **Visit the [documented process](https://github.com/github/pe-security-lab/blob/main/docs/bug_bounty.md)** - -- [ ] CodeQL Initial assessment - In case of rejection, please record your decision in the comment below: - - [ ] Acceptance - - [ ] Generate result set and post the URL in the comment -- [ ] Security Lab assessment - In case of rejection, please record your decision in the comment below: - - [ ] Acceptance - - [ ] Score the Vulnerability Impact, the Vulnerability Scope, and the False Positive ratio based on the provided CodeQL result set - - [ ] Document your assessments in comments below, for the CodeQL team - - [ ] Provide feedback to the author in the PR -- [ ] CodeQL assessment: - - [ ] Provide feedback to the author in the PR - - [ ] Merge the PR into the experimental folder - - [ ] Score the Code Maturity and the Documentation -- [ ] Bounty Payment -`; -const COMMENT_TASK_LIST_BS = `## Task List -- [ ] Security Lab assessment: - - [ ] Acceptance - - [ ] Confirm the CVE - - [ ] Assess the Vulnerability Impact, the Vulnerability Scope - - [ ] Get the CodeQL scores (False Positive ratio, Code Maturity and the Documentation) from the previous query rating - - [ ] PR is merged? Finalize the score -- [ ] Bounty Payment`; -const COMMENT_TASK_LIST = { - 'All For One': COMMENT_TASK_LIST_AFO, - 'The Bug Slayer': COMMENT_TASK_LIST_BS -}; -const COMMENT_SCORING = `## Scoring - -- **Visit the [scoring guidelines](https://github.com/github/pe-security-lab/blob/main/docs/bug_bounty.md)** -- **Accepted values are: 0 (= NA), or 1 (minimal) to 5 (maximal). Any other value will throw an error** - -| Criterion | Score| -|--- | --- | -| Vulnerability Impact | | -| Vulnerability Scope | | -| False Positive | | -| Code Maturity | | -| Documentation | | - -- [ ] Reject -- [ ] Reject with thank you reward -- [ ] Reject with encouragement swag (Decision: Dev Advocacy) -- [ ] Accept -`; -const getIssueFromRef = async (issueRef) => { - if (!issueRef) - return undefined; - const token = process.env['GITHUB_TOKEN']; - if (token === undefined) - return undefined; - const octokit = new github.GitHub(token); - const issueResponse = await octokit.issues.get({ - owner: github.context.repo.owner, - repo: github.context.repo.repo, - issue_number: Number(issueRef), - }); - return issueResponse.data; -}; -exports.generateInternalIssueContentFromPayload = async (payload, issueRef) => { - const issue = await getIssueFromRef(issueRef) || (payload === null || payload === void 0 ? void 0 : payload.issue); - let result = { title: 'none', body: 'none', labels: [], bountyType: 'All For One' }; - let bountyIssue = false; - if (!issue || !issue.user || !issue.html_url) { - core.debug("Invalid issue payload"); - return undefined; - } - issue.labels.forEach((element) => { - result.labels.push(element.name); - if (!bountyIssue) { - bountyIssue = exports.BOUNTY_LABELS.includes(element.name); - if (bountyIssue) { - result.bountyType = element.name; - } - } - }); - if (!bountyIssue) { - core.debug("Not a bounty"); - return undefined; - } - result.title = `[${result.bountyType}] ${issue.title}`, - // In order to differentiate immediately the issues from others in the repo - // And with the current situation, the robot with Read access cannot add labels to the issue - result.body = `Original external [issue](${issue.html_url}) - -Submitted by [${issue.user.login}](${issue.user.html_url}) - -${issue.body ? issue.body : ""}`; - return result; -}; -exports.createInternalIssue = async (issue) => { - const internalRepoAccessToken = process.env['INT_REPO_TOKEN']; - let internal_ref = undefined; - if (!internalRepoAccessToken) { - core.debug("No valid token for creating issues on the internal repo"); - return; - } - try { - const octokit = new github.GitHub(internalRepoAccessToken); - const internalRepo = core.getInput('internal_repo') || '/'; - const [owner, repo] = internalRepo.split('/'); - const issueResponse = await octokit.issues.create({ - owner, - repo, - title: issue.title, - body: issue.body, - labels: issue.labels - }); - internal_ref = issueResponse.data.number; - core.debug(`issue created: ${internal_ref}`); - const labelsResponse = await octokit.issues.addLabels({ - owner, - repo, - issue_number: internal_ref, - labels: issue.labels - }); - core.debug(`Labels addition result: ${labelsResponse.status} ${(labelsResponse.status == 200) ? "OK" : "FAILED"}`); - const issueCommentResponse1 = await octokit.issues.createComment({ - owner, - repo, - issue_number: internal_ref, - body: COMMENT_TASK_LIST[issue.bountyType], - }); - core.debug(`comment created ${issueCommentResponse1.data.url}`); - const issueCommentResponse2 = await octokit.issues.createComment({ - owner, - repo, - issue_number: internal_ref, - body: COMMENT_SCORING, - }); - core.debug(`comment created ${issueCommentResponse2.data.url}`); - const issueCard = await octokit.projects.createCard({ - column_id: (issue.labels.includes(exports.BOUNTY_LABELS[1])) ? 10205381 : 10205379, - content_id: internal_ref, - content_type: 'issue', - }); - core.debug(`Card creation status: ${issueCard.status}`); - } - catch (error) { - core.debug(error.message); - } - return internal_ref; -}; -const checkDuplicates = async (payload) => { - var _a; - const internalRepoAccessToken = process.env['INT_REPO_TOKEN']; - const internalRepo = core.getInput('internal_repo') || '/'; - const [owner, repo] = internalRepo.split('/'); - const internalIssues = await issues_1.getIssueList(owner, repo, internalRepoAccessToken, false, false); - if (!internalIssues) { - core.debug('Internal error. Cannot check for duplicates. Aborting'); - return true; - } - else { - const ref = issues_1.internalIssueAlreadyCreated((_a = payload.issue) === null || _a === void 0 ? void 0 : _a.html_url, internalIssues); - if (ref) { - core.debug(`This issue has already been duplicated with reference ${ref}`); - return true; - } - } - return false; -}; -const run = async () => { - const internalIssue = await exports.generateInternalIssueContentFromPayload(github.context.payload, core.getInput('specific_issue')); - if (!internalIssue) - return; - if (await checkDuplicates(github.context.payload)) - return; - const internal_ref = await exports.createInternalIssue(internalIssue); - if (!internal_ref) - return; -}; -run(); -//# sourceMappingURL=replicate.js.map diff --git a/.github/actions/replicate/replicate.ts b/.github/actions/replicate/replicate.ts deleted file mode 100644 index fc1c9e8..0000000 --- a/.github/actions/replicate/replicate.ts +++ /dev/null @@ -1,206 +0,0 @@ -import * as core from '@actions/core' -import * as github from '@actions/github' -import { WebhookPayload } from '@actions/github/lib/interfaces' -import { getIssueList, internalIssueAlreadyCreated } from './issues' - -export const BOUNTY_LABELS = ['All For One', 'The Bug Slayer'] as const -export type BountyType = typeof BOUNTY_LABELS[number] -type CommentMap = {[K in BountyType]: string} -export type Issue = {title: string, body: string, labels: string[], bountyType: BountyType} -type GitHubIssue = { [key: string]: any, number: number, html_url?: string | undefined, body?: string | undefined} - -const COMMENT_TASK_LIST_AFO = `## Task List - -- **If this is your first time in this process, have a look at that [5 min video](https://drive.google.com/file/d/1Uy3JukURoSk-2Bq7EjyagVdpsyvKI67E)** -- **Visit the [documented process](https://github.com/github/pe-security-lab/blob/main/docs/bug_bounty.md)** - -- [ ] CodeQL Initial assessment - In case of rejection, please record your decision in the comment below: - - [ ] Acceptance - - [ ] Generate result set and post the URL in the comment -- [ ] Security Lab assessment - In case of rejection, please record your decision in the comment below: - - [ ] Acceptance - - [ ] Score the Vulnerability Impact, the Vulnerability Scope, and the False Positive ratio based on the provided CodeQL result set - - [ ] Document your assessments in comments below, for the CodeQL team - - [ ] Provide feedback to the author in the PR -- [ ] CodeQL assessment: - - [ ] Provide feedback to the author in the PR - - [ ] Merge the PR into the experimental folder - - [ ] Score the Code Maturity and the Documentation -- [ ] Bounty Payment -` - -const COMMENT_TASK_LIST_BS = `## Task List -- [ ] Security Lab assessment: - - [ ] Acceptance - - [ ] Confirm the CVE - - [ ] Assess the Vulnerability Impact, the Vulnerability Scope - - [ ] Get the CodeQL scores (False Positive ratio, Code Maturity and the Documentation) from the previous query rating - - [ ] PR is merged? Finalize the score -- [ ] Bounty Payment` - -const COMMENT_TASK_LIST: CommentMap = { - 'All For One': COMMENT_TASK_LIST_AFO, - 'The Bug Slayer': COMMENT_TASK_LIST_BS -} - -const COMMENT_SCORING = `## Scoring - -- **Visit the [scoring guidelines](https://github.com/github/pe-security-lab/blob/main/docs/bug_bounty.md)** -- **Accepted values are: 0 (= NA), or 1 (minimal) to 5 (maximal). Any other value will throw an error** - -| Criterion | Score| -|--- | --- | -| Vulnerability Impact | | -| Vulnerability Scope | | -| False Positive | | -| Code Maturity | | -| Documentation | | - -- [ ] Reject -- [ ] Reject with thank you reward -- [ ] Reject with encouragement swag (Decision: Dev Advocacy) -- [ ] Accept -` - -const getIssueFromRef = async (issueRef: string | undefined): Promise => { - if(!issueRef) - return undefined - const token: string | undefined = process.env['GITHUB_TOKEN'] - if(token === undefined) - return undefined - const octokit: github.GitHub = new github.GitHub(token) - const issueResponse = await octokit.issues.get({ - owner: github.context.repo.owner, - repo: github.context.repo.repo, - issue_number: Number(issueRef), - }); - return issueResponse.data -} - -export const generateInternalIssueContentFromPayload = async (payload?: WebhookPayload, issueRef?: string): Promise => { - const issue = await getIssueFromRef(issueRef) || payload?.issue - let result: Issue = {title: 'none', body: 'none', labels: [], bountyType: 'All For One'} - let bountyIssue: boolean = false - - if(!issue || !issue.user || !issue.html_url) { - core.debug("Invalid issue payload") - return undefined - } - - issue.labels.forEach((element:any) => { - result.labels.push(element.name) - if(!bountyIssue) { - bountyIssue = BOUNTY_LABELS.includes(element.name) - if(bountyIssue) { - result.bountyType = element.name - } - } - }); - - if(!bountyIssue) { - core.debug("Not a bounty") - return undefined - } - - result.title = `[${result.bountyType}] ${issue.title}`, - // In order to differentiate immediately the issues from others in the repo - // And with the current situation, the robot with Read access cannot add labels to the issue - result.body = `Original external [issue](${issue.html_url}) - -Submitted by [${issue.user.login}](${issue.user.html_url}) - -${issue.body? issue.body : ""}` - - return result -} - -export const createInternalIssue = async (issue: Issue) : Promise => { - const internalRepoAccessToken: string | undefined = process.env['INT_REPO_TOKEN'] - let internal_ref: number | undefined = undefined - - if(!internalRepoAccessToken) { - core.debug("No valid token for creating issues on the internal repo") - return - } - try { - const octokit: github.GitHub = new github.GitHub(internalRepoAccessToken) - const internalRepo = core.getInput('internal_repo') || '/' - const [owner, repo] = internalRepo.split('/') - const issueResponse = await octokit.issues.create( { - owner, - repo, - title: issue.title, - body: issue.body, - labels: issue.labels - }) - internal_ref = issueResponse.data.number - core.debug(`issue created: ${internal_ref}`) - const labelsResponse = await octokit.issues.addLabels( { - owner, - repo, - issue_number: internal_ref, - labels: issue.labels - }) - core.debug(`Labels addition result: ${labelsResponse.status} ${(labelsResponse.status==200)? "OK" : "FAILED"}`) - - const issueCommentResponse1 = await octokit.issues.createComment({ - owner, - repo, - issue_number: internal_ref, - body: COMMENT_TASK_LIST[issue.bountyType], - }) - core.debug(`comment created ${issueCommentResponse1.data.url}`) - - const issueCommentResponse2 = await octokit.issues.createComment({ - owner, - repo, - issue_number: internal_ref, - body: COMMENT_SCORING, - }) - core.debug(`comment created ${issueCommentResponse2.data.url}`) - - const issueCard = await octokit.projects.createCard({ - column_id: (issue.labels.includes(BOUNTY_LABELS[1]))? 10205381 : 10205379, - content_id: internal_ref, - content_type: 'issue', - }); - core.debug(`Card creation status: ${issueCard.status}`) - - } catch(error) { - core.debug(error.message) - } - return internal_ref -} - -const checkDuplicates = async (payload: WebhookPayload): Promise => { - const internalRepoAccessToken: string | undefined = process.env['INT_REPO_TOKEN'] - const internalRepo = core.getInput('internal_repo') || '/' - const [owner, repo] = internalRepo.split('/') - const internalIssues = await getIssueList(owner, repo, internalRepoAccessToken, false, false) - if(!internalIssues) { - core.debug('Internal error. Cannot check for duplicates. Aborting') - return true - } else { - const ref = internalIssueAlreadyCreated(payload.issue?.html_url, internalIssues) - if(ref) { - core.debug(`This issue has already been duplicated with reference ${ref}`) - return true - } - } - return false -} - -const run = async (): Promise => { - const internalIssue = await generateInternalIssueContentFromPayload(github.context.payload, core.getInput('specific_issue')) - if(!internalIssue) - return - - if(await checkDuplicates(github.context.payload)) - return - - const internal_ref = await createInternalIssue(internalIssue) - if(!internal_ref) - return -} - -run() diff --git a/.github/workflows/check-replication-manual.yml b/.github/workflows/check-replication-manual.yml deleted file mode 100644 index 0e1eef3..0000000 --- a/.github/workflows/check-replication-manual.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: 'Bounty issue manual replication check' -on: workflow_dispatch - -jobs: - build: - name: check-replicate-manual - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - - run: npm install - - run: npm run build - - uses: ./.github/actions/check - with: - internal_repo: 'github/securitylab-bounties' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - INT_REPO_TOKEN: ${{ secrets.INT_REPO_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/check-replication.yml b/.github/workflows/check-replication.yml deleted file mode 100644 index 21c243f..0000000 --- a/.github/workflows/check-replication.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: 'Bounty issue replication check' -on: - schedule: - - cron: '0 17 * * *' - -jobs: - build: - name: check-replicate - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - - run: npm install - - run: npm run build - - uses: ./.github/actions/check - with: - internal_repo: 'github/securitylab-bounties' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - INT_REPO_TOKEN: ${{ secrets.INT_REPO_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/replicate-manual.yml b/.github/workflows/replicate-manual.yml deleted file mode 100644 index 183ab15..0000000 --- a/.github/workflows/replicate-manual.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: 'Bounty issue manual replication workflow' -on: - workflow_dispatch: - inputs: - issue: - description: 'Issue number to replicate' - required: true - -jobs: - build: - name: replicate-manual - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - - run: npm install - - run: npm run build - - uses: ./.github/actions/replicate - with: - internal_repo: 'github/securitylab-bounties' - existing_issue: false - specific_issue: ${{ github.event.inputs.issue }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - INT_REPO_TOKEN: ${{ secrets.INT_REPO_TOKEN }} - diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml deleted file mode 100644 index 0b42c85..0000000 --- a/.github/workflows/workflow.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: 'Bounty issue replication workflow' -on: - issues: - types: [opened] -jobs: - build: - name: replicate-new - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - - run: npm install - - run: npm run build - - uses: ./.github/actions/replicate - with: - internal_repo: 'github/securitylab-bounties' - existing_issue: false - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - INT_REPO_TOKEN: ${{ secrets.INT_REPO_TOKEN }} -