ci: lint GitHub workflows with actionlint (#9590)

[`actionlint`](https://github.com/rhysd/actionlint) is a static analysis
tool for GitHub workflows and actions. It detects various issues ahead
of time and runs shellcheck on all `run` blocks. It is worth noting that
this does **not** lint the contents of composite actions so we still
need to be vigilant when working with those.
This commit is contained in:
Thomas Eizinger
2025-06-24 10:05:10 +02:00
committed by GitHub
parent 56b70215a7
commit 40f0609d90
11 changed files with 91 additions and 60 deletions

18
.github/actionlint.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
self-hosted-runner:
labels:
- macos-13-xlarge,
- macos-14-xlarge
- macos-14-xlarge,
- macos-15-xlarge
- macos-15-xlarge,
- ubuntu-22.04-arm-xlarge
- ubuntu-22.04-xlarge
- ubuntu-22.04-xlarge,
- ubuntu-24.04-xlarge
- ubuntu-24.04-xlarge,
- ubuntu-latest-xlarge
- windows-2022-xlarge
- windows-2022-xlarge,
- windows-2025-xlarge
- windows-2025-xlarge,
- windows-latest-xlarge

View File

@@ -151,7 +151,7 @@ jobs:
fi
cargo build $PROFILE -p ${{ matrix.package }} --target ${{ matrix.target }}
mv target/${{ matrix.target }}/${{ inputs.profile }}/${{ matrix.package }}.exe $ARTIFACT_PATH
mv target/${{ matrix.target }}/${{ inputs.profile }}/${{ matrix.package }}.exe "$ARTIFACT_PATH"
- name: Install AzureSignTool
shell: bash
run: dotnet tool install --global AzureSignTool
@@ -163,7 +163,7 @@ jobs:
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }}
run: ../scripts/build/sign.sh $ARTIFACT_PATH
run: ../scripts/build/sign.sh "$ARTIFACT_PATH"
- name: Upload Release Assets
if: ${{ inputs.profile == 'release' && inputs.stage == 'release' && matrix.release_name }}
shell: bash
@@ -314,22 +314,22 @@ jobs:
fi
# Used for release artifact
cp target/${{ matrix.arch.target }}/${{ inputs.profile }}/${{ matrix.name.package }} $BINARY_DEST_PATH
sha256sum $BINARY_DEST_PATH > $BINARY_DEST_PATH.sha256sum.txt
cp target/${{ matrix.arch.target }}/${{ inputs.profile }}/${{ matrix.name.package }} "$BINARY_DEST_PATH"
sha256sum "$BINARY_DEST_PATH" > "$BINARY_DEST_PATH".sha256sum.txt
gh release upload ${{ matrix.name.release_name }} \
${{ env.BINARY_DEST_PATH }} \
${{ env.BINARY_DEST_PATH }}.sha256sum.txt \
$clobber \
"$clobber" \
--repo ${{ github.repository }}
- name: Copy binaries to Google Cloud Storage
if: ${{ inputs.profile == 'release' && matrix.stage == 'release' && contains(fromJSON('["gateway", "client"]'), matrix.name.image_name) }}
run: |
gcloud storage cp \
${BINARY_DEST_PATH} \
"$BINARY_DEST_PATH" \
gs://firezone-staging-artifacts/firezone-${{ matrix.name.image_name }}/${{ inputs.sha }}/${{ matrix.arch.shortname }}
gcloud storage cp \
${BINARY_DEST_PATH}.sha256sum.txt \
"$BINARY_DEST_PATH".sha256sum.txt \
gs://firezone-staging-artifacts/firezone-${{ matrix.name.image_name }}/${{ inputs.sha }}/${{ matrix.arch.shortname }}.sha256sum.txt
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
@@ -342,8 +342,8 @@ jobs:
version="${{ matrix.name.version }}"
MAJOR_VERSION="${version%%.*}"
MAJOR_MINOR_VERSION="${version%.*}"
echo "MAJOR_VERSION=${MAJOR_VERSION}" >> $GITHUB_ENV
echo "MAJOR_MINOR_VERSION=${MAJOR_MINOR_VERSION}" >> $GITHUB_ENV
echo "MAJOR_VERSION=$MAJOR_VERSION" >> "$GITHUB_ENV"
echo "MAJOR_MINOR_VERSION=$MAJOR_MINOR_VERSION" >> "$GITHUB_ENV"
- name: Docker meta
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
@@ -395,7 +395,7 @@ jobs:
retention-days: 1
- name: Output image name
id: image-name
run: echo "${{ matrix.name.image_name }}_image=${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.name.image_name }}" >> $GITHUB_OUTPUT
run: echo "${{ matrix.name.image_name }}_image=${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.name.image_name }}" >> "$GITHUB_OUTPUT"
merge-docker-artifacts:
name: merge-${{ matrix.image.name }}
@@ -447,8 +447,8 @@ jobs:
version="${{ matrix.image.version }}"
MAJOR_VERSION="${version%%.*}"
MAJOR_MINOR_VERSION="${version%.*}"
echo "MAJOR_VERSION=${MAJOR_VERSION}" >> $GITHUB_ENV
echo "MAJOR_MINOR_VERSION=${MAJOR_MINOR_VERSION}" >> $GITHUB_ENV
echo "MAJOR_VERSION=${MAJOR_VERSION}" >> "$GITHUB_ENV"
echo "MAJOR_MINOR_VERSION=${MAJOR_MINOR_VERSION}" >> "$GITHUB_ENV"
- name: Docker meta
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
@@ -466,7 +466,11 @@ jobs:
working-directory: /tmp/digests/${{ matrix.image.name }}
run: |
tags=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON")
sources=$(printf '${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.image.name }}@sha256:%s ' *)
echo "$sources"
docker buildx imagetools create $tags $sources
sources=$(printf '${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.image.name }}@sha256:%s' *)
echo "Tags: $tags"
echo "Sources: $sources"
# shellcheck disable=SC2086 # $tags must be split by whitespace
docker buildx imagetools create $tags "$sources"
docker buildx imagetools inspect "${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_prefix && format('{0}/', matrix.image_prefix) || '' }}${{ matrix.image.name }}"

View File

@@ -65,10 +65,10 @@ jobs:
id: plt_cache
with:
path: elixir/priv/plts
key: dialyzer-ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ steps.setup-beam.outputs.erlang-version }}-${{ hashFiles('elixir/mix.lock') }}
key: dialyzer-ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ steps.setup-beam.outputs.otp-version }}-${{ hashFiles('elixir/mix.lock') }}
# This will make sure that we can incrementally build the PLT from older cache and save it under a new key
restore-keys: |
dialyzer-ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ steps.setup-beam.outputs.erlang-version }}-
dialyzer-ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ steps.setup-beam.outputs.otp-version }}-
- name: Create PLTs
if: ${{ steps.plt_cache.outputs.cache-hit != 'true' }}
run: mix dialyzer --plt

View File

@@ -125,7 +125,7 @@ jobs:
run: |
set -xe
if [[ ! -z "${{ matrix.test.rust_log }}" ]]; then
if [[ -n "${{ matrix.test.rust_log }}" ]]; then
export RUST_LOG="${{ matrix.test.rust_log }}"
fi

View File

@@ -112,7 +112,7 @@ jobs:
FIREBASE_CREDENTIALS_PATH: firebase-credentials.json
FIREBASE_APP_TESTERS: ${{ vars.FIREBASE_APP_TESTERS }}
run: |
echo -n "$FIREBASE_APP_DISTRIBUTION_CREDENTIALS" > $FIREBASE_CREDENTIALS_PATH
echo -n "$FIREBASE_APP_DISTRIBUTION_CREDENTIALS" > "$FIREBASE_CREDENTIALS_PATH"
./gradlew appDistributionUploadRelease uploadCrashlyticsSymbolFileRelease
build_debug:

View File

