Skip to content

ci: add Go test+vet+build workflow for PRs and main#8

Merged
vigneshsubbiah16 merged 1 commit into
mainfrom
chore/add-ci-workflow
Apr 19, 2026
Merged

ci: add Go test+vet+build workflow for PRs and main#8
vigneshsubbiah16 merged 1 commit into
mainfrom
chore/add-ci-workflow

Conversation

@vigneshsubbiah16

@vigneshsubbiah16 vigneshsubbiah16 commented Apr 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds .github/workflows/ci.yaml — Go test + vet + build, gated on every PR and push-to-main. Before this, release.yaml (tag-triggered) was the only workflow; merges relied on local-test-passed trust.

What the workflow runs

go vet   ./internal/...
go build ./internal/...
go test -race -count=1 ./internal/...
  • Scope: ./internal/..., not ./.... The top-level ./... pulls in internal/web/embed.go which has //go:embed all:dist — the embed fails without a frontend build. The workflow creates a stub internal/web/dist/index.html so the embed compiles, but wiring the actual frontend build into CI is a separate concern (follow-up).
  • Go version from go.mod (1.22) via setup-go's go-version-file — no hardcoded version to drift.
  • -race because the per-app deploy mutex (handlers.go) is the obvious concurrency surface; we want it exercised.
  • -count=1 disables the test cache so flakes surface on every run.

Why separate from the auto-rollback PR

PR #7 is already through three review passes and architect-signed-off. Tacking CI onto it would re-open scope. Simpler to merge them independently — PR #7 first (feature), then this one (gate subsequent PRs).

Verification

Ran the exact three commands locally against origin/main:

  • go vet ./internal/... → clean
  • go build ./internal/... → clean
  • go test -race -count=1 ./internal/...ok internal/api 1.800s, ok internal/k8s 8.241s (six auxiliary packages have no tests, reported as ?)

Test plan

  • Local dry-run of workflow commands — all green
  • After merge: open any throwaway PR; confirm the Go test + vet + build check appears and goes green
  • After merge: intentionally push a failing test on a branch; confirm the check blocks

Follow-ups (not in this PR)

  • Frontend build jobnpm ci && npm run build in web/, then go build ./... against the real embed. Separate job so a broken frontend doesn't mask a green Go suite.
  • Branch protection rule on main requiring this check to pass before merge. GitHub settings, not workflow.
  • Lintgofmt -l, goimports, or a golangci-lint action. Nice-to-have.

🤖 Generated with Claude Code

Greptile Summary

This PR adds a CI workflow (.github/workflows/ci.yaml) that runs go vet, go build, and go test -race -count=1 against ./internal/... on every PR and push to main. The design choices are sound: Go version is read from go.mod, permissions are locked to contents: read, and the stub approach for the missing frontend embed is a reasonable workaround documented clearly in both the workflow and the PR description.

Confidence Score: 5/5

Safe to merge — all findings are P2 style suggestions that do not affect correctness or reliability.

The workflow is well-structured with correct trigger events, minimal permissions, and no hardcoded Go version. The two findings (mutable action tags, missing concurrency group/timeout) are best-practice hardening suggestions, not blocking defects.

No files require special attention.

Security Review

  • actions/checkout@v4 and actions/setup-go@v5 are pinned to mutable major-version tags. A supply-chain compromise that re-points a tag would execute arbitrary code on the runner, with access to runner filesystem and any secrets scoped to the workflow — even though permissions: contents: read constrains the GitHub API token. Pinning to full commit SHAs mitigates this risk.

Important Files Changed

Filename Overview
.github/workflows/ci.yaml New CI workflow adding go vet + build + race-enabled test against ./internal/...; correctly reads Go version from go.mod, limits permissions to contents: read, and stubs the frontend embed — two minor style suggestions (action SHA pinning, concurrency group/timeout).

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[PR opened / push to main] --> B[Checkout repo]
    B --> C[Setup Go via go.mod]
    C --> D[Stub internal/web/dist/index.html]
    D --> E[go vet ./internal/...]
    E --> F[go build ./internal/...]
    F --> G[go test -race -count=1 ./internal/...]
    G --> H{All steps pass?}
    H -- Yes --> I[✅ CI green]
    H -- No --> J[❌ CI red — blocks merge]
Loading

Reviews (1): Last reviewed commit: "ci: add Go test+vet+build workflow for P..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

Before this, the only workflow on the repo was release.yaml (tag-
triggered). Merges went in on local-test-passed trust, which is fine
with one contributor but will not scale.

The new workflow runs on every PR and push-to-main:
- go vet   ./internal/...
- go build ./internal/...
- go test -race -count=1 ./internal/...

Scoped to ./internal/... rather than ./... because internal/web/embed.go
has //go:embed all:dist and the frontend build is not part of this job;
a single stub file is created so the embed directive compiles. Building
the frontend and wiring it into CI is a separate concern.

Go version comes from go.mod (1.22) via setup-go go-version-file.

-race enabled because the per-app deploy mutex in handlers.go is the
obvious concurrency surface we want exercised. -count=1 disables the
test cache so flakes surface on every run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread .github/workflows/ci.yaml
Comment on lines +17 to +22
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 security Actions pinned to mutable version tags

actions/checkout@v4 and actions/setup-go@v5 use mutable major-version tags. If either upstream repo were compromised and a tag re-pointed to malicious code, this workflow would execute it with write access to the runner (even though permissions: contents: read limits GitHub API access, the runner filesystem and secrets are still exposed). GitHub's own hardening guide recommends pinning third-party actions to a full commit SHA.

Suggested change
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
      - name: Set up Go
        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0

Comment thread .github/workflows/ci.yaml
Comment on lines +12 to +14
go:
name: Go test + vet + build
runs-on: ubuntu-latest

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 No concurrency group or job timeout

Without a concurrency group, every push to an open PR queues a new run while old ones are still running, burning CI minutes needlessly. A timeout-minutes guard also prevents a hung test or infinite loop from consuming all available runner time.

Suggested change
go:
name: Go test + vet + build
runs-on: ubuntu-latest
go:
name: Go test + vet + build
runs-on: ubuntu-latest
timeout-minutes: 15

And add at the workflow level (before jobs:):

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

@vigneshsubbiah16 vigneshsubbiah16 merged commit d2a06b8 into main Apr 19, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant