workplan: ACTIVITY-WP-0020 weekly Forgejo package prune (retain 3)
Policy-driven OCI/PyPI/npm/generic pruning via activity-core shell resolver and railiance-platform forgejo-package-prune command.
This commit is contained in:
parent
4f26826d6c
commit
a853cd3118
1 changed files with 263 additions and 0 deletions
263
workplans/ACTIVITY-WP-0020-weekly-forgejo-package-prune.md
Normal file
263
workplans/ACTIVITY-WP-0020-weekly-forgejo-package-prune.md
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
---
|
||||
id: ACTIVITY-WP-0020
|
||||
type: workplan
|
||||
title: "Weekly Forgejo package prune (retain 3 versions)"
|
||||
domain: infotech
|
||||
repo: activity-core
|
||||
status: proposed
|
||||
owner: codex
|
||||
topic_slug: activity-core
|
||||
created: "2026-07-12"
|
||||
updated: "2026-07-12"
|
||||
state_hub_workstream_id: "33a5b5e0-310c-442e-a29f-902227b9d7e1"
|
||||
---
|
||||
|
||||
# Weekly Forgejo package prune (retain 3 versions)
|
||||
|
||||
## Problem
|
||||
|
||||
Forgejo `forgejo dump` backups are dominated by **OCI container image layers**
|
||||
under `data/packages` (~80% of blob zip; ~1.3 GB today). Growth is ~686 MiB
|
||||
(Jul 7) → ~1.0 GiB (Jul 9) → ~1.3 GiB (Jul 12) because CI pushes new image tags
|
||||
on every deploy and **no automated prune** runs yet
|
||||
(`railiance-apps/docs/forgejo-package-registry.md`).
|
||||
|
||||
Manual UI deletion does not scale. Prune must be policy-driven, dry-run first,
|
||||
and emit non-secret evidence for backup/ops gates.
|
||||
|
||||
## Goal
|
||||
|
||||
Establish a **retention depth of 3 versions per package** (newest three kept;
|
||||
older versions deleted) across Forgejo package types that affect backup size, and
|
||||
run pruning **weekly via activity-core** on railiance01.
|
||||
|
||||
## Retention policy (canonical)
|
||||
|
||||
| Rule | Value |
|
||||
| --- | --- |
|
||||
| Versions kept per package | **3** (newest by `created_at`; tie-break on version string) |
|
||||
| Package types in scope (phase 1) | `container` (OCI), `pypi`, `npm`, `generic` |
|
||||
| Protected versions | Any tag/version referenced by **production deploy manifests** in `railiance-apps` Helm values / chart defaults (never delete even if outside top 3) |
|
||||
| Org scope | `coulomb` |
|
||||
| Default mode | **dry-run**; deletes only with explicit `--apply` |
|
||||
| Evidence | Non-secret summary posted to State Hub (`forgejo_package_prune`) |
|
||||
|
||||
Phase 2 (out of scope here): Helm/Maven/Go registries when consumer inventory
|
||||
proves need.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
activity-core (weekly cron)
|
||||
→ shell context resolver: forgejo_package_prune
|
||||
→ railiance-platform: tools/cmd/forgejo-package-prune --apply
|
||||
→ Forgejo API DELETE /api/v1/packages/{owner}/{type}/{name}/{version}
|
||||
→ State Hub progress evidence (counts, bytes estimate, errors; no tokens)
|
||||
```
|
||||
|
||||
**Credential routing:** Forgejo PAT with `read:package` + `write:package` from
|
||||
OpenBao via `warden route find "forgejo package"` — never stored in Git,
|
||||
workplans, or activity-definition files. Runtime token file path only.
|
||||
|
||||
**Schedule:** Sunday **03:30 UTC** — after daily `make forgejo-backup` cron
|
||||
(02:15 UTC) so a fresh backup exists before destructive prune.
|
||||
|
||||
## Scope boundary
|
||||
|
||||
| In scope | Out of scope |
|
||||
| --- | --- |
|
||||
| Prune script + Make target in `railiance-platform` | Rewriting `forgejo-backup` chunk copy |
|
||||
| Weekly ActivityDefinition in `activity-core` | Gitea legacy registry cleanup |
|
||||
| Retention docs in `railiance-apps` + `railiance-platform` | SBOM signing, vulnerability scanning |
|
||||
| Production-tag protection from Helm inventory | Cross-org packages outside `coulomb` |
|
||||
| Dry-run + first apply evidence | Auto-prune git `repos/` or `repo-archive` blobs |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Forgejo API reachable (`forgejo.coulomb.social`)
|
||||
- Valid Forgejo operator/service PAT lane (OpenBao)
|
||||
- `activity-core` worker on railiance01 with `ACTIVITY_DEFINITION_DIRS` including
|
||||
repo definitions and network egress to Forgejo
|
||||
- `make sync-schedules` / worker startup schedule reconciliation
|
||||
|
||||
## Tasks
|
||||
|
||||
### T01 — Document retention policy and operator guardrails
|
||||
|
||||
```task
|
||||
id: ACTIVITY-WP-0020-T01
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "d4212ce4-9292-4c56-abcd-952e0c1bbab7"
|
||||
```
|
||||
|
||||
Add canonical retention prose to:
|
||||
|
||||
- `railiance-platform/docs/forgejo-package-prune.md` (new)
|
||||
- `railiance-apps/docs/forgejo-package-registry.md` § Retention (replace
|
||||
"no auto-prune yet")
|
||||
|
||||
Cover: depth-3 rule, protected production tags, dry-run default, weekly
|
||||
activity-core schedule, evidence event type, and rollback posture (restore from
|
||||
Nextcloud dump if a needed tag was removed).
|
||||
|
||||
Acceptance: operator can answer "what gets deleted, what is protected, how often"
|
||||
without reading source.
|
||||
|
||||
---
|
||||
|
||||
### T02 — Implement `forgejo-package-prune` command
|
||||
|
||||
```task
|
||||
id: ACTIVITY-WP-0020-T02
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "3abec46e-fca8-4583-b681-c0836e0bf666"
|
||||
```
|
||||
|
||||
In `railiance-platform`:
|
||||
|
||||
- `tools/cmd/forgejo-package-prune` — list packages for owner `coulomb`, group
|
||||
versions, compute deletions beyond newest 3, subtract protected tags from Helm
|
||||
inventory scan (`railiance-apps/helm/*-values.yaml`,
|
||||
`railiance-apps/charts/*/values.yaml` image tags).
|
||||
- Flags: `--dry-run` (default), `--apply`, `--max-versions 3`, `--types
|
||||
container,pypi,npm,generic`, `--owner coulomb`.
|
||||
- Auth: `FORGEJO_TOKEN` or OpenBao field via existing backup-lane pattern;
|
||||
preflight `401` → clear error.
|
||||
- Output: JSON summary on stdout for activity-core parsing
|
||||
(`deleted`, `skipped_protected`, `would_delete`, `errors[]`); human lines via
|
||||
`railiance-print.sh`.
|
||||
- `Makefile` targets: `forgejo-package-prune-dry-run`, `forgejo-package-prune`.
|
||||
|
||||
Acceptance: dry-run against production lists candidates; no deletes without
|
||||
`--apply`; unit or fixture tests for version sorting and protection logic.
|
||||
|
||||
---
|
||||
|
||||
### T03 — Register shell resolver query `forgejo_package_prune`
|
||||
|
||||
```task
|
||||
id: ACTIVITY-WP-0020-T03
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "f8c6eb1a-2682-49b0-a6ab-e96c8174f75f"
|
||||
```
|
||||
|
||||
In `activity-core`, extend the `shell` context resolver (same pattern as
|
||||
`reuse_surface_report_gaps` in `context_resolvers/reuse_surface.py`):
|
||||
|
||||
- Query: `forgejo_package_prune`
|
||||
- Params: `prune_script` (default
|
||||
`~/railiance-platform/tools/cmd/forgejo-package-prune`), `apply` (bool, default
|
||||
`false` for first ship), `max_versions`, `timeout_seconds`
|
||||
- Invoke script with bounded timeout; parse JSON stdout into `context.prune`
|
||||
- Never capture or persist token env vars in context/working memory
|
||||
|
||||
Acceptance: resolver tests with mocked subprocess JSON; failure surfaces non-zero
|
||||
exit and stderr snippet (truncated, no secrets).
|
||||
|
||||
---
|
||||
|
||||
### T04 — Add weekly ActivityDefinition
|
||||
|
||||
```task
|
||||
id: ACTIVITY-WP-0020-T04
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "2da2ca5d-1c59-4835-b48e-7bf3bfae97b4"
|
||||
```
|
||||
|
||||
Add `activity-definitions/weekly-forgejo-package-prune.md`:
|
||||
|
||||
```yaml
|
||||
trigger:
|
||||
type: cron
|
||||
cron_expression: "30 3 * * 0"
|
||||
timezone: UTC
|
||||
misfire_policy: skip
|
||||
context_sources:
|
||||
- type: shell
|
||||
query: forgejo_package_prune
|
||||
params:
|
||||
apply: true
|
||||
max_versions: 3
|
||||
evidence_sinks:
|
||||
- type: state-hub-progress
|
||||
event_type: forgejo_package_prune
|
||||
author: activity-core
|
||||
bind_to: context.prune
|
||||
```
|
||||
|
||||
Ship `enabled: false` until dry-run evidence exists. No rules / task emission —
|
||||
observational prune + evidence only (same shape as `weekly-legacy-meter-review`).
|
||||
|
||||
Acceptance: definition parses via `sync-definitions`; schedule id derivable from
|
||||
`make automation-inventory`.
|
||||
|
||||
---
|
||||
|
||||
### T05 — Dry-run verify, enable, and runbook
|
||||
|
||||
```task
|
||||
id: ACTIVITY-WP-0020-T05
|
||||
status: todo
|
||||
priority: medium
|
||||
state_hub_task_id: "debc74f0-d43d-401e-b65f-c6dbb5b399d7"
|
||||
```
|
||||
|
||||
1. Run resolver smoke with `apply: false`; capture candidate counts vs Jul 12
|
||||
backup analysis (~800 MiB packages).
|
||||
2. Operator review of dry-run output; confirm protected tags (e.g.
|
||||
`vergabe-teilnahme:064d295`) never appear in `would_delete`.
|
||||
3. Flip `enabled: true`; `make sync-schedules` on railiance01 worker.
|
||||
4. Document in `activity-core/docs/runbook.md` alongside
|
||||
`weekly-sbom-staleness` and `weekly-legacy-meter-review`.
|
||||
|
||||
Acceptance: one successful dry-run workflow in Temporal; schedule visible in
|
||||
automation inventory; runbook lists cron, credential pointer, and rollback.
|
||||
|
||||
---
|
||||
|
||||
### T06 — First apply run and backup impact evidence
|
||||
|
||||
```task
|
||||
id: ACTIVITY-WP-0020-T06
|
||||
status: todo
|
||||
priority: medium
|
||||
state_hub_task_id: "600c7b22-9278-430b-9cba-902acb5c279a"
|
||||
```
|
||||
|
||||
After T05 approval, run one manual `make forgejo-package-prune` with `--apply`
|
||||
(or trigger workflow once with `apply: true`). Then:
|
||||
|
||||
1. Post `forgejo_package_prune` progress to State Hub (deleted counts, errors).
|
||||
2. Run `make forgejo-backup-dry-run` and record dump size delta vs pre-prune
|
||||
baseline in `railiance-platform/docs/evidence/forgejo-package-prune-YYYYMMDD.json`.
|
||||
3. Update `railiance-apps/docs/forgejo-package-registry.md` retention table with
|
||||
automated prune row.
|
||||
|
||||
Acceptance: evidence file exists; next backup blob zip measurably smaller or
|
||||
stable; no production deploy tag removed (smoke: `crictl pull` or helm image
|
||||
still present).
|
||||
|
||||
---
|
||||
|
||||
## Registration
|
||||
|
||||
After approval, register in State Hub:
|
||||
|
||||
```bash
|
||||
statehub fix-consistency --repo activity-core
|
||||
```
|
||||
|
||||
Cross-repo implementation commits land in `railiance-platform` and
|
||||
`railiance-apps`; link them in T06 evidence — no separate hub workplan required
|
||||
unless scope expands.
|
||||
|
||||
## Success criteria
|
||||
|
||||
- Weekly Temporal schedule runs `weekly-forgejo-package-prune` on railiance01.
|
||||
- Each package under `coulomb` retains at most **3** versions unless protected.
|
||||
- State Hub receives `forgejo_package_prune` evidence every run.
|
||||
- `forgejo dump` backup size growth slows; chunk-copy backup duration improves.
|
||||
Loading…
Add table
Add a link
Reference in a new issue