@@ -98,16 +98,16 @@ jobs:
cargo test --all-features ${{ steps.setup-rust.outputs.test-packages }} -- --include-ignored --nocapture
# Poor man's test coverage testing: Grep the generated logs for specific patterns / lines.
rg --count --no-ignore SendIcmpPacket $TESTCASES_DIR
rg --count --no-ignore SendUdpPacket $TESTCASES_DIR
rg --count --no-ignore SendTcpPayload $TESTCASES_DIR
rg --count --no-ignore SendDnsQueries $TESTCASES_DIR
rg --count --no-ignore "Packet for DNS resource" $TESTCASES_DIR
rg --count --no-ignore "Packet for CIDR resource" $TESTCASES_DIR
rg --count --no-ignore "Packet for Internet resource" $TESTCASES_DIR
rg --count --no-ignore "Truncating DNS response" $TESTCASES_DIR
rg --count --no-ignore "Destination is unreachable" $TESTCASES_DIR
rg --count --no-ignore "Forwarding query for DNS resource to corresponding site" $TESTCASES_DIR
rg --count --no-ignore SendIcmpPacket "$TESTCASES_DIR"
rg --count --no-ignore SendUdpPacket "$TESTCASES_DIR"
rg --count --no-ignore SendTcpPayload "$TESTCASES_DIR"
rg --count --no-ignore SendDnsQueries "$TESTCASES_DIR"
rg --count --no-ignore "Packet for DNS resource" "$TESTCASES_DIR"
rg --count --no-ignore "Packet for CIDR resource" "$TESTCASES_DIR"
rg --count --no-ignore "Packet for Internet resource" "$TESTCASES_DIR"
rg --count --no-ignore "Truncating DNS response" "$TESTCASES_DIR"
rg --count --no-ignore "Destination is unreachable" "$TESTCASES_DIR"
rg --count --no-ignore "Forwarding query for DNS resource to corresponding site" "$TESTCASES_DIR"
env:
# <https://github.com/rust-lang/cargo/issues/5999>

View File

