Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a safe-upload-artifacts action #601

Merged
merged 3 commits into from
Sep 18, 2024
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
45 changes: 0 additions & 45 deletions .github/actions/mask_secrets/README.md

This file was deleted.

35 changes: 0 additions & 35 deletions .github/actions/mask_secrets/action.yml

This file was deleted.

33 changes: 33 additions & 0 deletions .github/actions/safe-upload-artifacts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Safe Upload Artifacts Github Action

Upload artifacts from a given set of paths. Before the archive is
uploaded the files will be scanned for GitHub secrets and masked when
found with `***NAME_OF_SECRET***`. This prevents secrets from appearing
in publicly-downloadable archives attached to workflow runs.

## Known Issues

The regex used for the replacement cannot be applied to secrets that
have linefeed characters in them. These secrets will be skipped without
notice.

## Usage

```
- name: Safe upload artifacts
id: safe-upload-artifacts
if: always()
uses: ./.github/actions/safe-upload-artifacts
with:
secrets-json: ${{ toJson(secrets) }}
name: name-for-the-uploaded-archive
path: |
path-to/file-to-archive.log
```

- The `uses` path may change based on how your workflow checks out the
repository. (eg: `uses:
./modules/lib/golioth-firmware-sdk/.github/actions/safe-upload-artifacts`).
- Secrets must be passed as serialized JSON as in the example above.
This is because actions cannot inherit secrets. Reusable workflows can
inherit secrets but they cannot be run as steps (only as jobs).
70 changes: 70 additions & 0 deletions .github/actions/safe-upload-artifacts/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Mask secrets in files

description: |
Search all files in a given path(s) and replace any GitHub secrets with ***NAME_OF_SECRET***

inputs:
secrets-json:
description: 'Secrets context to be masked, in JSON format'
required: true
name:
description: 'String to use as the archive name'
required: true
path:
description: 'Path(s) to the files to be include in the upload'
required: true

runs:
using: composite
steps:
- name: Check for installed commands
shell: bash
run: |
if ! command -v jq; then
apt update && apt install -y jq

if ! command -v jq; then
echo "Could not install command: jq"
exit 1
fi
fi

- name: Find and mask
id: find-and-mask
shell: bash
env:
SECRETS_CONTEXT: '${{ inputs.secrets-json }}'
run: |
rm -rf __grep_search_output.txt

# Enable globbing
shopt -s globstar

for key in $(jq -r "keys[]" <<< "$SECRETS_CONTEXT");
do
secret_val=$(jq -r ".$key" <<< "$SECRETS_CONTEXT")

if [[ ! $secret_val =~ "\n" ]]; then
# This approach to escaping the regex found: https://stackoverflow.com/a/29613573/922013
ESCAPED_SECRET=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< "$secret_val")

# Iterate list of input path patterns and use grep to create a list of files that
# contain secrets
while IFS= read -r search_path || [[ -n $search_path ]];
do
[ $(grep -Rl $ESCAPED_SECRET $search_path 2>/dev/null >> __grep_search_output.txt) >= 0 ]
done < <(printf '%s' "${{ inputs.path }}")

if [ -s __grep_search_output.txt ]; then
szczys marked this conversation as resolved.
Show resolved Hide resolved
uniq __grep_search_output.txt | xargs -I{} sed -i "s/$ESCAPED_SECRET/***$key***/g" {}
fi

rm -rf __grep_search_output.txt
fi
done

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.name }}
path: ${{ inputs.path }}
19 changes: 7 additions & 12 deletions .github/workflows/hil_sample_zephyr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -205,17 +205,12 @@ jobs:
--pytest-args="--hil-board=${{ inputs.hil_board }}" \
-v

- name: Mask secrets in logs
id: mask-logs
- name: Safe upload twister artifacts
id: safe-upload-artifacts
if: always()
uses: ./modules/lib/golioth-firmware-sdk/.github/actions/mask_secrets
uses: ./modules/lib/golioth-firmware-sdk/.github/actions/safe-upload-artifacts
with:
secrets-json: ${{ toJson(secrets) }}

- name: Upload artifacts
uses: actions/upload-artifact@v4
if: always() && steps.mask-logs.outcome == 'success'
with:
name: twister-run-artifacts-${{ inputs.hil_board }}
path: |
reports/*
Expand All @@ -225,15 +220,15 @@ jobs:
twister-out/*.json

- name: Prepare CI report summary
if: always() && steps.mask-logs.outcome == 'success'
if: always()
run: |
rm -rf summary
mkdir summary
cp twister-out/twister_suite_report.xml summary/samples-zephyr-${{ inputs.hil_board }}.xml

- name: Upload CI report summary
uses: actions/upload-artifact@v4
if: always() && steps.mask-logs.outcome == 'success'
- name: Safe upload CI report summary
uses: ./modules/lib/golioth-firmware-sdk/.github/actions/safe-upload-artifacts
if: always()
with:
name: ci-summary-samples-zephyr-${{ inputs.hil_board }}
path: summary/*
Expand Down
22 changes: 8 additions & 14 deletions .github/workflows/hil_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -231,17 +231,12 @@ jobs:
--pytest-args="--runner-name=${{ runner.name }}" \
--pytest-args="--hil-board=${{ matrix.artifact_suffix }}"

- name: Mask secrets in logs
id: mask-logs
- name: Safe upload twister artifacts
id: safe-upload-artifacts
if: always()
uses: ./modules/lib/golioth-firmware-sdk/.github/actions/mask_secrets
uses: ./modules/lib/golioth-firmware-sdk/.github/actions/safe-upload-artifacts
with:
secrets-json: ${{ toJson(secrets) }}

- name: Upload artifacts
uses: actions/upload-artifact@v4
if: always() && steps.mask-logs.outcome == 'success'
with:
name: twister-run-artifacts-${{ matrix.artifact_suffix }}
path: |
reports/*
Expand All @@ -253,19 +248,18 @@ jobs:
twister-out/*.json

- name: Prepare CI report summary
if: always() && steps.mask-logs.outcome == 'success'
if: always()
run: |
rm -rf summary
mkdir summary
cp twister-out/twister_suite_report.xml summary/samples-zephyr-${{ matrix.artifact_suffix }}.xml

- name: Upload CI report summary
uses: actions/upload-artifact@v4
if: always() && steps.mask-logs.outcome == 'success'
- name: Safe upload CI report summary
uses: ./modules/lib/golioth-firmware-sdk/.github/actions/safe-upload-artifacts
if: always()
with:
name: ci-summary-samples-zephyr-${{ matrix.artifact_suffix }}
path: |
summary/*
path: summary/*

- name: Upload Allure reports
uses: actions/upload-artifact@v4
Expand Down
Loading