Commit c19721b
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
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
5 | 8 | | |
6 | 9 | | |
7 | 10 | | |
| |||
11 | 14 | | |
12 | 15 | | |
13 | 16 | | |
14 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
15 | 20 | | |
16 | 21 | | |
17 | | - | |
| 22 | + | |
18 | 23 | | |
19 | 24 | | |
20 | 25 | | |
| |||
34 | 39 | | |
35 | 40 | | |
36 | 41 | | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
19 | 20 | | |
20 | 21 | | |
21 | | - | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | | - | |
| 25 | + | |
25 | 26 | | |
26 | 27 | | |
27 | | - | |
| 28 | + | |
28 | 29 | | |
29 | 30 | | |
30 | | - | |
| 31 | + | |
31 | 32 | | |
32 | 33 | | |
33 | 34 | | |
34 | 35 | | |
35 | 36 | | |
36 | 37 | | |
37 | | - | |
| 38 | + | |
38 | 39 | | |
39 | 40 | | |
40 | 41 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| 26 | + | |
| 27 | + | |
26 | 28 | | |
27 | 29 | | |
28 | 30 | | |
| |||
0 commit comments