Skip to content

feat(workflows): add reusable go-ci + release-image at .github/workflows#3

Merged
ensarkovankaya merged 2 commits into
mainfrom
feat/reusable-workflows
May 6, 2026
Merged

feat(workflows): add reusable go-ci + release-image at .github/workflows#3
ensarkovankaya merged 2 commits into
mainfrom
feat/reusable-workflows

Conversation

@ensarkovankaya
Copy link
Copy Markdown
Contributor

Summary

  • Migrate go-ci and release-image from workflow-templates/ (GitHub UI new-repo template feature) to .github/workflows/ so consumers can call them via uses:.
  • Original workflow-templates/*.yaml retained for the new-repo bootstrap feature; a future PR can decide their fate post-Task-32.
  • Required by paper-board/agents Task 30 (CI wrapper); chained PR follows in agents repo.

Reusable upgrades over template versions

go-ci.yml

  • golangci-lint v2 (was v1.59 — matches agents repo .golangci.yml v2 schema).
  • Per-package coverage via consumer-owned coverage-script input (default ./scripts/cover-check.sh). Replaces the project-wide single-threshold gate that contradicts the per-package ramp.
  • Split jobs: lint, unit, cover-check, integration (-tags=integration), e2e (-tags=e2e), sqlc-verify, helm-lint, commitlint. Each gateable via enable-* inputs.
  • GHCR_TOKEN preserved for private-module git config insteadOf trick.

release-image.yml

  • Tag triple per agent-manager/docs/standards/build-release.md §4.1: <git_tag>, sha-<short_sha>, latest (was missing sha-<sha>).
  • buildx + docker/metadata-action for canonical tag computation.
  • --build-arg TARGET=<binary> wired alongside --target so a multi-binary Dockerfile (server + migrator) works from one reusable workflow; consumer matrices over binary: [server, migrator].
  • API: service + binary instead of single image-name — image is ghcr.io/paper-board/${service}-${binary}:<tag>.

Test plan

  • paper-board/agents wrapper PR (chained, follow-up) green on first push.
  • Lint job consumes .golangci.yml v2 schema without error.
  • cover-check job runs ./scripts/cover-check.sh and passes 70% on internal/core.
  • integration + e2e jobs spin testcontainers Postgres successfully.
  • Tag push (Task 31) produces 3 image tags per binary: v0.2.0, sha-<sha>, latest.

🤖 Generated with Claude Code

Migrates go-ci + release-image from `workflow-templates/` (GitHub UI new-repo
template feature) to `.github/workflows/` so consumers can `uses:` them.
Original templates retained for the new-repo bootstrap feature.

Reusable upgrades over the template versions:
- go-ci: golangci-lint v2 (was v1.59); per-package coverage via consumer-owned
  cover-script input (was project-wide single threshold); split jobs for unit /
  cover-check / integration / e2e (build-tag matrix); sqlc-verify + helm-lint;
  gated by enable-* inputs.
- release-image: tag triple per build-release §4.1 (added sha-<sha>); buildx +
  metadata-action; --build-arg TARGET=<binary> wired alongside --target so
  multi-binary Dockerfile (server + migrator) works from one workflow.

Spec: agent-manager/docs/standards/build-release.md §2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 6, 2026

Greptile Summary

  • Adds two reusable workflows (go-ci.yml, release-image.yml) to .github/workflows/ so consumers can call them via uses:; previously flagged issues (ungated cover-check, wrong latest tag condition, unquoted coverage-script) are all addressed in this revision.
  • go-ci.yml splits CI into eight independently gateable jobs; two remaining run steps still interpolate inputs.sqlc-version and inputs.service-name directly via ${{ }} without env-var quoting — the same injection pattern fixed for coverage-script.
  • release-image.yml correctly implements the tag triple (<git_tag>, sha-<short_sha>, latest) using github.ref_type == 'tag' and wires cosign signing + SBOM generation behind an optional COSIGN_KEY secret.

Confidence Score: 5/5

Safe to merge; all previously flagged P1 issues are resolved and only a P2 style suggestion remains

The three P1/P0 findings from the prior review round (ungated cover-check, broken latest tag, unquoted coverage-script injection) are all fixed. The only remaining finding is a P2 — two run steps still use unquoted ${{ }} input interpolation for sqlc-version and service-name, matching the same pattern that was already fixed for coverage-script. P2s do not lower the score.

.github/workflows/go-ci.yml lines 147 and 162 — minor injection-pattern cleanup to match the already-fixed cover-check step

Important Files Changed

Filename Overview
.github/workflows/go-ci.yml Reusable Go CI workflow with split lint/unit/cover-check/integration/e2e/sqlc-verify/helm-lint/commitlint jobs; previously flagged gateability and injection issues are addressed, but inputs.sqlc-version and inputs.service-name retain the same unquoted interpolation pattern in run steps
.github/workflows/release-image.yml Reusable Docker release workflow; previously flagged latest tag bug fixed with github.ref_type == 'tag'; cosign signing and SBOM generation gated correctly on optional secret; no new issues found

Sequence Diagram

sequenceDiagram
    participant C as Consumer Repo
    participant GCI as go-ci.yml (reusable)
    participant RCI as release-image.yml (reusable)
    participant GHCR as ghcr.io

    Note over C,GCI: On push / PR
    C->>GCI: "workflow_call (service-name, enable-*, secrets: inherit)"
    par Parallel jobs
        GCI->>GCI: lint (golangci-lint v2)
        GCI->>GCI: unit (go test -race)
        GCI->>GCI: cover-check (if enable-cover-check)
        GCI->>GCI: "integration (if enable-integration, -tags=integration)"
        GCI->>GCI: "e2e (if enable-e2e, -tags=e2e)"
        GCI->>GCI: sqlc-verify (if enable-sqlc-verify)
        GCI->>GCI: helm-lint (if enable-helm-lint)
        GCI->>GCI: commitlint (if enable-commitlint)
    end

    Note over C,GHCR: On tag push (matrix: binary)
    C->>RCI: workflow_call (service, binary, secrets: inherit)
    RCI->>GHCR: docker login (GHCR_TOKEN)
    RCI->>RCI: metadata-action → tags (git_tag, sha-short, latest)
    RCI->>GHCR: "build-push (--target binary, --build-arg TARGET=binary)"
    alt COSIGN_KEY provided
        RCI->>RCI: cosign sign image digest
        RCI->>RCI: anchore/sbom-action → spdx-json
    end
Loading

Reviews (2): Last reviewed commit: "fix(workflows): gate cover-check, fix la..." | Re-trigger Greptile

Comment thread .github/workflows/go-ci.yml Outdated
Comment thread .github/workflows/release-image.yml Outdated
Comment thread .github/workflows/go-ci.yml Outdated
… shell input

Greptile P1 (round 1):
- cover-check job had no enable-* toggle while every other optional job did
  (enable-integration / enable-e2e / etc.). Added `enable-cover-check` input
  (default true) + `if: inputs.enable-cover-check`. Consumers without
  scripts/cover-check.sh can now opt out.
- release-image `latest` tag was gated on `is_default_branch`, which evaluates
  to `false` on tag pushes (github.ref = refs/tags/v0.2.0, not refs/heads/main).
  Tag triple §4.1 silently lost the third tag. Switched to
  `enable=${{ github.ref_type == 'tag' }}` so latest is set on every tag push.

Greptile P2:
- coverage-script input was inlined into `bash ${{ inputs.coverage-script }}`
  without quoting — workflow-template injection vulnerability. Bot suggested
  shell-quoting; chose env-var indirection instead (canonical safe pattern):
  `env: COVERAGE_SCRIPT: ${{ inputs.coverage-script }}; run: bash "$COVERAGE_SCRIPT"`.
  Quoting alone breaks if input contains a `"`; env var fully sandboxes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ensarkovankaya ensarkovankaya merged commit 98a4fb4 into main May 6, 2026
@ensarkovankaya ensarkovankaya deleted the feat/reusable-workflows branch May 6, 2026 22:50
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