diff --git a/.github/actions/embedded-pg-cache/download/action.yml b/.github/actions/embedded-pg-cache/download/action.yml index c2c3c0c0b299c..854e5045c2dda 100644 --- a/.github/actions/embedded-pg-cache/download/action.yml +++ b/.github/actions/embedded-pg-cache/download/action.yml @@ -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. diff --git a/.github/actions/test-cache/download/action.yml b/.github/actions/test-cache/download/action.yml index 06a87fee06d4b..623bb61e11c52 100644 --- a/.github/actions/test-cache/download/action.yml +++ b/.github/actions/test-cache/download/action.yml @@ -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 diff --git a/.github/actions/upload-datadog/action.yaml b/.github/actions/upload-datadog/action.yaml index a2df93ab14b28..274ff3df6493a 100644 --- a/.github/actions/upload-datadog/action.yaml +++ b/.github/actions/upload-datadog/action.yaml @@ -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 }} diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1d9f1ac0eff77..76becb50adf14 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -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 }}" diff --git a/.github/workflows/contrib.yaml b/.github/workflows/contrib.yaml index 27dffe94f4000..e9c5c9ec2afd8 100644 --- a/.github/workflows/contrib.yaml +++ b/.github/workflows/contrib.yaml @@ -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 diff --git a/.github/workflows/dependabot.yaml b/.github/workflows/dependabot.yaml index f86601096ae96..f95ae3fa810e6 100644 --- a/.github/workflows/dependabot.yaml +++ b/.github/workflows/dependabot.yaml @@ -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 }} diff --git a/.github/workflows/docker-base.yaml b/.github/workflows/docker-base.yaml index dd36ab5a45ea0..5c8fa142450bb 100644 --- a/.github/workflows/docker-base.yaml +++ b/.github/workflows/docker-base.yaml @@ -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 diff --git a/.github/workflows/docs-ci.yaml b/.github/workflows/docs-ci.yaml index cba5bcbcd2b42..887db40660caf 100644 --- a/.github/workflows/docs-ci.yaml +++ b/.github/workflows/docs-ci.yaml @@ -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 }} diff --git a/.github/workflows/dogfood.yaml b/.github/workflows/dogfood.yaml index 6735f7d2ce8ae..119cd4fe85244 100644 --- a/.github/workflows/dogfood.yaml +++ b/.github/workflows/dogfood.yaml @@ -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' diff --git a/.github/workflows/nightly-gauntlet.yaml b/.github/workflows/nightly-gauntlet.yaml index 7bbf690f5e2db..5769b3b652c44 100644 --- a/.github/workflows/nightly-gauntlet.yaml +++ b/.github/workflows/nightly-gauntlet.yaml @@ -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 }}" diff --git a/.github/workflows/pr-auto-assign.yaml b/.github/workflows/pr-auto-assign.yaml index 746b471f57b39..7e2f6441de383 100644 --- a/.github/workflows/pr-auto-assign.yaml +++ b/.github/workflows/pr-auto-assign.yaml @@ -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] diff --git a/.github/workflows/pr-cleanup.yaml b/.github/workflows/pr-cleanup.yaml index 4c3023990efe5..32e260b112dea 100644 --- a/.github/workflows/pr-cleanup.yaml +++ b/.github/workflows/pr-cleanup.yaml @@ -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 }} diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index e31cc26e7927c..ccf7511eafc78 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -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 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 06041e1865d3a..f4f9c8f317664 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -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 diff --git a/.github/workflows/security.yaml b/.github/workflows/security.yaml index 27b5137738098..e7fde82bf1dce 100644 --- a/.github/workflows/security.yaml +++ b/.github/workflows/security.yaml @@ -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 diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml index c0c2494db6fbf..27ec157fa0f3f 100644 --- a/.github/workflows/stale.yaml +++ b/.github/workflows/stale.yaml @@ -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: diff --git a/.github/workflows/weekly-docs.yaml b/.github/workflows/weekly-docs.yaml index 8d152f73981f5..56f5e799305e8 100644 --- a/.github/workflows/weekly-docs.yaml +++ b/.github/workflows/weekly-docs.yaml @@ -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 }} diff --git a/Makefile b/Makefile index a5341ee79f753..e72a1f7b6257a 100644 --- a/Makefile +++ b/Makefile @@ -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 := \ diff --git a/docs/tutorials/testing-templates.md b/docs/tutorials/testing-templates.md index bcfa33a74e16f..025c0d6ace26f 100644 --- a/docs/tutorials/testing-templates.md +++ b/docs/tutorials/testing-templates.md @@ -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 diff --git a/scripts/zizmor.sh b/scripts/zizmor.sh new file mode 100755 index 0000000000000..a9326e2ee0868 --- /dev/null +++ b/scripts/zizmor.sh @@ -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" "$@" pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy