CI for custom-app releases (Gitea Actions runner vs Woodpecker) — decision + tracking #30

Open
opened 2026-10-26 03:51:52 +00:00 by inference-bot · 0 comments
Owner

What this is

A tracking issue for the one infrastructure step we deferred tonight (2026-10-26): standing up CI so that builds and releases stop depending on the steward agent. Related context in #17 (agent on co-op infra).

Tonight's session closed a chunk of this: the LibreChat per-member key seed moved inside the chat app (co-op/librechat-custom #1, shipped as image 20261026-13f2b3a), the release flow is documented and reproducible as ./release.sh in that repo, and the appstore pin was bumped to 1.4.5 (20261026-60ee597). Both releases were built remotely and deployed with verification. What remains: the build credential still lives on the agent host, and releases still need either the agent or a human holding that credential.

What already exists (no new purchases needed)

  • Gitea Actions is enabled on git.inference.coop (Gitea 28.2.0): the engine, runs UI, and org/repo secrets are built in. What's missing is a runner — a small stateless binary that registers with the org (registration token mints via the API in one call) and executes jobs. No runner exists yet.
  • The registry app (registry.inference.coop) runs builds remotely on its own BuildKit. A CI layer needs no docker anywhere — just the cloudron CLI plus two credentials (CLOUDRON_TOKEN, a registry app password). The librechat-custom repo's ./release.sh already encodes the whole flow (build → pin → deploy → verify) and survived two real releases tonight.
  • Woodpecker CI is in the Cloudron appstore (org.woodpecker_ci.cloudronapp 3.19.0) — I checked, assuming it wasn't.

The decision: two viable routes

Route A — Gitea Actions + act_runner (est. 2–3 h, incl. debugging)

  • Workflows live in each app's repo (.gitea/workflows/), so the release path is readable by any member next to the code it ships. Runs and logs live in Gitea next to the PRs.
  • Runner is a single binary in shell mode; needs custom Cloudron packaging (~a 30-line Dockerfile + manifest) since nothing packages it.
  • Org secrets hold the two credentials — moving them off the agent host entirely.
  • YAML dialect is the GitHub one most people already know.

Route B — Woodpecker CI from the appstore (est. 1–1.5 h, mostly config)

  • Install from the store, wire to Gitea via OAuth app + webhook, put the credentials in its secret store, add .woodpecker/ pipelines that call the same ./release.sh.
  • Costs a second always-on service with its own update cadence and YAML dialect, and its agents conventionally want docker for step isolation — an open question on Cloudron.

Both routes end in the same architecture: builds on merge, deploys deliberate (manual dispatch), the registry credential held by CI instead of by the agent or a person.

Why the agent shouldn't hold the build credential long-term

The interim state is acceptable — the token is scoped to the registry app only, stored in a 0600 file, and minted deliberately — but it's a credential that lets its holder push images, sitting on a host whose long-term role (per #17) is reporting and conversation, not infrastructure mutation. Once CI holds it, the agent-side copy gets revoked and the agent's routine powers shrink another notch.

Open decisions

  1. Route — my lean is A: one fewer service, the workflow format travels, and the release record lives in Gitea next to the code. B is right if we want it running tonight with the least custom code.
  2. Where the runner runs — recommended: its own tiny Cloudron app (disposable, backed up, off the agent VM). The agent VM is the one place I'd not put it: shell-mode runners execute workflow steps locally, and workflow files are just files in repos.
  3. Which app onboards first — chat is done (it was the test case). Suggest the portal next, since it changes most often; the others are mechanical after that.
  4. Who presses deploy — recommend manual dispatch (build automatic, deploy deliberate). A scheduled/auto-deploy is a later, separate decision.

Interim state (safe to sit here)

./release.sh is human-runnable from any host with the registry credential; the current pinned images are verified (20261026-60ee597 on base 1.4.5, with 20261026-13f2b3a and 20261023-65a38bb as rollback tags). The credential is rotated-revocable in one place. Nothing is blocked waiting on this issue — but the longer we wait, the more releases run through the interim path.

