Static Debian APT repository and GPG public key for Zurvan Linux, served by
GitHub Pages at https://repo.zurvanlinux.org (CNAME in this repo; proxied
through Cloudflare per distribution-update-strategy.md §2).
pool/ # source of truth: committed .deb files (flat layout)
dists/zurvan/ # generated by publish-repo.yml (NOT hand-edited)
main/binary-amd64/
Packages, Packages.gz
Release # apt-ftparchive output (checksums of everything above)
Release.gpg # detached signature of Release
InRelease # clear-signed Release
public.key # GPG public key consumed at install time (P0 deliverable)
apt-ftparchive.conf # Release metadata (Origin/Label/Suite/Codename/...)
.github/workflows/
publish-repo.yml # regenerate + sign indices; commit dists/ back to main
.nojekyll # serve all files verbatim on Pages
CNAME # repo.zurvanlinux.org
Committed .debs in pool/ are the source of truth. The publish workflow
regenerates indices statelessly on every run — no database, no committed
Packages/Release state edited by hand.
On a Debian Stable system:
# 1. Install the signing key into the modern keyring location.
sudo install -d -m 755 /etc/apt/keyrings
curl -fsSL https://repo.zurvanlinux.org/public.key \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/zurvan-archive-keyring.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/zurvan-archive-keyring.gpg
# 2. Add the repository (suite "zurvan", component "main", amd64).
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/zurvan-archive-keyring.gpg] https://repo.zurvanlinux.org zurvan main" \
| sudo tee /etc/apt/sources.list.d/zurvan.list
# 3. Update — expect NO GPG warnings.
sudo apt updateExit criterion (M1.2): curl https://repo.zurvanlinux.org/public.key succeeds
and apt update against the line above produces no GPG warnings.
.github/workflows/publish-repo.yml runs on:
pushtomaintouchingpool/**(e.g. a new.deblands), andworkflow_dispatch(manual).
It:
- Regenerates
dists/zurvan/main/binary-amd64/Packages[.gz]viadpkg-scanpackages, anddists/zurvan/Releaseviaapt-ftparchive. - Imports the signing-only subkey from the
APT_SIGNING_SUBKEYsecret, signsReleaseintoRelease.gpg(detached) +InRelease(clear-signed) using theAPT_SIGNING_PASSPHRASEsecret with loopback pinentry, self-verifies, then strips the subkey before the job ends. - Commits the generated
dists/back tomain; GitHub Pages serves it.
The workflow fails fast and clearly if the secrets are absent (see P0 below).
This skeleton is fully buildable except for the cryptographic signing step, which depends on offline work the maintainer must complete:
- Offline / air-gapped: generate a 4096-bit RSA primary key
(
Zurvan Linux Archive <archive@zurvanlinux.org>), back it up offline, never expose it. From it, derive a signing-only subkey. - Export: the armored public key → commit here as
public.key(root). Export the secret subkey + passphrase. - Secrets (repo Settings → Secrets): add
APT_SIGNING_SUBKEY(the armored secret subkey) andAPT_SIGNING_PASSPHRASE.
Until these exist, publish-repo.yml regenerates indices successfully but errors
at signing with an explicit message. If the subkey ever leaks, only the subkey
needs revocation — the primary key (held offline) is unaffected.
Per the project plan's risk note, there is no automatic keyring refresh in Phase 1, so a leaked signing subkey requires every installed system to update its keyring manually. To rotate:
- Revoke the compromised subkey from the offline primary key; export the revocation.
- Derive a new signing-only subkey; update the two secrets
(
APT_SIGNING_SUBKEY,APT_SIGNING_PASSPHRASE). - Re-export and commit the updated
public.key(still the same primary key, so the keyid and trust chain are preserved). - Re-run
publish-repo.ymlto re-sign all indices with the new subkey. - Publish a rotation advisory: installed users must re-fetch
public.keyand runsudo apt update(apt will surface the new subkey via the primary key).
Authoring custom .debs (DNS switcher, branding, welcome app), building and
publishing them, and wiring them into the ISO. Those land in Phase 2
(zurvan-dns-bypass.deb, zurvan-branding-assets.deb). This repo only provides
the signed skeleton + publish pipeline.