From a932b95c390ef5234ff24d8129ee5356348d3dd3 Mon Sep 17 00:00:00 2001 From: Andrea Brancaleoni Date: Thu, 6 Jun 2024 19:37:30 +0200 Subject: [PATCH] Remove root actions --- action.cjs | 268 ----------------------------------------------------- action.yml | 127 ------------------------- 2 files changed, 395 deletions(-) delete mode 100644 action.cjs delete mode 100644 action.yml diff --git a/action.cjs b/action.cjs deleted file mode 100644 index 0ce2f644..00000000 --- a/action.cjs +++ /dev/null @@ -1,268 +0,0 @@ -const fs = require('fs') -const { spawn } = require('child_process') - -const CONSOLE_BLUE = '\x1B[0;34m' -const CONSOLE_RED = '\x1b[0;31m' -const RESET_CONSOLE_COLOR = '\x1b[0m' - -const ASSIGNEES = `thypon -bcaller` -const HOTWORDS = `password -cryptography -login -policy -authentication -authorization -authn -authz -oauth -secure -insecure -safebrowsing -safe browsing -csp -url parse -urlparse -:disableDigestUpdates -pinDigest` - -function runCommand () { - const args = Array.prototype.slice.call(arguments) - return new Promise((resolve, reject) => { - const childProcess = spawn.apply(null, args) - - childProcess.stdout.on('data', (data) => { - console.log(`stdout: ${data}`) - }) - - childProcess.stderr.on('data', (data) => { - console.error(`stderr: ${data}`) - }) - - childProcess.on('close', (code) => { - if (code !== 0) { - reject(new Error(`Command exited with code ${code}`)) - } else { - resolve() - } - }) - }) -} - -module.exports = async ({ github, context, inputs, actionPath, core, debug = false }) => { - const { default: getConfig } = await import(`${actionPath}/src/getConfig.js`) - const { default: getProperties } = await import(`${actionPath}/src/getProperties.js`) - - // delete if empty string in inputs value - Object.keys(inputs).forEach(key => inputs[key] === '' && delete inputs[key]) - - const config = await getConfig({ owner: context.repo.owner, repo: context.repo.repo, path: '.github/security-action.json', debug, github }) - const properties = await getProperties({ owner: context.repo.owner, repo: context.repo.repo, debug, github, prefix: 'security_action_' }) - - const options = Object.assign({ - enabled: 'true', - baseline_scan_only: 'true', - assignees: ASSIGNEES, - hotwords: HOTWORDS, - hotwords_enabled: 'true' - }, config, properties, inputs) - - options.enabled = options.enabled === 'true' - options.hotwords_enabled = options.hotwords_enabled === 'true' - options.baseline_scan_only = options.baseline_scan_only === 'true' - options.debug = options.debug ? (options.debug === 'true') : debug - - const debugLog = options.debug ? console.log : () => {} - - debugLog('Options: ', options) - - if (!options.enabled) { return } - - debugLog('Security Action enabled') - // reviewdog-enabled-pr steps - const reviewdogEnabledPr = options.baseline_scan_only && process.env.GITHUB_EVENT_NAME === 'pull_request' && context.actor !== 'dependabot[bot]' - debugLog(`Security Action enabled for PR: ${reviewdogEnabledPr}, baseline_scan_only: ${options.baseline_scan_only}, GITHUB_EVENT_NAME: ${process.env.GITHUB_EVENT_NAME}, context.actor: ${context.actor}`) - // reviewdog-enabled-full steps - const reviewdogEnabledFull = !reviewdogEnabledPr && (!options.baseline_scan_only || process.env.GITHUB_EVENT_NAME === 'workflow_dispatch') - debugLog(`Security Action enabled for full: ${reviewdogEnabledFull}, baseline_scan_only: ${options.baseline_scan_only}, GITHUB_EVENT_NAME: ${process.env.GITHUB_EVENT_NAME}`) - // reviewdog-enabled steps - if (!reviewdogEnabledPr && !reviewdogEnabledFull) { return } - debugLog('Security Action enabled for reviewdog') - - // Install semgrep & pip-audit - await runCommand(`pip install --disable-pip-version-check -r ${actionPath}/requirements.txt`, { shell: true }) - debugLog('Installed semgrep & pip-audit') - // Install xmllint for safesvg - await runCommand('sudo apt-get install -y libxml2-utils', { shell: true }) - debugLog('Installed xmllint') - - // debug step - if (options.debug) { - const env = { - ...process.env, - ASSIGNEES: options.assignees - } - await runCommand(`${actionPath}/assets/debug.sh`, { env }) - debugLog('Debug step completed') - } - - // run-reviewdog-full step - if (reviewdogEnabledFull) { - const env = { ...process.env } - delete env.GITHUB_BASE_REF - await runCommand(`${actionPath}/assets/reviewdog.sh`, { env }) - debugLog('Reviewdog full step completed') - } - - if (reviewdogEnabledPr) { - // changed-files steps - const { default: pullRequestChangedFiles } = await import(`${actionPath}/src/pullRequestChangedFiles.js`) - const changedFiles = await pullRequestChangedFiles({ github, owner: context.repo.owner, name: context.repo.repo, prnumber: context.payload.pull_request.number }) - debugLog('Changed files:', changedFiles) - - // Write changed files to file - fs.writeFileSync(`${actionPath}/assets/all_changed_files.txt`, changedFiles.join('\0')) - debugLog('Wrote changed files to file') - - // comments-before steps - const { default: commentsNumber } = await import(`${actionPath}/src/steps/commentsNumber.js`) - const { default: cleanupComments } = await import(`${actionPath}/src/steps/cleanupComments.js`) - debugLog('Comments before:', await commentsNumber({ context, github })) - - const commentsBefore = await commentsNumber({ context, github }) - await cleanupComments({ context, github }) - - // unverified-commits steps - const { default: unverifiedCommits } = await import(`${actionPath}/src/steps/unverifiedCommits.js`) - - // add unverified-commits label step - const unverifiedCommitsSteps = await unverifiedCommits({ context, github }) - if (unverifiedCommitsSteps === '"UNVERIFIED-CHANGED"') { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - labels: ['unverified-commits'] - }) - debugLog('Added unverified-commits label') - } - - // run-reviewdog-pr step - const env = { - ...process.env, - ASSIGNEES: options.assignees, - REVIEWDOG_GITHUB_API_TOKEN: options.github_token, - SEC_ACTION_DEBUG: options.debug, - PYPI_INDEX_URL: options.pip_audit_pypi_index_url, - PYPI_INSECURE_HOSTS: options.pip_audit_pypi_insecure_hosts - } - await runCommand(`${actionPath}/assets/reviewdog.sh`, { env }) - debugLog('Reviewdog PR step completed') - - // comments-after step - const commentsAfter = await commentsNumber({ context, github }) - debugLog('Comments after:', commentsAfter) - - // assignees-after step - const { default: assigneesAfter } = await import(`${actionPath}/src/steps/assigneesAfter.js`) - const assigneesAfterVal = await assigneesAfter({ context, github, assignees: options.assignees }) - debugLog('Assignees after:', assigneesAfterVal) - - // assignee-removed-label step - const { default: assigneeRemoved } = await import(`${actionPath}/src/steps/assigneeRemoved.js`) - const assigneeRemovedLabel = await assigneeRemoved({ context, github, assignees: assigneesAfterVal }) - debugLog('Assignee removed:', assigneeRemovedLabel) - - // add description-contains-hotwords step - const { default: hotwords } = await import(`${actionPath}/src/steps/hotwords.js`) - const descriptionContainsHotwords = (context.actor !== 'renovate[bot]' && options.hotwords_enabled) ? await hotwords({ context, github, hotwords: options.hotwords }) : false - debugLog('Description contains hotwords:', descriptionContainsHotwords) - - // add should-trigger label step - const shouldTrigger = reviewdogEnabledPr && context.payload.pull_request.draft === false && !assigneeRemovedLabel && ((commentsBefore < commentsAfter) || descriptionContainsHotwords) - debugLog('Should trigger:', shouldTrigger) - - if (shouldTrigger) { - // add label step - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - labels: ['needs-security-review'] - }) - debugLog('Added needs-security-review label') - // add assignees step - await github.rest.issues.addAssignees({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - assignees: assigneesAfterVal.split(/\s+/).filter((str) => str !== '') - }) - debugLog('Added assignees') - } - - const { default: sendSlackMessage } = await import(`${actionPath}/src/sendSlackMessage.js`) - - const message = `Repository: [${process.env.GITHUB_REPOSITORY}](https://github.com/${process.env.GITHUB_REPOSITORY})\npull-request: ${context.payload.pull_request.html_url}\nFindings: ${commentsAfter}` - - let githubToSlack = {} - try { - githubToSlack = JSON.parse(options.gh_to_slack_user_map) - } catch (e) { - console.log('GH_TO_SLACK_USER_MAP is not valid JSON') - } - - // assignees-slack step - const assignees = assigneesAfterVal.toLowerCase().split(/\s+/).map(e => e.trim()).filter(Boolean) - const slackAssignees = assignees.map(m => githubToSlack[m] ? githubToSlack[m] : `@${m}`).join(' ') - core.setSecret(slackAssignees) - debugLog('Slack assignees:', slackAssignees) - - // actor-slack step - const actor = githubToSlack[context.actor] ? githubToSlack[context.actor] : `@${context.actor}` - core.setSecret(actor) - - if (fs.existsSync('reviewdog.fail.log')) { - // print reviewdog.fail.log to the console - const log = fs.readFileSync('reviewdog.fail.log', 'UTF-8').replaceAll(/^/g, CONSOLE_BLUE) - console.log(`${CONSOLE_RED}This action encountered an error while reporting the following findings via the Github API:`) - console.log(log) - console.log(`${CONSOLE_RED}The failure of this action should not prevent you from merging your PR. Please report this failure to the maintainers of https://github.com/brave/security-action ${RESET_CONSOLE_COLOR}`) - debugLog('Error log printed to console') - - if (options.slack_token) { - // reviewdog-fail-log-head step - const reviewdogFailLogHead = '\n' + fs.readFileSync('reviewdog.fail.log', 'UTF-8').split('\n').slice(0, 4).join('\n') - debugLog('Reviewdog fail log head:', reviewdogFailLogHead) - - // send error slack message, if there is any error - await sendSlackMessage({ - token: options.slack_token, - text: `[error] ${actor} action failed, plz take a look. /cc ${slackAssignees} ${reviewdogFailLogHead}`, - message, - channel: '#secops-hotspots', - color: 'red', - username: 'security-action' - }) - debugLog('Sent error slack message') - } else { - // throw error if no slack token is provided, and there is an error log - debugLog('Error was thrown and Slack token is missing, exiting eagerly!') - throw new Error('Error was thrown and Slack token is missing, exiting eagerly!') - } - } - - if (options.slack_token && shouldTrigger) { - // Send slack message, if there are any findings - await sendSlackMessage({ - token: options.slack_token, - text: `[security-action] ${actor} pushed commits. /cc ${slackAssignees}`, - message, - channel: '#secops-hotspots', - color: 'green', - username: 'security-action' - }) - debugLog('Comments after:', commentsAfter) - } - } -} diff --git a/action.yml b/action.yml deleted file mode 100644 index 32281b51..00000000 --- a/action.yml +++ /dev/null @@ -1,127 +0,0 @@ -name: 'Security Action' -description: 'Collect and Generalize multiple CI Security checks' -inputs: - # in-name: - # description: yadda yadda - # required: true - # default: 0 - github_token: - description: | - Secret token to push review comments, and - interact with the repository systematically - required: true - slack_token: - description: | - Secret token to forward findings to slack - required: false - assignees: - description: assign PR to the people linked - required: false - hotwords: - description: body hotwords which should trigger the action - required: false - hotwords_enabled: - description: control if the hotwords should trigger the action - required: false - debug: - description: enables debug output for this action - required: false - enabled: - description: may disable the whole action, big red button for emergency cases - required: false - baseline_scan_only: - description: compare changed files with the base ref, do not scan the entire repo with reviewdog - required: false - pip_audit_pypi_index_url: - description: Pypi index for pip-audit to use in case you have a private index - required: false - pip_audit_pypi_insecure_hosts: - description: Hosts for --trusted-host in pip-audit in case you have an untrusted private index, comma separated - required: false - gh_to_slack_user_map: - description: JSON map of github usernames to slack usernames - required: false -outputs: - reviewdog-findings: - description: number of reviewdog findings - value: ${{ steps.script.outputs.findings }} - safesvg-count: - description: number of safesvg findings via reviewdog - value: ${{ steps.script.outputs.safesvg_count }} - tfsec-count: - description: number of tfsec findings via reviewdog - value: ${{ steps.script.outputs.tfsec_count }} - semgrep-count: - description: number of semgrep findings via reviewdog - value: ${{ steps.script.outputs.semgrep_count }} - sveltegrep-count: - description: number of sveltegrep findings via reviewdog - value: ${{ steps.script.outputs.sveltegrep_count }} - npm-audit-count: - description: number of npm-audit findings via reviewdog - value: ${{ steps.script.outputs.npm_audit_count }} - pip-audit-count: - description: number of pip-audit findings via reviewdog - value: ${{ steps.script.outputs.pip_audit_count }} -runs: - using: 'composite' - steps: - - name: Store reviewdog enabled - # inputs.enabled != 'false' && ( - # (inputs.baseline_scan_only != 'false' && github.event_name == 'pull_request' && github.event.pull_request.draft == false && github.actor != 'dependabot[bot]') # reviewdog-enabled-pr - # || - # (inputs.baseline_scan_only == 'false' || github.event_name == 'workflow_dispatch') # reviewdog-enabled-full - # ) - if: ${{ inputs.enabled != 'false' && ( (inputs.baseline_scan_only != 'false' && github.event_name == 'pull_request' && github.event.pull_request.draft == false && github.actor != 'dependabot[bot]') || (inputs.baseline_scan_only == 'false' || github.event_name == 'workflow_dispatch') )}} - id: reviewdog-enabled - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - script: return true - - if: ${{ steps.reviewdog-enabled.outputs.result == 'true' }} - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 - with: - python-version: '3.12' - - if: ${{ steps.reviewdog-enabled.outputs.result == 'true' }} - name: Cache pip cache - id: cache-pip - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: ~/.cache/pip/ - key: ${{ runner.os }}-pip - - if: ${{ steps.reviewdog-enabled.outputs.result == 'true' }} - uses: reviewdog/action-setup@3f401fe1d58fe77e10d665ab713057375e39b887 # v1.3.0 - with: - reviewdog_version: latest # Optional. [latest,nightly,v.X.Y.Z] - - if: ${{ steps.reviewdog-enabled.outputs.result == 'true' }} - name: Setup Ruby - id: ruby - uses: ruby/setup-ruby@v1 - env: - BUNDLE_GEMFILE: ${{ github.action_path }}/Gemfile - with: - ruby-version: '3.2' - bundler-cache: true - - if: ${{ steps.reviewdog-enabled.outputs.result == 'true' }} - id: npm - run: cd ${{ github.action_path }}; npm ci - shell: bash - - if: ${{ steps.reviewdog-enabled.outputs.result == 'true' }} - name: Install tfsec - uses: jaxxstorm/action-install-gh-release@71d17cb091aa850acb2a1a4cf87258d183eb941b # v1.11.0 - with: # Grab a specific tag with caching - repo: aquasecurity/tfsec - tag: v1.28.1 - cache: enable - - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - if: ${{ steps.reviewdog-enabled.outputs.result == 'true' }} - id: script - env: - DEBUG: ${{ (inputs.debug == 'true' || runner.debug) && 'true' || 'false'}} - with: - script: |- - const actionPath = '${{ github.action_path }}' - const inputs = ${{ toJson(inputs) }} - - const script = require(`${actionPath}/action.cjs`) - await script({github, context, inputs, actionPath, core, - debug: process.env.DEBUG === 'true'})