## What this is A tracking issue for the one infrastructure step we deferred tonight (2026-10-26): standing up CI so that **builds and releases stop depending on the steward agent**. Related context in #17 (agent on co-op infra). Tonight's session closed a chunk of this: the LibreChat per-member key seed moved **inside the chat app** (co-op/librechat-custom #1, shipped as image `20261026-13f2b3a`), the release flow is documented and reproducible as `./release.sh` in that repo, and the appstore pin was bumped to 1.4.5 (`20261026-60ee597`). Both releases were built remotely and deployed with verification. What remains: the *build credential* still lives on the agent host, and releases still need either the agent or a human holding that credential. ## What already exists (no new purchases needed) - **Gitea Actions is enabled** on git.inference.coop (Gitea 28.2.0): the engine, runs UI, and org/repo secrets are built in. What's missing is a **runner** — a small stateless binary that registers with the org (registration token mints via the API in one call) and executes jobs. No runner exists yet. - **The registry app** (registry.inference.coop) runs builds remotely on its own BuildKit. A CI layer needs **no docker anywhere** — just the `cloudron` CLI plus two credentials (`CLOUDRON_TOKEN`, a registry app password). The librechat-custom repo's `./release.sh` already encodes the whole flow (build → pin → deploy → verify) and survived two real releases tonight. - **Woodpecker CI is in the Cloudron appstore** (`org.woodpecker_ci.cloudronapp` 3.19.0) — I checked, assuming it wasn't. ## The decision: two viable routes **Route A — Gitea Actions + act_runner** (est. 2–3 h, incl. debugging) - Workflows live in each app's repo (`.gitea/workflows/`), so the release path is readable by any member next to the code it ships. Runs and logs live in Gitea next to the PRs. - Runner is a single binary in shell mode; needs custom Cloudron packaging (~a 30-line Dockerfile + manifest) since nothing packages it. - Org secrets hold the two credentials — moving them off the agent host entirely. - YAML dialect is the GitHub one most people already know. **Route B — Woodpecker CI from the appstore** (est. 1–1.5 h, mostly config) - Install from the store, wire to Gitea via OAuth app + webhook, put the credentials in its secret store, add `.woodpecker/` pipelines that call the same `./release.sh`. - Costs a second always-on service with its own update cadence and YAML dialect, and its agents conventionally want docker for step isolation — an open question on Cloudron. Both routes end in the same architecture: **builds on merge, deploys deliberate (manual dispatch), the registry credential held by CI instead of by the agent or a person.** ## Why the agent shouldn't hold the build credential long-term The interim state is acceptable — the token is scoped to the registry app only, stored in a 0600 file, and minted deliberately — but it's a credential that lets its holder push images, sitting on a host whose long-term role (per #17) is reporting and conversation, not infrastructure mutation. Once CI holds it, the agent-side copy gets revoked and the agent's routine powers shrink another notch. ## Open decisions 1. **Route** — my lean is A: one fewer service, the workflow format travels, and the release record lives in Gitea next to the code. B is right if we want it running tonight with the least custom code. 2. **Where the runner runs** — recommended: its own tiny Cloudron app (disposable, backed up, off the agent VM). The agent VM is the one place I'd *not* put it: shell-mode runners execute workflow steps locally, and workflow files are just files in repos. 3. **Which app onboards first** — chat is done (it was the test case). Suggest the portal next, since it changes most often; the others are mechanical after that. 4. **Who presses deploy** — recommend manual dispatch (build automatic, deploy deliberate). A scheduled/auto-deploy is a later, separate decision. ## Interim state (safe to sit here) `./release.sh` is human-runnable from any host with the registry credential; the current pinned images are verified (`20261026-60ee597` on base 1.4.5, with `20261026-13f2b3a` and `20261023-65a38bb` as rollback tags). The credential is rotated-revocable in one place. Nothing is blocked waiting on this issue — but the longer we wait, the more releases run through the interim path.
inference-admin added the Infrastructure label 2026-11-09 16:24:09 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: co-op/support#30