Build destination, both builder-image references and the three publish pins now point at novoyuuparosk-wiki/*. The publish pins name a tag that does not exist in the new namespace until this run's build job pushes it and the pin job rewrites them, so publishes are briefly broken mid-run.
novoyuuparosk-auto-wiki
CI/CD pipelines that auto-apply commits to https://wiki.novoyuuparosk.org from upstream content repos.
Pipelines
| Path | Source repo | Purpose | Status |
|---|---|---|---|
pipelines/songs/ |
novoyuuparosk-wiki/ncmr-songs |
Song lyric pages | v1 live |
pipelines/ses/ |
novoyuuparosk-wiki/ses-light-novel |
SES light novel pages | v1 in development |
pipelines/tech/ |
novoyuuparosk-wiki/tech-blogs |
Tech blog posts | v1 live |
Per-pipeline READMEs cover everything specific to that pipeline (source schema, renderer, runtime, decisions). This root README covers only what's cross-cutting.
Architecture
Hybrid layout. The Gitea Actions trigger must live in the source repo (Gitea only fires workflows from .gitea/workflows/ of the pushed-to repo); the rendering logic lives here. The source-repo workflow is self-contained but clones this repo at runtime to get the renderer.
<source-repo>/
.gitea/workflows/<name>.yml <- workflow: clones this repo, runs renderer (deps pre-baked in job image)
novoyuuparosk-auto-wiki/ <- this repo
.gitea/workflows/<pipeline>.yml <- reusable workflow stubs (kept for reference; not actively called; may be stale)
pipelines/<pipeline>/ <- per-pipeline code, schema, templates
lib/ <- shared modules (MediaWiki client, etc.)
Note: workflow_call across private repos was abandoned — the auto-generated run token is scoped to the triggering repo only and cannot clone a private callee. The source-repo workflow clones this repo directly using FAPAT.
Wiki
- Base URL: https://wiki.novoyuuparosk.org
- MediaWiki API: https://wiki.novoyuuparosk.org/api.php (confirmed)
Bot identity
MediaWiki BotPassword issued for user Mikkeli, bot name giteaBot. Login form: Mikkeli@giteaBot.
Mikkeli holds the bot right, so pipeline edits are flagged as bot edits and stay out of default Recent Changes — mwclient's page.save() requests the bot flag and the wiki honours it.
This section previously named Dubrowski@giteaAutomaton, but every bot-flagged revision in the wiki's history is attributed to Mikkeli, so that had been stale for some time — the live secret never matched the doc.
Credentials are stored in the Gitea org-scope secret vault under novoyuuparosk-wiki (WIKI_BOT_USER, WIKI_BOT_PASSWORD). Not stored in this repo.
Runner infrastructure
One act_runner instance serves all pipelines. Runs on a Pi 5 (Raspberry Pi OS Bookworm, aarch64) inside the same docker-compose stack that hosts the Gitea instance. Job execution is via the host Docker socket — runner is a container, jobs spawn as sibling containers.
act_runner build: linux-arm64, from the gitea/act_runner Docker image.
Container network mode: host — required so job containers can reach localhost:3005 (Gitea) and resolve mDNS hostnames.
Job container image
All pipelines share a single pre-built Docker image, served from the Gitea registry at pi5-16.local:3005/novoyuuparosk-wiki/novoyuuparosk-wiki-runner. The Dockerfile is at the repo root. It bakes in system deps (git, pandoc, ca-certificates) and all pipeline Python packages so job containers start instantly with no install steps.
The image builds automatically via .gitea/workflows/build-image.yml, which triggers on pushes that touch the Dockerfile, any pipeline requirements.txt, or that workflow itself. It uses kaniko (daemonless, unprivileged) to build and push two tags: an immutable :<short-sha> and a moving :latest.
A follow-up pin job then rewrites the image: pin in each publish-*.yml to the new :<short-sha> and commits it back to master (using FAPAT for contents write). The publish workflows therefore always reference an immutable tag, kept current automatically — no manual bump. The pin commit only touches workflow_call files, so it triggers no further runs.
Gitea Actions setup (cross-cutting)
Secrets and variables are scoped to the novoyuuparosk-wiki org, inherited by all repos under it. Runs belong to the caller repo, so a source repo calling a reusable workflow here resolves secrets and variables from its own owner — which is why they live at org scope rather than on this repo.
Secrets:
WIKI_BOT_USER=Mikkeli@giteaBotWIKI_BOT_PASSWORD= the value from Bot identity aboveFAPAT= Full-Access PAT owned bymikkeli, used by source-repo workflows to clone this repo at runtime. The PAT stays personal; only its storage scope moved to the org — hence themikkeli:basic-auth username in the clone URLs.PKGRW_PAT= package read/write PAT owned bymikkeli, used bybuild-image.ymlto push to the container registry
Variables:
WIKI_BASE_URL=https://wiki.novoyuuparosk.orgWIKI_API_URL=https://wiki.novoyuuparosk.org/api.phpURL_TO_GITEA= Gitea instance base URL (e.g.http://localhost:3005). Named withURL_TO_prefix — Gitea blocks variable names starting withGITEA_orGITHUB_.
Branch naming
- This repo:
automation/<pipeline-name>for pipeline-development branches (e.g.,automation/songs). - Source repos: each pipeline's README defines the source-side branch convention (e.g.,
autowiki/<song-slug>inncmr-songs).
Decisions log (cross-cutting)
| Decision | Value | Date |
|---|---|---|
| Architecture | Hybrid: source-repo workflow clones this repo at runtime for the renderer | 2026-06-09 |
| Workflow pattern | Self-contained (not workflow_call) — cross-repo workflow_call blocked by token scoping on private repos |
2026-06-09 |
| Runner execution | Docker, added as a service to the existing Gitea docker-compose | 2026-06-09 |
| Runner network mode | host — job containers need to reach Gitea on localhost |
2026-06-09 |
| Secret/runner scope | User-level on mikkeli (no orgs on this instance) |
2026-06-09 |
| Ownership | This repo and all three source repos moved to the novoyuuparosk-wiki org. Secrets/variables re-created at org scope; runner re-registered instance-level so it serves org-owned runs |
2026-08-11 |
| This repo must stay public | act_runner resolves a cross-repo uses: by cloning the callee anonymously — the job token is not applied. A private callee therefore 404s with repository not found, regardless of the caller sharing its owner. Shared ownership does not satisfy the read requirement. Alternative if it must be private again: Settings → Actions → General → collaborative owners (Gitea 1.26+), untested here |
2026-08-11 |
| Runner cache masks this | The resolved callee is cached at /root/.cache/act/<owner>-<repo>@<ref>. Changing owner changes the key, so a working pipeline can break on a clone that had been served from cache for months. Suspect the cache before suspecting permissions |
2026-08-11 |
| Container registry | Gitea cannot transfer packages, so images were rebuilt into pi5-16.local:3005/novoyuuparosk-wiki/* rather than moved. kaniko-act bootstrapped via the new dispatch-only build-kaniko-act.yml, running in the old mikkeli copy; novoyuuparosk-wiki-runner came from a normal build-image.yml run. Registry auth is still the mikkeli-owned PKGRW_PAT, hence the mikkeli: username in the auth blob |
2026-08-11 |
| Old images left in place | The mikkeli/* package versions are orphaned but retained — nothing references them, and deleting a container version is irreversible. Safe to purge once the org images have proven themselves |
2026-08-11 |
| MediaWiki API path | api.php (classic action API) |
2026-06-09 |
| Branch naming (this repo) | automation/<pipeline> for pipeline-development branches |
2026-06-09 |
| Variable naming | URL_TO_GITEA not GITEA_URL — Gitea blocks GITEA_/GITHUB_ prefixes |
2026-06-09 |
| Columns shorthand | Side-by-side columns authored as a ```columns fenced block, expanded post-Pandoc in shared lib/wiki.py (universal across pipelines). No wiki template or PHP extension — runs Pi-side before the API call |
2026-06-14 |
Per-pipeline decisions live in each pipeline's README.
Setup checklist (cross-cutting)
Via the Gitea web UI logged in as mikkeli (an owner of novoyuuparosk-wiki):
- Org-scoped secrets and variables set per Gitea Actions setup above
WIKI_BOT_USERWIKI_BOT_PASSWORDFAPAT(Full-Access PAT — value not stored in this README; saved directly into the Gitea secret. Regenerate if lost.)WIKI_BASE_URLWIKI_API_URLURL_TO_GITEA
With Pi access:
- Add
act_runnerservice to the existing Gitea docker-compose - Generate a runner registration token at
/-/admin/actions/runners, bake into the compose env,docker compose up -d act_runner, confirm "online" in the Gitea UI
Per-pipeline setup lives in each pipeline's README. Start with pipelines/songs/.