Add Forgejo tier-3 remote_url and sweep playbook
Document State Hub PATCH procedure, sweep implications, railiance01 host_paths, state-hub image specifics, and rollback. Include batch patch helper; applied tier-2.5 remote_url updates in hub DB.
This commit is contained in:
@@ -149,7 +149,8 @@ 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
|
||||
- [x] State Hub `remote_url` + sweep checkout path update playbook —
|
||||
`docs/forgejo-tier3-remote-url-sweep-playbook.md` (execute per repo on promotion)
|
||||
- [ ] Gitea read-only mirror or push-disable policy for repos after cutover
|
||||
- [ ] Scheduled Forgejo backups (disaster-control track; restore drill passed)
|
||||
|
||||
|
||||
238
docs/forgejo-tier3-remote-url-sweep-playbook.md
Normal file
238
docs/forgejo-tier3-remote-url-sweep-playbook.md
Normal file
@@ -0,0 +1,238 @@
|
||||
# Forgejo Tier 3 — State Hub `remote_url` and Sweep Playbook
|
||||
|
||||
Date: 2026-07-04
|
||||
Workplans: `RAIL-HO-WP-0005-T10`, `RAIL-HO-WP-0005-T11`, `CUST-WP-0054-T04`, `CUST-WP-0054-T05`
|
||||
`no_secret_material_recorded: true`
|
||||
|
||||
## Purpose
|
||||
|
||||
Operational playbook for promoting a **registered** State Hub repo from Gitea
|
||||
(`gitea-remote`) to Forgejo (`forgejo-remote`) without breaking the consistency
|
||||
sweep, DoI checks, or agent attribution.
|
||||
|
||||
Applies to:
|
||||
|
||||
- **Tier 2.5** (done on Forgejo, hub `remote_url` may still say Gitea) — run
|
||||
§4 after git promotion.
|
||||
- **Tier 3** (`state-hub`, `issue-core`, production wave) — full §3–§8 with
|
||||
operator approval.
|
||||
|
||||
Does **not** perform cutover by itself. Gitea remains canonical until tier gates
|
||||
and explicit approval per `RAIL-HO-WP-0005` safety contract.
|
||||
|
||||
## Preconditions (gates)
|
||||
|
||||
| Gate | Tier 2.5 | Tier 3 (`state-hub`) |
|
||||
| --- | --- | --- |
|
||||
| Forgejo repo exists + history mirrored | required | required |
|
||||
| Workstation `origin=forgejo-remote`, `gitea` legacy remote | required | required |
|
||||
| Operator SSH on Forgejo (`tegwick` or team keys) | required | required |
|
||||
| CI smoke green on Forgejo (`.forgejo/workflows/ci-smoke.yaml`) | required | required |
|
||||
| Image workflow if applicable | optional | required for `state-hub` |
|
||||
| Restore drill passed | recommended | required |
|
||||
| Scheduled backups automated | optional | required (disaster-control) |
|
||||
| Operator approval recorded | not required | **required** |
|
||||
| `CUST-WP-0011-T07` freeze/restore for hub primary | n/a | required before hub production |
|
||||
|
||||
## Canonical remote conventions
|
||||
|
||||
State Hub stores the **SSH remote name form** used on the operator workstation,
|
||||
not the HTTPS URL. This matches existing registrations
|
||||
(`gitea-remote:coulomb/<slug>.git`).
|
||||
|
||||
| Role | Remote name | Example |
|
||||
| --- | --- | --- |
|
||||
| Canonical (post-promotion) | `origin` → `forgejo-remote` | `forgejo-remote:coulomb/state-hub.git` |
|
||||
| Rollback mirror | `gitea` → `gitea-remote` | `gitea-remote:coulomb/state-hub.git` |
|
||||
| Hub `remote_url` field | same as `origin` | `forgejo-remote:coulomb/state-hub.git` |
|
||||
|
||||
HTTPS canonical URL for humans and archive CI:
|
||||
`https://forgejo.coulomb.social/coulomb/<slug>.git`
|
||||
|
||||
SSH config block (workstation `~/.ssh/config`):
|
||||
|
||||
```ssh
|
||||
Host forgejo-remote
|
||||
HostName 92.205.62.239
|
||||
Port 30022
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_gitea
|
||||
StrictHostKeyChecking accept-new
|
||||
```
|
||||
|
||||
## Per-repo promotion procedure
|
||||
|
||||
### 1. Git forge (workstation)
|
||||
|
||||
Use `railiance-enablement/tools/promote-repo-to-forgejo.sh` or manually:
|
||||
|
||||
```bash
|
||||
cd ~/REPO_SLUG
|
||||
# Create empty repo on Forgejo if needed (org coulomb)
|
||||
git push forgejo-remote:coulomb/REPO_SLUG.git main # first mirror
|
||||
git remote rename origin gitea
|
||||
git remote add origin forgejo-remote:coulomb/REPO_SLUG.git
|
||||
git push -u origin main
|
||||
# Optional: keep Gitea mirror current
|
||||
git push gitea main
|
||||
```
|
||||
|
||||
Add `.forgejo/workflows/ci-smoke.yaml` from
|
||||
`railiance-enablement/workflows/ci-smoke.yaml`. For images, use
|
||||
`container-build-push.yaml` or `container-build-push-multirepo.yaml` (state-hub +
|
||||
hub-core).
|
||||
|
||||
### 2. Verify git + SSH
|
||||
|
||||
```bash
|
||||
git remote -v
|
||||
# origin forgejo-remote:coulomb/REPO_SLUG.git (fetch/push)
|
||||
# gitea gitea-remote:coulomb/REPO_SLUG.git (fetch/push)
|
||||
|
||||
ssh forgejo-remote # expect: Hi there, tegwick!
|
||||
git ls-remote origin # reachable
|
||||
```
|
||||
|
||||
### 3. Patch State Hub registration
|
||||
|
||||
```bash
|
||||
API=http://127.0.0.1:8000
|
||||
SLUG=REPO_SLUG
|
||||
NEW_URL="forgejo-remote:coulomb/${SLUG}.git"
|
||||
|
||||
curl -s -X PATCH "${API}/repos/${SLUG}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"remote_url\": \"${NEW_URL}\"}" | python3 -m json.tool
|
||||
|
||||
# Confirm
|
||||
curl -s "${API}/repos/${SLUG}" | python3 -c \
|
||||
"import json,sys; r=json.load(sys.stdin); print(r['slug'], r['remote_url'])"
|
||||
```
|
||||
|
||||
Batch helper for tier-2.5 stack (skips slugs not registered in State Hub):
|
||||
|
||||
```bash
|
||||
~/the-custodian/tools/patch-forgejo-remote-urls.sh --tier-25
|
||||
```
|
||||
|
||||
Applied 2026-07-04 for registered tier-2.5 repos + `key-cape`. `glas-harness` is
|
||||
not in State Hub registration — patch when/if registered.
|
||||
|
||||
### 4. Consistency sweep / fix-consistency
|
||||
|
||||
The sweep (`POST /consistency/sweep/remote-all` or `statehub fix-consistency`)
|
||||
resolves repos by `host_paths[hostname]` or `local_path`, then `git pull
|
||||
--ff-only` from the checkout's **tracking branch** (now Forgejo `origin`).
|
||||
|
||||
After `remote_url` patch:
|
||||
|
||||
```bash
|
||||
cd ~/REPO_SLUG
|
||||
git fetch origin
|
||||
statehub fix-consistency --repo REPO_SLUG
|
||||
# or from state-hub checkout:
|
||||
cd ~/state-hub && make fix-consistency REPO=REPO_SLUG
|
||||
```
|
||||
|
||||
**Attribution:** `consistency_check.py` matches repos by git fingerprint and
|
||||
`remote_url` string. Stale `gitea-remote` in the hub causes mis-attribution when
|
||||
multiple checkouts exist — patch hub **before** relying on sweep writebacks.
|
||||
|
||||
### 5. DoI verification
|
||||
|
||||
```bash
|
||||
curl -s "http://127.0.0.1:8000/repos/REPO_SLUG/doi" | python3 -m json.tool
|
||||
# C4 Remote URL set → pass
|
||||
# C4 reachability → git ls-remote origin succeeds
|
||||
```
|
||||
|
||||
## Railiance01 sweep checkout paths (`CUST-WP-0054-T05`)
|
||||
|
||||
Today sweeps write back from **workstation** `host_paths` (`bnt-lap001`). Wave 2
|
||||
moves primary checkouts to **railiance01** so triage survives workstation loss.
|
||||
|
||||
When railiance01 clone tree exists (e.g. `/home/tegwick/<slug>` or agreed path):
|
||||
|
||||
```bash
|
||||
API=http://127.0.0.1:8000
|
||||
SLUG=REPO_SLUG
|
||||
HOST=railiance01 # must match socket.gethostname() on that machine
|
||||
PATH_ON_HOST=/home/tegwick/REPO_SLUG
|
||||
|
||||
curl -s -X POST "${API}/repos/${SLUG}/paths" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"host\": \"${HOST}\", \"path\": \"${PATH_ON_HOST}\"}" | python3 -m json.tool
|
||||
```
|
||||
|
||||
Clone on railiance01 **from Forgejo**:
|
||||
|
||||
```bash
|
||||
git clone forgejo-remote:coulomb/REPO_SLUG.git /home/tegwick/REPO_SLUG
|
||||
# or HTTPS with deploy key / token
|
||||
```
|
||||
|
||||
Sweep on railiance01 then uses `host_paths[railiance01]`; workstation path
|
||||
remains in map for dev but is no longer the production writeback source.
|
||||
|
||||
## Tier 3 — `state-hub` specifics
|
||||
|
||||
Before promoting `state-hub`:
|
||||
|
||||
1. **Multi-repo image workflow** — copy
|
||||
`railiance-enablement/workflows/container-build-push-multirepo.yaml` to
|
||||
`state-hub/.forgejo/workflows/image.yaml`; set `IMAGE_NAME=coulomb/state-hub`,
|
||||
`EXTRA_REPOS="coulomb/hub-core@hub_core_src"`.
|
||||
2. **Prove image pull** on railiance01 (`crictl pull` or deployment dry-run).
|
||||
3. **Hub primary cutover** — follow `CUST-WP-0011-T07` (freeze → restore →
|
||||
rewire); independent of forge remote but same maintenance window may apply.
|
||||
4. **ArgoCD / GitOps** — repoint repository URLs to Forgejo (Wave 5 in
|
||||
`docs/coulombcore-drain-placement-plan.md`).
|
||||
5. **Record approval** — `POST /decisions/` or workplan note with operator id.
|
||||
|
||||
`state-hub` promotion order:
|
||||
|
||||
```
|
||||
mirror git → Forgejo remotes → CI image workflow green → PATCH remote_url →
|
||||
fix-consistency → (later) railiance01 host_paths → CUST-WP-0011-T07 cutover
|
||||
```
|
||||
|
||||
## Gitea read-only policy (post-cutover per repo)
|
||||
|
||||
After Forgejo is canonical **for that repo** and hub `remote_url` is patched:
|
||||
|
||||
1. Do **not** delete the Gitea repo (safety contract).
|
||||
2. Org/repo setting: disable push for non-admin users, or maintenance flag.
|
||||
3. Workstation: stop pushing to `gitea` except intentional rollback mirror.
|
||||
4. Document rollback: `git push gitea main` from last known-good Forgejo SHA.
|
||||
|
||||
Org-wide Gitea read-only is an operator action (T11); per-repo is enough for
|
||||
staged ladder.
|
||||
|
||||
## Rollback
|
||||
|
||||
| Step | Action |
|
||||
| --- | --- |
|
||||
| Git canonical | `git remote rename origin forgejo; git remote rename gitea origin` |
|
||||
| Hub | `PATCH /repos/{slug}` → `gitea-remote:coulomb/<slug>.git` |
|
||||
| Sweep | `statehub fix-consistency` on reverted checkout |
|
||||
| Gitea | Re-enable push if read-only was set |
|
||||
|
||||
## Verification checklist
|
||||
|
||||
- [ ] `GET /repos/{slug}` → `remote_url` is `forgejo-remote:coulomb/<slug>.git`
|
||||
- [ ] Workstation `git remote -v` → `origin` is Forgejo
|
||||
- [ ] `ssh forgejo-remote` → operator user (not only `forgejo_admin`)
|
||||
- [ ] `statehub fix-consistency --repo <slug>` → PASS
|
||||
- [ ] Forgejo Actions `ci-smoke` → success (tier 1+)
|
||||
- [ ] Gitea copy exists and matches SHA (optional `git push gitea` mirror)
|
||||
- [ ] Tier 3 only: image workflow + pull smoke + operator approval on record
|
||||
|
||||
## References
|
||||
|
||||
- `docs/forgejo-repo-migration-pilot-glas-harness.md` (tiers 1–2.5)
|
||||
- `railiance-enablement/docs/forgejo-actions-workflow-templates.md`
|
||||
- `railiance-enablement/tools/promote-repo-to-forgejo.sh`
|
||||
- `state-hub/docs/consistency-sweep-runbook.md`
|
||||
- `state-hub/policies/repo-doi.md` (C4 remote URL)
|
||||
- `docs/coulombcore-drain-placement-plan.md` (Wave 1–2)
|
||||
- `disaster-control/history/2026-07-04-forgejo-backup-strategy-assessment.md`
|
||||
Reference in New Issue
Block a user