Skip to content

Publish a package repository from GitHub Pages - #95

Merged
miharp merged 1 commit into
mainfrom
package-repository
Sep 2, 2026
Merged

miharp merged 1 commit into
mainfrom
package-repository

Conversation

@miharp

@miharp miharp commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Closes #42 once the first deploy lands.

What this is

A yum and apt repository as static files on GitHub Pages, at https://mikeharp.com/codavox (the github.io address redirects there). The Repository workflow rebuilds it in full from GitHub Releases whenever a release is published, and on demand: every rpm and deb ever released, indexed with createrepo_c and apt-ftparchive, metadata signed, deployed with deploy-pages. No branch to maintain; the releases page stays the source of truth and this is a view of it.

What is signed

The metadata, not the packages: repomd.xml and Release each carry every package's SHA-256, so a signed index vouches for every file below it. That is how apt has always worked, and dnf verifies it with repo_gpgcheck=1, which the shipped .repo file sets. It keeps the packages byte-for-byte the release assets, including releases made before this existed, so checksums.txt still describes them. The key's secret half is in the repository secrets (REPO_GPG_PRIVATE_KEY, REPO_GPG_PASSPHRASE, already set); the public half is exported into the site as codavox.asc.

Verified

Locally with a throwaway key, against the eight rpm and eight deb files of the four releases: dnf on Rocky 9 and apt on Debian 12 each imported the key, verified the metadata, installed a pinned 0.7.0, and upgraded to 0.8.0. One finding on the way: apt-ftparchive's Tree mode indexed nothing from the pool, so the builder runs the per-architecture scan directly.

Docs

README and installation.md install from the repository; installation.md keeps install-by-URL as the fallback for a host that cannot reach it, which is now the only place a VERSION= line lives, so the release workflow's version check covers that file alone. CONTRIBUTING's release steps mention the Repository workflow.

After merging

Run the Repository workflow once by hand (gh workflow run repository.yml); Pages is already enabled for workflow deploys. Then the Puppet module can manage the repository instead of a package_source URL, and the lab can drop its pinned asset.

Assisted by Claude.

Every install was by URL, so every consumer encoded the release filename
convention, the architecture segment did not match the fact it came from,
ensure => latest could not work, and the lab and the Puppet module both had
to pin a raw asset. Hosting a repository looked like a standing commitment:
a server, createrepo, an apt indexer, a key to generate, distribute, and
rotate.

It is a build step after all. The repository is static files: a directory
with repodata in it is a yum repository, and one with Packages and Release
files is an apt repository, and GitHub Pages serves both. The Repository
workflow rebuilds it in full from GitHub Releases whenever a release is
published — every rpm and deb ever released, indexed and signed — so there
is no branch to maintain and nothing to get out of step with the releases
page, which stays the source of truth.

What is signed is the metadata, not the packages. repomd.xml and Release
each name every package's SHA-256, so a signed index vouches for every file
below it; apt has always worked this way and dnf verifies it with
repo_gpgcheck. That keeps the packages byte-for-byte the release assets,
including releases made before this existed, so checksums.txt still
describes them. The key's secret half lives only in the repository secrets;
its public half is exported into the site beside the packages.

Verified locally with a throwaway key: dnf on Rocky 9 and apt on Debian 12
each imported the key, verified the metadata, installed a pinned older
version, and upgraded to the latest. apt-ftparchive's Tree mode indexed
nothing from the pool, so the builder scans per architecture directly.

The README installs from the repository and needs no version; only the
install-by-URL fallback in installation.md carries one, so the release
workflow's version check now covers that file alone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Michael Harp <mike@mikeharp.com>
@miharp
miharp merged commit 31b4520 into main Sep 2, 2026
13 checks passed
@miharp
miharp deleted the package-repository branch September 2, 2026 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish a package repository instead of release URLs

1 participant