Skip to content

ci: centralize CI workflows and pre-commit hooks#45

Merged
danielewood merged 7 commits intomainfrom
ci/reusable-workflows
Feb 16, 2026
Merged

ci: centralize CI workflows and pre-commit hooks#45
danielewood merged 7 commits intomainfrom
ci/reusable-workflows

Conversation

@danielewood
Copy link
Collaborator

Summary

  • Move PR conventions and Go CI checks to org-wide reusable workflows in sensiblebit/.github
  • Centralize all pre-commit hooks (branch-name, commit-message, goimports, wasm, go-vet, go-build, go-test) to sensiblebit/.github
  • Remove local scripts/checks.py — single source of truth is now the central repo
  • Add weekly pre-commit autoupdate workflow to keep hook versions current
  • Downgrade prettier from v4 alpha to v3.1.0 stable

Test plan

  • CI passes with reusable workflows (PR conventions, Go CI)
  • Pre-commit hooks work locally via central .github repo
  • WASM check skips gracefully (no cmd/wasm path argument needed)
  • Pre-commit autoupdate workflow can be triggered manually

🤖 Generated with Claude Code

danielewood and others added 3 commits February 16, 2026 14:23
Replace inline PR title, branch name, commit message, verified commit,
and Go build/test/lint/vuln jobs with calls to reusable workflows from
sensiblebit/.github. Project-specific jobs (WASM, Web, Lint) remain.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move go-vet, go-build, go-test, goimports, branch-name,
commit-message, and wasm hooks to the org-wide .github repo.
Remove local scripts/checks.py — single source of truth is now
the central repo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Calls org-wide reusable workflow to run `pre-commit autoupdate`
weekly and open a PR when hook versions are outdated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 16, 2026 19:39
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR centralizes CI and pre-commit enforcement by switching this repo to org-wide reusable workflows and shared pre-commit hooks in sensiblebit/.github, removing the duplicated local implementation.

Changes:

  • Replace local pre-commit hook implementations with hooks sourced from sensiblebit/.github and remove scripts/checks.py.
  • Refactor GitHub Actions CI to use org-wide reusable workflows for PR conventions and Go CI, while keeping project-specific jobs (e.g., WASM).
  • Add a scheduled/manual workflow to run pre-commit autoupdate, and pin Prettier back to a stable v3 release in pre-commit.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
scripts/checks.py Removes the local shared-checks implementation now replaced by centralized tooling.
.pre-commit-config.yaml Switches several hooks to sensiblebit/.github and downgrades the Prettier mirror to v3.1.0.
.github/workflows/pre-commit-autoupdate.yml Adds a scheduled/manual workflow that delegates to the org-wide autoupdate workflow.
.github/workflows/ci.yml Replaces local CI jobs with org-wide reusable workflows and keeps/updates project-specific job wiring.


- repo: local
- repo: https://github.com/sensiblebit/.github
rev: "27cc26b"
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

The hook repo revision is pinned to a short SHA ("27cc26b"). For reproducibility and supply-chain safety, pin to an immutable ref (prefer a full commit SHA or a version tag) so pre-commit resolves the exact intended revision even if the short SHA becomes ambiguous.

Suggested change
rev: "27cc26b"
rev: "27cc26b4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b"

Copilot uses AI. Check for mistakes.

jobs:
autoupdate:
uses: sensiblebit/.github/.github/workflows/pre-commit-autoupdate.yml@main
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

This workflow calls a reusable workflow pinned to the moving @main ref. Consider pinning to a tag or full commit SHA to avoid unexpected CI changes/breakages when the central workflow is updated.

Suggested change
uses: sensiblebit/.github/.github/workflows/pre-commit-autoupdate.yml@main
uses: sensiblebit/.github/.github/workflows/pre-commit-autoupdate.yml@v1

Copilot uses AI. Check for mistakes.
Comment on lines 16 to 21
pr-conventions:
name: PR Conventions
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Check branch name
id: branch
run: python3 scripts/checks.py branch-name "${{ github.head_ref }}"
- name: Check commit messages
if: success() || failure()
id: commits
run: python3 scripts/checks.py commit-message --ci --base-ref "origin/${{ github.base_ref }}"
- name: Check commits are verified
if: success() || failure()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: python3 scripts/checks.py verified-commits "${{ github.repository }}" "${{ github.event.pull_request.number }}"

# ── Go ──────────────────────────────────────────────

go-checks:
name: Go Checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: stable
check-latest: true
cache: true
- name: Build
id: build
run: go build -trimpath ./...
- name: Vet
if: success() || failure()
id: vet
run: go vet ./...
- name: Check goimports
if: success() || failure()
run: python3 scripts/checks.py goimports

go-test:
name: Go Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: stable
check-latest: true
cache: true
- run: go test -race -count=1 ./...

