diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c6a9e2c..fe0d131 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -239,7 +239,19 @@ func (s *UserService) ProcessUsers(ctx context.Context, ids []string) error { When updating CI workflows or release logic: -- Use the repository's standard Go setup (typically `actions/setup-go@v5` with pinned version and go.sum caching). +- Use the repository's standard Go setup (typically `actions/setup-go@v5` with pinned version). +- Enforce Go dependency/build caching in every Go CI job to reduce repeated module and build downloads. + - Require `actions/setup-go@v5` caching with `cache: true` and `cache-dependency-path: go.sum`. + - For workflows that split jobs across multiple Go-related steps (test/lint/security), ensure caches are restored in each job. +- Enforce formatting in local and CI workflows: + - Require `go fmt ./...` before commit. + - Require formatting validation in CI (for example `test -z "$(gofmt -l .)"`), or use a standard formatter action that provides equivalent enforcement. +- Enforce module hygiene in local and CI workflows: + - Require `go mod tidy` and `go mod verify` as part of validation. + - CI may use standard actions/automation that perform equivalent module tidy and verification checks. +- Enforce changelog gate in PR validation workflows: + - Fail PR validation when no entry is added under `## [Unreleased]` in `CHANGELOG.md` for code, behavior, security, workflow, or tooling changes. + - Repository policy may allow explicit docs-only/metadata-only exceptions. - Keep workflow summary output using the summary-file pattern: - Define `SUMMARY_FILE` environment variable per job. - Append markdown output from steps to the summary file. @@ -249,13 +261,62 @@ When updating CI workflows or release logic: - `CONTEXT_PARAMS` is optional; available params are `branch`, `event`, `style` for badge URLs and `branch`, `event` for badge-link targets. Prefer `branch` and `event` when filtering run context; if `style` is used, place it last. - Prefer latest-run pages for badge links for fast status triage. +### Required Go Security Actions and Caching Pattern (GitHub Actions) + +When using GitHub Actions for Go repositories, explicitly use these actions in CI: + +- `securego/gosec@v2` +- `golang/govulncheck-action@v1` + +Minimum recommended pattern: + +```yaml +jobs: + security: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Go with cache + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + cache-dependency-path: go.sum + + - name: Validate formatting + run: | + set -euo pipefail + test -z "$(gofmt -l .)" + + - name: Module hygiene + run: | + set -euo pipefail + go mod tidy + go mod verify + + - name: Run gosec + uses: securego/gosec@v2 + with: + args: ./... + + - name: Run govulncheck + id: govulncheck + uses: golang/govulncheck-action@v1 + with: + go-package: ./... + cache: true + cache-dependency-path: go.sum +``` + ### Composite Actions and Release Orchestration Use `https://git.hrafn.xyz/aether/vociferate` as the default release-management tool when integrating Æther composite actions: -- Pin all action references to released tags (for example `@v1.0.0`). +- **Always use full `https://` URLs** in `uses:` references for all vociferate actions (for example `uses: https://git.hrafn.xyz/aether/vociferate/prepare@v1.0.2`). This ensures correct action resolution on both GitHub and self-hosted Gitea instances. Never use shorthand coordinates like `aether/vociferate` without the full URL. +- Pin all action references to released tags (for example `@v1.0.2`). - Keep all vociferate references on the same tag within a workflow. -- In self-hosted runner environments (git.hrafn.xyz), use explicit `https://` action paths in `uses:` references and avoid shorthand owner/repo coordinates. - Use `prepare` action to update changelog/version and create release tags. - Use `publish` action to create/update release notes and assets from existing tags. - Do not mix alternate release actions unless a repository-local policy explicitly documents an override. @@ -303,6 +364,8 @@ jobs: - **Automation**: Prefer `justfile` for task automation; mirror core CI operations locally. - **Dependency management**: Use `go.mod` and `go.sum` for version tracking. +- **Code formatting**: Run `go fmt ./...` before committing changes. +- **Module hygiene**: Run `go mod tidy` and `go mod verify` during local validation. - **Structure**: Keep code organized in logical packages; avoid deep nesting. ## Security Standards @@ -319,6 +382,11 @@ Security standards (self-contained): - Purpose: Detect vulnerabilities in direct and transitive dependencies. - Address: Update vulnerable dependencies to patched versions. +- **GitHub Actions enforcement** (for GitHub-hosted CI): + - Use `securego/gosec@v2` in CI workflows. + - Use `golang/govulncheck-action@v1` in CI workflows. + - Enable caching in these workflows (`actions/setup-go@v5` with `cache: true` and `cache-dependency-path`). + - **Dependency hygiene**: Keep `go.mod` and `go.sum` clean; run `go mod tidy` and `go mod verify` regularly. Integrate both tools into CI workflows; fail builds on high/critical findings. @@ -327,12 +395,15 @@ Integrate both tools into CI workflows; fail builds on high/critical findings. Execute validation in this order (unless repository policy specifies otherwise): -1. Run focused package tests that directly cover the changed code. -2. Run broader package or module test suites as needed. -3. Run `gosec ./...` for security analysis. -4. Run `govulncheck ./...` for vulnerability scanning. -5. Run full project or behavior/integration suites when change scope or risk warrants it. -6. Verify coverage gates per changed module/class (target 80%, low bound 65%, fail below 50%). +1. Run `go fmt ./...` for code formatting. +2. Validate formatting (for example `test -z "$(gofmt -l .)"`) before or within CI. +3. Run `go mod tidy` and `go mod verify` (or equivalent standard automation). +4. Run focused package tests that directly cover the changed code. +5. Run broader package or module test suites as needed. +6. Run `gosec ./...` for security analysis. +7. Run `govulncheck ./...` for vulnerability scanning. +8. Run full project or behavior/integration suites when change scope or risk warrants it. +9. Verify coverage gates per changed module/class (target 80%, low bound 65%, fail below 50%). ## Safety and Scope @@ -358,6 +429,9 @@ Before considering a task done: - ✓ Refactoring happened only after tests were green. - ✓ Focused tests passed for all changed packages. - ✓ Broader validation was run when risk or scope justified it. +- ✓ Code was formatted with `go fmt ./...` and formatting validation passed. +- ✓ Module hygiene checks passed (`go mod tidy` and `go mod verify`, or equivalent standard automation). +- ✓ PR validation changelog gate passed (`CHANGELOG.md` has required addition under `## [Unreleased]` when policy applies). - ✓ Coverage gates were evaluated per changed module/class (target 80%, low bound 65%, fail below 50%). - ✓ Behavioral parity expectations were preserved unless change was explicitly requested. - ✓ Security scanning passed: `gosec ./...` and `govulncheck ./...` without unacknowledged findings. diff --git a/AGENTS.md b/AGENTS.md index 7e4e966..e62c94b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,11 +8,11 @@ Pin all action references to a released tag (for example `@v1.0.2`) and keep all Published composite actions: -- `git.hrafn.xyz/aether/vociferate@v1.0.2` (root action) -- `git.hrafn.xyz/aether/vociferate/prepare@v1.0.2` -- `git.hrafn.xyz/aether/vociferate/publish@v1.0.2` -- `git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2` -- `git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2` +- `https://git.hrafn.xyz/aether/vociferate@v1.0.2` (root action) +- `https://git.hrafn.xyz/aether/vociferate/prepare@v1.0.2` +- `https://git.hrafn.xyz/aether/vociferate/publish@v1.0.2` +- `https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2` +- `https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2` ## Action Selection Matrix @@ -94,11 +94,11 @@ jobs: with: fetch-depth: 0 - id: prepare - uses: git.hrafn.xyz/aether/vociferate/prepare@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/prepare@v1.0.2 publish: needs: prepare - uses: aether/vociferate/.gitea/workflows/do-release.yml@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/.gitea/workflows/do-release.yml@v1.0.2 with: tag: ${{ needs.prepare.outputs.version }} secrets: inherit @@ -115,7 +115,7 @@ jobs: with: fetch-depth: 0 - id: publish - uses: git.hrafn.xyz/aether/vociferate/publish@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/publish@v1.0.2 with: version: v1.2.3 ``` @@ -136,7 +136,7 @@ jobs: - name: Run tests with coverage run: go test -covermode=atomic -coverprofile=coverage.out ./... - id: badge - uses: git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2 with: artefact-bucket-name: ${{ vars.ARTEFACT_BUCKET_NAME }} artefact-bucket-endpoint: ${{ vars.ARTEFACT_BUCKET_ENDPONT }} @@ -159,12 +159,12 @@ jobs: - name: Run tests with coverage run: go test -covermode=atomic -coverprofile=coverage.out ./... - id: badge - uses: git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2 with: artefact-bucket-name: ${{ vars.ARTEFACT_BUCKET_NAME }} artefact-bucket-endpoint: ${{ vars.ARTEFACT_BUCKET_ENDPONT }} - name: Decorate PR - uses: git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2 with: coverage-percentage: ${{ steps.badge.outputs.total }} badge-url: ${{ steps.badge.outputs.badge-url }} diff --git a/README.md b/README.md index 6bed39a..715ed54 100644 --- a/README.md +++ b/README.md @@ -41,13 +41,13 @@ jobs: with: fetch-depth: 0 - - uses: git.hrafn.xyz/aether/vociferate/prepare@v1.0.2 + - uses: https://git.hrafn.xyz/aether/vociferate/prepare@v1.0.2 with: version: ${{ inputs.version }} publish: needs: prepare - uses: aether/vociferate/.gitea/workflows/do-release.yml@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/.gitea/workflows/do-release.yml@v1.0.2 with: tag: ${{ needs.prepare.outputs.version }} secrets: inherit @@ -61,7 +61,7 @@ For repositories that embed the version inside source code, pass `version-file` and `version-pattern`: ```yaml -- uses: git.hrafn.xyz/aether/vociferate/prepare@v1.0.2 +- uses: https://git.hrafn.xyz/aether/vociferate/prepare@v1.0.2 with: version-file: internal/myapp/version/version.go version-pattern: 'const Version = "([^"]+)"' @@ -85,7 +85,7 @@ on: jobs: release: - uses: aether/vociferate/.gitea/workflows/do-release.yml@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/.gitea/workflows/do-release.yml@v1.0.2 with: tag: ${{ inputs.tag }} secrets: inherit @@ -105,7 +105,7 @@ assets after it runs: ```yaml - id: publish - uses: git.hrafn.xyz/aether/vociferate/publish@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/publish@v1.0.2 - name: Upload my binary run: | @@ -125,7 +125,7 @@ Run your coverage tests first, then call the action to generate `coverage.html`, run: go test -covermode=atomic -coverprofile=coverage.out ./... - id: coverage - uses: git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2 with: artefact-bucket-name: ${{ vars.ARTEFACT_BUCKET_NAME }} artefact-bucket-endpoint: ${{ vars.ARTEFACT_BUCKET_ENDPONT }} @@ -150,14 +150,14 @@ with a clear message when token permissions are insufficient. run: go test -covermode=atomic -coverprofile=coverage.out ./... - id: coverage - uses: git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2 with: artefact-bucket-name: ${{ vars.ARTEFACT_BUCKET_NAME }} artefact-bucket-endpoint: ${{ vars.ARTEFACT_BUCKET_ENDPONT }} - name: Decorate pull request if: github.event_name == 'pull_request' - uses: git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2 with: coverage-percentage: ${{ steps.coverage.outputs.total }} badge-url: ${{ steps.coverage.outputs.badge-url }} @@ -170,7 +170,7 @@ Enable changelog validation to enforce that code changes include `Unreleased` ch ```yaml - name: Decorate pull request with changelog gate if: github.event_name == 'pull_request' - uses: git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2 with: coverage-percentage: ${{ steps.coverage.outputs.total }} badge-url: ${{ steps.coverage.outputs.badge-url }} @@ -196,7 +196,7 @@ Decision outputs enable downstream workflow logic: - name: Decorate PR and check gate id: decorate if: github.event_name == 'pull_request' - uses: git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2 + uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2 with: coverage-percentage: ${{ steps.coverage.outputs.total }} badge-url: ${{ steps.coverage.outputs.badge-url }}