@@ -20,7 +20,7 @@ jobs:
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
REPOSITORY_NAME: ${{ github.repository }}
run: |
PR_TITLE=$(gh pr view $PULL_REQUEST_NUMBER --repo $REPOSITORY_NAME --json title -q '.title')
PR_TITLE=$(gh pr view "$PULL_REQUEST_NUMBER" --repo "$REPOSITORY_NAME" --json title -q '.title')
pr_title_length=${#PR_TITLE}
@@ -43,7 +43,7 @@ jobs:
echo "Version manifests up to date"
else
# Uncommitted changes
echo '`scripts/bump-versions.sh` found outdated files! Showing diff'
echo "'scripts/bump-versions.sh' found outdated files! Showing diff"
git diff
exit 1
fi
@@ -57,6 +57,12 @@ jobs:
fail: true
args: --offline --verbose --no-progress **/*.md
actionlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: raven-actions/actionlint@3a24062651993d40fed1019b58ac6fbdfbf276cc # v2.0.1
global-linter:
runs-on: ubuntu-22.04-xlarge
steps:

View File

@@ -35,14 +35,14 @@ jobs:
# For workflow_dispatch or workflow_call, run all jobs
if [ "${{ github.event_name }}" = "workflow_dispatch" ] || [ "${{ github.event_name }}" = "workflow_call" ]; then
echo "jobs_to_run=$jobs" >> $GITHUB_OUTPUT
echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT"
exit 0;
fi
# For main branch runs, run all jobs
if [ "${{ github.event_name }}" = "push" ] && [ "${{ github.ref_name }}" = "main" ]; then
echo "jobs_to_run=$jobs" >> $GITHUB_OUTPUT
echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT"
exit 0;
fi
@@ -68,19 +68,19 @@ jobs:
# Run all jobs if CI configuration changes
if grep -q '^\.github/' changed_files.txt; then
echo "jobs_to_run=$jobs" >> $GITHUB_OUTPUT
echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT"
exit 0;
fi
# Run all jobs if tool versions change
if grep -q '^\.tool-versions' changed_files.txt; then
echo "jobs_to_run=$jobs" >> $GITHUB_OUTPUT
echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT"
exit 0;
fi
# Run all jobs if docker-compose changes
if grep -q '^docker-compose.yml' changed_files.txt; then
echo "jobs_to_run=$jobs" >> $GITHUB_OUTPUT
echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT"
exit 0;
fi
@@ -105,7 +105,7 @@ jobs:
jobs="${jobs},codeql"
fi
echo "jobs_to_run=$jobs" >> $GITHUB_OUTPUT
echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT"
required-check:
name: required-check
@@ -127,14 +127,14 @@ jobs:
failed_jobs=$(echo "$jobs_json" | jq -r '[.[] | select(.conclusion == "failure")] | length')
completed_jobs=$(echo "$jobs_json" | jq '[.[] | select(.status == "completed")] | length')
if [ $failed_jobs -gt 0 ]; then
if [ "$failed_jobs" -gt 0 ]; then
echo "At least one job has failed."
exit 1
fi
echo "Completed: $completed_jobs/$total_jobs"
if [ $completed_jobs -eq $total_jobs ]; then
if [ "$completed_jobs" -eq "$total_jobs" ]; then
break
fi
@@ -312,7 +312,7 @@ jobs:
# We need to increase the log level to make sure that they don't hold off storm of packets
# generated by UDP tests. Wire is especially chatty.
sed -i 's/^\(\s*\)RUST_LOG:.*$/\1RUST_LOG: wire=error,info/' docker-compose.yml
cat docker-compose.yml | grep RUST_LOG
grep RUST_LOG docker-compose.yml
# Start services in the same order each time for the tests
docker compose up -d iperf3
@@ -392,9 +392,10 @@ jobs:
--testbed github-actions \
--file bmf.json \
--adapter json \
--branch "${{ github.head_ref || github.ref_name }}" \
--branch "${{ env.BRANCH }}" \
--branch-start-point "${{ github.base_ref }}" \
--github-actions ${{ secrets.GITHUB_TOKEN }} \
--ci-only-on-alert
env:
BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
BRANCH: "${{ github.head_ref || github.ref_name }}"

View File

@@ -25,7 +25,7 @@ jobs:
run: |
version=${{ inputs.release_name || github.event.release.name }}
version=${version#${{ matrix.tag_prefix }}-}
echo "version=$version" >> $GITHUB_OUTPUT
echo "version=$version" >> "$GITHUB_OUTPUT"
shell: bash
- uses: vedantmgoyal9/winget-releaser@19e706d4c9121098010096f9c495a70a7518b30f # main
if: ${{ startsWith((inputs.release_name || github.event.release.name), matrix.tag_prefix) }}

View File

@@ -63,11 +63,12 @@ jobs:
sha=$(gh release view "${release_name}" --json targetCommitish -q '.targetCommitish')
# shellcheck disable=SC2129 # individual env exports are cleaner
echo "artifact=$ARTIFACT" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "major_version=$MAJOR_VERSION" >> "$GITHUB_OUTPUT"
echo "major_minor_version=$MAJOR_MINOR_VERSION" >> "$GITHUB_OUTPUT"
echo "sha=${sha}" >> "$GITHUB_OUTPUT"
echo "sha=$sha" >> "$GITHUB_OUTPUT"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
- name: Pull and push
@@ -101,25 +102,25 @@ jobs:
for arch in "${ARCHITECTURES[@]}"; do
# Copy sha256sum.txt
gcloud storage cp \
gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch}.sha256sum.txt \
gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/latest/${arch}.sha256sum.txt
"gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch.sha256sum.txt" \
"gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/latest/$arch.sha256sum.txt"
gcloud storage cp \
gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch}.sha256sum.txt \
gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch}.sha256sum.txt
"gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch.sha256sum.txt" \
"gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch.sha256sum.txt"
gcloud storage cp \
gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch}.sha256sum.txt \
gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.version }}/${arch}.sha256sum.txt
"gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch.sha256sum.txt" \
"gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.version }}/$arch.sha256sum.txt"
# Copy binaries
gcloud storage cp \
gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch} \
gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/latest/${arch}
"gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch" \
"gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/latest/$arch"
gcloud storage cp \
gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch} \
gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch}
"gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch" \
"gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch"
gcloud storage cp \
gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/${arch} \
gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.version }}/${arch}
"gs://firezone-staging-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.sha }}/$arch" \
"gs://firezone-prod-artifacts/firezone-${{ steps.set-variables.outputs.artifact }}/${{ steps.set-variables.outputs.version }}/$arch"
done
create-publish-pr:
@@ -143,21 +144,22 @@ jobs:
version=${version#${{ matrix.component }}-}
# Configure gpg
echo "${RELEASE_PR_BOT_GPG_KEY}" | gpg --import --batch
echo "$RELEASE_PR_BOT_GPG_KEY" | gpg --import --batch
GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format long "github-bot@firezone.dev" | grep sec | sed 's/.*\/\([^ ]*\).*/\1/')
# Configure git
git config --local user.email "github-bot@firezone.dev"
git config --local user.name "Firezone Bot"
git config --local user.signingkey "${GPG_KEY_ID}"
git config --local user.signingkey "$GPG_KEY_ID"
git config --local commit.gpgsign true
echo "use-agent" >> ~/.gnupg/gpg.conf
echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf
export GPG_TTY=$(tty)
GPG_TTY=$(tty)
export GPG_TTY
# Create the PR
scripts/create-publish-pr.sh ${{ matrix.component }} $version
scripts/create-publish-pr.sh ${{ matrix.component }} "$version"
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_PR_BOT_GITHUB_TOKEN }}