diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index c3d1b65ae6..0000000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: "CodeQL" - -permissions: - security-events: write - -on: - push: - branches: ["main"] - pull_request: - # The branches below must be a subset of the branches above - branches: ["main"] - schedule: - # run every week at 10:24 on Thursday - - cron: "24 10 * * 4" - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: ["go", "javascript"] - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - - - name: Setup Go - if: matrix.language == 'go' - uses: actions/setup-go@v3 - with: - go-version: "~1.19" - - - name: Go Cache Paths - if: matrix.language == 'go' - id: go-cache-paths - run: | - echo "::set-output name=go-mod::$(go env GOMODCACHE)" - - - name: Go Mod Cache - if: matrix.language == 'go' - uses: actions/cache@v3 - with: - path: ${{ steps.go-cache-paths.outputs.go-mod }} - key: ${{ runner.os }}-release-go-mod-${{ hashFiles('**/go.sum') }} - - - name: Remove Makefile # workaround to prevent CodeQL from building site - if: matrix.language == 'go' - run: | - # Disable Analysis step from trying to build the project. - rm Makefile - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: "/language:${{matrix.language}}" diff --git a/.github/workflows/coder.yaml b/.github/workflows/coder.yaml index 37ce3bd17e..055ea4f896 100644 --- a/.github/workflows/coder.yaml +++ b/.github/workflows/coder.yaml @@ -198,19 +198,19 @@ jobs: - name: Echo Go Cache Paths id: go-cache-paths run: | - echo "::set-output name=go-build::$(go env GOCACHE)" - echo "::set-output name=go-mod::$(go env GOMODCACHE)" + echo "GOCACHE=$(go env GOCACHE)" >> $GITHUB_OUTPUT + echo "GOMODCACHE=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT - name: Go Build Cache uses: actions/cache@v3 with: - path: ${{ steps.go-cache-paths.outputs.go-build }} + path: ${{ steps.go-cache-paths.outputs.GOCACHE }} key: ${{ github.job }}-go-build-${{ hashFiles('**/go.sum', '**/**.go') }} - name: Go Mod Cache uses: actions/cache@v3 with: - path: ${{ steps.go-cache-paths.outputs.go-mod }} + path: ${{ steps.go-cache-paths.outputs.GOMODCACHE }} key: ${{ github.job }}-go-mod-${{ hashFiles('**/go.sum') }} - name: Install sqlc @@ -296,22 +296,25 @@ jobs: with: go-version: "~1.19" + # Sadly the new "set output" syntax (of writing env vars to + # $GITHUB_OUTPUT) does not work on both powershell and bash so we use the + # deprecated syntax here. - name: Echo Go Cache Paths id: go-cache-paths run: | - echo "::set-output name=go-build::$(go env GOCACHE)" - echo "::set-output name=go-mod::$(go env GOMODCACHE)" + echo "::set-output name=GOCACHE::$(go env GOCACHE)" + echo "::set-output name=GOMODCACHE::$(go env GOMODCACHE)" - name: Go Build Cache uses: actions/cache@v3 with: - path: ${{ steps.go-cache-paths.outputs.go-build }} + path: ${{ steps.go-cache-paths.outputs.GOCACHE }} key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.**', '**.go') }} - name: Go Mod Cache uses: actions/cache@v3 with: - path: ${{ steps.go-cache-paths.outputs.go-mod }} + path: ${{ steps.go-cache-paths.outputs.GOMODCACHE }} key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }} - name: Install gotestsum @@ -335,10 +338,10 @@ jobs: # prevents test caching, so we disable it on alternate operating # systems. if [ "${{ matrix.os }}" == "ubuntu-latest" ]; then - echo ::set-output name=cover::true + echo "cover=true" >> $GITHUB_OUTPUT export COVERAGE_FLAGS='-covermode=atomic -coverprofile="gotests.coverage" -coverpkg=./...' else - echo ::set-output name=cover::false + echo "cover=false" >> $GITHUB_OUTPUT fi gotestsum --junitfile="gotests.xml" --packages="./..." -- -parallel=8 -timeout=5m -short -failfast $COVERAGE_FLAGS @@ -380,19 +383,19 @@ jobs: - name: Echo Go Cache Paths id: go-cache-paths run: | - echo "::set-output name=go-build::$(go env GOCACHE)" - echo "::set-output name=go-mod::$(go env GOMODCACHE)" + echo "GOCACHE=$(go env GOCACHE)" >> $GITHUB_OUTPUT + echo "GOMODCACHE=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT - name: Go Build Cache uses: actions/cache@v3 with: - path: ${{ steps.go-cache-paths.outputs.go-build }} + path: ${{ steps.go-cache-paths.outputs.GOCACHE }} key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum', '**/**.go') }} - name: Go Mod Cache uses: actions/cache@v3 with: - path: ${{ steps.go-cache-paths.outputs.go-mod }} + path: ${{ steps.go-cache-paths.outputs.GOMODCACHE }} key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }} - name: Install gotestsum @@ -429,7 +432,7 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} files: ./gotests.coverage - flags: unittest-go-postgres-${{ matrix.os }} + flags: unittest-go-postgres-linux deploy: name: "deploy" @@ -463,19 +466,19 @@ jobs: - name: Echo Go Cache Paths id: go-cache-paths run: | - echo "::set-output name=go-build::$(go env GOCACHE)" - echo "::set-output name=go-mod::$(go env GOMODCACHE)" + echo "GOCACHE=$(go env GOCACHE)" >> $GITHUB_OUTPUT + echo "GOMODCACHE=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT - name: Go Build Cache uses: actions/cache@v3 with: - path: ${{ steps.go-cache-paths.outputs.go-build }} + path: ${{ steps.go-cache-paths.outputs.GOCACHE }} key: ${{ runner.os }}-release-go-build-${{ hashFiles('**/go.sum') }} - name: Go Mod Cache uses: actions/cache@v3 with: - path: ${{ steps.go-cache-paths.outputs.go-mod }} + path: ${{ steps.go-cache-paths.outputs.GOMODCACHE }} key: ${{ runner.os }}-release-go-mod-${{ hashFiles('**/go.sum') }} - name: Cache Node @@ -607,19 +610,19 @@ jobs: - name: Echo Go Cache Paths id: go-cache-paths run: | - echo "::set-output name=go-build::$(go env GOCACHE)" - echo "::set-output name=go-mod::$(go env GOMODCACHE)" + echo "GOCACHE=$(go env GOCACHE)" >> $GITHUB_OUTPUT + echo "GOMODCACHE=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT - name: Go Build Cache uses: actions/cache@v3 with: - path: ${{ steps.go-cache-paths.outputs.go-build }} + path: ${{ steps.go-cache-paths.outputs.GOCACHE }} key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }} - name: Go Mod Cache uses: actions/cache@v3 with: - path: ${{ steps.go-cache-paths.outputs.go-mod }} + path: ${{ steps.go-cache-paths.outputs.GOMODCACHE }} key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }} - name: Build diff --git a/.github/workflows/dogfood.yaml b/.github/workflows/dogfood.yaml index 0dede0bf1b..b93b6ba16f 100644 --- a/.github/workflows/dogfood.yaml +++ b/.github/workflows/dogfood.yaml @@ -25,7 +25,7 @@ jobs: tag=${{ steps.branch-name.outputs.current_branch }} # Replace / with --, e.g. user/feature => user--feature. tag=${tag//\//--} - echo "::set-output name=tag::${tag}" + echo "tag=${tag}" >> $GITHUB_OUTPUT - name: Set up QEMU uses: docker/setup-qemu-action@v2 @@ -54,7 +54,7 @@ jobs: uses: actions/checkout@v3 - name: Get short commit SHA id: vars - run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" + run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: "Install latest Coder" run: | curl -L https://coder.com/install.sh | sh diff --git a/.github/workflows/security.yaml b/.github/workflows/security.yaml new file mode 100644 index 0000000000..3addc3d8b8 --- /dev/null +++ b/.github/workflows/security.yaml @@ -0,0 +1,135 @@ +name: "Security" + +permissions: + actions: read + contents: read + security-events: write + +on: + push: + branches: ["main"] + + pull_request: + branches: ["main"] + + workflow_dispatch: + + schedule: + # Run every week at 10:24 on Thursday. + - cron: "24 10 * * 4" + +# Cancel in-progress runs for pull requests when developers push +# additional changes +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-security + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + codeql: + name: CodeQL + runs-on: ${{ github.repository_owner == 'coder' && 'ubuntu-latest-16-cores' || 'ubuntu-latest' }} + strategy: + fail-fast: false + matrix: + language: ["go", "javascript"] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Setup Go + if: matrix.language == 'go' + uses: actions/setup-go@v3 + with: + go-version: "~1.19" + + - name: Go Cache Paths + if: matrix.language == 'go' + id: go-cache-paths + run: | + echo "GOMODCACHE=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT + + - name: Go Mod Cache + if: matrix.language == 'go' + uses: actions/cache@v3 + with: + path: ${{ steps.go-cache-paths.outputs.GOMODCACHE }} + key: ${{ runner.os }}-release-go-mod-${{ hashFiles('**/go.sum') }} + + # Workaround to prevent CodeQL from building the dashboard. + - name: Remove Makefile + if: matrix.language == 'go' + run: | + rm Makefile + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" + + trivy: + name: Trivy + runs-on: ${{ github.repository_owner == 'coder' && 'ubuntu-latest-16-cores' || 'ubuntu-latest' }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - uses: actions/setup-go@v3 + with: + go-version: "~1.19" + + - name: Go Cache Paths + id: go-cache-paths + run: | + echo "GOMODCACHE=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT + + - name: Go Mod Cache + uses: actions/cache@v3 + with: + path: ${{ steps.go-cache-paths.outputs.GOMODCACHE }} + key: ${{ runner.os }}-release-go-mod-${{ hashFiles('**/go.sum') }} + + - name: Cache Node + id: cache-node + uses: actions/cache@v3 + with: + path: | + **/node_modules + .eslintcache + key: js-${{ runner.os }}-test-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + js-${{ runner.os }}- + + - name: Build Coder linux amd64 Docker image + id: build + run: | + set -euo pipefail + image_job="build/coder_$(./scripts/version.sh)_linux_amd64.tag" + DOCKER_IMAGE_NO_PREREQUISITES=true make -j "$image_job" + echo "image=$(cat "$image_job")" >> $GITHUB_OUTPUT + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@7b7aa264d83dc58691451798b4d117d53d21edfe + with: + image-ref: ${{ steps.build.outputs.image }} + format: sarif + output: trivy-results.sarif + severity: "CRITICAL,HIGH" + + - name: Upload Trivy scan results to GitHub Security tab + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: trivy-results.sarif + + - name: Upload Trivy scan results as an artifact + uses: actions/upload-artifact@v2 + with: + name: trivy + path: trivy-results.sarif + retention-days: 7 diff --git a/Makefile b/Makefile index 1d10189b40..de06035632 100644 --- a/Makefile +++ b/Makefile @@ -92,6 +92,19 @@ CODER_FAT_NOVERSION_BINARIES := $(addprefix build/coder_,$(OS_ARCHES)) CODER_ALL_NOVERSION_IMAGES := $(foreach arch, $(DOCKER_ARCHES), build/coder_linux_$(arch).tag) build/coder_linux.tag CODER_ALL_NOVERSION_IMAGES_PUSHED := $(addprefix push/, $(CODER_ALL_NOVERSION_IMAGES)) +# If callers are only building Docker images and not the packages and archives, +# we can skip those prerequisites as they are not actually required and only +# specified to avoid concurrent write failures. +ifdef DOCKER_IMAGE_NO_PREREQUISITES +CODER_ARCH_IMAGE_PREREQUISITES := +else +CODER_ARCH_IMAGE_PREREQUISITES := \ + build/coder_$(VERSION)_%.apk \ + build/coder_$(VERSION)_%.deb \ + build/coder_$(VERSION)_%.rpm \ + build/coder_$(VERSION)_%.tar.gz +endif + clean: rm -rf build site/out @@ -296,13 +309,7 @@ $(CODER_ALL_NOVERSION_IMAGES_PUSHED): push/build/coder_%: push/build/coder_$(VER # # Images need to run after the archives and packages are built, otherwise they # cause errors like "file changed as we read it". -$(CODER_ARCH_IMAGES): build/coder_$(VERSION)_%.tag: \ - build/coder_$(VERSION)_% \ - build/coder_$(VERSION)_%.apk \ - build/coder_$(VERSION)_%.deb \ - build/coder_$(VERSION)_%.rpm \ - build/coder_$(VERSION)_%.tar.gz - +$(CODER_ARCH_IMAGES): build/coder_$(VERSION)_%.tag: build/coder_$(VERSION)_% $(CODER_ARCH_IMAGE_PREREQUISITES) $(get-mode-os-arch-ext) image_tag="$$(./scripts/image_tag.sh --arch "$$arch" --version "$(VERSION)")"