chore: add actionlint and zizmor linters (#19459)

This commit is contained in:
Dean Sheather
2025-08-21 22:14:43 +10:00
committed by GitHub
parent 338e8b5161
commit 8d0bc485df
20 changed files with 369 additions and 196 deletions
@@ -25,9 +25,11 @@ runs:
export YEAR_MONTH=$(date +'%Y-%m')
export PREV_YEAR_MONTH=$(date -d 'last month' +'%Y-%m')
export DAY=$(date +'%d')
echo "year-month=$YEAR_MONTH" >> $GITHUB_OUTPUT
echo "prev-year-month=$PREV_YEAR_MONTH" >> $GITHUB_OUTPUT
echo "cache-key=${{ inputs.key-prefix }}-${YEAR_MONTH}-${DAY}" >> $GITHUB_OUTPUT
echo "year-month=$YEAR_MONTH" >> "$GITHUB_OUTPUT"
echo "prev-year-month=$PREV_YEAR_MONTH" >> "$GITHUB_OUTPUT"
echo "cache-key=${INPUTS_KEY_PREFIX}-${YEAR_MONTH}-${DAY}" >> "$GITHUB_OUTPUT"
env:
INPUTS_KEY_PREFIX: ${{ inputs.key-prefix }}
# By default, depot keeps caches for 14 days. This is plenty for embedded
# postgres, which changes infrequently.
@@ -27,9 +27,11 @@ runs:
export YEAR_MONTH=$(date +'%Y-%m')
export PREV_YEAR_MONTH=$(date -d 'last month' +'%Y-%m')
export DAY=$(date +'%d')
echo "year-month=$YEAR_MONTH" >> $GITHUB_OUTPUT
echo "prev-year-month=$PREV_YEAR_MONTH" >> $GITHUB_OUTPUT
echo "cache-key=${{ inputs.key-prefix }}-${YEAR_MONTH}-${DAY}" >> $GITHUB_OUTPUT
echo "year-month=$YEAR_MONTH" >> "$GITHUB_OUTPUT"
echo "prev-year-month=$PREV_YEAR_MONTH" >> "$GITHUB_OUTPUT"
echo "cache-key=${INPUTS_KEY_PREFIX}-${YEAR_MONTH}-${DAY}" >> "$GITHUB_OUTPUT"
env:
INPUTS_KEY_PREFIX: ${{ inputs.key-prefix }}
# TODO: As a cost optimization, we could remove caches that are older than
# a day or two. By default, depot keeps caches for 14 days, which isn't
+14 -14
View File
@@ -12,13 +12,12 @@ runs:
run: |
set -e
owner=${{ github.repository_owner }}
echo "owner: $owner"
if [[ $owner != "coder" ]]; then
echo "owner: $REPO_OWNER"
if [[ "$REPO_OWNER" != "coder" ]]; then
echo "Not a pull request from the main repo, skipping..."
exit 0
fi
if [[ -z "${{ inputs.api-key }}" ]]; then
if [[ -z "${DATADOG_API_KEY}" ]]; then
# This can happen for dependabot.
echo "No API key provided, skipping..."
exit 0
@@ -31,37 +30,38 @@ runs:
TMP_DIR=$(mktemp -d)
if [[ "${{ runner.os }}" == "Windows" ]]; then
if [[ "${RUNNER_OS}" == "Windows" ]]; then
BINARY_PATH="${TMP_DIR}/datadog-ci.exe"
BINARY_URL="https://github.com/DataDog/datadog-ci/releases/download/${BINARY_VERSION}/datadog-ci_win-x64"
elif [[ "${{ runner.os }}" == "macOS" ]]; then
elif [[ "${RUNNER_OS}" == "macOS" ]]; then
BINARY_PATH="${TMP_DIR}/datadog-ci"
BINARY_URL="https://github.com/DataDog/datadog-ci/releases/download/${BINARY_VERSION}/datadog-ci_darwin-arm64"
elif [[ "${{ runner.os }}" == "Linux" ]]; then
elif [[ "${RUNNER_OS}" == "Linux" ]]; then
BINARY_PATH="${TMP_DIR}/datadog-ci"
BINARY_URL="https://github.com/DataDog/datadog-ci/releases/download/${BINARY_VERSION}/datadog-ci_linux-x64"
else
echo "Unsupported OS: ${{ runner.os }}"
echo "Unsupported OS: $RUNNER_OS"
exit 1
fi
echo "Downloading DataDog CI binary version ${BINARY_VERSION} for ${{ runner.os }}..."
echo "Downloading DataDog CI binary version ${BINARY_VERSION} for $RUNNER_OS..."
curl -sSL "$BINARY_URL" -o "$BINARY_PATH"
if [[ "${{ runner.os }}" == "Windows" ]]; then
if [[ "${RUNNER_OS}" == "Windows" ]]; then
echo "$BINARY_HASH_WINDOWS $BINARY_PATH" | sha256sum --check
elif [[ "${{ runner.os }}" == "macOS" ]]; then
elif [[ "${RUNNER_OS}" == "macOS" ]]; then
echo "$BINARY_HASH_MACOS $BINARY_PATH" | shasum -a 256 --check
elif [[ "${{ runner.os }}" == "Linux" ]]; then
elif [[ "${RUNNER_OS}" == "Linux" ]]; then
echo "$BINARY_HASH_LINUX $BINARY_PATH" | sha256sum --check
fi
# Make binary executable (not needed for Windows)
if [[ "${{ runner.os }}" != "Windows" ]]; then
if [[ "${RUNNER_OS}" != "Windows" ]]; then
chmod +x "$BINARY_PATH"
fi
"$BINARY_PATH" junit upload --service coder ./gotests.xml \
--tags os:${{runner.os}} --tags runner_name:${{runner.name}}
--tags "os:${RUNNER_OS}" --tags "runner_name:${RUNNER_NAME}"
env:
REPO_OWNER: ${{ github.repository_owner }}
DATADOG_API_KEY: ${{ inputs.api-key }}
+70 -40
View File
@@ -42,7 +42,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
# For pull requests it's not necessary to checkout the code
persist-credentials: false
- name: check changed files
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: filter
@@ -111,7 +111,9 @@ jobs:
- id: debug
run: |
echo "${{ toJSON(steps.filter )}}"
echo "$FILTER_JSON"
env:
FILTER_JSON: ${{ toJSON(steps.filter.outputs) }}
# Disabled due to instability. See: https://github.com/coder/coder/issues/14553
# Re-enable once the flake hash calculation is stable.
@@ -162,6 +164,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
@@ -171,10 +174,10 @@ jobs:
- name: Get golangci-lint cache dir
run: |
linter_ver=$(egrep -o 'GOLANGCI_LINT_VERSION=\S+' dogfood/coder/Dockerfile | cut -d '=' -f 2)
go install github.com/golangci/golangci-lint/cmd/golangci-lint@v$linter_ver
linter_ver=$(grep -Eo 'GOLANGCI_LINT_VERSION=\S+' dogfood/coder/Dockerfile | cut -d '=' -f 2)
go install "github.com/golangci/golangci-lint/cmd/golangci-lint@v$linter_ver"
dir=$(golangci-lint cache status | awk '/Dir/ { print $2 }')
echo "LINT_CACHE_DIR=$dir" >> $GITHUB_ENV
echo "LINT_CACHE_DIR=$dir" >> "$GITHUB_ENV"
- name: golangci-lint cache
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
@@ -206,7 +209,12 @@ jobs:
- name: make lint
run: |
make --output-sync=line -j lint
# zizmor isn't included in the lint target because it takes a while,
# but we explicitly want to run it in CI.
make --output-sync=line -j lint lint/actions/zizmor
env:
# Used by zizmor to lint third-party GitHub actions.
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check workflow files
run: |
@@ -234,6 +242,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
@@ -289,6 +298,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
@@ -305,8 +315,8 @@ jobs:
- name: make fmt
run: |
export PATH=${PATH}:$(go env GOPATH)/bin
make --output-sync -j -B fmt
PATH="${PATH}:$(go env GOPATH)/bin" \
make --output-sync -j -B fmt
- name: Check for unstaged files
run: ./scripts/check_unstaged.sh
@@ -340,8 +350,8 @@ jobs:
- name: Disable Spotlight Indexing
if: runner.os == 'macOS'
run: |
enabled=$(sudo mdutil -a -s | grep "Indexing enabled" | wc -l)
if [ $enabled -eq 0 ]; then
enabled=$(sudo mdutil -a -s | { grep -Fc "Indexing enabled" || true; })
if [ "$enabled" -eq 0 ]; then
echo "Spotlight indexing is already disabled"
exit 0
fi
@@ -353,12 +363,13 @@ jobs:
# a separate repository to allow its use before actions/checkout.
- name: Setup RAM Disks
if: runner.os == 'Windows'
uses: coder/setup-ramdisk-action@e1100847ab2d7bcd9d14bcda8f2d1b0f07b36f1b
uses: coder/setup-ramdisk-action@e1100847ab2d7bcd9d14bcda8f2d1b0f07b36f1b # v0.1.0
- name: Checkout
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
persist-credentials: false
- name: Setup Go Paths
id: go-paths
@@ -421,34 +432,34 @@ jobs:
set -o errexit
set -o pipefail
if [ "${{ runner.os }}" == "Windows" ]; then
if [ "$RUNNER_OS" == "Windows" ]; then
# Create a temp dir on the R: ramdisk drive for Windows. The default
# C: drive is extremely slow: https://github.com/actions/runner-images/issues/8755
mkdir -p "R:/temp/embedded-pg"
go run scripts/embedded-pg/main.go -path "R:/temp/embedded-pg" -cache "${EMBEDDED_PG_CACHE_DIR}"
elif [ "${{ runner.os }}" == "macOS" ]; then
elif [ "$RUNNER_OS" == "macOS" ]; then
# Postgres runs faster on a ramdisk on macOS too
mkdir -p /tmp/tmpfs
sudo mount_tmpfs -o noowners -s 8g /tmp/tmpfs
go run scripts/embedded-pg/main.go -path /tmp/tmpfs/embedded-pg -cache "${EMBEDDED_PG_CACHE_DIR}"
elif [ "${{ runner.os }}" == "Linux" ]; then
elif [ "$RUNNER_OS" == "Linux" ]; then
make test-postgres-docker
fi
# if macOS, install google-chrome for scaletests
# As another concern, should we really have this kind of external dependency
# requirement on standard CI?
if [ "${{ matrix.os }}" == "macos-latest" ]; then
if [ "${RUNNER_OS}" == "macOS" ]; then
brew install google-chrome
fi
# macOS will output "The default interactive shell is now zsh"
# intermittently in CI...
if [ "${{ matrix.os }}" == "macos-latest" ]; then
if [ "${RUNNER_OS}" == "macOS" ]; then
touch ~/.bash_profile && echo "export BASH_SILENCE_DEPRECATION_WARNING=1" >> ~/.bash_profile
fi
if [ "${{ runner.os }}" == "Windows" ]; then
if [ "${RUNNER_OS}" == "Windows" ]; then
# Our Windows runners have 16 cores.
# On Windows Postgres chokes up when we have 16x16=256 tests
# running in parallel, and dbtestutil.NewDB starts to take more than
@@ -458,7 +469,7 @@ jobs:
NUM_PARALLEL_TESTS=16
# Only the CLI and Agent are officially supported on Windows and the rest are too flaky
PACKAGES="./cli/... ./enterprise/cli/... ./agent/..."
elif [ "${{ runner.os }}" == "macOS" ]; then
elif [ "${RUNNER_OS}" == "macOS" ]; then
# Our macOS runners have 8 cores. We set NUM_PARALLEL_TESTS to 16
# because the tests complete faster and Postgres doesn't choke. It seems
# that macOS's tmpfs is faster than the one on Windows.
@@ -466,7 +477,7 @@ jobs:
NUM_PARALLEL_TESTS=16
# Only the CLI and Agent are officially supported on macOS and the rest are too flaky
PACKAGES="./cli/... ./enterprise/cli/... ./agent/..."
elif [ "${{ runner.os }}" == "Linux" ]; then
elif [ "${RUNNER_OS}" == "Linux" ]; then
# Our Linux runners have 8 cores.
NUM_PARALLEL_PACKAGES=8
NUM_PARALLEL_TESTS=8
@@ -475,7 +486,7 @@ jobs:
# by default, run tests with cache
TESTCOUNT=""
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
if [ "${GITHUB_REF}" == "refs/heads/main" ]; then
# on main, run tests without cache
TESTCOUNT="-count=1"
fi
@@ -485,7 +496,7 @@ jobs:
# terraform gets installed in a random directory, so we need to normalize
# the path to the terraform binary or a bunch of cached tests will be
# invalidated. See scripts/normalize_path.sh for more details.
normalize_path_with_symlinks "$RUNNER_TEMP/sym" "$(dirname $(which terraform))"
normalize_path_with_symlinks "$RUNNER_TEMP/sym" "$(dirname "$(which terraform)")"
gotestsum --format standard-quiet --packages "$PACKAGES" \
-- -timeout=20m -v -p $NUM_PARALLEL_PACKAGES -parallel=$NUM_PARALLEL_TESTS $TESTCOUNT
@@ -546,6 +557,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
persist-credentials: false
- name: Setup Go
uses: ./.github/actions/setup-go
@@ -594,6 +606,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
persist-credentials: false
- name: Setup Go
uses: ./.github/actions/setup-go
@@ -653,6 +666,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
persist-credentials: false
- name: Setup Go
uses: ./.github/actions/setup-go
@@ -679,11 +693,12 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
- run: pnpm test:ci --max-workers $(nproc)
- run: pnpm test:ci --max-workers "$(nproc)"
working-directory: site
test-e2e:
@@ -711,6 +726,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
@@ -785,6 +801,7 @@ jobs:
fetch-depth: 0
# 👇 Tells the checkout which commit hash to reference
ref: ${{ github.event.pull_request.head.ref }}
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
@@ -863,6 +880,7 @@ jobs:
with:
# 0 is required here for version.sh to work.
fetch-depth: 0
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
@@ -927,7 +945,7 @@ jobs:
egress-policy: audit
- name: Ensure required checks
run: |
run: | # zizmor: ignore[template-injection] We're just reading needs.x.result here, no risk of injection
echo "Checking required checks"
echo "- fmt: ${{ needs.fmt.result }}"
echo "- lint: ${{ needs.lint.result }}"
@@ -961,13 +979,16 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
persist-credentials: false
- name: Setup build tools
run: |
brew install bash gnu-getopt make
echo "$(brew --prefix bash)/bin" >> $GITHUB_PATH
echo "$(brew --prefix gnu-getopt)/bin" >> $GITHUB_PATH
echo "$(brew --prefix make)/libexec/gnubin" >> $GITHUB_PATH
{
echo "$(brew --prefix bash)/bin"
echo "$(brew --prefix gnu-getopt)/bin"
echo "$(brew --prefix make)/libexec/gnubin"
} >> "$GITHUB_PATH"
- name: Switch XCode Version
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
@@ -1045,6 +1066,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
@@ -1099,6 +1121,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
persist-credentials: false
- name: GHCR Login
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
@@ -1196,8 +1219,8 @@ jobs:
go mod download
version="$(./scripts/version.sh)"
tag="main-$(echo "$version" | sed 's/+/-/g')"
echo "tag=$tag" >> $GITHUB_OUTPUT
tag="main-${version//+/-}"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
make gen/mark-fresh
make -j \
@@ -1233,15 +1256,15 @@ jobs:
# build Docker images for each architecture
version="$(./scripts/version.sh)"
tag="main-$(echo "$version" | sed 's/+/-/g')"
echo "tag=$tag" >> $GITHUB_OUTPUT
tag="main-${version//+/-}"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
# build images for each architecture
# note: omitting the -j argument to avoid race conditions when pushing
make build/coder_"$version"_linux_{amd64,arm64,armv7}.tag
# only push if we are on main branch
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
if [ "${GITHUB_REF}" == "refs/heads/main" ]; then
# build and push multi-arch manifest, this depends on the other images
# being pushed so will automatically push them
# note: omitting the -j argument to avoid race conditions when pushing
@@ -1254,10 +1277,11 @@ jobs:
# we are adding `latest` tag and keeping `main` for backward
# compatibality
for t in "${tags[@]}"; do
# shellcheck disable=SC2046
./scripts/build_docker_multiarch.sh \
--push \
--target "ghcr.io/coder/coder-preview:$t" \
--version $version \
--version "$version" \
$(cat build/coder_"$version"_linux_{amd64,arm64,armv7}.tag)
done
fi
@@ -1267,12 +1291,13 @@ jobs:
continue-on-error: true
env:
COSIGN_EXPERIMENTAL: 1
BUILD_TAG: ${{ steps.build-docker.outputs.tag }}
run: |
set -euxo pipefail
# Define image base and tags
IMAGE_BASE="ghcr.io/coder/coder-preview"
TAGS=("${{ steps.build-docker.outputs.tag }}" "main" "latest")
TAGS=("${BUILD_TAG}" "main" "latest")
# Generate and attest SBOM for each tag
for tag in "${TAGS[@]}"; do
@@ -1411,7 +1436,7 @@ jobs:
# Report attestation failures but don't fail the workflow
- name: Check attestation status
if: github.ref == 'refs/heads/main'
run: |
run: | # zizmor: ignore[template-injection] We're just reading steps.attest_x.outcome here, no risk of injection
if [[ "${{ steps.attest_main.outcome }}" == "failure" ]]; then
echo "::warning::GitHub attestation for main tag failed"
fi
@@ -1471,6 +1496,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
persist-credentials: false
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@b7593ed2efd1c1617e1b0254da33b86225adb2a5 # v2.1.12
@@ -1535,6 +1561,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
persist-credentials: false
- name: Setup flyctl
uses: superfly/flyctl-actions/setup-flyctl@fc53c09e1bc3be6f54706524e3b82c4f462f77be # v1.5
@@ -1570,7 +1597,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
# We need golang to run the migration main.go
persist-credentials: false
- name: Setup Go
uses: ./.github/actions/setup-go
@@ -1606,15 +1633,15 @@ jobs:
"fields": [
{
"type": "mrkdwn",
"text": "*Workflow:*\n${{ github.workflow }}"
"text": "*Workflow:*\n'"${GITHUB_WORKFLOW}"'"
},
{
"type": "mrkdwn",
"text": "*Committer:*\n${{ github.actor }}"
"text": "*Committer:*\n'"${GITHUB_ACTOR}"'"
},
{
"type": "mrkdwn",
"text": "*Commit:*\n${{ github.sha }}"
"text": "*Commit:*\n'"${GITHUB_SHA}"'"
}
]
},
@@ -1622,7 +1649,7 @@ jobs:
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*View failure:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Click here>"
"text": "*View failure:* <'"${RUN_URL}"'|Click here>"
}
},
{
@@ -1633,4 +1660,7 @@ jobs:
}
}
]
}' ${{ secrets.CI_FAILURE_SLACK_WEBHOOK }}
}' "${SLACK_WEBHOOK}"
env:
SLACK_WEBHOOK: ${{ secrets.CI_FAILURE_SLACK_WEBHOOK }}
RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+1
View File
@@ -3,6 +3,7 @@ name: contrib
on:
issue_comment:
types: [created, edited]
# zizmor: ignore[dangerous-triggers] We explicitly want to run on pull_request_target.
pull_request_target:
types:
- opened
+10 -9
View File
@@ -15,7 +15,7 @@ jobs:
github.event_name == 'pull_request' &&
github.event.action == 'opened' &&
github.event.pull_request.user.login == 'dependabot[bot]' &&
github.actor_id == 49699333 &&
github.event.pull_request.user.id == 49699333 &&
github.repository == 'coder/coder'
permissions:
pull-requests: write
@@ -44,10 +44,6 @@ jobs:
GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Send Slack notification
env:
PR_URL: ${{github.event.pull_request.html_url}}
PR_TITLE: ${{github.event.pull_request.title}}
PR_NUMBER: ${{github.event.pull_request.number}}
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{
@@ -58,7 +54,7 @@ jobs:
"type": "header",
"text": {
"type": "plain_text",
"text": ":pr-merged: Auto merge enabled for Dependabot PR #${{ env.PR_NUMBER }}",
"text": ":pr-merged: Auto merge enabled for Dependabot PR #'"${PR_NUMBER}"'",
"emoji": true
}
},
@@ -67,7 +63,7 @@ jobs:
"fields": [
{
"type": "mrkdwn",
"text": "${{ env.PR_TITLE }}"
"text": "'"${PR_TITLE}"'"
}
]
},
@@ -80,9 +76,14 @@ jobs:
"type": "plain_text",
"text": "View PR"
},
"url": "${{ env.PR_URL }}"
"url": "'"${PR_URL}"'"
}
]
}
]
}' ${{ secrets.DEPENDABOT_PRS_SLACK_WEBHOOK }}
}' "${{ secrets.DEPENDABOT_PRS_SLACK_WEBHOOK }}"
env:
SLACK_WEBHOOK: ${{ secrets.DEPENDABOT_PRS_SLACK_WEBHOOK }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_URL: ${{ github.event.pull_request.html_url }}
+2
View File
@@ -44,6 +44,8 @@ jobs:
- name: Checkout
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- name: Docker login
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
+10 -2
View File
@@ -24,6 +24,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
@@ -39,10 +41,16 @@ jobs:
- name: lint
if: steps.changed-files.outputs.any_changed == 'true'
run: |
pnpm exec markdownlint-cli2 ${{ steps.changed-files.outputs.all_changed_files }}
# shellcheck disable=SC2086
pnpm exec markdownlint-cli2 $ALL_CHANGED_FILES
env:
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
- name: fmt
if: steps.changed-files.outputs.any_changed == 'true'
run: |
# markdown-table-formatter requires a space separated list of files
echo ${{ steps.changed-files.outputs.all_changed_files }} | tr ',' '\n' | pnpm exec markdown-table-formatter --check
# shellcheck disable=SC2086
echo $ALL_CHANGED_FILES | tr ',' '\n' | pnpm exec markdown-table-formatter --check
env:
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
+20 -11
View File
@@ -18,8 +18,7 @@ on:
workflow_dispatch:
permissions:
# Necessary for GCP authentication (https://github.com/google-github-actions/setup-gcloud#usage)
id-token: write
contents: read
jobs:
build_image:
@@ -33,6 +32,8 @@ jobs:
- name: Checkout
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- name: Setup Nix
uses: nixbuild/nix-quick-install-action@63ca48f939ee3b8d835f4126562537df0fee5b91 # v32
@@ -67,10 +68,11 @@ jobs:
- name: "Branch name to Docker tag name"
id: docker-tag-name
run: |
tag=${{ steps.branch-name.outputs.current_branch }}
# Replace / with --, e.g. user/feature => user--feature.
tag=${tag//\//--}
echo "tag=${tag}" >> $GITHUB_OUTPUT
tag=${BRANCH_NAME//\//--}
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
env:
BRANCH_NAME: ${{ steps.branch-name.outputs.current_branch }}
- name: Set up Depot CLI
uses: depot/setup-action@b0b1ea4f69e92ebf5dea3f8713a1b0c37b2126a5 # v1.6.0
@@ -107,15 +109,20 @@ jobs:
CURRENT_SYSTEM=$(nix eval --impure --raw --expr 'builtins.currentSystem')
docker image tag codercom/oss-dogfood-nix:latest-$CURRENT_SYSTEM codercom/oss-dogfood-nix:${{ steps.docker-tag-name.outputs.tag }}
docker image push codercom/oss-dogfood-nix:${{ steps.docker-tag-name.outputs.tag }}
docker image tag "codercom/oss-dogfood-nix:latest-$CURRENT_SYSTEM" "codercom/oss-dogfood-nix:${DOCKER_TAG}"
docker image push "codercom/oss-dogfood-nix:${DOCKER_TAG}"
docker image tag codercom/oss-dogfood-nix:latest-$CURRENT_SYSTEM codercom/oss-dogfood-nix:latest
docker image push codercom/oss-dogfood-nix:latest
docker image tag "codercom/oss-dogfood-nix:latest-$CURRENT_SYSTEM" "codercom/oss-dogfood-nix:latest"
docker image push "codercom/oss-dogfood-nix:latest"
env:
DOCKER_TAG: ${{ steps.docker-tag-name.outputs.tag }}
deploy_template:
needs: build_image
runs-on: ubuntu-latest
permissions:
# Necessary for GCP authentication (https://github.com/google-github-actions/setup-gcloud#usage)
id-token: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
@@ -124,6 +131,8 @@ jobs:
- name: Checkout
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- name: Setup Terraform
uses: ./.github/actions/setup-tf
@@ -152,12 +161,12 @@ jobs:
- name: Get short commit SHA
if: github.ref == 'refs/heads/main'
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
run: echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
- name: Get latest commit title
if: github.ref == 'refs/heads/main'
id: message
run: echo "pr_title=$(git log --format=%s -n 1 ${{ github.sha }})" >> $GITHUB_OUTPUT
run: echo "pr_title=$(git log --format=%s -n 1 ${{ github.sha }})" >> "$GITHUB_OUTPUT"
- name: "Push template"
if: github.ref == 'refs/heads/main'
+12 -8
View File
@@ -37,8 +37,8 @@ jobs:
- name: Disable Spotlight Indexing
if: runner.os == 'macOS'
run: |
enabled=$(sudo mdutil -a -s | grep "Indexing enabled" | wc -l)
if [ $enabled -eq 0 ]; then
enabled=$(sudo mdutil -a -s | { grep -Fc "Indexing enabled" || true; })
if [ "$enabled" -eq 0 ]; then
echo "Spotlight indexing is already disabled"
exit 0
fi
@@ -50,12 +50,13 @@ jobs:
# a separate repository to allow its use before actions/checkout.
- name: Setup RAM Disks
if: runner.os == 'Windows'
uses: coder/setup-ramdisk-action@e1100847ab2d7bcd9d14bcda8f2d1b0f07b36f1b
uses: coder/setup-ramdisk-action@e1100847ab2d7bcd9d14bcda8f2d1b0f07b36f1b # v0.1.0
- name: Checkout
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
persist-credentials: false
- name: Setup Go
uses: ./.github/actions/setup-go
@@ -185,15 +186,15 @@ jobs:
"fields": [
{
"type": "mrkdwn",
"text": "*Workflow:*\n${{ github.workflow }}"
"text": "*Workflow:*\n'"${GITHUB_WORKFLOW}"'"
},
{
"type": "mrkdwn",
"text": "*Committer:*\n${{ github.actor }}"
"text": "*Committer:*\n'"${GITHUB_ACTOR}"'"
},
{
"type": "mrkdwn",
"text": "*Commit:*\n${{ github.sha }}"
"text": "*Commit:*\n'"${GITHUB_SHA}"'"
}
]
},
@@ -201,7 +202,7 @@ jobs:
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*View failure:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Click here>"
"text": "*View failure:* <'"${RUN_URL}"'|Click here>"
}
},
{
@@ -212,4 +213,7 @@ jobs:
}
}
]
}' ${{ secrets.CI_FAILURE_SLACK_WEBHOOK }}
}' "${SLACK_WEBHOOK}"
env:
SLACK_WEBHOOK: ${{ secrets.CI_FAILURE_SLACK_WEBHOOK }}
RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
+1
View File
@@ -3,6 +3,7 @@
name: PR Auto Assign
on:
# zizmor: ignore[dangerous-triggers] We explicitly want to run on pull_request_target.
pull_request_target:
types: [opened]
+16 -6
View File
@@ -27,10 +27,12 @@ jobs:
id: pr_number
run: |
if [ -n "${{ github.event.pull_request.number }}" ]; then
echo "PR_NUMBER=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT
echo "PR_NUMBER=${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT"
else
echo "PR_NUMBER=${{ github.event.inputs.pr_number }}" >> $GITHUB_OUTPUT
echo "PR_NUMBER=${PR_NUMBER}" >> "$GITHUB_OUTPUT"
fi
env:
PR_NUMBER: ${{ github.event.inputs.pr_number }}
- name: Delete image
continue-on-error: true
@@ -51,17 +53,21 @@ jobs:
- name: Delete helm release
run: |
set -euo pipefail
helm delete --namespace "pr${{ steps.pr_number.outputs.PR_NUMBER }}" "pr${{ steps.pr_number.outputs.PR_NUMBER }}" || echo "helm release not found"
helm delete --namespace "pr${PR_NUMBER}" "pr${PR_NUMBER}" || echo "helm release not found"
env:
PR_NUMBER: ${{ steps.pr_number.outputs.PR_NUMBER }}
- name: "Remove PR namespace"
run: |
kubectl delete namespace "pr${{ steps.pr_number.outputs.PR_NUMBER }}" || echo "namespace not found"
kubectl delete namespace "pr${PR_NUMBER}" || echo "namespace not found"
env:
PR_NUMBER: ${{ steps.pr_number.outputs.PR_NUMBER }}
- name: "Remove DNS records"
run: |
set -euo pipefail
# Get identifier for the record
record_id=$(curl -X GET "https://api.cloudflare.com/client/v4/zones/${{ secrets.PR_DEPLOYMENTS_ZONE_ID }}/dns_records?name=%2A.pr${{ steps.pr_number.outputs.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" \
record_id=$(curl -X GET "https://api.cloudflare.com/client/v4/zones/${{ secrets.PR_DEPLOYMENTS_ZONE_ID }}/dns_records?name=%2A.pr${PR_NUMBER}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" \
-H "Authorization: Bearer ${{ secrets.PR_DEPLOYMENTS_CLOUDFLARE_API_TOKEN }}" \
-H "Content-Type:application/json" | jq -r '.result[0].id') || echo "DNS record not found"
@@ -73,9 +79,13 @@ jobs:
-H "Authorization: Bearer ${{ secrets.PR_DEPLOYMENTS_CLOUDFLARE_API_TOKEN }}" \
-H "Content-Type:application/json" | jq -r '.success'
) || echo "DNS record not found"
env:
PR_NUMBER: ${{ steps.pr_number.outputs.PR_NUMBER }}
- name: "Delete certificate"
if: ${{ github.event.pull_request.merged == true }}
run: |
set -euxo pipefail
kubectl delete certificate "pr${{ steps.pr_number.outputs.PR_NUMBER }}-tls" -n pr-deployment-certs || echo "certificate not found"
kubectl delete certificate "pr${PR_NUMBER}-tls" -n pr-deployment-certs || echo "certificate not found"
env:
PR_NUMBER: ${{ steps.pr_number.outputs.PR_NUMBER }}
+69 -53
View File
@@ -45,6 +45,8 @@ jobs:
- name: Checkout
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- name: Check if PR is open
id: check_pr
@@ -55,7 +57,7 @@ jobs:
echo "PR doesn't exist or is closed."
pr_open=false
fi
echo "pr_open=$pr_open" >> $GITHUB_OUTPUT
echo "pr_open=$pr_open" >> "$GITHUB_OUTPUT"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -82,6 +84,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
persist-credentials: false
- name: Get PR number, title, and branch name
id: pr_info
@@ -90,9 +93,11 @@ jobs:
PR_NUMBER=$(gh pr view --json number | jq -r '.number')
PR_TITLE=$(gh pr view --json title | jq -r '.title')
PR_URL=$(gh pr view --json url | jq -r '.url')
echo "PR_URL=$PR_URL" >> $GITHUB_OUTPUT
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT
echo "PR_TITLE=$PR_TITLE" >> $GITHUB_OUTPUT
{
echo "PR_URL=$PR_URL"
echo "PR_NUMBER=$PR_NUMBER"
echo "PR_TITLE=$PR_TITLE"
} >> "$GITHUB_OUTPUT"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -100,8 +105,8 @@ jobs:
id: set_tags
run: |
set -euo pipefail
echo "CODER_BASE_IMAGE_TAG=$CODER_BASE_IMAGE_TAG" >> $GITHUB_OUTPUT
echo "CODER_IMAGE_TAG=$CODER_IMAGE_TAG" >> $GITHUB_OUTPUT
echo "CODER_BASE_IMAGE_TAG=$CODER_BASE_IMAGE_TAG" >> "$GITHUB_OUTPUT"
echo "CODER_IMAGE_TAG=$CODER_IMAGE_TAG" >> "$GITHUB_OUTPUT"
env:
CODER_BASE_IMAGE_TAG: ghcr.io/coder/coder-preview-base:pr${{ steps.pr_info.outputs.PR_NUMBER }}
CODER_IMAGE_TAG: ghcr.io/coder/coder-preview:pr${{ steps.pr_info.outputs.PR_NUMBER }}
@@ -118,14 +123,16 @@ jobs:
id: check_deployment
run: |
set -euo pipefail
if helm status "pr${{ steps.pr_info.outputs.PR_NUMBER }}" --namespace "pr${{ steps.pr_info.outputs.PR_NUMBER }}" > /dev/null 2>&1; then
if helm status "pr${PR_NUMBER}" --namespace "pr${PR_NUMBER}" > /dev/null 2>&1; then
echo "Deployment already exists. Skipping deployment."
NEW=false
else
echo "Deployment doesn't exist."
NEW=true
fi
echo "NEW=$NEW" >> $GITHUB_OUTPUT
echo "NEW=$NEW" >> "$GITHUB_OUTPUT"
env:
PR_NUMBER: ${{ steps.pr_info.outputs.PR_NUMBER }}
- name: Check changed files
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
@@ -154,17 +161,20 @@ jobs:
- name: Print number of changed files
run: |
set -euo pipefail
echo "Total number of changed files: ${{ steps.filter.outputs.all_count }}"
echo "Number of ignored files: ${{ steps.filter.outputs.ignored_count }}"
echo "Total number of changed files: ${ALL_COUNT}"
echo "Number of ignored files: ${IGNORED_COUNT}"
env:
ALL_COUNT: ${{ steps.filter.outputs.all_count }}
IGNORED_COUNT: ${{ steps.filter.outputs.ignored_count }}
- name: Build conditionals
id: build_conditionals
run: |
set -euo pipefail
# build if the workflow is manually triggered and the deployment doesn't exist (first build or force rebuild)
echo "first_or_force_build=${{ (github.event_name == 'workflow_dispatch' && steps.check_deployment.outputs.NEW == 'true') || github.event.inputs.build == 'true' }}" >> $GITHUB_OUTPUT
echo "first_or_force_build=${{ (github.event_name == 'workflow_dispatch' && steps.check_deployment.outputs.NEW == 'true') || github.event.inputs.build == 'true' }}" >> "$GITHUB_OUTPUT"
# build if the deployment already exist and there are changes in the files that we care about (automatic updates)
echo "automatic_rebuild=${{ steps.check_deployment.outputs.NEW == 'false' && steps.filter.outputs.all_count > steps.filter.outputs.ignored_count }}" >> $GITHUB_OUTPUT
echo "automatic_rebuild=${{ steps.check_deployment.outputs.NEW == 'false' && steps.filter.outputs.all_count > steps.filter.outputs.ignored_count }}" >> "$GITHUB_OUTPUT"
comment-pr:
needs: get_info
@@ -226,6 +236,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
@@ -250,12 +261,13 @@ jobs:
make gen/mark-fresh
export DOCKER_IMAGE_NO_PREREQUISITES=true
version="$(./scripts/version.sh)"
export CODER_IMAGE_BUILD_BASE_TAG="$(CODER_IMAGE_BASE=coder-base ./scripts/image_tag.sh --version "$version")"
CODER_IMAGE_BUILD_BASE_TAG="$(CODER_IMAGE_BASE=coder-base ./scripts/image_tag.sh --version "$version")"
export CODER_IMAGE_BUILD_BASE_TAG
make -j build/coder_linux_amd64
./scripts/build_docker.sh \
--arch amd64 \
--target ${{ env.CODER_IMAGE_TAG }} \
--version $version \
--target "${CODER_IMAGE_TAG}" \
--version "$version" \
--push \
build/coder_linux_amd64
@@ -293,13 +305,13 @@ jobs:
set -euo pipefail
foundTag=$(
gh api /orgs/coder/packages/container/coder-preview/versions |
jq -r --arg tag "pr${{ env.PR_NUMBER }}" '.[] |
jq -r --arg tag "pr${PR_NUMBER}" '.[] |
select(.metadata.container.tags == [$tag]) |
.metadata.container.tags[0]'
)
if [ -z "$foundTag" ]; then
echo "Image not found"
echo "${{ env.CODER_IMAGE_TAG }} not found in ghcr.io/coder/coder-preview"
echo "${CODER_IMAGE_TAG} not found in ghcr.io/coder/coder-preview"
exit 1
else
echo "Image found"
@@ -314,40 +326,42 @@ jobs:
curl -X POST "https://api.cloudflare.com/client/v4/zones/${{ secrets.PR_DEPLOYMENTS_ZONE_ID }}/dns_records" \
-H "Authorization: Bearer ${{ secrets.PR_DEPLOYMENTS_CLOUDFLARE_API_TOKEN }}" \
-H "Content-Type:application/json" \
--data '{"type":"CNAME","name":"*.${{ env.PR_HOSTNAME }}","content":"${{ env.PR_HOSTNAME }}","ttl":1,"proxied":false}'
--data '{"type":"CNAME","name":"*.'"${PR_HOSTNAME}"'","content":"'"${PR_HOSTNAME}"'","ttl":1,"proxied":false}'
- name: Create PR namespace
if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true'
run: |
set -euo pipefail
# try to delete the namespace, but don't fail if it doesn't exist
kubectl delete namespace "pr${{ env.PR_NUMBER }}" || true
kubectl create namespace "pr${{ env.PR_NUMBER }}"
kubectl delete namespace "pr${PR_NUMBER}" || true
kubectl create namespace "pr${PR_NUMBER}"
- name: Checkout
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- name: Check and Create Certificate
if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true'
run: |
# Using kubectl to check if a Certificate resource already exists
# we are doing this to avoid letsenrypt rate limits
if ! kubectl get certificate pr${{ env.PR_NUMBER }}-tls -n pr-deployment-certs > /dev/null 2>&1; then
if ! kubectl get certificate "pr${PR_NUMBER}-tls" -n pr-deployment-certs > /dev/null 2>&1; then
echo "Certificate doesn't exist. Creating a new one."
envsubst < ./.github/pr-deployments/certificate.yaml | kubectl apply -f -
else
echo "Certificate exists. Skipping certificate creation."
fi
echo "Copy certificate from pr-deployment-certs to pr${{ env.PR_NUMBER }} namespace"
until kubectl get secret pr${{ env.PR_NUMBER }}-tls -n pr-deployment-certs &> /dev/null
echo "Copy certificate from pr-deployment-certs to pr${PR_NUMBER} namespace"
until kubectl get secret "pr${PR_NUMBER}-tls" -n pr-deployment-certs &> /dev/null
do
echo "Waiting for secret pr${{ env.PR_NUMBER }}-tls to be created..."
echo "Waiting for secret pr${PR_NUMBER}-tls to be created..."
sleep 5
done
(
kubectl get secret pr${{ env.PR_NUMBER }}-tls -n pr-deployment-certs -o json |
kubectl get secret "pr${PR_NUMBER}-tls" -n pr-deployment-certs -o json |
jq 'del(.metadata.namespace,.metadata.creationTimestamp,.metadata.resourceVersion,.metadata.selfLink,.metadata.uid,.metadata.managedFields)' |
kubectl -n pr${{ env.PR_NUMBER }} apply -f -
kubectl -n "pr${PR_NUMBER}" apply -f -
)
- name: Set up PostgreSQL database
@@ -355,13 +369,13 @@ jobs:
run: |
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install coder-db bitnami/postgresql \
--namespace pr${{ env.PR_NUMBER }} \
--namespace "pr${PR_NUMBER}" \
--set auth.username=coder \
--set auth.password=coder \
--set auth.database=coder \
--set persistence.size=10Gi
kubectl create secret generic coder-db-url -n pr${{ env.PR_NUMBER }} \
--from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${{ env.PR_NUMBER }}.svc.cluster.local:5432/coder?sslmode=disable"
kubectl create secret generic coder-db-url -n "pr${PR_NUMBER}" \
--from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${PR_NUMBER}.svc.cluster.local:5432/coder?sslmode=disable"
- name: Create a service account, role, and rolebinding for the PR namespace
if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true'
@@ -383,8 +397,8 @@ jobs:
run: |
set -euo pipefail
helm dependency update --skip-refresh ./helm/coder
helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm/coder \
--namespace "pr${{ env.PR_NUMBER }}" \
helm upgrade --install "pr${PR_NUMBER}" ./helm/coder \
--namespace "pr${PR_NUMBER}" \
--values ./pr-deploy-values.yaml \
--force
@@ -393,8 +407,8 @@ jobs:
run: |
helm repo add coder-logstream-kube https://helm.coder.com/logstream-kube
helm upgrade --install coder-logstream-kube coder-logstream-kube/coder-logstream-kube \
--namespace "pr${{ env.PR_NUMBER }}" \
--set url="https://${{ env.PR_HOSTNAME }}"
--namespace "pr${PR_NUMBER}" \
--set url="https://${PR_HOSTNAME}"
- name: Get Coder binary
if: needs.get_info.outputs.NEW == 'true' || github.event.inputs.deploy == 'true'
@@ -402,16 +416,16 @@ jobs:
set -euo pipefail
DEST="${HOME}/coder"
URL="https://${{ env.PR_HOSTNAME }}/bin/coder-linux-amd64"
URL="https://${PR_HOSTNAME}/bin/coder-linux-amd64"
mkdir -p "$(dirname ${DEST})"
mkdir -p "$(dirname "$DEST")"
COUNT=0
until $(curl --output /dev/null --silent --head --fail "$URL"); do
until curl --output /dev/null --silent --head --fail "$URL"; do
printf '.'
sleep 5
COUNT=$((COUNT+1))
if [ $COUNT -ge 60 ]; then
if [ "$COUNT" -ge 60 ]; then
echo "Timed out waiting for URL to be available"
exit 1
fi
@@ -435,24 +449,24 @@ jobs:
# add mask so that the password is not printed to the logs
echo "::add-mask::$password"
echo "password=$password" >> $GITHUB_OUTPUT
echo "password=$password" >> "$GITHUB_OUTPUT"
coder login \
--first-user-username pr${{ env.PR_NUMBER }}-admin \
--first-user-email pr${{ env.PR_NUMBER }}@coder.com \
--first-user-password $password \
--first-user-username "pr${PR_NUMBER}-admin" \
--first-user-email "pr${PR_NUMBER}@coder.com" \
--first-user-password "$password" \
--first-user-trial=false \
--use-token-as-session \
https://${{ env.PR_HOSTNAME }}
"https://${PR_HOSTNAME}"
# Create a user for the github.actor
# TODO: update once https://github.com/coder/coder/issues/15466 is resolved
# coder users create \
# --username ${{ github.actor }} \
# --username ${GITHUB_ACTOR} \
# --login-type github
# promote the user to admin role
# coder org members edit-role ${{ github.actor }} organization-admin
# coder org members edit-role ${GITHUB_ACTOR} organization-admin
# TODO: update once https://github.com/coder/internal/issues/207 is resolved
- name: Send Slack notification
@@ -461,17 +475,19 @@ jobs:
curl -s -o /dev/null -X POST -H 'Content-type: application/json' \
-d \
'{
"pr_number": "'"${{ env.PR_NUMBER }}"'",
"pr_url": "'"${{ env.PR_URL }}"'",
"pr_title": "'"${{ env.PR_TITLE }}"'",
"pr_access_url": "'"https://${{ env.PR_HOSTNAME }}"'",
"pr_username": "'"pr${{ env.PR_NUMBER }}-admin"'",
"pr_email": "'"pr${{ env.PR_NUMBER }}@coder.com"'",
"pr_password": "'"${{ steps.setup_deployment.outputs.password }}"'",
"pr_actor": "'"${{ github.actor }}"'"
"pr_number": "'"${PR_NUMBER}"'",
"pr_url": "'"${PR_URL}"'",
"pr_title": "'"${PR_TITLE}"'",
"pr_access_url": "'"https://${PR_HOSTNAME}"'",
"pr_username": "'"pr${PR_NUMBER}-admin"'",
"pr_email": "'"pr${PR_NUMBER}@coder.com"'",
"pr_password": "'"${PASSWORD}"'",
"pr_actor": "'"${GITHUB_ACTOR}"'"
}' \
${{ secrets.PR_DEPLOYMENTS_SLACK_WEBHOOK }}
echo "Slack notification sent"
env:
PASSWORD: ${{ steps.setup_deployment.outputs.password }}
- name: Find Comment
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
@@ -504,7 +520,7 @@ jobs:
run: |
set -euo pipefail
cd .github/pr-deployments/template
coder templates push -y --variable namespace=pr${{ env.PR_NUMBER }} kubernetes
coder templates push -y --variable "namespace=pr${PR_NUMBER}" kubernetes
# Create workspace
coder create --template="kubernetes" kube --parameter cpu=2 --parameter memory=4 --parameter home_disk_size=2 -y
+56 -42
View File
@@ -68,6 +68,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
persist-credentials: false
# If the event that triggered the build was an annotated tag (which our
# tags are supposed to be), actions/checkout has a bug where the tag in
@@ -80,9 +81,11 @@ jobs:
- name: Setup build tools
run: |
brew install bash gnu-getopt make
echo "$(brew --prefix bash)/bin" >> $GITHUB_PATH
echo "$(brew --prefix gnu-getopt)/bin" >> $GITHUB_PATH
echo "$(brew --prefix make)/libexec/gnubin" >> $GITHUB_PATH
{
echo "$(brew --prefix bash)/bin"
echo "$(brew --prefix gnu-getopt)/bin"
echo "$(brew --prefix make)/libexec/gnubin"
} >> "$GITHUB_PATH"
- name: Switch XCode Version
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
@@ -169,6 +172,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
persist-credentials: false
# If the event that triggered the build was an annotated tag (which our
# tags are supposed to be), actions/checkout has a bug where the tag in
@@ -183,9 +187,9 @@ jobs:
run: |
set -euo pipefail
version="$(./scripts/version.sh)"
echo "version=$version" >> $GITHUB_OUTPUT
echo "version=$version" >> "$GITHUB_OUTPUT"
# Speed up future version.sh calls.
echo "CODER_FORCE_VERSION=$version" >> $GITHUB_ENV
echo "CODER_FORCE_VERSION=$version" >> "$GITHUB_ENV"
echo "$version"
# Verify that all expectations for a release are met.
@@ -227,7 +231,7 @@ jobs:
release_notes_file="$(mktemp -t release_notes.XXXXXX)"
echo "$CODER_RELEASE_NOTES" > "$release_notes_file"
echo CODER_RELEASE_NOTES_FILE="$release_notes_file" >> $GITHUB_ENV
echo CODER_RELEASE_NOTES_FILE="$release_notes_file" >> "$GITHUB_ENV"
- name: Show release notes
run: |
@@ -377,9 +381,9 @@ jobs:
set -euo pipefail
if [[ "${CODER_RELEASE:-}" != *t* ]] || [[ "${CODER_DRY_RUN:-}" == *t* ]]; then
# Empty value means use the default and avoid building a fresh one.
echo "tag=" >> $GITHUB_OUTPUT
echo "tag=" >> "$GITHUB_OUTPUT"
else
echo "tag=$(CODER_IMAGE_BASE=ghcr.io/coder/coder-base ./scripts/image_tag.sh)" >> $GITHUB_OUTPUT
echo "tag=$(CODER_IMAGE_BASE=ghcr.io/coder/coder-base ./scripts/image_tag.sh)" >> "$GITHUB_OUTPUT"
fi
- name: Create empty base-build-context directory
@@ -414,7 +418,7 @@ jobs:
# available immediately
for i in {1..10}; do
rc=0
raw_manifests=$(docker buildx imagetools inspect --raw "${{ steps.image-base-tag.outputs.tag }}") || rc=$?
raw_manifests=$(docker buildx imagetools inspect --raw "${IMAGE_TAG}") || rc=$?
if [[ "$rc" -eq 0 ]]; then
break
fi
@@ -436,6 +440,8 @@ jobs:
echo "$manifests" | grep -q linux/amd64
echo "$manifests" | grep -q linux/arm64
echo "$manifests" | grep -q linux/arm/v7
env:
IMAGE_TAG: ${{ steps.image-base-tag.outputs.tag }}
# GitHub attestation provides SLSA provenance for Docker images, establishing a verifiable
# record that these images were built in GitHub Actions with specific inputs and environment.
@@ -503,7 +509,7 @@ jobs:
# Save multiarch image tag for attestation
multiarch_image="$(./scripts/image_tag.sh)"
echo "multiarch_image=${multiarch_image}" >> $GITHUB_OUTPUT
echo "multiarch_image=${multiarch_image}" >> "$GITHUB_OUTPUT"
# For debugging, print all docker image tags
docker images
@@ -511,16 +517,15 @@ jobs:
# if the current version is equal to the highest (according to semver)
# version in the repo, also create a multi-arch image as ":latest" and
# push it
created_latest_tag=false
if [[ "$(git tag | grep '^v' | grep -vE '(rc|dev|-|\+|\/)' | sort -r --version-sort | head -n1)" == "v$(./scripts/version.sh)" ]]; then
# shellcheck disable=SC2046
./scripts/build_docker_multiarch.sh \
--push \
--target "$(./scripts/image_tag.sh --version latest)" \
$(cat build/coder_"$version"_linux_{amd64,arm64,armv7}.tag)
created_latest_tag=true
echo "created_latest_tag=true" >> $GITHUB_OUTPUT
echo "created_latest_tag=true" >> "$GITHUB_OUTPUT"
else
echo "created_latest_tag=false" >> $GITHUB_OUTPUT
echo "created_latest_tag=false" >> "$GITHUB_OUTPUT"
fi
env:
CODER_BASE_IMAGE_TAG: ${{ steps.image-base-tag.outputs.tag }}
@@ -528,24 +533,27 @@ jobs:
- name: SBOM Generation and Attestation
if: ${{ !inputs.dry_run }}
env:
COSIGN_EXPERIMENTAL: "1"
COSIGN_EXPERIMENTAL: '1'
MULTIARCH_IMAGE: ${{ steps.build_docker.outputs.multiarch_image }}
VERSION: ${{ steps.version.outputs.version }}
CREATED_LATEST_TAG: ${{ steps.build_docker.outputs.created_latest_tag }}
run: |
set -euxo pipefail
# Generate SBOM for multi-arch image with version in filename
echo "Generating SBOM for multi-arch image: ${{ steps.build_docker.outputs.multiarch_image }}"
syft "${{ steps.build_docker.outputs.multiarch_image }}" -o spdx-json > coder_${{ steps.version.outputs.version }}_sbom.spdx.json
echo "Generating SBOM for multi-arch image: ${MULTIARCH_IMAGE}"
syft "${MULTIARCH_IMAGE}" -o spdx-json > "coder_${VERSION}_sbom.spdx.json"
# Attest SBOM to multi-arch image
echo "Attesting SBOM to multi-arch image: ${{ steps.build_docker.outputs.multiarch_image }}"
cosign clean --force=true "${{ steps.build_docker.outputs.multiarch_image }}"
echo "Attesting SBOM to multi-arch image: ${MULTIARCH_IMAGE}"
cosign clean --force=true "${MULTIARCH_IMAGE}"
cosign attest --type spdxjson \
--predicate coder_${{ steps.version.outputs.version }}_sbom.spdx.json \
--predicate "coder_${VERSION}_sbom.spdx.json" \
--yes \
"${{ steps.build_docker.outputs.multiarch_image }}"
"${MULTIARCH_IMAGE}"
# If latest tag was created, also attest it
if [[ "${{ steps.build_docker.outputs.created_latest_tag }}" == "true" ]]; then
if [[ "${CREATED_LATEST_TAG}" == "true" ]]; then
latest_tag="$(./scripts/image_tag.sh --version latest)"
echo "Generating SBOM for latest image: ${latest_tag}"
syft "${latest_tag}" -o spdx-json > coder_latest_sbom.spdx.json
@@ -599,7 +607,7 @@ jobs:
- name: Get latest tag name
id: latest_tag
if: ${{ !inputs.dry_run && steps.build_docker.outputs.created_latest_tag == 'true' }}
run: echo "tag=$(./scripts/image_tag.sh --version latest)" >> $GITHUB_OUTPUT
run: echo "tag=$(./scripts/image_tag.sh --version latest)" >> "$GITHUB_OUTPUT"
# If this is the highest version according to semver, also attest the "latest" tag
- name: GitHub Attestation for "latest" Docker image
@@ -642,7 +650,7 @@ jobs:
# Report attestation failures but don't fail the workflow
- name: Check attestation status
if: ${{ !inputs.dry_run }}
run: |
run: | # zizmor: ignore[template-injection] We're just reading steps.attest_x.outcome here, no risk of injection
if [[ "${{ steps.attest_base.outcome }}" == "failure" && "${{ steps.attest_base.conclusion }}" != "skipped" ]]; then
echo "::warning::GitHub attestation for base image failed"
fi
@@ -707,11 +715,11 @@ jobs:
./build/*.apk
./build/*.deb
./build/*.rpm
./coder_${{ steps.version.outputs.version }}_sbom.spdx.json
"./coder_${VERSION}_sbom.spdx.json"
)
# Only include the latest SBOM file if it was created
if [[ "${{ steps.build_docker.outputs.created_latest_tag }}" == "true" ]]; then
if [[ "${CREATED_LATEST_TAG}" == "true" ]]; then
files+=(./coder_latest_sbom.spdx.json)
fi
@@ -722,6 +730,8 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CODER_GPG_RELEASE_KEY_BASE64: ${{ secrets.GPG_RELEASE_KEY_BASE64 }}
VERSION: ${{ steps.version.outputs.version }}
CREATED_LATEST_TAG: ${{ steps.build_docker.outputs.created_latest_tag }}
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@b7593ed2efd1c1617e1b0254da33b86225adb2a5 # v2.1.12
@@ -742,12 +752,12 @@ jobs:
cp "build/provisioner_helm_${version}.tgz" build/helm
gsutil cp gs://helm.coder.com/v2/index.yaml build/helm/index.yaml
helm repo index build/helm --url https://helm.coder.com/v2 --merge build/helm/index.yaml
gsutil -h "Cache-Control:no-cache,max-age=0" cp build/helm/coder_helm_${version}.tgz gs://helm.coder.com/v2
gsutil -h "Cache-Control:no-cache,max-age=0" cp build/helm/provisioner_helm_${version}.tgz gs://helm.coder.com/v2
gsutil -h "Cache-Control:no-cache,max-age=0" cp build/helm/index.yaml gs://helm.coder.com/v2
gsutil -h "Cache-Control:no-cache,max-age=0" cp helm/artifacthub-repo.yml gs://helm.coder.com/v2
helm push build/coder_helm_${version}.tgz oci://ghcr.io/coder/chart
helm push build/provisioner_helm_${version}.tgz oci://ghcr.io/coder/chart
gsutil -h "Cache-Control:no-cache,max-age=0" cp "build/helm/coder_helm_${version}.tgz" gs://helm.coder.com/v2
gsutil -h "Cache-Control:no-cache,max-age=0" cp "build/helm/provisioner_helm_${version}.tgz" gs://helm.coder.com/v2
gsutil -h "Cache-Control:no-cache,max-age=0" cp "build/helm/index.yaml" gs://helm.coder.com/v2
gsutil -h "Cache-Control:no-cache,max-age=0" cp "helm/artifacthub-repo.yml" gs://helm.coder.com/v2
helm push "build/coder_helm_${version}.tgz" oci://ghcr.io/coder/chart
helm push "build/provisioner_helm_${version}.tgz" oci://ghcr.io/coder/chart
- name: Upload artifacts to actions (if dry-run)
if: ${{ inputs.dry_run }}
@@ -798,12 +808,12 @@ jobs:
- name: Update homebrew
env:
# Variables used by the `gh` command
GH_REPO: coder/homebrew-coder
GH_TOKEN: ${{ secrets.CDRCI_GITHUB_TOKEN }}
VERSION: ${{ needs.release.outputs.version }}
run: |
# Keep version number around for reference, removing any potential leading v
coder_version="$(echo "${{ needs.release.outputs.version }}" | tr -d v)"
coder_version="$(echo "${VERSION}" | tr -d v)"
set -euxo pipefail
@@ -822,9 +832,9 @@ jobs:
wget "$checksums_url" -O checksums.txt
# Get the SHAs
darwin_arm_sha="$(cat checksums.txt | grep "darwin_arm64.zip" | awk '{ print $1 }')"
darwin_intel_sha="$(cat checksums.txt | grep "darwin_amd64.zip" | awk '{ print $1 }')"
linux_sha="$(cat checksums.txt | grep "linux_amd64.tar.gz" | awk '{ print $1 }')"
darwin_arm_sha="$(grep "darwin_arm64.zip" checksums.txt | awk '{ print $1 }')"
darwin_intel_sha="$(grep "darwin_amd64.zip" checksums.txt | awk '{ print $1 }')"
linux_sha="$(grep "linux_amd64.tar.gz" checksums.txt | awk '{ print $1 }')"
echo "macOS arm64: $darwin_arm_sha"
echo "macOS amd64: $darwin_intel_sha"
@@ -837,7 +847,7 @@ jobs:
# Check if a PR already exists.
pr_count="$(gh pr list --search "head:$brew_branch" --json id,closed | jq -r ".[] | select(.closed == false) | .id" | wc -l)"
if [[ "$pr_count" > 0 ]]; then
if [ "$pr_count" -gt 0 ]; then
echo "Bailing out as PR already exists" 2>&1
exit 0
fi
@@ -856,8 +866,8 @@ jobs:
-B master -H "$brew_branch" \
-t "coder $coder_version" \
-b "" \
-r "${{ github.actor }}" \
-a "${{ github.actor }}" \
-r "${GITHUB_ACTOR}" \
-a "${GITHUB_ACTOR}" \
-b "This automatic PR was triggered by the release of Coder v$coder_version"
publish-winget:
@@ -881,6 +891,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
persist-credentials: false
# If the event that triggered the build was an annotated tag (which our
# tags are supposed to be), actions/checkout has a bug where the tag in
@@ -899,7 +910,7 @@ jobs:
# The package version is the same as the tag minus the leading "v".
# The version in this output already has the leading "v" removed but
# we do it again to be safe.
$version = "${{ needs.release.outputs.version }}".Trim('v')
$version = $env:VERSION.Trim('v')
$release_assets = gh release view --repo coder/coder "v${version}" --json assets | `
ConvertFrom-Json
@@ -931,13 +942,14 @@ jobs:
# For wingetcreate. We need a real token since we're pushing a commit
# to GitHub and then making a PR in a different repo.
WINGET_GH_TOKEN: ${{ secrets.CDRCI_GITHUB_TOKEN }}
VERSION: ${{ needs.release.outputs.version }}
- name: Comment on PR
run: |
# wait 30 seconds
Start-Sleep -Seconds 30.0
# Find the PR that wingetcreate just made.
$version = "${{ needs.release.outputs.version }}".Trim('v')
$version = $env:VERSION.Trim('v')
$pr_list = gh pr list --repo microsoft/winget-pkgs --search "author:cdrci Coder.Coder version ${version}" --limit 1 --json number | `
ConvertFrom-Json
$pr_number = $pr_list[0].number
@@ -948,6 +960,7 @@ jobs:
# For gh CLI. We need a real token since we're commenting on a PR in a
# different repo.
GH_TOKEN: ${{ secrets.CDRCI_GITHUB_TOKEN }}
VERSION: ${{ needs.release.outputs.version }}
# publish-sqlc pushes the latest schema to sqlc cloud.
# At present these pushes cannot be tagged, so the last push is always the latest.
@@ -966,6 +979,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 1
persist-credentials: false
# We need golang to run the migration main.go
- name: Setup Go
+6 -2
View File
@@ -33,6 +33,8 @@ jobs:
- name: Checkout
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- name: Setup Go
uses: ./.github/actions/setup-go
@@ -75,6 +77,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Go
uses: ./.github/actions/setup-go
@@ -134,12 +137,13 @@ jobs:
# This environment variables forces scripts/build_docker.sh to build
# the base image tag locally instead of using the cached version from
# the registry.
export CODER_IMAGE_BUILD_BASE_TAG="$(CODER_IMAGE_BASE=coder-base ./scripts/image_tag.sh --version "$version")"
CODER_IMAGE_BUILD_BASE_TAG="$(CODER_IMAGE_BASE=coder-base ./scripts/image_tag.sh --version "$version")"
export CODER_IMAGE_BUILD_BASE_TAG
# We would like to use make -j here, but it doesn't work with the some recent additions
# to our code generation.
make "$image_job"
echo "image=$(cat "$image_job")" >> $GITHUB_OUTPUT
echo "image=$(cat "$image_job")" >> "$GITHUB_OUTPUT"
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@dc5a429b52fcf669ce959baa2c2dd26090d2a6c4
+2
View File
@@ -102,6 +102,8 @@ jobs:
- name: Checkout repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- name: Run delete-old-branches-action
uses: beatlabs/delete-old-branches-action@4eeeb8740ff8b3cb310296ddd6b43c3387734588 # v0.0.11
with:
+6 -1
View File
@@ -27,6 +27,8 @@ jobs:
- name: Checkout
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- name: Check Markdown links
uses: umbrelladocs/action-linkspector@874d01cae9fd488e3077b08952093235bd626977 # v1.3.7
@@ -41,7 +43,10 @@ jobs:
- name: Send Slack notification
if: failure() && github.event_name == 'schedule'
run: |
curl -X POST -H 'Content-type: application/json' -d '{"msg":"Broken links found in the documentation. Please check the logs at ${{ env.LOGS_URL }}"}' ${{ secrets.DOCS_LINK_SLACK_WEBHOOK }}
curl \
-X POST \
-H 'Content-type: application/json' \
-d '{"msg":"Broken links found in the documentation. Please check the logs at '"${LOGS_URL}"'"}' "${{ secrets.DOCS_LINK_SLACK_WEBHOOK }}"
echo "Sent Slack notification"
env:
LOGS_URL: https://github.com/coder/coder/actions/runs/${{ github.run_id }}
+17 -1
View File
@@ -559,7 +559,9 @@ else
endif
.PHONY: fmt/markdown
lint: lint/shellcheck lint/go lint/ts lint/examples lint/helm lint/site-icons lint/markdown
# Note: we don't run zizmor in the lint target because it takes a while. CI
# runs it explicitly.
lint: lint/shellcheck lint/go lint/ts lint/examples lint/helm lint/site-icons lint/markdown lint/actions/actionlint
.PHONY: lint
lint/site-icons:
@@ -598,6 +600,20 @@ lint/markdown: node_modules/.installed
pnpm lint-docs
.PHONY: lint/markdown
lint/actions: lint/actions/actionlint lint/actions/zizmor
.PHONY: lint/actions
lint/actions/actionlint:
go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.7
.PHONY: lint/actions/actionlint
lint/actions/zizmor:
./scripts/zizmor.sh \
--strict-collection \
--persona=regular \
.
.PHONY: lint/actions/zizmor
# All files generated by the database should be added here, and this can be used
# as a target for jobs that need to run after the database is generated.
DB_GEN_FILES := \
+1 -1
View File
@@ -86,7 +86,7 @@ jobs:
- name: Get short commit SHA to use as template version name
id: name
run: echo "version_name=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
run: echo "version_name=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
- name: Get latest commit title to use as template version description
id: message
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env bash
# Usage: ./zizmor.sh [args...]
#
# This script is a wrapper around the zizmor Docker image. Zizmor lints GitHub
# actions workflows.
#
# We use Docker to run zizmor since it's written in Rust and is difficult to
# install on Ubuntu runners without building it with a Rust toolchain, which
# takes a long time.
#
# The repo is mounted at /repo and the working directory is set to /repo.
set -euo pipefail
# shellcheck source=scripts/lib.sh
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
cdroot
image_tag="ghcr.io/zizmorcore/zizmor:1.11.0"
docker_args=(
"--rm"
"--volume" "$(pwd):/repo"
"--workdir" "/repo"
"--network" "host"
)
if [[ -t 0 ]]; then
docker_args+=("-it")
fi
# If no GH_TOKEN is set, try to get one from `gh auth token`.
if [[ "${GH_TOKEN:-}" == "" ]] && command -v gh &>/dev/null; then
set +e
GH_TOKEN="$(gh auth token)"
export GH_TOKEN
set -e
fi
# Pass through the GitHub token if it's set, which allows zizmor to scan
# imported workflows too.
if [[ "${GH_TOKEN:-}" != "" ]]; then
docker_args+=("--env" "GH_TOKEN")
fi
logrun exec docker run "${docker_args[@]}" "$image_tag" "$@"