# Research: Gitea 1.27 Debian + RPM package registry feasibility Issue: [Fenris deb + rpm release plan](https://git.bongbetic.com/xavierk/Fenris/issues/33) → [Research: Gitea 1.27 Debian + RPM package registry feasibility](https://git.bongbetic.com/xavierk/Fenris/issues/35) Verified 2026-09-03 against live instance `https://git.bongbetic.com` (reports `1.27.1` via `/api/v1/version`) and primary sources: docs.gitea.com 1.27 Debian/RPM registry pages and Gitea `v1.27.1` source (go-gitea/gitea tag). **Verdict: feasible.** Every publish/consume path tested live with throwaway packages `fenris-regtest` (all deleted afterward; package list verified empty). ## 1. Publish paths (verified live, HTTP 201) ### Debian (`.deb`) ```bash curl --user xavierk:$TOKEN --upload-file fenris_0.3.0_amd64.deb \ "https://git.bongbetic.com/api/packages/xavierk/debian/pool/{distribution}/{component}/upload" ``` - `distribution` and `component` are free-form path segments chosen at upload time (e.g. `bookworm/main`, `noble/main`). Gitea derives apt suites from what was uploaded — verified: same .deb published to `pool/bookworm/main` and `pool/noble/main` (both 201), both then served in `dists/bookworm/` and `dists/noble/` with correct `Suite:`/`Codename:` headers. - Republish of identical name+version+distribution+component+architecture → **409 Conflict** (verified). Must delete first. ### RPM (`.rpm`) ```bash # no group (flat repo) curl --user xavierk:$TOKEN --upload-file fenris-0.3.0-1.el9.x86_64.rpm \ "https://git.bongbetic.com/api/packages/xavierk/rpm/upload" # with group (distro tag, nestable) curl --user xavierk:$TOKEN --upload-file fenris-0.3.0-1.fc40.x86_64.rpm \ "https://git.bongbetic.com/api/packages/xavierk/rpm/el9/upload" # e.g. el9, rocky/el9, fc40 ``` - Group = free-form nesting used to partition repos per distro/track. Verified: publish to root group and `el9` group (both 201), duplicate → 409. - Owner can be the user (`xavierk`) or an org; packages under a public owner are readable anonymously (verified: metadata fetches without auth succeeded). ## 2. Consumer setup (exact commands) ### apt clients ```bash sudo mkdir -p /etc/apt/keyrings sudo curl -o /etc/apt/keyrings/gitea-xavierk.asc \ https://git.bongbetic.com/api/packages/xavierk/debian/repository.key echo "deb [signed-by=/etc/apt/keyrings/gitea-xavierk.asc] https://git.bongbetic.com/api/packages/xavierk/debian bookworm main" \ | sudo tee /etc/apt/sources.list.d/gitea.list # one line per distribution sudo apt update apt install fenris # or fenris=0.3.0 # private owner variant: https://{user}:{token}@git.bongbetic.com/api/packages/... in the URL ``` ### dnf clients ```bash sudo dnf config-manager --add-repo https://git.bongbetic.com/api/packages/xavierk/rpm/el9.repo # private owner: add user:token into the baseurl inside /etc/yum.repos.d/gitea-xavierk-el9.repo afterwards sudo dnf install fenris # or fenris-0.3.0 ``` The served `.repo` (verified live) sets `gpgcheck=1` and points `gpgkey` at `…/rpm/repository.key`, so `dnf` auto-imports on first use. ## 3. Metadata signing: native, not passthrough Gitea **signs generated metadata itself** with per-instance auto-generated PGP keys. Client-side signing config is limited to trusting the served keys. - Debian: `dists/{suite}/InRelease` is clearsigned; `Release.gpg` detached sig also served. Key (RSA) fetched from `…/debian/repository.key`, uid literally `(Automatically generated Debian Registry Key; created …)`. - RPM: `repodata/repomd.xml.asc` detached ASCII-armored signature, uid `(RPM Registry)`. Key from `…/rpm/repository.key`. - Both verified with `gpg --verify` → **Good signature** (keys are self-generated; the "not certified" warning is expected and handled by the signed-by/keyring flow above). - The apt `Release` also advertises `Acquire-By-Hash: yes` with MD5/SHA1/SHA256/SHA512 indexes of `Packages`/`.gz`/`.xz` (verified live). RPM repomd carries sha256 checksums for `primary/filelists/other.xml.gz`. There is **no bring-your-own-signing-key config** for these registries in 1.27 — trust anchor is the instance's auto keys. For Fenris this is acceptable; TOFU over TLS via the key URLs above. ## 4. Multi-distro metadata - Debian: distributions/suites are implicit — whatever `{distribution}` path segments appear on upload become `dists/{distribution}/` trees with `Suite:`/`Codename:` set to the segment. No server-side list to maintain; adding a new distro = upload with new segment + one more `deb …` sources line. Components likewise (`main`, etc.). Architectures come from each `.deb`'s control stanza (index served as `dists/{dist}/{component}/binary-{arch}/Packages`). - RPM: same via `{group}` path segments (`el9`, `rocky/el9`, …); each group gets its own `repodata/`. No `basearch` filtering — clients pick the group; Gitea publishes whatever RPM arch was uploaded. ## 5. Version retention - Default: **all versions retained indefinitely**; nothing auto-deletes. Old versions stay installable (`apt install fenris=0.2.9`, `dnf install fenris-0.2.9`). - Republishing an existing name+version (deb: same dist/component/arch; rpm: same file name in group) → 409; overwrite requires delete-then-upload. - Optional cleanup rules exist (per owner + package type): `KeepCount`, `KeepPattern`, `RemoveDays`, `RemovePattern`, `MatchFullName` (source: `models/packages/package_cleanup_rule.go`, executed by scheduled `CleanupTask` in `services/packages/cleanup/cleanup.go`). In 1.27.1 they are configurable **only in the web UI** (owner → Packages → Cleanup Rules); no v1 REST route (verified by route table grep of `routers/api/v1/api.go` — probes of `/api/v1/packages/{owner}/cleanuprules…` return 404/409-style errors). - Deletes: format-specific `DELETE …/debian/pool/{dist}/{component}/{name}/{version}/{arch}` and `DELETE …/rpm/{group}/package/{name}/{version}/{arch}` (both verified, 204). Deleting last file removes the version. Generic fallback: `DELETE /api/v1/packages/{owner}/{type}/{name}/{version}`. ## 6. Release attachment: not supported Gitea 1.27.1 has **no package↔release linkage**. Release assets (`…/releases/{id}/assets`) are standalone file uploads; the package model has no release field and no route links them (verified against `v1.27.1` source: `routers/api/v1/repo/release_attachment.go`, `models/packages/`). Options for Fenris releases: 1. Publish `.deb`/`.rpm` to the registry (real apt/dnf install UX) and reference the registry URLs in release notes. 2. Additionally upload tarballs/SHA256SUMS as plain release attachments. 3. Generic registry (`PUT /api/packages/{owner}/generic/{name}/{version}/{filename}`) if an untyped artifact store is needed. ## 7. Caveats for the release plan - Owner choice matters: publish under an **org** (e.g. `fenris`) if multiple maintainers need write; `xavierk` user owner works today (token owner is admin). - Metadata access follows owner visibility — public owner → anonymous consumers, no token in URLs (current state, verified). Keep owner public for frictionless installs, or embed `user:token` in sources/baseurl. - apt distro naming should match OS release names (`bookworm`, `trixie`, `noble`) purely for client convention; server accepts anything. - RPM groups should mirror `$distver` (e.g. `el9`, `fc40`) so `.repo` selection is obvious per target. ## 8. Test log (live, 2026-09-03) | Step | Result | |---|---| | `PUT debian/pool/bookworm/main/upload` | 201 | | `PUT debian/pool/noble/main/upload` (multi-dist) | 201 | | `PUT debian` duplicate | 409 (expected) | | `PUT rpm/upload` (no group) | 201 | | `PUT rpm/el9/upload` (group) | 201 | | `PUT rpm` duplicate | 409 (expected) | | `GET debian/repository.key` / `rpm/repository.key` | PGP public keys (200) | | `GET dists/bookworm/{Release,InRelease,Packages}` | correct; `gpg --verify` Good signature | | `GET rpm{,/el9}/repodata/repomd.xml{,.asc}` | 200; Good signature | | `GET rpm{,/el9}.repo` | generated repo files with `gpgcheck=1` | | Cleanup-rules REST probes | 404 (not in v1 API — UI only) | | `DELETE` all four test entries | 204 ×4; package list then empty | Sources: [docs.gitea.com 1.27 Debian registry](https://docs.gitea.com/1.27/usage/packages/debian), [docs.gitea.com 1.27 RPM registry](https://docs.gitea.com/1.27/usage/packages/rpm), Gitea source tag `v1.27.1` (`routers/api/v1/api.go`, `models/packages/package_cleanup_rule.go`, `services/packages/cleanup/cleanup.go`), live instance `git.bongbetic.com`.