ci: one workflow graph, so nothing publishes on red; add govulncheck and npm audit (M462 #4984)
release / govulncheck (push) Failing after 2s
release / go (push) Successful in 1m49s
release / web (push) Successful in 1m8s
release / integration (push) Successful in 4m39s
release / android (push) Successful in 5m45s
release / Build signed APK (releases and dev) (push) Successful in 5m58s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
release / govulncheck (push) Failing after 2s
release / go (push) Successful in 1m49s
release / web (push) Successful in 1m8s
release / integration (push) Successful in 4m39s
release / android (push) Successful in 5m45s
release / Build signed APK (releases and dev) (push) Successful in 5m58s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
test-go, test-web and android were separate workflows on the same push as release.yml, so the image build could not see their verdict: :dev meant "it built", never "it passed". All lanes now live in release.yml, and both publishing jobs (image-release and the new release-assets) need every lane and require `result == 'success'` from each by name, so a skipped lane blocks the publish just as a failed one does (rule 177). - New lanes: govulncheck (in golang:1.26-bookworm, the builder's image, so it checks the stdlib that ships) and `npm audit --omit=dev` in web. - Attaching the APK to a Release moved out of android-release into release-assets, behind the gate; the APK still builds in parallel. - `docker buildx build --pull`, so floating base tags can't serve a stale Go patch release from the runner's cache. - Integration wait uses `pg_isready` via docker exec: the old /dev/tcp probe never connects under dash (rule 81) and burned two minutes a run. - workflow_dispatch input force_red fails the go lane on purpose, to watch the gate refuse. - release_gate_test.go pins the gate: every job must be classified, and every publisher must need and require success from every lane. Lanes have no path filters any more; a web-only push runs the Go suite too, because "not run" must never read as "passed". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+9
-8
@@ -12,8 +12,9 @@ git.fabledsword.com/bvandeusen/ci-go:1.26
|
||||
git.fabledsword.com/bvandeusen/ci-android:36
|
||||
```
|
||||
|
||||
- `ci-go:1.26` — Go server tests (`.gitea/workflows/test-go.yml`), web SPA tests (`.gitea/workflows/test-web.yml`), and the release container build (`release.yml`'s `image-release` job).
|
||||
- `ci-android:36` — native Kotlin/Compose client: ktlint + detekt + unit tests + debug APK (`.gitea/workflows/android.yml`), and the signed release APK (`release.yml`'s `android-release` job).
|
||||
- `ci-go:1.26` — the `go`, `integration` and `web` lanes, `release-assets`, and the container build (`image-release`). All CI lives in one workflow, `.gitea/workflows/release.yml`, so every publishing job can depend on every lane (rule 177).
|
||||
- `golang:1.26-bookworm` (Docker Hub) — the `govulncheck` lane. Deliberately the same image as the Dockerfile's builder stage rather than `ci-go`, so the standard library it checks is the one in the shipped binary. Keep the two in step.
|
||||
- `ci-android:36` — native Kotlin/Compose client: ktlint + detekt + unit tests + debug APK (the `android` lane), and the signed release APK (`android-release`).
|
||||
|
||||
**`ci-flutter` is no longer consumed, and `ci-flutter` can now be retired.**
|
||||
The M8 rewrite replaced the Flutter client with the native Android app and
|
||||
@@ -30,9 +31,9 @@ split below. The label is a scheduling handle, not a toolchain assertion.
|
||||
|
||||
### From `ci-go:1.26`
|
||||
- **Go** (1.26 toolchain) — `go vet`, `go test -race`, `go build`, `go mod`.
|
||||
- **Node + npm** — `npm ci` and `npm test` / `npm run check` in `test-web.yml`.
|
||||
- **golangci-lint** — lint pass in `test-go.yml`.
|
||||
- **docker CLI** — bridge-IP discovery of the per-job Postgres service container in `test-go.yml` integration job (via the runner's shared `/var/run/docker.sock`).
|
||||
- **Node + npm** — `npm ci`, `npm audit`, `npm test` and `npm run check` in the `web` lane.
|
||||
- **golangci-lint** — lint pass in the `go` lane.
|
||||
- **docker CLI** — bridge-IP discovery of the per-job Postgres service container in the `integration` lane (via the runner's shared `/var/run/docker.sock`).
|
||||
- **docker buildx** — release container build + push in `release.yml`.
|
||||
- **curl** — release-asset polling / upload in `release.yml`.
|
||||
|
||||
@@ -45,7 +46,7 @@ split below. The label is a scheduling handle, not a toolchain assertion.
|
||||
No NDK: the native client has no C/C++ sources (this is why it isn't on
|
||||
`ci-flutter`).
|
||||
- **ktlint + detekt** — `./gradlew ktlintCheck` and `./gradlew detekt` in
|
||||
`android.yml`. Image pins track `android/gradle/libs.versions.toml` so local
|
||||
the `android` lane. Image pins track `android/gradle/libs.versions.toml` so local
|
||||
and CI checks agree.
|
||||
- **git** — `actions/checkout@v4` baseline (and any shell git operations).
|
||||
- **base64 + curl** — keystore decode + release-asset upload in `release.yml`'s
|
||||
@@ -58,10 +59,10 @@ None.
|
||||
## Notes
|
||||
|
||||
- **Label/image split.** Workflows keep `runs-on: go-ci` / `runs-on: flutter-ci` as the scheduling label per the [`ci-runners.md`](https://…/FabledRulebook/ci-runners.md) "label = scheduling handle, image = `container.image`" pattern. The labels are intentional handles, not toolchain assertions — which is why the Android jobs still schedule on `flutter-ci` while pulling `ci-android:36`. Switch them to `android-ci` if that runner label is ever registered; nothing breaks either way.
|
||||
- **Integration-job docker-socket dependency.** `test-go.yml`'s integration job uses the runner's shared docker socket (`/var/run/docker.sock`) to bridge-IP-discover the per-job Postgres service container by name + network intersection — the dev compose's `minstrel-postgres-*` containers are explicitly skipped as belt-and-suspenders. Depends on `act_runner.valid_volumes` whitelisting the socket; if that ever stops auto-mounting, integration tests fail at the `docker inspect` step.
|
||||
- **Integration-job docker-socket dependency.** The `integration` lane uses the runner's shared docker socket (`/var/run/docker.sock`) to bridge-IP-discover the per-job Postgres service container by name + network intersection — the dev compose's `minstrel-postgres-*` containers are explicitly skipped as belt-and-suspenders. Depends on `act_runner.valid_volumes` whitelisting the socket; if that ever stops auto-mounting, integration tests fail at the `docker inspect` step.
|
||||
- **Go toolchain pin.** `go.mod` is on `go 1.25.0` because `golang.org/x/crypto v0.51.0` declares 1.25 as its minimum. `ci-go:1.26` satisfies this with headroom. Future `x/crypto` bumps that move the Go floor should be paired with an image-tag bump in this file + the workflows.
|
||||
- **In-app update channel — `needs:`, not polling.** `release.yml`'s `image-release` job declares `needs: [android-release]`, so on tag pushes the signed APK is guaranteed present before the image build starts — no polling window, no race. (The old cross-workflow polling against `flutter.yml` is gone with that workflow.) On non-tag `main` pushes `android-release` is skipped and `image-release` instead pulls the most recent release's APK and reconstructs its exact `versionName`, so `:latest` never ships without an update channel. It degrades to an empty `client/` — never a wrong version — if no release, asset, or tag commit-count can be resolved.
|
||||
- **Cache server reachability.** `test-web.yml` does NOT use `cache: 'npm'` on `actions/setup-node` — the Gitea Actions cache server isn't reachable from this runner's container network and `setup-node` was burning ~4m41s on ETIMEDOUT before failing open. With the migration to `ci-go:1.26`, `setup-node` is removed entirely (Node is in the image). The cache concern reappears if a future change re-introduces a network-dependent action.
|
||||
- **Cache server reachability.** The `web` lane does NOT use `cache: 'npm'` on `actions/setup-node` — the Gitea Actions cache server isn't reachable from this runner's container network and `setup-node` was burning ~4m41s on ETIMEDOUT before failing open. With the migration to `ci-go:1.26`, `setup-node` is removed entirely (Node is in the image). The cache concern reappears if a future change re-introduces a network-dependent action.
|
||||
- **Artifacts — stock `actions/upload-artifact@v7` and `actions/download-artifact@v8`; never `@v3`.**
|
||||
```yaml
|
||||
uses: actions/upload-artifact@v7
|
||||
|
||||
Reference in New Issue
Block a user