Multi-registry package publisher for Forgejo/Gitea — RPM, ALT, Debian, Generic, npm
  • Zig 86.6%
  • Python 7.9%
  • Shell 5.5%
Find a file
2026-09-08 21:21:16 +00:00
docs feat: define candidate stable lifecycle 2026-09-08 21:21:16 +00:00
src feat: define candidate stable lifecycle 2026-09-08 21:21:16 +00:00
test feat: define candidate stable lifecycle 2026-09-08 21:21:16 +00:00
.gitignore feat: replace ALT publisher with Zig client 2026-09-08 18:33:54 +00:00
build.zig feat: define candidate stable lifecycle 2026-09-08 21:21:16 +00:00
build.zig.zon feat: define candidate stable lifecycle 2026-09-08 21:21:16 +00:00
LICENSE feat: replace ALT publisher with Zig client 2026-09-08 18:33:54 +00:00
README.md feat: define candidate stable lifecycle 2026-09-08 21:21:16 +00:00

forgejo-alt

Minimal Zig 0.16.0 client for the Forgejo ALT Linux package registry. It replaces the former Node.js publisher and intentionally supports only the ALT wire protocol that multi-alt needs.

What works

  • raw RPM PUT /api/packages/{owner}/alt/{group}/upload;
  • fail-closed handling of HTTP 409 duplicates;
  • mandatory repository read-back and SHA-256 comparison after every upload;
  • exact-file read and delete through {group}.repo/{arch}/RPMS.classic/{filename};
  • paginated ALT package listing through the Forgejo API v1;
  • reusable Zig library with an injectable transport and a real HTTP transport;
  • transport-independent candidate/stable lifecycle policy with canonical candidate/release identities, no-overwrite promotion, retention, revocation and previous-lock rollback planning;
  • CLI token input only through FORGEJO_TOKEN, with status-only errors and no token or response-body logging.

The repository does not publish anything during tests. The integration fixture uses a loopback mock server and checks raw request bodies, endpoint paths, read-back verification, duplicate rejection, digest mismatch rejection, and observable-output secret safety.

Build and test

Use exactly Zig 0.16.0:

zig version
zig fmt --check build.zig src test/forgejo_alt_test.zig
zig build test --summary all
zig build -Doptimize=ReleaseSafe --summary all

The executable is installed as zig-out/bin/forgejo-alt.

CLI

The token is deliberately not accepted as an argument because argv can be visible to other processes.

export FORGEJO_TOKEN='...'

forgejo-alt upload BASE_URL OWNER GROUP ARCH package.rpm
forgejo-alt read BASE_URL OWNER GROUP ARCH package.rpm output.rpm
forgejo-alt list BASE_URL OWNER [PAGE]
forgejo-alt delete BASE_URL OWNER GROUP ARCH package.rpm

upload hashes the local RPM, sends those exact bytes as application/octet-stream, downloads the exact repository object with Accept-Encoding: identity, and succeeds only when both SHA-256 digests match. DELETE is destructive and targets one exact repository filename.

Library

Import the forgejo_alt module. Construct Client with an allocator, HttpTransport.transport(), base URL, owner and token. The public operations are upload, readBack, list, and delete. Tests can supply Transport with a custom request function; production callers do not need a subprocess.

All returned byte slices are owned by the caller's allocator. readBack and list therefore require the caller to free their results.

Import release_lifecycle for the release policy. Its state transitions and promotion/rollback/revocation plans have no network side effects. The canonical wire formats and operator procedure are specified in docs/CANDIDATE-STABLE-LIFECYCLE.md.

Security and current limitations

  • Path components are restricted to ASCII alphanumeric characters, ., _ and -; group / separators are validated segment by segment.
  • Redirects are rejected, preventing credentials or digest checks from moving to another origin.
  • Response bodies are never included in diagnostics.
  • The current HTTP transport buffers each response in memory. The CLI limits local RPM input to 1 GiB, but callers should still apply artifact-size policy.
  • Listing returns Forgejo's JSON bytes rather than a version-coupled package model.
  • No package was uploaded to the live registry while implementing this change; external publication was explicitly out of scope. The raw PUT and repository paths match Forgejo 15.0.4 documentation and the separately verified live read-only ALT layout.
  • CI/reusable publishing and manual stable-promotion workflows are separate downstream tasks. This repository currently contains no publishing workflow; release_lifecycle supplies the policy boundary they must call.

Rollback

The last JavaScript implementation remains in Git history at commit 5fc1cc2. Revert the Zig migration commit to restore it; do not run both publishers as production defaults.

License

MIT