# Forgejo Repo Migration Pilots (tier 1–2) Date: 2026-07-03 (tier 1), 2026-07-04 (tier 2) Workplan: `CUST-WP-0054-T04`, `RAIL-HO-WP-0005-T10` Pilots: `glas-harness` (tier 1), `key-cape` (tier 2) --- ## Tier 1 — glas-harness Pilot repo: `coulomb/glas-harness` (non-production tooling; safe routing drill) ## Why this repo | Criterion | glas-harness | | --- | --- | | Production dependency | None — harness meta-framework, not deployed | | Size / complexity | 3 commits, no container image, no submodules | | Blast radius | Low — wrong remote or CI failure does not break triage, State Hub, or emission | | State Hub registration | Not in active production sweep set | Use lessons here before migrating `state-hub` (high value, high risk). ## Pilot outcome (2026-07-03) | Step | Result | Notes | | --- | --- | --- | | Create repo on Forgejo | **pass** | `POST /api/v1/orgs/coulomb/repos` | | Mirror git history (HTTPS) | **pass** | `main` @ `e35e287` pushed with admin token | | SSH `forgejo-remote` push | **pass** | After adding `id_gitea.pub` to `forgejo_admin`; NodePort `92.205.62.239:30022` | | `origin` → Forgejo, `gitea` legacy remote | **pass** | `origin=forgejo-remote:…`, `gitea=gitea-remote:…` | | Actions `ci-smoke` (host + container) | **pass** | `host-smoke` (`self-hosted`) + `container-smoke` (`ubuntu-latest`) both `success` | | Gitea left intact | **pass** | No delete; Gitea still at `e35e287` until mirror sync policy defined | ## Routing that works ### Git remotes (workstation) Add to `~/.ssh/config` (see `FORGEJO-REMOTE` block): ```ssh Host forgejo-remote HostName 92.205.62.239 Port 30022 User git IdentityFile ~/.ssh/id_gitea StrictHostKeyChecking accept-new ``` Per-repo layout after cutover: ```bash git remote rename origin gitea # if still on Gitea git remote add origin forgejo-remote:coulomb/.git git push -u origin main ``` Canonical URL: `https://forgejo.coulomb.social/coulomb/.git` ### HTTPS fallback (automation / first push) Admin or user token with `write:repository`: ```bash git push "https://:@forgejo.coulomb.social/coulomb/.git" main ``` ### CI runner labels (railiance01-build-01) | Label | Works for | Evidence | | --- | --- | --- | | `self-hosted` | Host runner smoke | glas-harness `host-smoke` | | `ubuntu-latest` | Container step jobs | glas-harness `container-smoke` | | `container-build` | Docker build/push jobs | forgejo-actions-probe `image-build` | ### Registry / image CI (from prior probe) - Org secrets `REGISTRY_USER` / `REGISTRY_TOKEN` via `PUT /api/v1/orgs/coulomb/actions/secrets/{name}` with plaintext `data` (HTTPS API). - Host runner has **no** `docker` CLI and **cannot** `apk add` (non-root). Use **static docker binary** in the job step. - `actions/checkout@v4` **fails** on host runner — use `git clone` in the job until resolved. ## Routing that does not work yet | Gap | Impact | Mitigation for next repos | | --- | --- | --- | | ~~`tegwick` not on Forgejo~~ | **Resolved 2026-07-04** — `tegwick` admin user + `workstation-automation` SSH key; `forgejo-remote` greets `Hi there, tegwick!` | Add other operator keys before team cutover | | No automated Gitea→Forgejo mirror | Gitea copy drifts after Forgejo becomes canonical | Staged cutover: freeze Gitea pushes, one-way mirror, or retire Gitea remote after verification | | `actions/checkout@v4` on host runner | Breaks multi-step workflows that depend on checkout | `git clone` in `run:` step (see image-build probe) | | Issues/wiki/releases/LFS | Not exercised in pilot | Classify per repo in migration inventory before production repos | | State Hub `remote_url` field | Still points at `gitea-remote:…` for most repos | Update registration when repo is promoted (separate step; not done for glas-harness) | ## Repeatable procedure (non-production repo) 1. Confirm repo is **not** in a production drain wave or has explicit operator approval. 2. Create empty repo on Forgejo (`auto_init: false` if mirroring existing history). 3. Push all branches/tags from workstation clone (HTTPS or SSH). 4. Add `forgejo-remote` remote; rename Gitea remote to `gitea`; set `origin` to Forgejo. 5. Add `.forgejo/workflows/` smoke (and image workflow if applicable). 6. Verify Actions green on Forgejo runner. 7. Leave Gitea repo read-only; do not delete (safety contract). 8. Record results in this doc or a per-repo row in the migration inventory. ## Tier 2 — key-cape (2026-07-04) Pilot repo: `coulomb/key-cape` — non-production identity tooling with a real multi-stage `Dockerfile` (Go build + distroless). | Step | Result | Notes | | --- | --- | --- | | Mirror git to Forgejo | **pass** | `main` mirrored; `origin=forgejo-remote` | | Port `.gitea/workflows/image.yaml` → `.forgejo/workflows/image.yaml` | **pass** | Archive checkout + static docker-cli; no `actions/checkout` | | Build and push on `container-build` | **pass** | `build-and-push` workflow `success` @ `ec706da` | | k3s pull on railiance01 | **pass** | `sudo crictl pull forgejo.coulomb.social/coulomb/key-cape:latest` | Workflow pattern (tier 2+): ```yaml # Checkout: repo archive (no git binary required on non-root runner) wget -qO /tmp/repo.tar.gz "https://forgejo.coulomb.social/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz" tar xzf /tmp/repo.tar.gz -C buildctx --strip-components=1 # Build: static docker-cli + DOCKER_HOST=tcp://127.0.0.1:2375 ``` Image: `forgejo.coulomb.social/coulomb/key-cape:latest` ## Tier 2.5 — railiance stack (2026-07-04) Infra/platform repos promoted before tier-3 production set. Canonical remote is Forgejo; Gitea `gitea` remote retained for rollback mirror. | Repo | Forgejo | `origin` | CI workflow | Notes | | --- | --- | --- | --- | --- | | `railiance-enablement` | yes | `forgejo-remote` | `ci-smoke` + templates in `workflows/` | S4 canonical templates | | `railiance-infra` | yes | `forgejo-remote` | `ci-smoke` | | | `railiance-apps` | yes | `forgejo-remote` | `ci-smoke` | | | `railiance-platform` | yes | `forgejo-remote` | `ci-smoke` | Local uncommitted `Makefile`/helm edits not in promotion | | `railiance-cluster` | yes | `forgejo-remote` | `ci-smoke` | | Promotion helper: `railiance-enablement/tools/promote-repo-to-forgejo.sh` Template docs: `railiance-enablement/docs/forgejo-actions-workflow-templates.md` Operator SSH (2026-07-04): user `tegwick` on Forgejo (admin, `coulomb` Owners team); workstation key moved from `forgejo_admin` to `tegwick`. ## Not ready for state-hub yet Before `state-hub`, the ladder still needs: - [x] Operator/user SSH identity on Forgejo (`tegwick` + workstation key) - [x] Reusable workflow templates in `railiance-enablement` (incl. multi-repo / `hub-core` context template) - [ ] State Hub `remote_url` + sweep checkout path update playbook - [ ] Gitea read-only mirror or push-disable policy for repos after cutover - [ ] Scheduled Forgejo backups (disaster-control track; restore drill passed) ## References - `docs/forgejo-production-decisions.md` - `railiance-forge/docs/forgejo-actions-runner-substrate.md` - `railiance-apps/docs/forgejo-on-railiance01.md` - Tier 1: https://forgejo.coulomb.social/coulomb/glas-harness - Tier 2: https://forgejo.coulomb.social/coulomb/key-cape