Strip key/values of external quotes #61
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
name: Scan for secret leaks and changes | |
on: | |
# Block PR modification of workflow | |
pull_request_target: | |
push: | |
workflow_dispatch: | |
# N/B: Default write-all permission for pull_request_target | |
permissions: read-all | |
env: | |
# How far back in history to go when scanning a branch/tag | |
# This is most significant when scanning vs new release-branches | |
# with commit IDs that may differ from those encoded in the | |
# .gitleaks/baseline.json data (which always comes from | |
# the default branch). | |
# TODO: Is there any way to not hard-code this? | |
# N/B: This value is reused by Cirrus-CI, see contrib/cirrus/prebuild.sh | |
brdepth: 50 | |
# GitLeaks container image to use. | |
# N/B: Updating this is hard to test, esp. care must be exercised re: new leak-ignore behaviors | |
# (example ref: 'Check for inline scan overrides' step below). Also b/c this workflow is not | |
# intended to be used with the 'pull_request' trigger - as doing so defeats gitleaks scan | |
# result trustworthiness. | |
# N/B: This value is reused by Cirrus-CI, see contrib/cirrus/prebuild.sh | |
glfqin: ghcr.io/gitleaks/gitleaks@sha256:e5f6d1a62786affd1abd882ecc73e9353ce78adea1650711f6e351767723712d # v8.18.0 | |
# General arguments to pass for all execution contexts | |
# Ref: https://github.com/gitleaks/gitleaks#usage | |
# N/B: This value is reused by Cirrus-CI, see contrib/cirrus/prebuild.sh | |
glargs: >- | |
--exit-code=1 | |
--no-banner | |
--verbose | |
--log-level=debug | |
--source=/subject | |
--config=/default/.gitleaks.toml | |
--report-path=/report/gitleaks-report.json | |
--baseline-path=/default/.gitleaks/baseline.json | |
# Where to send notification e-mail | |
RCPTCSV: [email protected] | |
jobs: | |
scan-secrets: | |
runs-on: ubuntu-latest | |
env: | |
# Reduce duplication & command-line length | |
gitlogcmd: "git -C ${{ github.workspace }}/_subject log -p -U0" | |
steps: | |
- name: Define git log command and options for re-use | |
id: gitlog | |
shell: bash | |
run: | | |
set -exuo pipefail | |
if [[ "${{ github.base_ref }}" == "" ]]; then # It's a branch/tag | |
echo "range=-${{ env.brdepth }}" >> $GITHUB_OUTPUT | |
else # It's a PR | |
echo "range=${{ github.event.pull_request.head.sha }}~${{ github.event.pull_request.commits }}..HEAD" >> $GITHUB_OUTPUT | |
fi | |
# On a large repo, there's no need to check out the entire thing. For PRs | |
# the depth can be limited to one-greater than the number of PR commits. | |
# Unfortunately, GHA is incapable of performing simple math in-line. | |
- name: Do some simple math for PR clone depth | |
if: github.base_ref != '' | |
id: one_more_commit | |
shell: bash | |
run: | | |
echo "depth=$((${{ github.event.pull_request.commits }} + 1))" >> $GITHUB_OUTPUT | |
- name: Show important context details | |
shell: bash | |
run: | | |
set -euo pipefail | |
echo "The workspace path is '${{ github.workspace }}'" | |
echo "The github.base_ref value is '${{ github.base_ref }}'" | |
echo "The branch scan depth value is '${{ env.brdepth }}'" | |
echo "The PR clone depth value is '${{ steps.one_more_commit.outputs.depth }}'" | |
echo "The gitlogcmd value is '${{ env.gitlogcmd }}'" | |
echo "The gitlog range value is '${{ steps.gitlog.outputs.range }}'" | |
echo "The GitLeaks container FQIN is '${{ env.glfqin }}'" | |
echo "::group::The trigger event JSON" | |
jq --color-output --indent 2 --sort-keys . $GITHUB_EVENT_PATH | |
echo "::endgroup::" | |
# N/B: Use "_" prefixed paths to (somewhat) guard against clashes. GHA has some | |
# non-POLA behaviors WRT `${{ github.workspace }}` + checkout action. | |
- name: Checkout PR | |
if: github.base_ref != '' | |
uses: actions/checkout@v4 | |
with: | |
persist-credentials: false | |
path: _subject | |
ref: ${{ github.event.pull_request.head.sha }} | |
fetch-depth: ${{ steps.one_more_commit.outputs.depth }} | |
- name: Checkout Branch/Tag | |
if: github.base_ref == '' | |
uses: actions/checkout@v4 | |
with: | |
persist-credentials: false | |
path: _subject | |
fetch-depth: ${{ env.brdepth }} | |
# Trusted source of gitleaks config. | |
- name: Checkout default branch | |
uses: actions/checkout@v4 | |
with: | |
persist-credentials: false | |
ref: ${{ github.event.repository.default_branch }} | |
path: _default | |
fetch-depth: 1 | |
- name: Create report directory | |
shell: bash | |
run: | | |
set -exuo pipefail | |
mkdir ${{ github.workspace }}/_report | |
touch ${{ github.workspace }}/_report/gitleaks-report.json | |
# A force-push to a PR can obscure Cirrus-CI logs, but not GHA logs | |
- name: Show content being scanned | |
shell: bash | |
run: | | |
set -exuo pipefail | |
${{ env.gitlogcmd }} ${{ steps.gitlog.outputs.range }} | |
# Unfortunately gitleaks provides several in-built ways to | |
# completely bypass an alert within PR-level commits. Assume | |
# it's not possible to detect these with gitleaks-config rules. | |
- name: Check for inline scan overrides | |
if: github.base_ref != '' # A PR | |
shell: bash | |
env: | |
# Workaround erronously detecting the string in this file | |
_rx1: "gitleaks" | |
_rx2: ":" | |
_rx3: "allow" | |
run: | | |
set -euo pipefail | |
verboten_rx="${_rx1}${_rx2}${_rx3}" | |
verboten=$(set -x ; ${{ env.gitlogcmd }} "-G$verboten_rx" ${{ steps.gitlog.outputs.range }}) | |
if [[ -n "$verboten" ]]; then | |
printf '::error::%s' 'Found comment(s) utilizing detection override(s) (see job log for details)' | |
# Hack: Grep will never colorize an end of a line match | |
echo "$verboten" | grep --color=always -E "($verboten_rx)|$" | |
exit 1 | |
fi | |
if [[ -r "${{ github.workspace }}/_subject/.gitleaksignore" ]]; then | |
printf '::error::%s' 'Detected a .gitleaksignore file from untrusted source.' | |
exit 1 | |
fi | |
- name: Scan for secrets | |
shell: bash | |
# gitleaks entrypoint runs as gitleaks user (UID/GID 1000) | |
run: | | |
set -exuo pipefail | |
# TODO: Workaround podman < v4.3.0 support for `--userns=keep-id:uid=1000,gid=1000`. | |
declare -a workaround_args | |
workaround_args=(\ | |
--user 1000:1000 | |
--uidmap 0:1:1000 | |
--uidmap 1000:0:1 | |
--uidmap 1001:1001:64536 | |
--gidmap 0:1:1000 | |
--gidmap 1000:0:1 | |
--gidmap 1001:1001:64536 | |
) | |
# Careful: Changes need coordination with contrib/cirrus/prebuild.sh | |
podman run --rm \ | |
--security-opt=label=disable \ | |
"${workaround_args[@]}" \ | |
-v ${{ github.workspace }}/_default:/default:ro \ | |
-v ${{ github.workspace }}/_subject:/subject:ro \ | |
-v ${{ github.workspace }}/_report:/report:rw \ | |
$glfqin \ | |
detect $glargs --log-opts=${{ steps.gitlog.outputs.range }} | |
- name: Collect scan report artifact | |
if: ${{ !cancelled() }} | |
uses: actions/upload-artifact@v3 | |
with: | |
name: gitleaks-report | |
path: ${{ github.workspace }}/_report/gitleaks-report.json | |
# Nobody monitors the actions-tab for failures, and may not see this | |
# fail on push to a nefarious PR. Send an e-mail alert to unmask | |
# this activity or some other general job failure. | |
- if: failure() && !contains(github.event.pull_request.labels.*.name,'BypassLeakNotification') | |
name: Send leak detection notification e-mail | |
uses: dawidd6/[email protected] | |
with: | |
server_address: ${{secrets.ACTION_MAIL_SERVER}} | |
server_port: 465 | |
username: ${{secrets.ACTION_MAIL_USERNAME}} | |
password: ${{secrets.ACTION_MAIL_PASSWORD}} | |
subject: Addition|Change|Use of sensitive ${{github.repository}}-CI value | |
to: ${{env.RCPTCSV}} | |
from: ${{secrets.ACTION_MAIL_SENDER}} | |
body: "Please investigate: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}" |