Conversation
Add tidy-check, vuln, secrets, security, release-check, and release targets to support the full CI quality gate and local release workflow.
- test.yml: 4 jobs (test, lint, govulncheck, race detection) - security.yml: 5 jobs (gitleaks, trivy, gosec, dependency-review, CodeQL) - release.yml: tag-triggered library release with guarded skills sync - dependabot-auto-merge.yml: auto-merge minor/patch dependency updates All actions SHA-pinned, explicit least-privilege permissions throughout.
- dependabot.yml: weekly Go + Actions updates with cooldown settings - CODEOWNERS: actions/, seed/, workflows/, scripts/ owned by @basecamp/sip - release.yml: changelog categories with dependabot exclusion - codeql-config.yml: security-and-quality query suite
- .pre-commit-config.yaml: golangci-lint, gitleaks, go mod tidy, test - scripts/release.sh: semver validation, quality gate, annotated tag - RELEASING.md: library release process and CI secrets documentation - .mise.toml: pin Go toolchain to prevent version mismatch
Add tidy-check, check-naming, replace-check, check-surface, vuln, secrets, security, provenance-check, release-check, release, sync-skills, collect-profile, and build-pgo targets for consumer CLIs.
- release.sh.tmpl: semver validation, quality gate, tag + push - check-cli-surface.sh: --help --agent JSON surface snapshot - check-cli-surface-diff.sh: diff two snapshots, fail on removals - collect-profile.sh: PGO profile collection from benchmarks - sync-skills.sh: fix SC2231 quoting in glob expansion
- test.yml: 7 jobs (test, lint, govulncheck, race, BATS, surface, benchmarks) - security.yml: 5 jobs (gitleaks, trivy, gosec, dependency-review, CodeQL) - release.yml: full pipeline with feature-flag guards for AI changelog, macOS notarization, AUR, Homebrew, skills sync, and PGO - ai-labeler.yml: AI-powered PR classification and breaking change detection - dependabot-auto-merge.yml: auto-merge minor/patch updates - labeler.yml: path-based PR labeling All optional features degrade gracefully with zero secrets configured.
GitHub config: dependabot, CODEOWNERS, PR template, release categories, labeler rules, CodeQL config. AI prompts for PR classification, breaking change detection, and changelog generation. Local dev: pre-commit hooks, gitleaks config, and release documentation templates.
Add all new seed files to the copy-and-customize section, fix skills template path (seed/skills/SKILL.md.tmpl -> seed/skills/app/SKILL.md.tmpl), add GitHub infra setup and secrets configuration documentation.
There was a problem hiding this comment.
Pull request overview
Adds a complete release-engineering stack for both this repo and the seed CLI templates, covering CI/security/release automation, local developer tooling, and documentation needed to bootstrap new CLIs with the same infra from day one.
Changes:
- Add/expand GitHub Actions workflows for tests, security scans, releases, labeling, and Dependabot automation.
- Add release/security tooling (Make targets, release + skills sync scripts, PGO profiling and CLI surface snapshot/diff utilities).
- Add templates/docs for RELEASING, pre-commit, gitleaks, and seed bootstrap instructions.
Reviewed changes
Copilot reviewed 39 out of 39 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| seed/scripts/sync-skills.sh | Fix quoting when iterating skills directories in seed script. |
| seed/scripts/release.sh.tmpl | Add seed release script template (tagging + preflight). |
| seed/scripts/collect-profile.sh | Add seed PGO profile collection script. |
| seed/scripts/check-cli-surface.sh | Add seed CLI surface snapshot generator. |
| seed/scripts/check-cli-surface-diff.sh | Add seed CLI surface diff gate (fail on removals). |
| seed/RELEASING.md.tmpl | Add seed release process + feature toggle matrix docs. |
| seed/Makefile | Add seed releng targets (tidy/security/release/surface/PGO/skills). |
| seed/.pre-commit-config.yaml.tmpl | Add seed pre-commit configuration template. |
| seed/.gitleaks.toml.tmpl | Add seed gitleaks configuration template. |
| seed/.github/workflows/test.yml | Add seed CI workflow (tests/lint/security/race/integration/surface/benchmarks). |
| seed/.github/workflows/security.yml | Add seed security workflow (gitleaks/trivy/gosec/codeql/dependency-review). |
| seed/.github/workflows/release.yml | Add seed release workflow (security + quality gate + GoReleaser + optional extras). |
| seed/.github/workflows/labeler.yml | Add seed labeler workflow (actions/labeler). |
| seed/.github/workflows/dependabot-auto-merge.yml | Add seed Dependabot auto-merge workflow (guarded). |
| seed/.github/workflows/ai-labeler.yml | Add seed AI PR classification + breaking-change labeling workflow. |
| seed/.github/release.yml | Add seed GitHub Releases changelog category config. |
| seed/.github/pull_request_template.md | Add seed PR template. |
| seed/.github/prompts/summarize-changelog.prompt.yml | Add seed AI prompt for release summary prose. |
| seed/.github/prompts/detect-breaking.prompt.yml | Add seed AI prompt for breaking-change detection. |
| seed/.github/prompts/classify-pr.prompt.yml | Add seed AI prompt for PR categorization labels. |
| seed/.github/labeler.yml.tmpl | Add seed labeler rules template. |
| seed/.github/dependabot.yml | Add seed Dependabot configuration template. |
| seed/.github/codeql/codeql-config.yml | Add seed CodeQL configuration. |
| seed/.github/CODEOWNERS.tmpl | Add seed CODEOWNERS template. |
| scripts/sync-skills.sh | Add repo skills distribution sync script (CI release hook). |
| scripts/release.sh | Add repo (library) release script (tagging + preflight). |
| prompts/seed-cli.md | Update bootstrap instructions to include new releng files and setup steps. |
| RELEASING.md | Add repo (library) releasing documentation. |
| Makefile | Add repo releng targets (tidy/security/release-check/release). |
| .pre-commit-config.yaml | Add repo pre-commit hooks configuration. |
| .mise.toml | Pin Go toolchain via mise. |
| .github/workflows/test.yml | Add repo CI workflow (test/lint/govulncheck/race). |
| .github/workflows/security.yml | Add repo security workflow (gitleaks/trivy/gosec/codeql/dependency-review). |
| .github/workflows/release.yml | Add repo release workflow (security + test gate + module publish + optional skills sync). |
| .github/workflows/dependabot-auto-merge.yml | Add repo Dependabot auto-merge workflow. |
| .github/release.yml | Update repo changelog exclusions (labels/authors). |
| .github/dependabot.yml | Expand repo Dependabot configuration (scheduling/groups/cooldowns). |
| .github/codeql/codeql-config.yml | Add repo CodeQL configuration. |
| .github/CODEOWNERS | Update repo code ownership rules. |
Comments suppressed due to low confidence (3)
seed/.github/workflows/release.yml:317
- The docs/template matrix says skills sync is gated by a guard combo (App ID + private key), but the job-level
if:only checksvars.SKILLS_APP_ID. If the var is set butsecrets.SKILLS_APP_PRIVATE_KEYis missing,actions/create-github-app-tokenwill fail and the job will error (even ifcontinue-on-errorhides it). Align the guard with the documented combo by adding a non-secret-derived env flag (e.g.,HAS_SKILLS_KEY) and checking that, or by adding an explicit preflight step that sets an output-and-guards subsequent steps.
if: >-
startsWith(github.ref, 'refs/tags/v') &&
vars.SKILLS_APP_ID != ''
scripts/sync-skills.sh:65
- This copy loop will mis-handle filenames containing spaces/newlines because it relies on newline-delimited output piped into
read -r f. Also,! -name '.*'won’t reliably exclude files under hidden directories like./.foo/bar.txt. Usefind ... -print0withwhile IFS= read -r -d '' fand exclude hidden paths via a-path '*/.*' -prune(or equivalent) to make the sync deterministic and safe.
# Copy non-Go, non-dotfiles preserving subdirectory structure
(cd "$skill_dir" && find . -type f ! -name '*.go' ! -name '.*' | while read -r f; do
mkdir -p "$dest/$(dirname "$f")"
cp "$f" "$dest/$f"
done)
seed/scripts/collect-profile.sh:1
- With
set -e, this will exit the script if./internal/...doesn’t exist or has no packages (common in early-stage repos or repos withoutinternal/). If this is intended as a general-purpose seed utility, consider falling back togo list ./..., or detect absence ofinternal/and emit a clear message / skip profile generation.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
All 37signals CLIs are on Go 1.26 now.
…om auto-merge - seed release.yml: replace `ls bin/` with `find bin/ -print -quit` for deterministic single-binary selection - dependabot-auto-merge.yml: exclude github_actions ecosystem from auto-merge to maintain review barrier on CI-critical code
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ebada31b06
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Add .golangci.yml (v2 format) matching the seed template linter set. Fix all unchecked return values: cleanup calls in error paths use explicit _ discard, test assertions use require.NoError.
When DRY_RUN=local, create a stub git repo instead of cloning the remote skills repo. This lets contributors run make sync-skills without needing access credentials.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 46 out of 46 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (5)
seed/Makefile:22
checkis meant to be the fast inner-loop target (fmt-check + vet + test (+ test-e2e for CLIs) per MAKEFILE-CONVENTION.md). Addingtidy-checkhere makescheckslower and introduces a git-diff dependency; consider movingtidy-checktocheck-all/ CI-only gates instead.
.github/workflows/security.yml:33- Installing gitleaks via
curl ... | tar -xzwithout checksum/signature verification weakens the supply-chain guarantees of this security workflow. Prefer using a pinned action for gitleaks, or download the release artifact and verify its checksum/signature before executing it.
- name: Install gitleaks
run: |
curl -sSfL https://github.com/gitleaks/gitleaks/releases/download/v8.21.2/gitleaks_8.21.2_linux_x64.tar.gz | tar -xz
sudo mv gitleaks /usr/local/bin/
seed/.github/workflows/security.yml:32
- Installing gitleaks via
curl ... | tar -xzwithout checksum/signature verification weakens the supply-chain guarantees of this security workflow. Prefer using a pinned gitleaks action, or verify the downloaded artifact’s checksum/signature before moving it into PATH.
scripts/sync-skills.sh:65 - This sync logic only copies files into the destination directory; if a file is deleted or renamed in the source skill, the old file will remain in the destination skill directory and keep getting published. Consider wiping the destination skill directory (or deleting files not present in the source) before copying so the target repo is an exact mirror of the current skill contents.
echo "No skills found in ${SKILLS_DIR}/"
exit 0
fi
echo "Found ${#SKILL_DIRS[@]} skill(s) to sync"
# Copy skills to target repo
MANAGED_SKILLS=()
seed/scripts/collect-profile.sh:2
- For portability/consistency with the other scripts in this template (which use
#!/usr/bin/env bash), consider switching this shebang from#!/bin/bashto#!/usr/bin/env bashso it works in environments where bash isn’t located at/bin/bash.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Nest settings under linters.settings (not top-level linters-settings) - Move gofmt to formatters.enable (formatter, not linter in v2) - Remove gosimple (merged into staticcheck in v2) - Remove exclude-use-default (removed in v2) - Set errcheck check-blank: false (true flags explicit _ = discards) - Add version: "2" to seed config
trivy-action 0.34.1 auto-resolves to latest Trivy which currently fails to download. Pin a known-good version.
|
This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation. |
- Add replace-check target to library Makefile (guards against replace directives in go.mod before release) - Include replace-check in release-check prerequisite chain - Add .DEFAULT_GOAL := check to both Makefiles so bare `make` runs the check target regardless of .PHONY ordering
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 47 out of 47 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (4)
seed/Makefile:162
vulnrunsgovulncheckbut doesn’t verify it’s installed. Sincerelease-checkdepends onvuln, missing tooling will fail with an unhelpful “command not found”. Add a presence check with a clear install hint (or installgovulncheckinside the target).
seed/scripts/collect-profile.sh:44- The PGO profiling
go test -bench=.invocation will still run package tests unless-runis set. That can significantly increase runtime and skew the profile away from benchmarks. Add-run=^$(or similar) so only benchmarks execute when collecting profiles.
seed/.github/workflows/release.yml:164 - This PGO collection step runs
go test -bench=.without-run, so it will execute unit tests in addition to benchmarks. That can make releases slower and produce profiles dominated by test setup rather than benchmark hot paths. Add-run=^$(or equivalent) to restrict execution to benchmarks for profiling.
Makefile:54 vulnassumesgovulncheckis already installed, butrelease-checkdepends on it, so a fresh dev machine will fail with a generic “command not found”. Mirror thesecretstarget pattern by checking forgovulncheckand printing an explicit install instruction (or install it in the target).
# Guard against local replace directives in go.mod
replace-check:
@if grep -q '^[[:space:]]*replace[[:space:]]' go.mod; then \
echo "ERROR: go.mod contains replace directives"; \
grep '^[[:space:]]*replace[[:space:]]' go.mod; \
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Use a temp gitconfig file with GIT_CONFIG_GLOBAL instead of embedding the token directly in the clone URL or passing it via git -c. The token is written to a temp file (cleaned up on exit) and never appears in process listings.
Summary
All optional features degrade gracefully with zero secrets. All actions SHA-pinned, explicit least-privilege permissions on every workflow. Passes actionlint, shellcheck, and make check.
Test plan
make checkpasses (Go 1.26.0)actionlint .github/workflows/*.ymlexits 0actionlint seed/.github/workflows/*.ymlexits 0shellcheck scripts/*.sh seed/scripts/*.shexits 0permissions:blocksuses:refs are SHA-pinnedsecrets.*in anyif:condition.tmplfiles render cleanly with fixture values, no unresolved markers