golangci-lint:
name: Lint (golangci-lint)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: stable
check-latest: true
cache: true
- uses: golangci/golangci-lint-action@v9
with:
version: latest
uses: sensiblebit/.github/.github/workflows/pr-conventions.yml@main

govulncheck:
name: Vulnerability Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: stable
check-latest: true
cache: true
- name: Install govulncheck
run: go install golang.org/x/vuln/cmd/govulncheck@latest
- name: Run govulncheck
run: govulncheck ./...
go-ci:
uses: sensiblebit/.github/.github/workflows/go-ci.yml@main
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

Both reusable workflows are referenced via the moving @main ref. To make CI deterministic and reduce the risk of unexpected breakages, pin these to a tag or full commit SHA (and bump intentionally when you want updates).

Copilot uses AI. Check for mistakes.
Comment on lines 73 to 74
if: success() || failure()
run: npx markdownlint-cli@0.47.0 --config .markdownlint.yaml '**/*.md'
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

The PR description says Prettier is downgraded to v3.1.0, but CI still runs npx prettier@latest --check ..., which can reintroduce v4+ behavior and create CI vs pre-commit drift. Pin the CI Prettier version to match .pre-commit-config.yaml (or update the PR description if using latest is intentional).

Copilot uses AI. Check for mistakes.
Replace inline prettier + markdownlint steps with call to
sensiblebit/.github lint workflow. Only wasm_exec.js exclusion
is project-specific.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@claude

This comment has been minimized.

Replace inline @claude mention handler with thin caller to
sensiblebit/.github reusable workflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 16, 2026 19:47
@claude

This comment has been minimized.

Issue templates now come from sensiblebit/.github fallback.
PR template kept as project-specific override (changelog checklist).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

actions: read

jobs:
claude:
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

The job-level if: guard was removed when switching to the reusable workflow, so this workflow will invoke the Claude workflow on every matching event (issue comment, review comment, issue opened/assigned, review submitted). That increases CI noise/cost and can expose the Claude secret to untrusted triggers unless the reusable workflow re-implements the same authorization and @claude-mention gating. Re-add an if: condition here (as before) or pass explicit inputs to ensure only trusted users and explicit @claude mentions can trigger runs.

Suggested change
claude:
claude:
if: >
(github.event_name == 'issue_comment' &&
contains(github.event.comment.body, '@claude') &&
(github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'COLLABORATOR')) ||
(github.event_name == 'pull_request_review_comment' &&
contains(github.event.comment.body, '@claude') &&
(github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'COLLABORATOR')) ||
(github.event_name == 'pull_request_review' &&
contains(github.event.review.body, '@claude') &&
(github.event.review.author_association == 'MEMBER' || github.event.review.author_association == 'OWNER' || github.event.review.author_association == 'COLLABORATOR')) ||
(github.event_name == 'issues' &&
contains(github.event.issue.body, '@claude') &&
(github.event.issue.author_association == 'MEMBER' || github.event.issue.author_association == 'OWNER' || github.event.issue.author_association == 'COLLABORATOR'))

Copilot uses AI. Check for mistakes.
if: success() || failure()
run: python3 scripts/checks.py goimports
go-ci:
uses: sensiblebit/.github/.github/workflows/go-ci.yml@main
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

go-ci is now delegated to a reusable workflow, but this repo’s documented CI requirements include running go test -race in CI (CLAUDE.md T-3) plus the previous lint/vuln checks that were removed from this file. Please ensure the reusable go-ci.yml still runs go test -race and the required checks, or add/enable the missing steps/inputs here so CI enforcement remains unchanged.

Suggested change
uses: sensiblebit/.github/.github/workflows/go-ci.yml@main
uses: sensiblebit/.github/.github/workflows/go-ci.yml@main
with:
run-race: true
run-lint: true
run-vuln: true

Copilot uses AI. Check for mistakes.

- repo: local
- repo: https://github.com/sensiblebit/.github
rev: "27cc26b"
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

The pre-commit rev is pinned to a short SHA (27cc26b). For reproducibility and to avoid ambiguity, pin to a full commit SHA (40 chars) or a signed/tagged release in sensiblebit/.github.

Suggested change
rev: "27cc26b"
rev: v1.0.0

Copilot uses AI. Check for mistakes.
always_run: true
pass_filenames: false

- id: commit-message
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

The commit-message hook previously ran only at the commit-msg stage. With the stage override removed here, it will run at the default stage unless the hook itself declares stages: [commit-msg] in the central repo. To avoid silently losing commit-msg enforcement, explicitly set stages: [commit-msg] for this hook in this config (or confirm it’s enforced by the hook definition).

Suggested change
- id: commit-message
- id: commit-message
stages: [commit-msg]

Copilot uses AI. Check for mistakes.
Avoid spinning up a runner for every issue comment/review
when only @claude mentions need processing. Auth check stays
in the reusable workflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@danielewood danielewood merged commit 8841eaf into main Feb 16, 2026
16 checks passed
@claude
Copy link

