Skip to content

Commit

Permalink
Create GitHub Action for validating CodeQL usage
Browse files Browse the repository at this point in the history
Signed-off-by: Brett Logan <lindluni@github.com>
  • Loading branch information
lindluni committed Oct 20, 2023
1 parent 1cb1b1e commit 506e66f
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Enforce
on:
pull_request: {}
permissions:
contents: read
pull-requests: write
security-events: read
jobs:
verify:
name: Verify CodeQL Usage
runs-on: ubuntu-latest
steps:
- name: Validate CodeQL Usage
uses: department-of-veterans-affairs/codeql-tools/verify-codeql-usage@main
with:
message_violation: |
Your repository is not in compliance with OIS requirements for CodeQL usage.
Your repository contains **{highAlerts} high severity** vulnerabilities and **{criticalAlerts} critical severity** vulnerabilities.
Per OIS policy, your repository must remediate critical and high vulnerabilities before you may merge additional source code changes. If this Pull Request remediates vulnerabilities, after your Pull Requests CodeQL scan completes, please re-trigger validation by clicking the `Re-run all jobs` button in the top-right corner at this link: <place link here>. Once validation reruns, you will be able to merge your Pull Request.
For additional information about OIS policy, please refer to the OIS SWA Wiki: https://department-of-veterans-affairs.github.io/ois-swa-wiki/docs/ghas/codeql-usage
File renamed without changes.
30 changes: 30 additions & 0 deletions enforce-ghas-policy/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Enforce GHAS Policy
description: Validates that repository is remediating GHAS vulnerability alerts
author: GitHub Expert Services
inputs:
org:
description: The slug of the organization
required: true
default: ${{ github.repository_owner }}
message_violation:
description: The message to use when CodeQL is missing
required: true
pull_request_number:
description: The ID of the pull request
required: true
default: ${{ github.event.pull_request.number }}
ref:
description: The ref to use for the pull request
required: true
default: ${{ github.ref }}
repo:
description: The slug of the repository
required: true
default: ${{ github.event.repository.name }}
token:
description: The token to use for authentication
required: true
default: ${{ github.token }}
runs:
using: node16
main: dist/index.js
98 changes: 98 additions & 0 deletions enforce-ghas-policy/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const core = require('@actions/core')
const {Octokit} = require('@octokit/rest')
const {retry} = require('@octokit/plugin-retry')
const {throttling} = require('@octokit/plugin-throttling')

const org = core.getInput('ORG', {required: true, trimWhitespace: true})
const repo = core.getInput('REPO', {required: true, trimWhitespace: true})
const ref = core.getInput('REF', {required: true, trimWhitespace: true})
const messageViolation = core.getInput('MESSAGE_VIOLATION', {required: true, trimWhitespace: true})
const pullRequestNumber = core.getInput('PULL_REQUEST_NUMBER', {required: true, trimWhitespace: true})
const token = core.getInput('TOKEN', {required: true, trimWhitespace: true})

const _Octokit = Octokit.plugin(retry, throttling)
const client = new _Octokit({
auth: token,
throttle: {
onRateLimit: (retryAfter, options, octokit) => {
octokit.log.warn(`Request quota exhausted for request ${options.method} ${options.url}`);
if (options.request.retryCount === 0) {
octokit.log.info(`Retrying after ${retryAfter} seconds!`);
return true;
}
},
onSecondaryRateLimit: (retryAfter, options, octokit) => {
octokit.log.warn(`Abuse detected for request ${options.method} ${options.url}`);
},
}

})

const comment = async (org, repo, number, message) => {
try {
core.info(`Commenting on PR #${number}`)
await client.issues.createComment({
owner: org,
repo: repo,
issue_number: number,
body: message
})
} catch (e) {
core.setFailed(`Error commenting on PR #${number}: ${e.message}`)
process.exit(0)
}
}

const main = async () => {
try {
core.info('Checking if repository ignored')
await client.repos.getContent({
owner: org,
repo: repo,
path: '.github/.emass-repo-ignore'
})
core.info(`Repository is ignored, skipping CodeQL usage check`)
process.exit(0)
} catch (e) {
if (e.status !== 404) {
core.setFailed(`Error checking if repository is ignored: ${e.message}`)
process.exit(0)
}
}

try {
core.info('Retrieving CodeQL Code Scanning alerts')
const highAlerts = await client.paginate(client.codeScanning.listAlertsForRepo, {
owner: org,
repo: repo,
ref: ref,
severity: 'high',
state: 'open',
tool_name: 'CodeQL',
})
const criticalAlerts = await client.paginate(client.codeScanning.listAlertsForRepo, {
owner: org,
repo: repo,
ref: ref,
severity: 'high',
state: 'open',
tool_name: 'CodeQL',
})
if (highAlerts.length > 0 || criticalAlerts.length > 0) {
core.info(`Found ${highAlerts.length} high and ${criticalAlerts.length} critical alerts`)
const message = messageViolation.replace('{highAlerts}', String(highAlerts.length)).replace('{criticalAlerts}', String(criticalAlerts.length))
await comment(org, repo, pullRequestNumber, message)
core.setFailed(`GHAS security policy violation found, please open a ticket here https://github.com/department-of-veterans-affairs/github-user-requests/issues/new/choose for additional help.`)
process.exit(1)
}
} catch (e) {
core.setFailed(`Error checking for GHAS usage, please open a ticket here https://github.com/department-of-veterans-affairs/github-user-requests/issues/new/choose for additional help: ${e.message}`)
process.exit(0)
}
core.info(`GHAS security policy check complete`)
}

main().catch(e => {
core.setFailed(e.message)
process.exit(0)
})

0 comments on commit 506e66f

Please sign in to comment.