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
10 changes: 10 additions & 0 deletions .github/actions/check/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
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'
55 changes: 55 additions & 0 deletions .github/actions/check/check-replication.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions .github/actions/check/check-replication.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as core from '@actions/core'
import * as github from '@actions/github'
import { getIssueList, internalIssueAlreadyCreated } from '../replicate/issues'

const run = async (): Promise<void> => {
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 {
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
}
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()

7 changes: 5 additions & 2 deletions .github/actions/replicate/action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: 'debug-action'
description: 'Outputs debug information'
name: 'replicate-action'
description: 'Replicates bounty internal'
author: 'xcorail'
inputs:
internal_repo:
Expand All @@ -8,6 +8,9 @@ inputs:
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'
3 changes: 2 additions & 1 deletion .github/actions/replicate/issues.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions .github/actions/replicate/issues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ 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}
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<Issue_info[] | undefined> => {
Expand Down Expand Up @@ -32,7 +32,8 @@ export const getIssueList = async (owner: string, repo: string, token: string |
title: issue.title,
author: issue.user?.login,
body: issue.body? issue.body : '',
number: issue.number
number: issue.number,
html_url: issue.html_url
}
result.push(item)
}
Expand Down
25 changes: 19 additions & 6 deletions .github/actions/replicate/replicate.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 28 additions & 6 deletions .github/actions/replicate/replicate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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
- [ ] CodeQL Initial assessment - In case of rejection, please record your decision in the comment below:
Expand Down Expand Up @@ -55,11 +56,25 @@ const COMMENT_SCORING = `## Scoring

const COMMENT_FIRST_SUBMISSION = `## :tada: First submission for this user :tada:`

export const generateInternalIssueContentFromPayload = async (payload: WebhookPayload): Promise<Issue | undefined> => {
const issue = payload.issue
const getIssueFromRef = async (issueRef: string | undefined): Promise<GitHubIssue | undefined> => {
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<Issue | undefined> => {
const issue = await getIssueFromRef(issueRef) || payload?.issue
let result: Issue = {title: 'none', body: 'none', labels: [], bountyType: 'All For One'}
let bountyIssue: boolean = false
let bountyType = ''

if(!issue || !issue.user || !issue.html_url) {
core.debug("Invalid issue payload")
Expand All @@ -71,7 +86,7 @@ export const generateInternalIssueContentFromPayload = async (payload: WebhookPa
if(!bountyIssue) {
bountyIssue = BOUNTY_LABELS.includes(element.name)
if(bountyIssue) {
bountyType = element.name
result.bountyType = element.name
}
}
});
Expand All @@ -81,7 +96,7 @@ export const generateInternalIssueContentFromPayload = async (payload: WebhookPa
return undefined
}

result.title = `[${bountyType}] ${issue.title}`,
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})
Expand Down Expand Up @@ -115,6 +130,13 @@ export const createInternalIssue = async (payload: WebhookPayload, issue: Issue)
})
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,
Expand Down Expand Up @@ -202,7 +224,7 @@ export const isFirstSubmission = async (payload: WebhookPayload, token : string
}

const run = async (): Promise<void> => {
const internalIssue = await generateInternalIssueContentFromPayload(github.context.payload)
const internalIssue = await generateInternalIssueContentFromPayload(github.context.payload, core.getInput('specific_issue'))
if(!internalIssue)
return

Expand Down
19 changes: 19 additions & 0 deletions .github/workflows/check-replication-manual.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: 'Bounty issue replication workflow'
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 }}
21 changes: 21 additions & 0 deletions .github/workflows/check-replication.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: 'Bounty issue replication workflow'
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 }}
27 changes: 27 additions & 0 deletions .github/workflows/replicate-manual.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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 }}

6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.