- Zig 86.6%
- Python 7.9%
- Shell 5.5%
| docs | ||
| src | ||
| test | ||
| .gitignore | ||
| build.zig | ||
| build.zig.zon | ||
| LICENSE | ||
| README.md | ||
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_lifecyclesupplies 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