Skip to content

Commit c19721b

Browse files
authored
Add CI workflow linting and publish :main image (#3)
## Summary - add `actionlint` and `zizmor` to the Nix dev shell (`flake.nix`) - extend CI to run on both pull requests and pushes to `main` - add a dedicated `lint-actions` job that runs `actionlint` and `zizmor` - add a `publish-main` job that builds and pushes `ghcr.io/coder/coder-k8s:main` on merges to `main` - harden workflow actions for security linting (pinned SHAs, `persist-credentials: false`, publish job cache disabled) ## Validation - `go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.10` - `zizmor .github/workflows/ci.yaml` --- <details> <summary>📋 Implementation Plan</summary> # Plan: Publish `:main` image on `main` merges + add Actions linting (actionlint + zizmor) ## Context / Why The request now includes three deliverables in one PR: (1) publish `ghcr.io/coder/coder-k8s:main` on merges to `main`, (2) enforce GitHub Actions validation with `actionlint`, and (3) run `zizmor` checks for workflow security issues, while also adding both tools to `flake.nix` for reproducible local use. The plan keeps these changes minimal by extending the existing `ci.yaml` workflow and updating the existing Nix dev shell. ## Evidence - Explore report `51ee42b024` (workflow baseline): - `.github/workflows/ci.yaml` currently only triggers on PRs. - `.github/workflows/release.yaml` already uses GHCR login via `docker/login-action@v3` + `GITHUB_TOKEN`. - Explore report `2afaa89579` (release conventions): - Existing image coordinates are `ghcr.io/coder/coder-k8s` with `Dockerfile.goreleaser`. - Explore report `3863c6adc3` (Nix tooling): - `flake.nix` provides tooling via `devShells.<system>.default.packages`. - `pkgs.actionlint` and `pkgs.zizmor` are available in the current nixpkgs input. - Explore report `8231c45f71` (CI integration shape): - A dedicated workflow lint job in `ci.yaml` fits the current style and `contents: read` permissions. These findings are sufficient to define concrete edit locations and commands for all requested additions. ## Implementation details 1. **Update `flake.nix` dev shell tooling** - Edit `devShells.<system>.default.packages` to include both workflow linters. - Keep the existing package set; append: ```nix default = pkgs.mkShell { packages = with pkgs; [ go gnumake git goreleaser actionlint zizmor ]; }; ``` 2. **Extend `.github/workflows/ci.yaml` trigger to include merged `main` pushes** - Keep existing PR trigger. - Add push trigger for `main` so merge commits run CI: ```yaml on: pull_request: push: branches: [main] ``` 3. **Add workflow lint/security job in `.github/workflows/ci.yaml`** - Add a dedicated `lint-actions` job for GH Actions validation. - Run both `actionlint` and `zizmor` in CI to catch syntax/semantic issues and security footguns. - Keep permissions minimal (`contents: read`); optionally pass `${{ github.token }}` to reduce rate-limit risk for metadata lookups. ```yaml jobs: lint-actions: name: Lint GitHub Actions runs-on: ubuntu-latest permissions: contents: read steps: - uses: actions/checkout@v4 - name: actionlint uses: rhysd/actionlint-action@v1 - name: zizmor uses: woodruffw/zizmor-action@v1 env: GH_TOKEN: ${{ github.token }} ``` 4. **Add main-branch image publish job in `.github/workflows/ci.yaml`** - Add `publish-main` job gated on successful `test` and `lint-actions`. - Restrict execution to `push` on `refs/heads/main`. - Reuse GHCR auth convention from `release.yaml`. - Build `coder-k8s` binary before Docker build (required by `Dockerfile.goreleaser`). ```yaml jobs: test: ... lint-actions: ... publish-main: name: Publish GHCR :main needs: [test, lint-actions] if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest permissions: contents: read packages: write steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: go.mod cache: true - name: Build linux/amd64 binary for image run: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o coder-k8s ./ - uses: docker/setup-buildx-action@v3 - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push :main uses: docker/build-push-action@v5 with: context: . file: Dockerfile.goreleaser push: true tags: ghcr.io/coder/coder-k8s:main ``` 5. **Validation checklist for the PR** - Confirm `flake.nix` evaluates and dev shell exposes `actionlint` + `zizmor`. - Confirm `ci.yaml` remains valid (`actionlint` passes in CI). - Confirm `zizmor` runs on PRs and fails on actionable workflow security findings. - Confirm `publish-main` is skipped on PRs and runs only on `push` to `main`. - After merge to `main`, verify `ghcr.io/coder/coder-k8s:main` exists. <details> <summary>Why this approach (concise)</summary> - **Single CI workflow extension:** keeps changes localized to `ci.yaml` plus one Nix file. - **Defensive gating:** `publish-main` waits for both code tests and workflow lint/security checks. - **Reproducibility:** adding tools to `flake.nix` makes local verification match CI expectations. - **Convention reuse:** preserves existing GHCR image naming and authentication patterns already used by release automation. </details> </details> --- _Generated with [`mux`](https://github.com/coder/mux) • Model: `openai:gpt-5.3-codex` • Thinking: `xhigh`_
1 parent a9b0cba commit c19721b

3 files changed

Lines changed: 88 additions & 8 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ name: CI
22

33
on:
44
pull_request:
5+
push:
6+
branches:
7+
- main
58

69
permissions:
710
contents: read
@@ -11,10 +14,12 @@ jobs:
1114
runs-on: ubuntu-latest
1215
steps:
1316
- name: Checkout
14-
uses: actions/checkout@v4
17+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
18+
with:
19+
persist-credentials: false
1520

1621
- name: Setup Go
17-
uses: actions/setup-go@v5
22+
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
1823
with:
1924
go-version-file: go.mod
2025
cache: true
@@ -34,3 +39,75 @@ jobs:
3439
env:
3540
GOFLAGS: -mod=vendor
3641
run: go build ./...
42+
43+
lint-actions:
44+
name: Lint GitHub Actions
45+
runs-on: ubuntu-latest
46+
permissions:
47+
contents: read
48+
steps:
49+
- name: Checkout
50+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
51+
with:
52+
persist-credentials: false
53+
54+
- name: Setup Go
55+
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
56+
with:
57+
go-version-file: go.mod
58+
cache: true
59+
60+
- name: Run actionlint
61+
run: go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.10
62+
63+
- name: Run zizmor
64+
uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d # v0.5.0
65+
with:
66+
advanced-security: false
67+
inputs: .github/workflows
68+
69+
publish-main:
70+
name: Publish GHCR :main
71+
needs: [test, lint-actions]
72+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
73+
runs-on: ubuntu-latest
74+
permissions:
75+
contents: read
76+
packages: write
77+
steps:
78+
- name: Checkout
79+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
80+
with:
81+
persist-credentials: false
82+
83+
- name: Setup Go
84+
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
85+
with:
86+
go-version-file: go.mod
87+
cache: false
88+
89+
- name: Build linux/amd64 binary for image
90+
env:
91+
GOFLAGS: -mod=vendor
92+
CGO_ENABLED: "0"
93+
GOOS: linux
94+
GOARCH: amd64
95+
run: go build -o coder-k8s ./
96+
97+
- name: Set up Docker Buildx
98+
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
99+
100+
- name: Log in to GitHub Container Registry
101+
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
102+
with:
103+
registry: ghcr.io
104+
username: ${{ github.actor }}
105+
password: ${{ secrets.GITHUB_TOKEN }}
106+
107+
- name: Build and push :main
108+
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5.4.0
109+
with:
110+
context: .
111+
file: Dockerfile.goreleaser
112+
push: true
113+
tags: ghcr.io/coder/coder-k8s:main

.github/workflows/release.yaml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,29 @@ jobs:
1313
runs-on: ubuntu-latest
1414
steps:
1515
- name: Checkout
16-
uses: actions/checkout@v4
16+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
1717
with:
1818
fetch-depth: 0
19+
persist-credentials: false
1920

2021
- name: Setup Go
21-
uses: actions/setup-go@v5
22+
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
2223
with:
2324
go-version-file: go.mod
24-
cache: true
25+
cache: false
2526

2627
- name: Set up Docker Buildx
27-
uses: docker/setup-buildx-action@v3
28+
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
2829

2930
- name: Log in to GitHub Container Registry
30-
uses: docker/login-action@v3
31+
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
3132
with:
3233
registry: ghcr.io
3334
username: ${{ github.actor }}
3435
password: ${{ secrets.GITHUB_TOKEN }}
3536

3637
- name: Run GoReleaser
37-
uses: goreleaser/goreleaser-action@v6
38+
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
3839
with:
3940
distribution: goreleaser
4041
version: latest

flake.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
gnumake
2424
git
2525
goreleaser
26+
actionlint
27+
zizmor
2628
];
2729
};
2830
}

0 commit comments

Comments
 (0)