diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 4d97958..6a0f573 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -5,16 +5,172 @@ on: push: branches: [master] tags: ['v*'] + pull_request: + branches: [master] workflow_dispatch: permissions: contents: read + security-events: write env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Download modules + run: go mod download + + - name: Verify go.mod tidy + run: | + go mod tidy + git diff --exit-code -- go.mod go.sum + + - name: gofmt + run: | + fmt_out=$(gofmt -l .) + if [ -n "$fmt_out" ]; then + echo "gofmt issues:" + echo "$fmt_out" + exit 1 + fi + + - name: go vet + run: go vet ./... + + - name: golangci-lint + uses: golangci/golangci-lint-action@v6 + with: + version: latest + + - name: go test + run: go test -race -cover -coverprofile=coverage.out -v ./... + + - name: Upload coverage + uses: actions/upload-artifact@v4 + with: + name: coverage + path: coverage.out + if-no-files-found: ignore + + - name: go build + run: go build ./... + + security: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: govulncheck + uses: golang/govulncheck-action@v1 + with: + go-version-file: go.mod + + - name: gosec + uses: securego/gosec@master + with: + args: '-no-fail -fmt sarif -out gosec.sarif ./...' + + - name: Upload gosec SARIF + uses: github/codeql-action/upload-sarif@v3 + if: always() + with: + sarif_file: gosec.sarif + category: gosec + + - name: gitleaks + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + config-path: '' + + - name: Trivy filesystem scan + uses: aquasecurity/trivy-action@0.24.0 + with: + scan-type: fs + scan-ref: . + format: sarif + output: trivy-fs.sarif + severity: CRITICAL,HIGH + exit-code: '1' + ignore-unfixed: true + + - name: Upload Trivy FS SARIF + uses: github/codeql-action/upload-sarif@v3 + if: always() + with: + sarif_file: trivy-fs.sarif + category: trivy-fs + + - name: Hadolint Dockerfile + uses: hadolint/hadolint-action@v3.1.0 + with: + dockerfile: Dockerfile + format: sarif + output-file: hadolint.sarif + no-fail: true + + - name: Upload Hadolint SARIF + uses: github/codeql-action/upload-sarif@v3 + if: always() + with: + sarif_file: hadolint.sarif + category: hadolint + + codeql: + runs-on: ubuntu-latest + permissions: + security-events: write + actions: read + contents: read + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Init CodeQL + uses: github/codeql-action/init@v3 + with: + languages: go + + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: CodeQL analyze + uses: github/codeql-action/analyze@v3 + with: + category: codeql-go + publish: + needs: [test, security, codeql] + if: github.event_name != 'pull_request' runs-on: ubuntu-latest steps: @@ -47,6 +203,34 @@ jobs: type=semver,pattern={{major}} type=raw,value=latest,enable={{is_default_branch}} + - name: Build local image for scan + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64 + load: true + tags: staticmap:scan + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Trivy image scan + uses: aquasecurity/trivy-action@0.24.0 + with: + image-ref: staticmap:scan + format: sarif + output: trivy-image.sarif + severity: CRITICAL,HIGH + exit-code: '1' + ignore-unfixed: true + vuln-type: 'os,library' + + - name: Upload Trivy image SARIF + uses: github/codeql-action/upload-sarif@v3 + if: always() + with: + sarif_file: trivy-image.sarif + category: trivy-image + - name: Build and push uses: docker/build-push-action@v6 with: @@ -57,5 +241,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max + provenance: true + sbom: true ...