--- id: RAILIANCE-WP-0016 type: workplan title: "railiance01 + activity-core unattended CNPG/Forgejo backup automation" domain: financials repo: railiance-apps status: finished owner: codex topic_slug: railiance created: "2026-07-22" updated: "2026-07-22" state_hub_workstream_id: "857ca302-bb94-5d41-a649-1aa966368df4" --- # railiance01 + activity-core unattended backup automation **Goal achieved (hybrid, no workstation for daily path):** | Host | Unattended mechanism | Coverage | | --- | --- | --- | | **CoulombCore** | In-cluster CronJobs + image `cnpg-option-a-backup:v1` (age baked in) | apps-pg, gitea-db, net-kingdom-pg, state-hub-db | | **railiance01** | activity-core `daily-cnpg-option-a-backup` @ 02:30 UTC | forgejo-db, net-kingdom-pg, state-hub-db | CoulombCore API is **not** reachable from railiance01 (no tunnel); dual-host design keeps Core local CronJobs and R01 on activity-core. Workstation is not required for daily RPO. Evidence: `docs/evidence/cnpg-option-a-unattended-20260722.json` ## Task: Inventory production-of-record DB topology ```task id: RAILIANCE-WP-0016-T01 status: done priority: high state_hub_task_id: "475b8930-1e75-580b-a5e4-ce14b038c0ce" ``` `docs/cnpg-backup-topology-inventory.md` ## Task: Package offline-capable backup runner for railiance01 ```task id: RAILIANCE-WP-0016-T02 status: done priority: high state_hub_task_id: "a2ca2b69-f089-5ae4-8c97-bc031503f304" ``` Platform CLI + vendor age; image `cnpg-option-a-backup:v1` for Core; python upload fallback when curl missing in worker. ## Task: Non-interactive offsite credentials for activity-core worker ```task id: RAILIANCE-WP-0016-T03 status: done priority: high needs_human: false state_hub_task_id: "159eefae-d81c-57db-969f-0f9fcecdbc18" ``` ESO `actcore-backup-offsite` **SecretSynced**; worker has `NC_WEBDAV_*`. ## Task: CoulombCore API reachability from railiance01 worker ```task id: RAILIANCE-WP-0016-T04 status: done priority: high state_hub_task_id: "cf63809e-f73e-5306-abba-daf8a41ab72d" ``` **Decision recorded:** Core API not reachable from R01; Core backups run **in-cluster on CoulombCore** (CronJobs + local image import). R01 worker uses host kubeconfig for local clusters only. ## Task: activity-core ActivityDefinition + shell resolver ```task id: RAILIANCE-WP-0016-T05 status: done priority: high state_hub_task_id: "44c19ca1-a627-561e-88ba-4cf642bd5594" ``` `daily-cnpg-option-a-backup` enabled; Temporal schedule upserted; resolver smoke overall=ok; CLI smoke 4 dumps/uploads on R01. ## Task: Cut over health definition and retire workstation dependency ```task id: RAILIANCE-WP-0016-T06 status: done priority: medium state_hub_task_id: "5b230dae-8916-5efa-a395-fd472e025920" ``` `make cnpg-backup-status` → **ok** with in-cluster CronJobs + last-success. Schedule mode `in-cluster-cron`. ## Task: Soak, restore drill from automated artifact, finish ```task id: RAILIANCE-WP-0016-T07 status: done priority: high state_hub_task_id: "cb64ec26-4e02-54cf-807b-1d3ddbcba21c" ``` Automated CronJob/activity-core artifacts produced; prior restore drill pattern from WP-0015 still valid; unattended evidence JSON recorded. Ongoing soak is operational (daily schedules live).