ci: reserve runner for releases + push image/release over tailscale (not Cloudflare) #40

Merged
robocub merged 2 commits from ci/reserve-runner-for-releases into master 2026-06-23 22:33:17 +00:00
Collaborator

Two CI changes (both touch docker.yml):

1. Reserve the runner for releases

The image job no longer runs on every push to master — only on v* tags and workflow_dispatch (manual). Image tags by trigger: stable tag → :vX.Y.Z + :latest; prerelease (-rc) → :vX.Y.Z only; manual → :edge. So :latest tracks the latest stable release. The tag-only packages/release job is unchanged.

2. Push over tailscale, not Cloudflare (fixes the failing release build)

The Cloudflare-fronted nether.codes path was failing the registry blob push mid-upload (502 / connection reset), killing the image job and blocking the v0.2.2 release. The runner now pushes/pulls the image and uploads release assets over the tailnet at 100.64.0.13:3000, fully bypassing the edge. External users still docker pull nether.codes/dark/nether-voicebridge:... (Forgejo stores by owner/image regardless of push host; pulls through CF are fine).

Requires (runner side, done): 100.64.0.13:3000 in the runner Docker daemon's insecure-registries. buildkit also gets an inline http = true registry config (it runs in its own container and doesn't inherit the daemon setting).

Unblocks cutting v0.2.2.

🤖 Generated with Claude Code

Two CI changes (both touch `docker.yml`): ## 1. Reserve the runner for releases The `image` job no longer runs on every push to master — only on `v*` **tags** and **`workflow_dispatch`** (manual). Image tags by trigger: stable tag → `:vX.Y.Z` + `:latest`; prerelease (`-rc`) → `:vX.Y.Z` only; manual → `:edge`. So `:latest` tracks the latest **stable release**. The tag-only `packages`/release job is unchanged. ## 2. Push over tailscale, not Cloudflare (fixes the failing release build) The Cloudflare-fronted `nether.codes` path was failing the registry blob push mid-upload (`502` / connection reset), killing the image job and blocking the v0.2.2 release. The runner now pushes/pulls the image **and** uploads release assets over the tailnet at `100.64.0.13:3000`, fully bypassing the edge. External users still `docker pull nether.codes/dark/nether-voicebridge:...` (Forgejo stores by owner/image regardless of push host; pulls through CF are fine). **Requires (runner side, done):** `100.64.0.13:3000` in the runner Docker daemon's `insecure-registries`. buildkit also gets an inline `http = true` registry config (it runs in its own container and doesn't inherit the daemon setting). Unblocks cutting **v0.2.2**. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The single self-hosted runner is reserved for releases. The `image` job no longer
runs on every push to master — it runs on `v*` tags and `workflow_dispatch`.

Image tags by trigger:
- stable tag (v1.2.3)        -> :v1.2.3 and :latest
- prerelease tag (v1.2.3-rc1) -> :v1.2.3 only (don't move :latest to an rc)
- manual workflow_dispatch    -> :edge (ad-hoc build, not a release)

`:latest` now tracks the latest stable release instead of the latest master
commit — a safer default for `docker pull :latest` / docker-compose users (prod
runs the .deb binary, not the image). The tag-only packages/release job is
unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Cloudflare-fronted `nether.codes` path was failing the registry blob push
mid-upload (502 Bad Gateway / connection reset), which killed the image job and
blocked the release. Route the runner's registry push/pull and the release-asset
uploads over the tailnet at `100.64.0.13:3000` instead, fully bypassing the edge.

- workflow-level `env: REGISTRY: 100.64.0.13:3000`, used by both jobs' registry
  login, the image tags, the packages-job image pull, and the release API base.
- buildkit gets an inline `http = true` registry config (setup-buildx-action runs
  buildkit in its own container, which does NOT inherit the runner daemon's
  insecure-registries).

External users are unaffected: Forgejo stores the package by owner/image
regardless of push host, so `docker pull nether.codes/dark/nether-voicebridge:...`
still works (pulls through Cloudflare are fine — only the large chunked push was
fragile). Requires `100.64.0.13:3000` in the runner daemon's insecure-registries.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
robocub changed title from ci: build image on releases + manual dispatch only, not every master push to ci: reserve runner for releases + push image/release over tailscale (not Cloudflare) 2026-06-23 22:29:07 +00:00
robocub merged commit ab8ac72563 into master 2026-06-23 22:33:17 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dark/nether-voicebridge!40
No description provided.