claude bot commented Feb 16, 2026

Code review

Issue found: Missing CHANGELOG.md entry

This PR modifies CI configuration files, adds a new workflow (pre-commit-autoupdate.yml), changes pre-commit configuration, and deletes scripts/checks.py (279 lines). This represents a notable architectural change (centralizing workflows to org-wide reusable workflows) that should be documented in CHANGELOG.md.

Rule violated: CL-1 (MUST)

Every commit that changes behavior, fixes a bug, or adds a feature must add a line to the ## [Unreleased] section of CHANGELOG.md. Internal-only changes (CI config, CLAUDE.md, test-only) do not require an entry unless they are notable. When in doubt, add an entry

This PR is notable because:

  • It fundamentally restructures how CI works by moving to organization-wide reusable workflows
  • It deletes the entire scripts/checks.py file that was core to the CI infrastructure
  • It removes local pre-commit hook implementations and replaces them with remote references
  • It adds a new weekly autoupdate workflow
  • It deletes all issue templates

Recommendation: Add an entry to the ## [Unreleased] section under ### Changed:

### Changed

- Migrate CI workflows and pre-commit hooks to organization-wide reusable workflows ([#45])

Checked for bugs and CLAUDE.md compliance.

@danielewood danielewood deleted the ci/reusable-workflows branch February 16, 2026 19:56
@claude
Copy link

claude bot commented Feb 16, 2026

Code review

1 security issue found:

Security: Authorization check removed from Claude workflow

Location: .github/workflows/claude.yml lines 22-27

Issue: The authorization check that restricted Claude Code workflow execution to repository owner, org members, and collaborators has been removed from the caller workflow.

Original code (before this PR):

if: |
  (
    (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
    (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
    (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
    (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
  ) && (
    github.event.sender.login == github.repository_owner ||
    github.event.comment.author_association == 'OWNER' ||
    github.event.comment.author_association == 'MEMBER' ||
    github.event.comment.author_association == 'COLLABORATOR'
  )

New code (after this PR):

if: |
  (
    (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
    (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
    (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
    (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
  )

Security implications:

This represents a defense-in-depth regression:

  1. Secret exposure before authorization: The CLAUDE_CODE_OAUTH_TOKEN secret is now passed to the reusable workflow for ANY user who writes @claude in a comment, with no local authorization gate. The original design had the authorization check at the earliest possible point—before the job runs, before secrets are transmitted.

  2. External auth dependency: The auth logic has moved to a separate repository (sensiblebit/.github) where changes are not subject to this repo's review process. If the reusable workflow's auth check has a bug, is misconfigured, or is later modified, the CLAUDE_CODE_OAUTH_TOKEN could be exposed to unauthorized users.

  3. Attack surface: Any GitHub user who can comment on an issue or PR in this repository can now trigger the workflow to start, allocate a runner, and receive the OAuth token secret before any authorization check occurs.

Recommendation:

Either:

  • Option 1 (Defense-in-depth): Restore the authorization check in the caller's if condition alongside the reusable workflow call. This provides layered security even if the reusable workflow also has the check.
  • Option 2 (Verify external check): Before merging, verify that the reusable workflow at sensiblebit/.github/.github/workflows/claude.yml@main contains an equivalent authorization check and accept the reduced defense-in-depth posture.

Security best practice for GitHub Actions is to gate secret-consuming workflows as early as possible. The caller-side authorization gate should be retained.

danielewood added a commit that referenced this pull request Feb 16, 2026
Defense-in-depth: gate secret transmission behind OWNER/MEMBER/
COLLABORATOR check at the caller level, not just the reusable
workflow. Also adds missing CHANGELOG entry for #45.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
danielewood added a commit that referenced this pull request Feb 17, 2026
Defense-in-depth: gate secret transmission behind OWNER/MEMBER/
COLLABORATOR check at the caller level, not just the reusable
workflow. Also adds missing CHANGELOG entry for #45.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
danielewood added a commit that referenced this pull request Feb 17, 2026
Defense-in-depth: gate secret transmission behind OWNER/MEMBER/
COLLABORATOR check at the caller level, not just the reusable
workflow. Check author_association on the correct event object for
each trigger type (comment, review, issue) — previously only
comment-based events were checked, silently blocking members on
review and issue events.

Also adds missing CHANGELOG entries for #45 and #46.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
danielewood added a commit that referenced this pull request Feb 17, 2026
Defense-in-depth: gate secret transmission behind OWNER/MEMBER/
COLLABORATOR check at the caller level, not just the reusable
workflow. Check author_association on the correct event object for
each trigger type (comment, review, issue) — previously only
comment-based events were checked, silently blocking members on
review and issue events.

Also adds missing CHANGELOG entries for #45 and #46.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.

2 participants