# Forgejo package prune (retention) Workplan: `ACTIVITY-WP-0020` · complements `docs/forgejo-backup.md` ## Policy | Rule | Value | | --- | --- | | Versions kept per package | **3** (newest by `created_at`) | | Package types (phase 1) | `container`, `pypi`, `npm`, `generic` | | Org scope | `coulomb` | | Protected versions | Image tags referenced in `railiance-apps` production Helm values / chart defaults | | Default mode | dry-run (no deletes) | | Schedule | Weekly Sunday 03:30 UTC via `activity-core` (`weekly-forgejo-package-prune`) | OCI container layers dominate `forgejo dump` size (~80% of blob zip). Pruning old tags slows backup growth and shortens chunked-copy duration. ## Operator commands ### 1. Authenticate to the approved token lane The steady-state credential path is `CCR-2026-0006`: OpenBao lane `platform/workloads/forgejo/forgejo-admin`, field `API_TOKEN`. 1. Confirm the sanctioned route first: ```bash warden plan "forgejo admin api token" --json ``` 2. Login with an identity allowed to read the lane: ```bash bao login -method=oidc -path=netkingdom role=forgejo-admin-workload-kv-read ``` 3. Run prune normally. If `FORGEJO_TOKEN`, `FORGEJO_ADMIN_TOKEN`, `FORGEJO_TOKEN_FILE`, and `FORGEJO_ADMIN_TOKEN_FILE` are unset, the loader now resolves the PAT directly from OpenBao. Do not commit the token or paste it into workplans, State Hub, chat, or shell history. ### 2. Break-glass overrides Short-lived overrides are still supported when the lane is unavailable or when an attended operator session needs an explicit handoff: ```bash # Option A — token env for one shell session export FORGEJO_TOKEN='' # alias: export FORGEJO_ADMIN_TOKEN='' # Option B — explicit file path for one invocation warden access forgejo-admin-api-token --out "$XDG_RUNTIME_DIR/forgejo-admin.token" --field API_TOKEN FORGEJO_TOKEN_FILE="$XDG_RUNTIME_DIR/forgejo-admin.token" make forgejo-package-prune-dry-run rm -f "$XDG_RUNTIME_DIR/forgejo-admin.token" ``` The retired `/tmp/forgejo-tegwick-api-token` drop is no longer the default. Use it only while unwinding legacy local state: ```bash FORGEJO_ALLOW_LEGACY_FILE_FALLBACK=1 make forgejo-package-prune-dry-run ``` ### 3. Run prune ```bash cd ~/railiance-platform make forgejo-package-prune-dry-run # list would-delete candidates make forgejo-package-prune # delete beyond retention depth ``` ## Durable multi-cluster image inventory The inventory belongs outside the platform checkout. On the production worker host, use `/home/tegwick/.local/state/railiance-platform/live-images/all.txt`. `make live-images-refresh LIVE_IMAGES_SOURCES="/path/railiance01.txt /path/coulombcore.txt"` merges complete, nonempty exports with the prior inventory under a writer lock, then atomically publishes sorted image references and a count/hash receipt. Set `LIVE_IMAGES_OUTPUT` when publishing for a different host user. Missing, empty, or malformed input fails without replacing the previous file. The prune CLI also refuses `--apply` before credential retrieval if any explicit `--live-images-file` is missing, unreadable, empty, or comment-only. Dry-run keeps reporting those files as warnings. This guard supplements the activity-core worker guard; it does not require exports for callers that have not configured any. Refresh only adds protection: removal of obsolete tags requires a separate review of every production cluster and rollback requirement. Migration and rollout sequence: 1. Seed from the restored `docs/evidence/live-images-all.txt` plus fresh exports from railiance01 and coulombcore; retain the restored multi-cluster entries. 2. Project the durable **directory** read-only into the activity-core worker and configure its inventory argument to `all.txt` in that directory. Do not mount the single file: atomic replacement must be visible to the worker. 3. Verify the worker reads a nonempty inventory and retains the existing hard refusal of apply when that file is missing or empty. Use only its dry-run verification; do not manually trigger prune. 4. After each cluster image rollout, export pod regular, init, and ephemeral container images to a temporary file. Require successful kubectl exit and nonempty output, then invoke this refresh target with that export. Keep other clusters' prior entries during outages. Run the hook on the durable host, or transfer the complete export there before invoking it. `tools/cmd/refresh-live-images` captures regular, init and ephemeral container images with a bounded kubectl call and publishes only after all requested contexts succeed. `CONTEXTS` selects contexts; `EXTRA_LIVE_FILES` supplies saved exports. Bare image names are accepted. Failed captures preserve the inventory. The host installation exposes `~/.local/bin/railiance-live-images-refresh`; invoke it after cluster image rollouts. Activity-core's `make refresh-live-images` delegates to the same implementation. Live installation evidence is tracked in `RPF-WP-0028`. ## Rollback procedure If a needed tag was removed, restore from the latest Nextcloud `forgejo-dump-*.zip.age` (`make forgejo-backup` evidence) using `railiance-infra/tools/forgejo-restore-drill.sh`, or re-push the image from CI. ## Evidence activity-core posts `forgejo_package_prune` progress to State Hub with non-secret counts (`deleted_count`, `candidate_count`, `skipped_protected_count`, `errors`). ## Related - `railiance-apps/docs/forgejo-package-registry.md` - `docs/forgejo-backup.md` - `docs/workload-kv-access-lanes.md`