Publish and consume: docker pull, apt install, promotion

Goal: let users docker pull and apt install straight from a project, and move artifacts from staging to rc to release without rebuilding.

Every build lands in staging

A green build’s artifacts are immediately consumable under the project’s channel labels, staging by default:

$ docker pull saggar.dev/val/web:staging
$ echo "deb [trusted=yes] https://saggar.dev/apt/val staging main" \
    | sudo tee /etc/apt/sources.list.d/saggar.list
$ sudo apt update && sudo apt install web

The owner-scoped paths (val/web, apt/val) name the project’s owner; the specific job id is a version tag of its own, and artifact files are downloadable one by one through the API (GET /api/v1/artifacts/:id/files/:filename). See The registries for the full address and auth rules, including docker login and apt’s auth.conf.d for private projects, and pull-only tokens for machine-readable credentials.

Promotion is a label, never a rebuild

Channels move one way, staging → rc → release, and promotion applies a label to the existing, immutable artifact:

$ curl -X POST -H "X-Auth-Token: sgt-…" -d '{"channel": "release"}' \
    https://saggar.dev/api/v1/artifacts/a-5b249e203f7076f7/promote

Promotion needs promoter standing on the project and is audited: who, what, when. After promoting, the same content pulls as …:rc or …:release, and the apt suite flips the same way:

$ echo "deb [trusted=yes] https://saggar.dev/apt/val release main" | …

Typical loop: submit, verify the staging pull, promote to rc, promote to release. Immutable artifacts mean “release” is a pointer to exactly what was tested: no drift.

Browsing what is published

$ curl -H "X-Auth-Token: sgt-…" \
    'https://saggar.dev/api/v1/artifacts?project=val/web&channel=release'

Or saggar watch ls-style visibility in the web app: artifacts, channels, files with digests. Ephemeral artifacts (--ephemeral) are the exception: excluded from the registries and collected after the instance’s TTL. For check-builds, never for publishing.

Sharing with someone outside the account

A share link hands one artifact to someone with no saggar account. Mint it with viewer standing:

$ curl -X POST -H "X-Auth-Token: sgt-…" -d '{"expires_in_secs": 86400}' \
    https://saggar.dev/api/v1/artifacts/a-5b249e203f7076f7/shares

The reply carries the link path exactly once, /s/<token>; prefix the service origin (https://saggar.dev) and send it. It serves the whole artifact as a .tar.gz bundle, or single files at /s/<token>/files/<filename>. Give it its own clock with expires_in_secs (absent: no expiry). The link grants its artifact and nothing else: not the job, not the logs, not the project. GET /api/v1/artifacts/:id/shares lists who minted what; DELETE /api/v1/shares/:id revokes it immediately, and a revoked link is then indistinguishable from an unknown one.

Private projects

Until a project is public, pulls follow the project ladder: members only, with the credentials from Sign the CLI in. Denials are indistinguishable from unknown names; a private project leaks nothing, not even its existence.