Skip to content

Commit

Permalink
feat: [SRE-830] Add trivy docker scan configuration and matrix outputs (
Browse files Browse the repository at this point in the history
#7)

Adds docker scan functionality. 

Sample usage/outputs: 

[app-base-image](https://github.com/stordco/app-base-image/pull/12)
[matrix job usage-
app-build-image](https://github.com/stordco/app-build-image/pull/27)
[logiwa_writer](https://github.com/stordco/logiwa_writer/pull/108)
[Sample slack
notifications](https://stord-team.slack.com/archives/C079PF36UTC/p1719331554969529)

---------

Co-authored-by: Parker DeBardelaben <[email protected]>
Co-authored-by: Parker DeBardelaben <[email protected]>
  • Loading branch information
3 people authored Sep 17, 2024
1 parent 05d56e0 commit 98c14a2
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 26 deletions.
73 changes: 66 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# actions-trivy

Github Action for running trivy scans

# Overview

stordco/actions-trivy is used to run [trivy](https://github.com/aquasecurity/trivy) scans with various scan types. The current scan types supported:
1. [Filesystem](https://aquasecurity.github.io/trivy/v0.52/docs/target/filesystem/)

1. [Filesystem](https://aquasecurity.github.io/trivy/v0.52/docs/target/filesystem/)
1. [Images](https://aquasecurity.github.io/trivy/v0.52/docs/target/container_image/)

# Filesystem scans

## Usage
<!-- {x-release-please-start-version} -->

Expand All @@ -19,29 +23,84 @@ stordco/actions-trivy is used to run [trivy](https://github.com/aquasecurity/tri
slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
```
## Inputs
<!-- {x-release-please-end} -->
## Inputs
| name | description | default value |
| --- | --- | --- |
| `scan-type` | (required) Specifies the type of scan to be perforemed (e.g., `fs` for filesystem scan). | |
| `github-token` | (optional) Should be set to `secrets.GH_PERSONAL_ACCESS_TOKEN` in order to interact with Github API. If not set, then PR comments will not be uploaded with the scan output. | "" |
| `scan-type` | (required) Specifies the type of scan to be performed (e.g., `fs` for filesystem scan). | |
| `slack-bot-token` | (optional) Should be set to `secrets.SLACK_BOT_TOKEN` to send messages through `Github Actions`. If not set, then slack messages will not be posted. | "" |

| `slack-channel-id` | (optional) Set to the desired Slack channel ID to receive alerts. If not set, then slack messages will not be posted. | "" |

## Outputs

| name | description | default value |
| --- | --- | --- |
| `artifact-url` | Returns link to trivy scan artifact. Main branch artifacts are retained for 90 days while others are retained for 1 day. | |

## General Information

For default usage:

1. When a merge into the `main` branch occurs that contains `CRITICAL` vulnerabilities, a notification will be sent to the `#trivy-alerts` Slack channel containing the number of critical vulnerabilities detected and a link to the full trivy scan report artifact.
1. When any vulnerabilities `(UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL)` are detected on PR builds, a comment will be posted to the PR including the full output of the OS and library vulnerabilities detected based on the `mix.lock` dependencies.

# Image scans

## Usage
<!-- {x-release-please-start-version} -->
### Simple

```yaml
- name: Trivy Image Scan
uses: stordco/actions-trivy@v1
with:
scan-type: image
image-ref: gcr.io/stord-ci/app-base:2024.06.25_d5cd08e
github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
slack-channel-id: ${{ secrets.SLACK_SECURITY_ALERTS }}
```

### Matrix Jobs

```yaml
- name: Trivy Image Scan
uses: stordco/actions-trivy@v1
with:
scan-type: image
image-ref: gcr.io/stord-ci/app-base:2024.06.25_d5cd08e
matrix-id: unique-identifier
github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }}
slack-channel-id: ${{ secrets.SLACK_SECURITY_ALERTS }}
```
<!-- {x-release-please-end} -->
## Inputs

| name | description | default value |
| --- | --- | --- |
| `github-token` | (optional) Should be set to `secrets.GH_PERSONAL_ACCESS_TOKEN` in order to interact with Github API. If not set, then PR comments will not be uploaded with the scan output. | "" |
| `image-ref` | (optional) Specifies the Docker image to be scanned | "" |
| `matrix-id` | (optional) If matrix jobs are being leveraged, add in an unique matrix job identifier to be leveraged for the notifications. | "" |
| `scan-type` | (required) Specifies the type of scan to be performed (e.g., `image` for container image scan). | |
| `slack-bot-token` | (optional) Should be set to `secrets.SLACK_BOT_TOKEN` to send messages through `Github Actions`. If not set, then slack messages will not be posted. | "" |
| `slack-channel-id` | (optional) Set to the desired Slack channel ID to receive alerts. If not set, then slack messages will not be posted. | "" |

## Outputs

| name | description | default value |
| --- | --- | --- |
| `artifact-url` | Returns link to trivy scan artifact. Main branch artifacts are retained for 90 days while others are retained for 1 day. | |

## General Information

For default usage:
1. When a merge into the `main` branch occurs that contains `Critical` vulnerabilities, a notification will be sent to the #trivy-alerts Slack channel containing the number of critical vulnerabilities detected and a link to the full trivy scan report artifact.
1. When any vulnerabilities `(UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL)` are detected on PR builds, a comment will be posted to the PR including the full output of the OS vulnerabilities detected based on the `mix.lock` dependencies.

1. When a merge into the `main` branch occurs that contains `CRITICAL` vulnerabilities, a notification will be sent to the `#trivy-alerts` Slack channel containing the number of critical vulnerabilities detected and a link to the full trivy scan report artifact.
1. When any vulnerabilities `(UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL)` are detected on PR builds, a comment will be posted to the PR including the full output of the OS, library vulnerabilities and secrets detected found on the container image.

# Releasing

Releases are handled via `release-please`. Once a PR is merged, a new PR will be created that bumps all the versions. When that PR is merged the new release will be created and published for consumption.
Releases are handled via `release-please`. Once a PR is merged, a new PR will be created that bumps all the versions. When that PR is merged the new release will be created and published for consumption.
106 changes: 87 additions & 19 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,24 @@ description: >-
GitHub Composite Action for running Trivy scans
inputs:
scan-type:
description: >-
"Specify the type of scan to be perforemed (e.g., 'fs' for filesystem scan)."
type: string
required: true
github-token:
description: "GitHub token for authentication."
type: string
required: false
image-ref:
description: "Specify the local Docker image to be scanned. This value needs to be set if the scan-type = image."
required: false
matrix-id:
description: "Specify the matrix indicator to be leveraged on notification steps."
required: false
scan-type:
description: >-
"Specify the type of scan to be perforemed (e.g., 'fs' for filesystem scan, `image` for image scan)."
required: true
slack-bot-token:
description: "Slackbot token for sending notifications."
type: string
required: false
slack-channel-id:
description: "Slack channel ID for sending notifications."
required: false

outputs:
Expand All @@ -36,13 +42,17 @@ runs:
if [[ '${{ inputs.scan-type }}' == 'fs' ]]; then
echo "config_file_type=fs" >> "$GITHUB_OUTPUT"
fi
if [[ '${{ inputs.scan-type }}' == 'image' ]]; then
echo "config_file_type=image" >> "$GITHUB_OUTPUT"
fi
shell: bash

- name: Run Trivy vulnerability scanner in ${{ inputs.scan-type }} mode
id: trivy_scan
uses: aquasecurity/[email protected]
with:
scan-type: ${{ inputs.scan-type }}
image-ref: ${{ inputs.image-ref }}
trivy-config: .trivy/${{ steps.configuration_file.outputs.config_file_type }}-config.yaml
continue-on-error: true

Expand All @@ -56,29 +66,35 @@ runs:
echo "Keep trivy artifact for 1 day on PR builds"
echo "days=1" >> "$GITHUB_OUTPUT"
fi
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
sha_short=$(git rev-parse --short HEAD)
sanitized_ref_name=$(echo "${{ github.ref_name }}" | sed 's/[\\\/:*?<>|]/-/g')
echo "ref_name=${sanitized_ref_name}" >> $GITHUB_OUTPUT
if [[ -z '${{ inputs.matrix-id }}' ]]; then
echo "name=trivy-${{ inputs.scan-type }}-results-${sha_short}-${sanitized_ref_name}" >> $GITHUB_OUTPUT
else
echo "name=trivy-${{ inputs.scan-type }}-results-${sha_short}-${sanitized_ref_name}-${{ inputs.matrix-id }}" >> $GITHUB_OUTPUT
fi
shell: bash

- name: Upload Trivy report to artifacts
uses: actions/upload-artifact@v4
id: trivy_artifact_upload
with:
name: trivy-${{ inputs.scan-type }}-results-${{ steps.artifact_metadata.outputs.sha_short }}-${{ steps.artifact_metadata.outputs.ref_name }}
name: ${{ steps.artifact_metadata.outputs.name }}
path: trivy-${{ inputs.scan-type }}-results.json
retention-days: ${{ steps.artifact_metadata.outputs.days }}
if-no-files-found: ignore
overwrite: true

- name: Upload Trivy Report as PR Comment and parse Critical vulnerabilities
id: trivy_report_notification
if: ${{ inputs.github-token }}
if: ${{ inputs.github-token && github.event_name == 'pull_request' }}
uses: actions/github-script@v7
env:
GITHUB_TOKEN: ${{ inputs.github-token }}
SCAN_TYPE: ${{ inputs.scan-type }}
MATRIX_ID: ${{ inputs.matrix-id }}
with:
script: |
const fs = require('fs');
Expand All @@ -93,7 +109,12 @@ runs:
const owner = context.repo.owner;
const repo = context.repo.repo;
const commentIdentifier = `<!-- trivyReportComment-${process.env.SCAN_TYPE}-->`;
let commentIdentifier;
if (!process.env.MATRIX_ID) {
commentIdentifier = `<!-- trivyReportComment-${process.env.SCAN_TYPE}-->`;
} else {
commentIdentifier = `<!-- trivyReportComment-${process.env.SCAN_TYPE}-${process.env.MATRIX_ID}-->`;
}
const filePath = path.join(process.env.GITHUB_WORKSPACE, `trivy-${process.env.SCAN_TYPE}-results.json`);
const fileContent = fs.readFileSync(filePath, 'utf8');
Expand Down Expand Up @@ -148,9 +169,11 @@ runs:
const botComment = comments.data.find(comment => comment.body.includes(commentIdentifier));
core.info(`Parsed Vulnerabilities: ${JSON.stringify(vulnerabilities)}`)
const scanTypeName = process.env.SCAN_TYPE === 'fs' ? 'filesystem' : 'image';
if (vulnerabilities.flatMap(result => result.Vulnerabilities).length === 0) {
if (botComment) {
const noErrorsComment = `No vulnerabilities to be reported.\n${commentIdentifier}`;
const noErrorsComment = `No Trivy ${scanTypeName} vulnerabilities to be reported${process.env.MATRIX_ID ? ` for ${process.env.MATRIX_ID}` : ''}.\n${commentIdentifier}`;
await github.rest.issues.updateComment({
owner,
Expand Down Expand Up @@ -178,15 +201,16 @@ runs:
if (formattedContent.length > MAX_COMMENT_LENGTH) {
fullCommentBody = `
The Trivy scan report is too large to display here. Please view the detailed output from the job:
The Trivy ${scanTypeName} scan report${process.env.MATRIX_ID ? ` for ${process.env.MATRIX_ID}` : ''} is too large to display here. Please view the detailed output from the job:
[View Trivy Report](https://github.com/${owner}/${repo}/actions/runs/${context.runId})
${commentIdentifier}
`;
} else {
fullCommentBody = `
View the Trivy scan report below. Click on the dropdown to expand the report.
View the Trivy ${scanTypeName} scan report${process.env.MATRIX_ID ? ` for ${process.env.MATRIX_ID}` : ''} below. Click on the dropdown to expand the report.
${formattedContent}
`;
}
Expand All @@ -206,25 +230,65 @@ runs:
issue_number,
body: fullCommentBody,
});
core.info('Created new Pr comment');
core.info('Created new PR comment');
}
}
- name: Notify Slack of critical vulnerabilities
if: ${{ steps.trivy_report_notification.outputs.critical_vulnerabilities_count != '0' && github.ref_name == 'main' && inputs.slack-bot-token }}
if: ${{ steps.trivy_report_notification.outputs.critical_vulnerabilities_count != '0' && github.ref_name == 'main' && inputs.slack-bot-token && !inputs.matrix-id }}
uses: slackapi/[email protected]
env:
SLACK_BOT_TOKEN: ${{ inputs.slack-bot-token }}
with:
channel-id: ${{ inputs.slack-channel-id }}
payload: |
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":alert: *Critical vulnerabilities detected* in Trivy ${{ inputs.scan-type }} scan. `${{ steps.trivy_report_notification.outputs.critical_vulnerabilities_count }}` critical vulnerabilities detected."
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Repository:*\n`${{ github.repository }}`"
},
{
"type": "mrkdwn",
"text": "*Branch:*\n`${{ github.ref_name }}`"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "<${{ steps.trivy_artifact_upload.outputs.artifact-url }}|View Artifacts>"
}
}
]
}
- name: Notify Slack of critical vulnerabilities (${{ inputs.matrix-id }})
if: ${{ steps.trivy_report_notification.outputs.critical_vulnerabilities_count != '0' && github.ref_name == 'main' && inputs.slack-bot-token && inputs.matrix-id }}
uses: slackapi/[email protected]
env:
SLACK_BOT_TOKEN: ${{ inputs.slack-bot-token }}
with:
channel-id: "C078TPMGC21"
channel-id: ${{ inputs.slack-channel-id }}
payload: |
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":alert: *Critical vulnerabilities detected* in Trivy ${{ inputs.scan-type }} scan. ${{ steps.trivy_report_notification.outputs.critical_vulnerabilities_count }} critical vulnerabilities detected."
"text": ":alert: *Critical vulnerabilities detected* in Trivy ${{ inputs.scan-type }} scan. `${{ steps.trivy_report_notification.outputs.critical_vulnerabilities_count }}` critical vulnerabilities detected."
}
},
{
Expand All @@ -237,6 +301,10 @@ runs:
{
"type": "mrkdwn",
"text": "*Branch:*\n`${{ github.ref_name }}`"
},
{
"type": "mrkdwn",
"text": "*Matrix ID:*\n`${{ inputs.matrix-id }}`"
}
]
},
Expand Down

0 comments on commit 98c14a2

Please sign in to comment.