From cb81879d85858fcc2638a4ace81b46ca2b5d261a Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 17:36:53 +0000 Subject: [PATCH 1/7] docs: document the spec 013 gates and e2e jobs (T059, T060) Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: Claude --- docs/contributing.md | 25 +++++++++++++++++++++++++ specs/013-expand-test-coverage/tasks.md | 5 +++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index 406df1f52..a9fe6468b 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -61,6 +61,17 @@ Every job in every workflow must have: Documented exceptions with longer timeouts are the five e2e jobs (60 minutes each) and the image build in `publish-edge.yaml` (35 minutes). +### Security and drift gates + +These jobs block merging. Each one has a `hack/*_test.sh` self-test that proves it can fail. Fix the cause: never add an ignore file, a suppression comment or a looser threshold. + +- **`vuln (go)`** runs `hack/govulncheck-all.sh`, which runs govulncheck over every module in `go.work`. It fails when a module reaches a symbol with a known vulnerability. Bump the affected dependency (or the Go toolchain) in that module's `go.mod`, run `make tidy`, and commit both. +- **`vuln (images)`** runs `hack/trivy-scan-images.sh` over the built images. It fails on any HIGH or CRITICAL vulnerability that has a fix. Bump the base-image digest, or bump the Go or npm dependency the finding names in that image's module. +- **`workflow lint`** also runs hadolint over every tracked Dockerfile, failing on any warning (`.hadolint.yaml`). Fix the Dockerfile: pin `apk`/`apt` package versions, and set a `SHELL` with `-o pipefail` before any piped `RUN` step. +- **`dependency review`** runs on pull requests only. It fails when the PR adds a dependency with a HIGH or CRITICAL advisory. Pick a version without the advisory, or drop the dependency. +- **`codegen drift`** runs `make generate manifests` and `make tidy`, then fails if `git diff` is not empty. Run the same commands locally and commit what they change (CLAUDE.md rule 7). +- **`submodule freshness`** runs `hack/check-submodule-freshness.sh`. It fails when the `modules` or `website` pointer names a commit that is not on that repo's `main`. Merge the submodule PR first, then bump the pointer to the merged commit. + ## Testing Run the whole suite: @@ -123,6 +134,20 @@ the dev ingress-nginx manifest pinned in `deploy/kind/up.sh` to finish (its replica available). It only runs when `deploy/kind/**` or the CI workflow file itself changes. +The `optional-components` bucket (`TestOptionalComponents_Lifecycle`) owns its +cluster because it runs `helm upgrade`. It checks that the MCP server, the +audit-syslog bridge and the tunnel are absent by default, then enables them +and checks each one. Its fixtures are `test/e2e/fixtures/frps.yaml` and +`test/e2e/fixtures/syslog-sink.yaml`. + +The `e2e postgres / amd64 (kind)` job runs the API against PostgreSQL. It +boots the cluster with `./deploy/kind/e2e.sh up "$CLUSTER" e2e postgres`, +which applies `deploy/kind/postgres.yaml` and installs the chart with +`api.db.driver=postgres`. It then runs the `api-auth`, `api-roles` and +`api-rbac` buckets, restarting the API between them to reset the in-memory +login rate limiter. The frozen 001–012 upgrade path is covered separately by +`TestPostgres_MigrateFromFrozenBaseline` in the `api (postgres)` job. + ## AI-assisted development Much of this codebase is developed with AI coding assistants (Claude diff --git a/specs/013-expand-test-coverage/tasks.md b/specs/013-expand-test-coverage/tasks.md index 9c2136da6..9e2f5350b 100644 --- a/specs/013-expand-test-coverage/tasks.md +++ b/specs/013-expand-test-coverage/tasks.md @@ -394,8 +394,9 @@ description: "Task list for 013-expand-test-coverage" ## Phase 8: Polish & cross-cutting -- [ ] T059 [P] Update `docs/contributing.md`, under "CI and workflows", with one short paragraph per new gate: what fails it, and how to fix it without suppressing it. Update "E2E testing" for the `optional-components` bucket and the `e2e-postgres` job. CI's `make check-links` verifies the new anchors. -- [ ] T060 [P] Grep the full feature diff for forbidden directives: `git diff origin/master -- . ':!specs' | grep -nE "nolint|eslint-disable|@ts-ignore|hadolint ignore|trivyignore|allow-ghsas"` must print nothing (SC-006). +- [X] T059 [P] Update `docs/contributing.md`, under "CI and workflows", with one short paragraph per new gate: what fails it, and how to fix it without suppressing it. Update "E2E testing" for the `optional-components` bucket and the `e2e-postgres` job. CI's `make check-links` verifies the new anchors. +- [X] T060 [P] Grep the full feature diff for forbidden directives: `git diff origin/master -- . ':!specs' | grep -nE "nolint|eslint-disable|@ts-ignore|hadolint ignore|trivyignore|allow-ghsas"` must print nothing (SC-006). + Result (2026-10-16): the feature diff runs from before #671 to master after #707, excluding `specs/`. Its only added lines that match are prose in `.md` files (CLAUDE.md, agent and skill docs) telling contributors not to use these directives. No code, config or Dockerfile it adds contains one. - [ ] T061 Confirm `coverage-gaps.md` has no `open` or `in-progress` rows and that `make check-coverage-gaps` passes in CI. Then run `/speckit-analyze` on this folder. - [ ] T062 Once every PR above is merged and every task is checked or withdrawn, `git mv specs/013-expand-test-coverage specs/done_013-expand-test-coverage` and update every in-repo reference (including `hack/check-coverage-gaps.sh`'s default path) in one `docs:` commit (Constitution IV). From 0805c18023236b3dc58349e1d8ed2d65c1b0fd33 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 17:54:36 +0000 Subject: [PATCH 2/7] ci: print secrets_managed.go per-file coverage (spec 013 G-19) Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: Claude --- .github/workflows/ci.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2c256e20e..22ac236ae 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -871,6 +871,17 @@ jobs: fetch - name: merge profiles + threshold gate run: make cover-go-merge && make cover-go-check + - name: per-file coverage of secrets_managed.go (spec 013 G-19) + # The threshold gate checks package totals only. Print this one file's + # statement coverage from the merged profile so coverage-gaps.md can + # cite a measured figure. + if: matrix.module == 'api' && matrix.arch == 'amd64' + run: | + awk '$1 ~ /\/internal\/handlers\/secrets_managed\.go:/ { total += $2; if ($3 > 0) covered += $2 } + END { if (total == 0) { print "secrets_managed.go not found in profile"; exit 1 } + printf "secrets_managed.go: %d/%d statements covered (%.1f%%)\n", covered, total, 100 * covered / total }' \ + api/coverage/merged.out + (cd api && go tool cover -func=coverage/merged.out | grep -F 'internal/handlers/secrets_managed.go') web: name: web From 5fec342d79aa7023cf76f17756abcace2639e34f Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 18:49:34 +0000 Subject: [PATCH 3/7] docs(specs): close 013 G-19 with the measured per-file coverage Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: Claude --- .github/workflows/ci.yaml | 2 +- specs/013-expand-test-coverage/coverage-gaps.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 22ac236ae..970994123 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -879,7 +879,7 @@ jobs: run: | awk '$1 ~ /\/internal\/handlers\/secrets_managed\.go:/ { total += $2; if ($3 > 0) covered += $2 } END { if (total == 0) { print "secrets_managed.go not found in profile"; exit 1 } - printf "secrets_managed.go: %d/%d statements covered (%.1f%%)\n", covered, total, 100 * covered / total }' \ + printf "G-19 coverage of secrets_managed.go = %d/%d statements (%.1f%%)\n", covered, total, 100 * covered / total }' \ api/coverage/merged.out (cd api && go tool cover -func=coverage/merged.out | grep -F 'internal/handlers/secrets_managed.go') diff --git a/specs/013-expand-test-coverage/coverage-gaps.md b/specs/013-expand-test-coverage/coverage-gaps.md index 441cef81f..5b588c789 100644 --- a/specs/013-expand-test-coverage/coverage-gaps.md +++ b/specs/013-expand-test-coverage/coverage-gaps.md @@ -1,7 +1,7 @@ # Coverage Gap Record -**Summary**: 21/24 closed · 1 closed unproven · 1 in progress · 0 open · 1 unit-only by design -**Last updated**: 2026-10-15 +**Summary**: 22/24 closed · 1 closed unproven · 0 in progress · 0 open · 1 unit-only by design +**Last updated**: 2026-10-16 | ID | Category | Gap | Story | FR | Priority | Status | Evidence | Notes | |---|---|---|---|---|---|---|---|---| @@ -23,7 +23,7 @@ | G-16 | e2e-optional | tunnel (tailscale, playit) | US3 | FR-003 | P2 | unit-only-by-design | | Tailscale and playit need external accounts and network reachability that CI cannot provide; covered by unit tests only (research R7). | | G-17 | e2e-optional | telemetry receiver | US3 | FR-003 | P2 | closed | `TestTelemetryLifecycle` in bucket `telemetry` (job `e2e telemetry`), spec 022: https://github.com/GameplanePanel/Gameplane/blob/master/test/e2e/telemetry_e2e_test.go | | | G-18 | e2e-optional | disabled state + no interference | US3 | FR-003 | P2 | closed | `e2e optional-components / amd64 (kind)` and `/ arm64 (kind)` https://github.com/GameplanePanel/Gameplane/actions/runs/38789759814 | `disabled` and `core-unaffected` subtests on #704: no MCP, bridge or tunnel Deployments or Services before enabling; afterward a GameServer reaches Running with a heartbeat and a viewer gets 403 on `/admin/audit`. | -| G-19 | unit | `secrets_managed.go` 100 % | US4 | FR-004 | P2 | in-progress | | `secrets_managed_test.go` added in https://github.com/GameplanePanel/Gameplane/pull/677; CI publishes only package totals, so the per-file figure is not yet measured. The `json.Marshal` error branch in `upsertLabelledSecret` is unreachable. | +| G-19 | unit | `secrets_managed.go` 100 % | US4 | FR-004 | P2 | closed | `go (api / amd64)` step "per-file coverage of secrets_managed.go" https://github.com/GameplanePanel/Gameplane/actions/runs/38943306694/job/117117194910 | Measured on #710: 27/28 statements (96.4 %); `deleteManagedSecret` 100 %, `upsertLabelledSecret` 95.5 %. The one uncovered statement is the unreachable `json.Marshal` error branch in `upsertLabelledSecret`, so this is the highest reachable figure (tests from #677). | | G-20 | unit | `ConsoleShell.test.tsx` ≥ 80 % lines | US4 | FR-004 | P2 | closed | `web` https://github.com/GameplanePanel/Gameplane/actions/runs/38189418314 | `ConsoleShell.tsx` 100 % lines, 95 % branches (lcov from https://github.com/GameplanePanel/Gameplane/pull/677). | | G-21 | unit | `CloneServerDialog` ≥ 80 % lines + cancel/error | US4 | FR-004 | P2 | closed | `web` https://github.com/GameplanePanel/Gameplane/actions/runs/38189418314 | 89.29 % lines before T053; T053 adds API-error (409, 403, other status, non-API) and cancel-discards-changes cases in https://github.com/GameplanePanel/Gameplane/pull/677. | | G-22 | unit | `ServerActionsMenu` ≥ 80 % lines + cancel/error | US4 | FR-004 | P2 | closed | `web` https://github.com/GameplanePanel/Gameplane/actions/runs/38189418314 | 100 % lines, branches and functions. The menu makes no API calls; cancel and API errors live in its dialogs, covered by their own tests (G-21 for clone). | From d3608c75fe8542a0cf67417be8fba0642b90c81b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 18:51:22 +0000 Subject: [PATCH 4/7] docs(specs): align 013 checkpoint and plan OD count with the G-19 result Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: Claude --- specs/013-expand-test-coverage/plan.md | 2 +- specs/013-expand-test-coverage/tasks.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/013-expand-test-coverage/plan.md b/specs/013-expand-test-coverage/plan.md index 58d69e472..d324b48ac 100644 --- a/specs/013-expand-test-coverage/plan.md +++ b/specs/013-expand-test-coverage/plan.md @@ -95,7 +95,7 @@ specs/013-expand-test-coverage/ ├── research.md # Phase 0 (R0 baseline + R1–R11 decisions) ├── data-model.md # Phase 1: gate, fixture, gap, record entities ├── quickstart.md # Phase 1: how to validate each story in CI -├── OPEN-DECISIONS.md # OD-1..OD-3, all ruled (rule 10) +├── OPEN-DECISIONS.md # OD-1..OD-5, all ruled (rule 10) ├── contracts/ │ ├── static-gates.md # per-gate trigger / failing condition / proof script contract │ ├── coverage-gap-record.md # coverage-gaps.md format + validator rules diff --git a/specs/013-expand-test-coverage/tasks.md b/specs/013-expand-test-coverage/tasks.md index 9e2f5350b..756ae324f 100644 --- a/specs/013-expand-test-coverage/tasks.md +++ b/specs/013-expand-test-coverage/tasks.md @@ -351,7 +351,7 @@ description: "Task list for 013-expand-test-coverage" *Implementation note (2026-10-12)*: lcov from run 38189418314: `CloneServerDialog.tsx` 89.29 % lines / 69.23 % branches, with a Cancel case but no API-error case, so T053 adds the API-error and cancel-discards-changes cases. `ServerActionsMenu.tsx` 100 % lines / branches / functions; it makes no API calls, so cancel and API errors are dialog-level (G-22 note). `ConsoleShell.tsx` 100 % lines. G-19 stays in progress: CI reports only package coverage for Go. -**Checkpoint**: SC-004 stays pending until G-19 has per-file proof for `secrets_managed.go` (G-20 to G-22 are proven). Module thresholds stay unchanged. +**Checkpoint**: G-19 to G-22 are proven. G-19 was measured in CI at 27/28 statements (96.4 %) for `secrets_managed.go`; the one miss is the unreachable `json.Marshal` error branch (valgul chose "Measure in CI", 2026-10-16). Module thresholds stay unchanged. --- From 5e6f23ed352ae9e50a6676c5d47147afeee56a8b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 19:02:49 +0000 Subject: [PATCH 5/7] fix: address CodeRabbit findings on spec 013 polish Qualify the gate self-test claim in contributing.md (dependency review has no fixture), print the uncovered secrets_managed.go blocks in CI, and drop the wrong json.Marshal attribution from G-19. Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: Claude --- .github/workflows/ci.yaml | 5 +++-- docs/contributing.md | 2 +- specs/013-expand-test-coverage/coverage-gaps.md | 2 +- specs/013-expand-test-coverage/tasks.md | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 970994123..582db3409 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -877,9 +877,10 @@ jobs: # cite a measured figure. if: matrix.module == 'api' && matrix.arch == 'amd64' run: | - awk '$1 ~ /\/internal\/handlers\/secrets_managed\.go:/ { total += $2; if ($3 > 0) covered += $2 } + awk '$1 ~ /\/internal\/handlers\/secrets_managed\.go:/ { total += $2; if ($3 > 0) covered += $2; else { split($1, pos, ":"); missed = missed " " pos[2] } } END { if (total == 0) { print "secrets_managed.go not found in profile"; exit 1 } - printf "G-19 coverage of secrets_managed.go = %d/%d statements (%.1f%%)\n", covered, total, 100 * covered / total }' \ + printf "G-19 coverage of secrets_managed.go = %d/%d statements (%.1f%%)\n", covered, total, 100 * covered / total + printf "G-19 uncovered blocks (startLine.col,endLine.col):%s\n", missed }' \ api/coverage/merged.out (cd api && go tool cover -func=coverage/merged.out | grep -F 'internal/handlers/secrets_managed.go') diff --git a/docs/contributing.md b/docs/contributing.md index a9fe6468b..02d4af518 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -63,7 +63,7 @@ Documented exceptions with longer timeouts are the five e2e jobs (60 minutes eac ### Security and drift gates -These jobs block merging. Each one has a `hack/*_test.sh` self-test that proves it can fail. Fix the cause: never add an ignore file, a suppression comment or a looser threshold. +These jobs block merging. Each gate with a fixture has a `hack/*_test.sh` self-test that proves it can fail; dependency review is validated by configuration review only. Fix the cause: never add an ignore file, a suppression comment or a looser threshold. - **`vuln (go)`** runs `hack/govulncheck-all.sh`, which runs govulncheck over every module in `go.work`. It fails when a module reaches a symbol with a known vulnerability. Bump the affected dependency (or the Go toolchain) in that module's `go.mod`, run `make tidy`, and commit both. - **`vuln (images)`** runs `hack/trivy-scan-images.sh` over the built images. It fails on any HIGH or CRITICAL vulnerability that has a fix. Bump the base-image digest, or bump the Go or npm dependency the finding names in that image's module. diff --git a/specs/013-expand-test-coverage/coverage-gaps.md b/specs/013-expand-test-coverage/coverage-gaps.md index 5b588c789..3ec9e061d 100644 --- a/specs/013-expand-test-coverage/coverage-gaps.md +++ b/specs/013-expand-test-coverage/coverage-gaps.md @@ -23,7 +23,7 @@ | G-16 | e2e-optional | tunnel (tailscale, playit) | US3 | FR-003 | P2 | unit-only-by-design | | Tailscale and playit need external accounts and network reachability that CI cannot provide; covered by unit tests only (research R7). | | G-17 | e2e-optional | telemetry receiver | US3 | FR-003 | P2 | closed | `TestTelemetryLifecycle` in bucket `telemetry` (job `e2e telemetry`), spec 022: https://github.com/GameplanePanel/Gameplane/blob/master/test/e2e/telemetry_e2e_test.go | | | G-18 | e2e-optional | disabled state + no interference | US3 | FR-003 | P2 | closed | `e2e optional-components / amd64 (kind)` and `/ arm64 (kind)` https://github.com/GameplanePanel/Gameplane/actions/runs/38789759814 | `disabled` and `core-unaffected` subtests on #704: no MCP, bridge or tunnel Deployments or Services before enabling; afterward a GameServer reaches Running with a heartbeat and a viewer gets 403 on `/admin/audit`. | -| G-19 | unit | `secrets_managed.go` 100 % | US4 | FR-004 | P2 | closed | `go (api / amd64)` step "per-file coverage of secrets_managed.go" https://github.com/GameplanePanel/Gameplane/actions/runs/38943306694/job/117117194910 | Measured on #710: 27/28 statements (96.4 %); `deleteManagedSecret` 100 %, `upsertLabelledSecret` 95.5 %. The one uncovered statement is the unreachable `json.Marshal` error branch in `upsertLabelledSecret`, so this is the highest reachable figure (tests from #677). | +| G-19 | unit | `secrets_managed.go` 100 % | US4 | FR-004 | P2 | closed | `go (api / amd64)` step "per-file coverage of secrets_managed.go" https://github.com/GameplanePanel/Gameplane/actions/runs/38943306694/job/117117194910 | Measured on #710: 27/28 statements (96.4 %); `deleteManagedSecret` 100 %, `upsertLabelledSecret` 95.5 %. The same step lists the uncovered block (tests from #677). | | G-20 | unit | `ConsoleShell.test.tsx` ≥ 80 % lines | US4 | FR-004 | P2 | closed | `web` https://github.com/GameplanePanel/Gameplane/actions/runs/38189418314 | `ConsoleShell.tsx` 100 % lines, 95 % branches (lcov from https://github.com/GameplanePanel/Gameplane/pull/677). | | G-21 | unit | `CloneServerDialog` ≥ 80 % lines + cancel/error | US4 | FR-004 | P2 | closed | `web` https://github.com/GameplanePanel/Gameplane/actions/runs/38189418314 | 89.29 % lines before T053; T053 adds API-error (409, 403, other status, non-API) and cancel-discards-changes cases in https://github.com/GameplanePanel/Gameplane/pull/677. | | G-22 | unit | `ServerActionsMenu` ≥ 80 % lines + cancel/error | US4 | FR-004 | P2 | closed | `web` https://github.com/GameplanePanel/Gameplane/actions/runs/38189418314 | 100 % lines, branches and functions. The menu makes no API calls; cancel and API errors live in its dialogs, covered by their own tests (G-21 for clone). | diff --git a/specs/013-expand-test-coverage/tasks.md b/specs/013-expand-test-coverage/tasks.md index 756ae324f..66e4926bd 100644 --- a/specs/013-expand-test-coverage/tasks.md +++ b/specs/013-expand-test-coverage/tasks.md @@ -351,7 +351,7 @@ description: "Task list for 013-expand-test-coverage" *Implementation note (2026-10-12)*: lcov from run 38189418314: `CloneServerDialog.tsx` 89.29 % lines / 69.23 % branches, with a Cancel case but no API-error case, so T053 adds the API-error and cancel-discards-changes cases. `ServerActionsMenu.tsx` 100 % lines / branches / functions; it makes no API calls, so cancel and API errors are dialog-level (G-22 note). `ConsoleShell.tsx` 100 % lines. G-19 stays in progress: CI reports only package coverage for Go. -**Checkpoint**: G-19 to G-22 are proven. G-19 was measured in CI at 27/28 statements (96.4 %) for `secrets_managed.go`; the one miss is the unreachable `json.Marshal` error branch (valgul chose "Measure in CI", 2026-10-16). Module thresholds stay unchanged. +**Checkpoint**: G-19 to G-22 are proven. G-19 was measured in CI at 27/28 statements (96.4 %) for `secrets_managed.go` (valgul chose "Measure in CI", 2026-10-16). Module thresholds stay unchanged. --- From 2eab1f3b589c705fc55d3dbcc1e7061a5e84e2e7 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 19:13:53 +0000 Subject: [PATCH 6/7] docs(specs): settle 013 SC-004 and T060 wording, tick T061 valgul amended SC-004 to 100 % of reachable statements and chose to exclude Markdown prose from the T060 directive grep. CI names the one uncovered secrets_managed.go block (lines 66-68), which cannot run. Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: Claude --- specs/013-expand-test-coverage/coverage-gaps.md | 2 +- specs/013-expand-test-coverage/spec.md | 4 +++- specs/013-expand-test-coverage/tasks.md | 9 +++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/specs/013-expand-test-coverage/coverage-gaps.md b/specs/013-expand-test-coverage/coverage-gaps.md index 3ec9e061d..99b2a91bd 100644 --- a/specs/013-expand-test-coverage/coverage-gaps.md +++ b/specs/013-expand-test-coverage/coverage-gaps.md @@ -23,7 +23,7 @@ | G-16 | e2e-optional | tunnel (tailscale, playit) | US3 | FR-003 | P2 | unit-only-by-design | | Tailscale and playit need external accounts and network reachability that CI cannot provide; covered by unit tests only (research R7). | | G-17 | e2e-optional | telemetry receiver | US3 | FR-003 | P2 | closed | `TestTelemetryLifecycle` in bucket `telemetry` (job `e2e telemetry`), spec 022: https://github.com/GameplanePanel/Gameplane/blob/master/test/e2e/telemetry_e2e_test.go | | | G-18 | e2e-optional | disabled state + no interference | US3 | FR-003 | P2 | closed | `e2e optional-components / amd64 (kind)` and `/ arm64 (kind)` https://github.com/GameplanePanel/Gameplane/actions/runs/38789759814 | `disabled` and `core-unaffected` subtests on #704: no MCP, bridge or tunnel Deployments or Services before enabling; afterward a GameServer reaches Running with a heartbeat and a viewer gets 403 on `/admin/audit`. | -| G-19 | unit | `secrets_managed.go` 100 % | US4 | FR-004 | P2 | closed | `go (api / amd64)` step "per-file coverage of secrets_managed.go" https://github.com/GameplanePanel/Gameplane/actions/runs/38943306694/job/117117194910 | Measured on #710: 27/28 statements (96.4 %); `deleteManagedSecret` 100 %, `upsertLabelledSecret` 95.5 %. The same step lists the uncovered block (tests from #677). | +| G-19 | unit | `secrets_managed.go` 100 % of reachable statements | US4 | FR-004 | P2 | closed | `go (api / amd64)` step "per-file coverage of secrets_managed.go" https://github.com/GameplanePanel/Gameplane/actions/runs/38951995010/job/117146106880 | Measured on #710: 27/28 statements (96.4 %); `deleteManagedSecret` 100 %, `upsertLabelledSecret` 95.5 %. The one uncovered block is lines 66–68, the `existing.Labels == nil` branch in `upsertLabelledSecret`. It cannot run: when `Labels` is nil, the feature-label check on line 62 has already returned. SC-004 was amended to 100 % of reachable statements (valgul, 2026-10-16). Tests from #677. | | G-20 | unit | `ConsoleShell.test.tsx` ≥ 80 % lines | US4 | FR-004 | P2 | closed | `web` https://github.com/GameplanePanel/Gameplane/actions/runs/38189418314 | `ConsoleShell.tsx` 100 % lines, 95 % branches (lcov from https://github.com/GameplanePanel/Gameplane/pull/677). | | G-21 | unit | `CloneServerDialog` ≥ 80 % lines + cancel/error | US4 | FR-004 | P2 | closed | `web` https://github.com/GameplanePanel/Gameplane/actions/runs/38189418314 | 89.29 % lines before T053; T053 adds API-error (409, 403, other status, non-API) and cancel-discards-changes cases in https://github.com/GameplanePanel/Gameplane/pull/677. | | G-22 | unit | `ServerActionsMenu` ≥ 80 % lines + cancel/error | US4 | FR-004 | P2 | closed | `web` https://github.com/GameplanePanel/Gameplane/actions/runs/38189418314 | 100 % lines, branches and functions. The menu makes no API calls; cancel and API errors live in its dialogs, covered by their own tests (G-21 for clone). | diff --git a/specs/013-expand-test-coverage/spec.md b/specs/013-expand-test-coverage/spec.md index 9dc6de4ad..141736a76 100644 --- a/specs/013-expand-test-coverage/spec.md +++ b/specs/013-expand-test-coverage/spec.md @@ -290,7 +290,9 @@ migrations and queries work identically. telemetry-receiver) have at least one E2E test in a CI bucket, and the test verifies the component's primary operation works correctly. - **SC-004**: api/internal/handlers/secrets_managed.go (92 lines, upsertLabelledSecret, - deleteManagedSecret) has 100% test coverage; web components ConsoleShell, + deleteManagedSecret) has 100% test coverage of reachable statements (the + `existing.Labels == nil` branch in upsertLabelledSecret cannot run, because the + feature-label check above it has already returned); web components ConsoleShell, CloneServerDialog, ServerActionsMenu each have a .test.tsx file with ≥ 80% line coverage. - **SC-005**: When the Postgres build tag is enabled, a named e2e bucket runs the same diff --git a/specs/013-expand-test-coverage/tasks.md b/specs/013-expand-test-coverage/tasks.md index 66e4926bd..aa7e05b33 100644 --- a/specs/013-expand-test-coverage/tasks.md +++ b/specs/013-expand-test-coverage/tasks.md @@ -351,7 +351,7 @@ description: "Task list for 013-expand-test-coverage" *Implementation note (2026-10-12)*: lcov from run 38189418314: `CloneServerDialog.tsx` 89.29 % lines / 69.23 % branches, with a Cancel case but no API-error case, so T053 adds the API-error and cancel-discards-changes cases. `ServerActionsMenu.tsx` 100 % lines / branches / functions; it makes no API calls, so cancel and API errors are dialog-level (G-22 note). `ConsoleShell.tsx` 100 % lines. G-19 stays in progress: CI reports only package coverage for Go. -**Checkpoint**: G-19 to G-22 are proven. G-19 was measured in CI at 27/28 statements (96.4 %) for `secrets_managed.go` (valgul chose "Measure in CI", 2026-10-16). Module thresholds stay unchanged. +**Checkpoint**: G-19 to G-22 are proven. G-19 was measured in CI at 27/28 statements (96.4 %) for `secrets_managed.go`, which is 100 % of its reachable statements: the one miss is the unreachable `existing.Labels == nil` branch (lines 66–68). valgul chose "Measure in CI" and amended SC-004 to match, 2026-10-16. Module thresholds stay unchanged. --- @@ -395,9 +395,10 @@ description: "Task list for 013-expand-test-coverage" ## Phase 8: Polish & cross-cutting - [X] T059 [P] Update `docs/contributing.md`, under "CI and workflows", with one short paragraph per new gate: what fails it, and how to fix it without suppressing it. Update "E2E testing" for the `optional-components` bucket and the `e2e-postgres` job. CI's `make check-links` verifies the new anchors. -- [X] T060 [P] Grep the full feature diff for forbidden directives: `git diff origin/master -- . ':!specs' | grep -nE "nolint|eslint-disable|@ts-ignore|hadolint ignore|trivyignore|allow-ghsas"` must print nothing (SC-006). - Result (2026-10-16): the feature diff runs from before #671 to master after #707, excluding `specs/`. Its only added lines that match are prose in `.md` files (CLAUDE.md, agent and skill docs) telling contributors not to use these directives. No code, config or Dockerfile it adds contains one. -- [ ] T061 Confirm `coverage-gaps.md` has no `open` or `in-progress` rows and that `make check-coverage-gaps` passes in CI. Then run `/speckit-analyze` on this folder. +- [X] T060 [P] Grep the full feature diff for forbidden directives: `git diff origin/master -- . ':!specs' ':!*.md' | grep -nE "nolint|eslint-disable|@ts-ignore|hadolint ignore|trivyignore|allow-ghsas"` must print nothing (SC-006). + Result (2026-10-16): over the feature diff, from before #671 to master after #707, the command prints nothing. Markdown is excluded (valgul, 2026-10-16) because its only matches are prose in CLAUDE.md and the agent and skill docs telling contributors not to use these directives; SC-006 covers in-source directives. +- [X] T061 Confirm `coverage-gaps.md` has no `open` or `in-progress` rows and that `make check-coverage-gaps` passes in CI. Then run `/speckit-analyze` on this folder. + Result (2026-10-16): no open or in-progress rows; `make check-coverage-gaps` passed in "docs and repository checks" on #710 (https://github.com/GameplanePanel/Gameplane/actions/runs/38951995010/job/117146106043). `/speckit-analyze` found 0 critical issues; its two medium findings (the tasks.md checkpoint and the plan.md decision count) are fixed on #710, and SC-004 was amended. - [ ] T062 Once every PR above is merged and every task is checked or withdrawn, `git mv specs/013-expand-test-coverage specs/done_013-expand-test-coverage` and update every in-repo reference (including `hack/check-coverage-gaps.sh`'s default path) in one `docs:` commit (Constitution IV). --- From 6bb0e754cfe5cc1b5de6d8afcd62c2386b3707e4 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 20:05:55 +0000 Subject: [PATCH 7/7] docs: address second CodeRabbit pass on spec 013 polish Describe the non-vulnerability failure modes of the vuln (go), vuln (images) and submodule freshness gates, and align the Phase 6 goal and independent test with SC-004's reachable-statement target. Co-Authored-By: Claude Opus 5.5 (1M context) Signed-off-by: Claude --- docs/contributing.md | 6 +++--- specs/013-expand-test-coverage/tasks.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index 02d4af518..edef1368a 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -65,12 +65,12 @@ Documented exceptions with longer timeouts are the five e2e jobs (60 minutes eac These jobs block merging. Each gate with a fixture has a `hack/*_test.sh` self-test that proves it can fail; dependency review is validated by configuration review only. Fix the cause: never add an ignore file, a suppression comment or a looser threshold. -- **`vuln (go)`** runs `hack/govulncheck-all.sh`, which runs govulncheck over every module in `go.work`. It fails when a module reaches a symbol with a known vulnerability. Bump the affected dependency (or the Go toolchain) in that module's `go.mod`, run `make tidy`, and commit both. -- **`vuln (images)`** runs `hack/trivy-scan-images.sh` over the built images. It fails on any HIGH or CRITICAL vulnerability that has a fix. Bump the base-image digest, or bump the Go or npm dependency the finding names in that image's module. +- **`vuln (go)`** runs `hack/govulncheck-all.sh`, which runs govulncheck over every module in `go.work`. It fails when a module reaches a symbol with a known vulnerability, and also when govulncheck itself hits a build or tool error. For a vulnerability, bump the affected dependency (or the Go toolchain) in that module's `go.mod`, run `make tidy`, and commit both. For any other error, fix the build or tool problem it reports. +- **`vuln (images)`** runs `hack/trivy-scan-images.sh` over the e2e images CI builds (`gameplane-test/:e2e` and `:e2e-postgres`). It fails on any HIGH or CRITICAL vulnerability that has a fix, and on a scan error. For a vulnerability, bump the base-image digest, or bump the Go or npm dependency the finding names in that image's module. For a scan error, fix what Trivy reports and re-run. - **`workflow lint`** also runs hadolint over every tracked Dockerfile, failing on any warning (`.hadolint.yaml`). Fix the Dockerfile: pin `apk`/`apt` package versions, and set a `SHELL` with `-o pipefail` before any piped `RUN` step. - **`dependency review`** runs on pull requests only. It fails when the PR adds a dependency with a HIGH or CRITICAL advisory. Pick a version without the advisory, or drop the dependency. - **`codegen drift`** runs `make generate manifests` and `make tidy`, then fails if `git diff` is not empty. Run the same commands locally and commit what they change (CLAUDE.md rule 7). -- **`submodule freshness`** runs `hack/check-submodule-freshness.sh`. It fails when the `modules` or `website` pointer names a commit that is not on that repo's `main`. Merge the submodule PR first, then bump the pointer to the merged commit. +- **`submodule freshness`** runs `hack/check-submodule-freshness.sh`. It fails when the `modules` or `website` pointer names a commit that is not on that repo's `main`, when a gitlink is missing, or when the script cannot fetch that repo's `main`. For a pointer that is not on `main`, merge the submodule PR first, then bump the pointer to the merged commit. Otherwise restore the gitlink, or fix the fetch error, and re-run. ## Testing diff --git a/specs/013-expand-test-coverage/tasks.md b/specs/013-expand-test-coverage/tasks.md index aa7e05b33..69dcf3f48 100644 --- a/specs/013-expand-test-coverage/tasks.md +++ b/specs/013-expand-test-coverage/tasks.md @@ -318,9 +318,9 @@ description: "Task list for 013-expand-test-coverage" ## Phase 6: User Story 4 – Unit coverage gaps (Priority: P2) -**Goal**: 100 % of `secrets_managed.go`, and ≥ 80 % lines for ConsoleShell, CloneServerDialog and ServerActionsMenu (research R8, SC-004). +**Goal**: 100 % of the reachable statements in `secrets_managed.go`, and ≥ 80 % lines for ConsoleShell, CloneServerDialog and ServerActionsMenu (research R8, SC-004). -**Independent Test**: the `go (api / amd64)` coverage artifact shows `secrets_managed.go` at 100 %, and the `web` job's lcov shows each of the three components at ≥ 80 % lines. +**Independent Test**: the `go (api / amd64)` step "per-file coverage of secrets_managed.go" shows every statement covered except the uncovered blocks it lists, and each of those is unreachable (on #710: 27/28, the one miss being the `existing.Labels == nil` branch at lines 66–68), and the `web` job's lcov shows each of the three components at ≥ 80 % lines. **PR**: `test: unit coverage for managed secrets and console shell`. Independent of every other phase.