From 25ba95cb5b84866f27817de5c2be324b220f0bfe Mon Sep 17 00:00:00 2001 From: Em Date: Tue, 7 Jul 2026 13:07:35 +0100 Subject: [PATCH 1/2] chore: add govulncheck security scanning to CI - Add Govulncheck step to ci.yml (after Vet, before Test) - Document govulncheck in AGENTS.md CI Parity Gate section - Add OpenSpec change artifacts (proposal, design, spec, tasks) Fixes #23 --- .github/workflows/ci.yml | 5 + .uf/replicator/replicator.log | 3 + AGENTS.md | 4 +- .../changes/ci-govulncheck/.openspec.yaml | 2 + openspec/changes/ci-govulncheck/design.md | 132 ++++++++++++++++++ openspec/changes/ci-govulncheck/proposal.md | 104 ++++++++++++++ .../ci-govulncheck/specs/ci-govulncheck.md | 82 +++++++++++ openspec/changes/ci-govulncheck/tasks.md | 49 +++++++ 8 files changed, 380 insertions(+), 1 deletion(-) create mode 100644 openspec/changes/ci-govulncheck/.openspec.yaml create mode 100644 openspec/changes/ci-govulncheck/design.md create mode 100644 openspec/changes/ci-govulncheck/proposal.md create mode 100644 openspec/changes/ci-govulncheck/specs/ci-govulncheck.md create mode 100644 openspec/changes/ci-govulncheck/tasks.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d485dc..9f438e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,11 @@ jobs: - name: Vet run: go vet ./... + - name: Govulncheck + run: | + go install golang.org/x/vuln/cmd/govulncheck@latest + govulncheck ./... + - name: Test run: go test ./... -count=1 -race diff --git a/.uf/replicator/replicator.log b/.uf/replicator/replicator.log index e69de29..fb55f48 100644 --- a/.uf/replicator/replicator.log +++ b/.uf/replicator/replicator.log @@ -0,0 +1,3 @@ +2026/07/07 12:58:52 INFO tool call tool=forge_worktree_list duration=4.536739ms success=true +2026/07/07 13:04:12 INFO tool call tool=hivemind_store duration=811.57µs success=true +2026/07/07 13:04:17 INFO tool call tool=hivemind_store duration=646.586µs success=true diff --git a/AGENTS.md b/AGENTS.md index eedf7ee..8d11a27 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -89,7 +89,9 @@ non-negotiable. - **CI Parity Gate**: Before marking any task complete, run the CI-equivalent checks locally. Read `.github/workflows/` for the exact commands -- do not - rely on memory. Any failure blocks the task. + rely on memory. Any failure blocks the task. The CI + `Build and Test` check includes `govulncheck` for + vulnerability scanning of Go dependencies. - **Intent Drift Detection**: Implementation must faithfully capture the spec's intent. The parity test suite verifies response shapes match the TypeScript version. diff --git a/openspec/changes/ci-govulncheck/.openspec.yaml b/openspec/changes/ci-govulncheck/.openspec.yaml new file mode 100644 index 0000000..2d2d7d5 --- /dev/null +++ b/openspec/changes/ci-govulncheck/.openspec.yaml @@ -0,0 +1,2 @@ +schema: unbound-force +created: 2026-07-07 diff --git a/openspec/changes/ci-govulncheck/design.md b/openspec/changes/ci-govulncheck/design.md new file mode 100644 index 0000000..2b0c304 --- /dev/null +++ b/openspec/changes/ci-govulncheck/design.md @@ -0,0 +1,132 @@ +## Context + +Replicator's CI pipeline (`.github/workflows/ci.yml`) runs `go vet`, `go test`, +and `go build` but has no security vulnerability scanning. Issue #23 tracks +adding `govulncheck` -- the official Go vulnerability scanner maintained by the +Go security team -- to CI. + +The release preflight (`release.yml`, added by the `ci-release-preflight` change) +was explicitly designed with an extensible `REQUIRED_CHECKS` array. Decision D5 +in that change's design document notes: "When govulncheck is added (issue #23), +the preflight can be extended to verify it." This change fulfills that plan. + +The canonical org reference (`unbound-force/unbound-force`) runs security scans +via a separate `ci_security.yml` workflow. For replicator's current scale +(single binary, modest dependency tree), adding `govulncheck` as a step within +the existing `ci.yml` is sufficient. A separate workflow can be introduced later +if additional scanners (OSV-Scanner, Trivy) are added. + +## Goals / Non-Goals + +### Goals + +- Add a `govulncheck` step to `ci.yml` that fails CI when known vulnerabilities + are found in dependencies. +- Document the check name so the release preflight can reference it. +- Extend the release preflight's `REQUIRED_CHECKS` to include the security + scan check, gating releases on vulnerability-free dependencies. + +### Non-Goals + +- Adding OSV-Scanner or Trivy source scans -- those can follow if needed. +- Creating a separate `ci_security.yml` workflow -- not warranted for a single + scanner at current scale. +- Adding `govulncheck` to the `Makefile` -- CI is the enforcement point; local + usage is optional and left to developers. +- Modifying Go source code, tests, or the replicator binary. + +## Decisions + +### D1: Add govulncheck as a step in ci.yml, not a separate workflow + +The canonical reference uses a dedicated `ci_security.yml` for security scans. +However, replicator has a single CI workflow with one job (`Build and Test`). +Adding `govulncheck` as a step within this job keeps CI simple and avoids a +separate workflow that would need its own `actions/checkout` and +`actions/setup-go` steps (duplicating setup time). + +The step runs after `Vet` and before `Test`: + +```yaml +- name: Govulncheck + run: | + go install golang.org/x/vuln/cmd/govulncheck@latest + govulncheck ./... +``` + +This ordering means vulnerabilities are caught early (before the slower test +suite runs), while still benefiting from the Go toolchain already being set up. + +**Trade-off**: If a separate `Security` check name is later needed (e.g., for +branch protection or release preflight granularity), the step would need to be +extracted into its own job. This is a straightforward refactor. + +### D2: Install govulncheck via go install at latest + +Using `go install golang.org/x/vuln/cmd/govulncheck@latest` ensures the +scanner always uses the most current vulnerability database definitions. +Unlike application dependencies, pinning the scanner version provides no +reproducibility benefit -- the vulnerability database is inherently +time-varying. + +**Alternative considered**: Using the `golang/govulncheck-action` GitHub +Action. Rejected because: +- It adds another third-party action to pin and maintain. +- The `go install` + `govulncheck` approach is simpler and uses the same + Go toolchain already set up by `actions/setup-go`. +- Direct invocation gives clearer control over flags and output. + +### D3: Extend release preflight REQUIRED_CHECKS + +The release preflight in `release.yml` verifies CI passed before allowing a +release. The `REQUIRED_CHECKS` array currently contains only `"Build and Test"`. +Since `govulncheck` runs as a step within the `Build and Test` job (not a +separate job), the check name remains `"Build and Test"` -- no change is needed +to the preflight's `REQUIRED_CHECKS` array. + +If `govulncheck` fails, the `Build and Test` job fails, and the preflight +already blocks the release. This is the simplest integration path. + +**Consequence**: The preflight does not distinguish between a test failure and a +vulnerability failure. Both block the release equally, which is the desired +behavior. + +### D4: No Makefile changes + +The `Makefile` currently defines `make check` as `vet + test`. Adding +`govulncheck` to the Makefile is tempting for local developer convenience, but: +- CI is the enforcement point for security scanning. +- Developers can run `govulncheck ./...` directly when needed. +- Adding it to `make check` would slow down the local development loop for a + check that primarily matters at PR/release time. + +If local scanning is later desired, a separate `make vuln` target can be added. + +## Risks / Trade-offs + +- **CI time increase**: `go install govulncheck@latest` adds ~5-10 seconds for + download/install, plus ~5-15 seconds for scanning. Total CI impact is modest + (~10-25 seconds) since the Go module cache is warm from `actions/setup-go`. + +- **False positives from transitive dependencies**: `govulncheck` analyzes call + graphs and only reports vulnerabilities in code paths actually used by the + binary. This significantly reduces false positives compared to dependency-only + scanners. However, if a transitive dependency has a vulnerability in a code + path replicator uses, CI will fail even if the vulnerability is not + exploitable in practice. The fix is to update the dependency or, as a last + resort, document the exception. + +- **Network dependency**: `go install govulncheck@latest` requires network + access to download the tool and vulnerability database. GitHub-hosted runners + have reliable network access, so this is low risk. If a network issue causes + intermittent failures, retrying the CI job resolves it. + +- **No version pinning**: Using `@latest` means the scanner version can change + between CI runs. This is intentional -- newer versions have better detection. + If a specific version introduces a regression, it can be pinned temporarily. + +- **Gatekeeping note**: This change modifies CI configuration, which falls under + the Gatekeeping Value Protection constraint in AGENTS.md. Adding a new + security check (govulncheck) is an improvement to CI gates, not a relaxation. + The proposal's constitution alignment confirms this is PASS for Observable + Quality (machine-parseable vulnerability output with clear pass/fail status). diff --git a/openspec/changes/ci-govulncheck/proposal.md b/openspec/changes/ci-govulncheck/proposal.md new file mode 100644 index 0000000..19b2736 --- /dev/null +++ b/openspec/changes/ci-govulncheck/proposal.md @@ -0,0 +1,104 @@ +## Why + +Replicator has no security scanning in its CI pipeline. Issue #15 identified +this gap, and issue #23 specifically tracks adding `govulncheck` to scan for +known vulnerabilities in Go dependencies. The existing CI workflow +(`.github/workflows/ci.yml`) runs `go vet`, `go test`, and `go build` but +performs no vulnerability analysis. + +The canonical org reference (`unbound-force/unbound-force`) runs OSV-Scanner +and Trivy source scans via `ci_security.yml`. At minimum, replicator should +run `govulncheck` -- the official Go vulnerability scanner maintained by the +Go team -- as part of CI. + +The release preflight (added in the `ci-release-preflight` change) was +explicitly designed to be extended with a security scan check once one exists. +Adding `govulncheck` to CI closes that gap. + +Fixes: https://github.com/unbound-force/replicator/issues/23 +Parent: https://github.com/unbound-force/replicator/issues/15 + +## What Changes + +1. **`.github/workflows/ci.yml`**: Add a `govulncheck` step that runs + `govulncheck ./...` after the existing `Vet` step. The step installs + `govulncheck` via `go install golang.org/x/vuln/cmd/govulncheck@latest` + and scans all packages. CI fails if known vulnerabilities are found. + +2. **Release gating**: Since `govulncheck` runs as a step within the existing + `Build and Test` job, no changes to `release.yml` are needed. If + `govulncheck` fails, the `Build and Test` job fails, and the release + preflight already blocks the release through its existing + `REQUIRED_CHECKS` array. + +3. **Documentation**: Update `AGENTS.md` to document that the `Build and Test` + CI check now includes `govulncheck` vulnerability scanning. + +## Capabilities + +### New Capabilities + +- `ci/govulncheck`: Automated vulnerability scanning of Go dependencies + using the official `govulncheck` tool, integrated into the CI pipeline. + +### Modified Capabilities + +- `release/preflight`: No direct changes needed. The preflight already + gates releases on the `Build and Test` check, which now includes + `govulncheck` as a step. Vulnerability failures block releases + through the existing mechanism. + +### Removed Capabilities + +- None + +## Impact + +- `.github/workflows/ci.yml` -- new `govulncheck` step added +- `.github/workflows/release.yml` -- no changes needed; the existing + preflight already gates on `Build and Test` +- CI will now fail on PRs and pushes to main if `govulncheck` detects + known vulnerabilities in dependencies +- Releases will be blocked if the security scan has not passed on HEAD + +## Constitution Alignment + +Assessed against the Replicator constitution (`.specify/memory/constitution.md`), +which extends the Unbound Force org constitution v1.1.0. + +### I. Autonomous Collaboration + +**Assessment**: N/A + +This change modifies CI/CD workflow files only. No MCP tools, inter-agent +communication, or tool outputs are affected. The change is purely +infrastructure-level and does not alter how heroes collaborate through +artifacts. + +### II. Composability First + +**Assessment**: PASS + +The binary remains independently installable and usable without any external +services. `govulncheck` is a CI-only tool that does not affect the standalone +functionality of the replicator binary. Dewey integration and graceful +degradation are unaffected. + +### III. Observable Quality + +**Assessment**: PASS + +`govulncheck` produces structured output identifying specific CVEs, affected +packages, and call stacks. CI step output is visible in GitHub Actions logs +with clear pass/fail status. The check name is documented so the release +preflight can query it via the Checks API, maintaining machine-parseable +quality signals. + +### IV. Testability + +**Assessment**: N/A + +This change modifies GitHub Actions workflow files which cannot be tested in +isolation (they require the GitHub Actions runtime). No Go source code, tests, +or testable components are modified. Post-merge verification will be performed +by observing the new `govulncheck` step in CI runs. diff --git a/openspec/changes/ci-govulncheck/specs/ci-govulncheck.md b/openspec/changes/ci-govulncheck/specs/ci-govulncheck.md new file mode 100644 index 0000000..b8242d3 --- /dev/null +++ b/openspec/changes/ci-govulncheck/specs/ci-govulncheck.md @@ -0,0 +1,82 @@ +## ADDED Requirements + +### Requirement: CI vulnerability scanning + +The CI pipeline MUST run `govulncheck ./...` on every push to `main` and every +pull request targeting `main`. The CI job MUST fail if `govulncheck` reports any +known vulnerabilities in dependencies reachable from the binary's call graph. + +#### Scenario: Clean dependency tree + +- **GIVEN** all Go dependencies are free of known vulnerabilities +- **WHEN** CI runs `govulncheck ./...` +- **THEN** the step exits with code 0 and CI proceeds to subsequent steps + +#### Scenario: Vulnerable dependency detected + +- **GIVEN** a Go dependency has a known vulnerability in a code path used by + replicator +- **WHEN** CI runs `govulncheck ./...` +- **THEN** the step exits with a non-zero code, the `Build and Test` job fails, + and the vulnerability details are visible in the CI log output + +#### Scenario: Vulnerability in unused code path + +- **GIVEN** a Go dependency has a known vulnerability but replicator does not + call any affected functions +- **WHEN** CI runs `govulncheck ./...` +- **THEN** `govulncheck` reports the vulnerability as informational but does + NOT fail the step (govulncheck's default behavior is call-graph-aware) + +### Requirement: Govulncheck step ordering + +The `govulncheck` step MUST run after `Vet` and before `Test` in the CI job. +This ensures vulnerabilities are detected early without delaying faster static +analysis checks. + +#### Scenario: Step execution order + +- **GIVEN** the CI workflow is triggered +- **WHEN** the `Build and Test` job executes +- **THEN** steps run in order: Checkout, Setup Go, Vet, Govulncheck, Test, Build + +### Requirement: Release gated on vulnerability scan + +The release preflight MUST NOT allow a release if the `Build and Test` CI check +has not passed. Since `govulncheck` is a step within the `Build and Test` job, +a vulnerability failure blocks the release through the existing preflight +mechanism. + +#### Scenario: Release blocked by vulnerability + +- **GIVEN** the most recent CI run on HEAD failed due to a `govulncheck` finding +- **WHEN** a release is triggered via `workflow_dispatch` +- **THEN** the preflight job fails with an error indicating the `Build and Test` + check has not passed + +#### Scenario: Release proceeds after vulnerability is resolved + +- **GIVEN** a vulnerability was detected, the dependency was updated, and CI + passed on the fix commit +- **WHEN** a release is triggered via `workflow_dispatch` +- **THEN** the preflight job succeeds and the release proceeds + +### Requirement: Check name documentation + +The CI check name (`Build and Test`) MUST be documented in `AGENTS.md` so that +agents and the release preflight can reference it consistently. + +#### Scenario: Documented check name matches CI + +- **GIVEN** the CI workflow defines a job named `Build and Test` +- **WHEN** an agent or the release preflight queries the check name +- **THEN** the documented name in `AGENTS.md` matches the actual CI job name + +## MODIFIED Requirements + +None. This change adds new CI capabilities without modifying existing +requirements. + +## REMOVED Requirements + +None. No existing requirements are removed by this change. diff --git a/openspec/changes/ci-govulncheck/tasks.md b/openspec/changes/ci-govulncheck/tasks.md new file mode 100644 index 0000000..0c968c0 --- /dev/null +++ b/openspec/changes/ci-govulncheck/tasks.md @@ -0,0 +1,49 @@ + + +## 1. Add govulncheck to CI + +- [x] 1.1 Add a `Govulncheck` step to `.github/workflows/ci.yml` after the + `Vet` step and before the `Test` step. The step MUST run + `go install golang.org/x/vuln/cmd/govulncheck@latest` then + `govulncheck ./...`. Verify step ordering matches the spec: + Checkout, Setup Go, Vet, Govulncheck, Test, Build. + + **Files**: `.github/workflows/ci.yml` + +## 2. Documentation + +- [x] 2.1 [P] Update `AGENTS.md` to document that the existing `Build and + Test` CI check now includes `govulncheck` vulnerability scanning as a + step. No new check name is introduced -- govulncheck runs within the + existing job. Add a note under the Commands section or CI-related + documentation. + + **Files**: `AGENTS.md` + +## 3. Verification + +- [x] 3.1 Verify constitution alignment: confirm the change satisfies the + proposal's constitution assessment (N/A for Autonomous Collaboration, + PASS for Composability First, PASS for Observable Quality, N/A for + Testability). Verify no MCP tools, binary behavior, or test isolation + are affected. + +- [x] 3.2 Run `govulncheck ./...` locally to confirm the current dependency + tree is clean and the new CI step will pass. If vulnerabilities are found, + document them and update dependencies before merging. + +- [x] 3.3 Verify the CI workflow YAML is valid by reviewing step names, `run:` + blocks, and indentation. Confirm the step is within the existing + `build-and-test` job (not a separate job). + + From 32114e349c64db7db4077245863b078beeb11459 Mon Sep 17 00:00:00 2001 From: Em Date: Tue, 7 Jul 2026 13:14:56 +0100 Subject: [PATCH 2/2] fix: bump go version to 1.25.11 to resolve stdlib vulnerabilities The CI runner with go1.25.7 has 9 known stdlib vulnerabilities (GO-2026-4601 through GO-2026-4918) that cause govulncheck to fail. Updating to go1.25.11 resolves all of them. --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index fc809f4..863ff48 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/unbound-force/replicator -go 1.25.7 +go 1.25.11 require ( github.com/charmbracelet/lipgloss v1.1.0