Anca's plotting-book app now builds its image in her own GitHub repo to
the private package ghcr.io/passionprojectsanca/book-plotter (off public
DockerHub viktorbarzin/book-plotter). Wire the cluster to pull it:
- stacks/plotting-book: point the deployment baseline image at the ghcr
package and add imagePullSecrets {ghcr-credentials} so the pod can pull
the private image (the live tag is still CI-owned via ignore_changes).
- stacks/kyverno: add the plotting-book namespace to the ghcr-credentials
allowlist so the Kyverno generate policy clones the pull secret into it.
Verified the shared ghcr_pull_token (Viktor, repo-admin on Anca's repo)
can read the private package before wiring this.
Docs: correct ci-cd.md (it wrongly listed plotting-book as already on
ghcr — it was on DockerHub) and note the special arrangement; amend
ADR-0003 to record that this GitHub-first repo builds to its own org's
ghcr namespace.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.1 KiB
Keep Forgejo as the canonical forge; complete the one-way GitHub mirror instead of swapping to GitHub
Status: accepted (extends ADR-0002)
Context
Repo trees kept diverging between the Forgejo Canonical repo (viktor/<name>) and its GitHub mirror. A 2026-06-15 audit found the cause: an incomplete rollout of the Forgejo→GitHub push-mirror, not anything inherent to Forgejo. 14 repos carry both remotes and are hand-pushed to each (push_mirrors = 0 on Forgejo — e.g. infra, finance, Website), so a human forgets one side and the trees drift; the ADR-0002-onboarded repos have a working one-way mirror (push_mirrors = 1 — e.g. tripit, recruiter-responder) and never diverge. infra/CONTEXT.md already says Forgejo is the only place commits land and the GitHub mirror must never be a second writable remote — practice had simply drifted from the documented model.
The trigger was a proposal to swap Forgejo out for GitHub entirely. The grilling reframed it: the pain (divergence) is a "two writable remotes" problem, and the stated preference is self-hosted-primary with the remote as backup.
Decision
Do not swap to GitHub. Reaffirm and complete the model already in CONTEXT.md:
- Every first-party repo has exactly one push target — its Canonical repo on Forgejo. GitHub is a one-way push-mirror (off-site backup + the source GitHub Actions builds from). No repo is ever dual-pushed.
- A small, explicit set of GitHub-first repos are the exception (canonical lives on GitHub, outside the mirror policy): third-party clones/forks where GitHub is genuinely upstream (
jsoncrack.com,snmp_exporter,SparkyFitness,agent-rules-books,Plotting-Your-Dream-Book) and the deliberately-public first-partyhealth.Plotting-Your-Dream-Book(owned by Anca, dev in her org) keeps its GHA build in-place and pushes the image to its own org's ghcr (ghcr.io/passionprojectsanca/book-plotter, private) via the workflow's built-inGITHUB_TOKEN— no Forgejo mirror, noviktorbarzin-namespace push, no shared PAT in her repo (2026-06-27, migrated off DockerHub). infrais reconciled into the standard model: its GitHub-only.github/workflows/build-*.ymlare brought onto Forgejo-canonical (inert on Forgejo, active on the mirror), then the mirror is enabled — ending the deliberate divergence while keeping Woodpecker on the Forgejo forge.- Enforcement is structural: reconciled clones keep only the Forgejo remote, so there is no GitHub remote to habitually push to; the execution rule is "push to the canonical forge only, never the mirror."
Considered options
- Swap to GitHub (retire Forgejo). Rejected: takes on a hard WAN dependency for all git ops — including
infra, the repo you use to recover from outages — plus git-crypt secrets on GitHub as primary, a Woodpecker forge migration (WP authenticates against and watches Forgejo), and GitHub private-repo CI-minute/size limits. All to fix a problem that is actually an incomplete mirror, not Forgejo's existence. Contradicts the self-hosted-primary preference. - GitHub canonical, Forgejo demoted to a DR pull-mirror. Rejected for the same WAN-dependency and forge-migration cost; unnecessary once the real cause is understood.
Consequences
- Divergence becomes structurally impossible — one push target per repo.
- Forgejo stays load-bearing (canonical git + the Woodpecker forge), so every cost of the swap is avoided.
- The GitHub-limits worry is neutralized: private code lives on Forgejo (unlimited, self-hosted); GitHub holds mirrors for CI + backup. (GitHub Free has unlimited private repos anyway; the real limits are GHA minutes and ~1 GB repo size —
travel_blogat 1.4 GB is why it never went to GHA.) - One-time remediation is required and carries a data-loss footgun: the Forgejo→GitHub mirror force-overwrites GitHub, so for each currently-diverged repo, any GitHub-only commits must be merged into Forgejo before the mirror is enabled, or they are lost. Scope: the 14 dual-push repos + the
infrareconciliation; all other repos are already single-remote and non-diverging.