Skip to content

Latest commit

 

History

History
271 lines (221 loc) · 12 KB

File metadata and controls

271 lines (221 loc) · 12 KB

InterGenOS Public Binary Mirror — v1.0 Design

Status. Live and publishing. repo.intergenos.org/x86_64/current/ serves a signed InterGenOS.db index, per-package .igos.tar.gz archives, and the GPL sources/ tree, emitted by the build pipeline's publish phase. The remaining v1.0 work is full package coverage across the archive set.

This document describes the mirror as it exists on disk, on the VPS, and in the canonical publish script. The fundamental decisions — hostname, cPanel account, docroot, and SSH coordinates — are settled, and the artifacts that implement them already exist on the master branch. The layout details and atomic-promote semantics described here match what scripts/publish-repo.sh implements.

Canonical companion artifacts.


1 — Hostname, docroot, and access

Mirror docroot (server-side):  /home/intergenos/repo/x86_64/
Mirror URL (client-side):      https://repo.intergenos.org/x86_64/current/
Publish SSH target:            [email protected] -p 2200

Domain. intergenos.org is secured at the Registrar for five years (registered 2026-05-11; expiry beyond v1.0 ship + the full v1.x release cadence). repo.intergenos.org is the public binary mirror's subdomain.

Underlying VPS. origin.intergenstudios.com — KnownHost-managed cPanel/WHM container. The intergenos cPanel account (distinct from the intergen account that owns the intergenstudios.com document root, and distinct from the christopher admin account) owns the repo.intergenos.org subdomain's docroot.

DNS. repo.intergenos.org162.255.162.237, TTL 7199s, cPanel-as-authoritative on origin.intergenstudios.com.

TLS. Let's Encrypt R12 cert via cPanel AutoSSL. CN = www.repo.intergenos.org, notAfter Aug 9 2026, auto-renewing. TLS is transport-only — see §3 for the trust model.

Publish access. SSH-key authentication as the intergenos cPanel user:

ssh -p 2200 [email protected]

A dedicated ed25519 publish key is installed in ~intergenos/.ssh/authorized_keys. The publish script (scripts/publish-repo.sh) writes directly into the docroot under this account, with no intermediate staging account, no VPS-root step, and no cPanel UI intervention.

Provenance. DNS, TLS, SSH access, the docroot layout, and the placeholder index were stood up on 2026-05-11. pkm/repo.py's DEFAULT_REPOS already encodes the hostname on the master branch, and docs/repository-trust.md references it as the integrity-chain endpoint.


2 — Layout under the mirror docroot

/home/intergenos/repo/x86_64/
├── current/                              # Symlink → live staging snapshot
├── _staging-<UTC_ISO_TS>/                # Per-publish dir; promoted via symlink swap
│   ├── InterGenOS.db                     # Gzipped JSON index (pkm/repo.py format)
│   ├── InterGenOS.db.sig                 # GPG detached signature
│   └── <name>-<version>-<release>.igos.tar.gz
└── _previous/                            # Archived snapshots
    └── <dir-name>-prev-<UTC_ISO_TS>/

Atomic-promote pattern: symlink-swap. The current/ entry is a symlink that points at the most recently published _staging-<TS>/ directory. Promotion is a ln -sfn + mv -T of a temporary symlink over the existing current/, which is a single atomic syscall on ext4. The old _staging-<TS>/ directory is moved into _previous/ under a prev-<TS> suffix only after the swap, so clients in flight either complete reads against the prior target (still present at its prior path) or restart against the new target. No partial-state visibility, no 404 window.

Why symlink-swap and not directory-rename. The symlink target is the staging directory, which stays where rsync placed it; the swap is a single inode update. A directory rename would also be atomic on a single ext4 filesystem, but symlink-swap composes cleanly with the rsync → stage → promote workflow without requiring the staging directory to land at its final path before promotion. The promote step in scripts/publish-repo.sh implements this pattern.

Per-archive .sig files: a later defense-in-depth augmentation. The v1.0 mirror uses a signed index only; docs/architecture/per-archive-sig-decision.md records this decision and lists per-archive signatures as a future defense-in-depth augmentation with documented trigger conditions. The v1.0 publish script emits no .tar.gz.sig files.

_previous/ retention. The five most recent snapshots are retained; older ones are auto-rotated by a small VPS-side cron job. The retention policy is tunable after the v1.0 launch if usage data motivates a change.


3 — Trust model

Integrity boundary: the GPG signature on InterGenOS.db.

1. /etc/pkm/trusted.gpg ships with the OS (in the live ISO and the
   installed system). Contains the InterGenOS release-signing topology:
     Master FP:    5597A3E0 587B2530 06D0DD7B 8C508261 82083050
                   (certifies subkeys; NEVER signs release artifacts)
     Subkey [S1]:  D7AA641D 81ACD690 C5AD865E 7276E14D D8886BFE
                   (on hardware token NK#1; signs release indexes)
     Subkey [S2]:  81DD223F 9BA9B3F2 AFBFFC5A FA24B042 975F775E
                   (on hardware token NK#2; backup signer)
2. Client downloads InterGenOS.db + InterGenOS.db.sig.
3. Client verifies the signature against /etc/pkm/trusted.gpg
   (signature is from [S1] or [S2], both subkeys certified by the master).
4. If valid: the index is authentic. Every per-package SHA256 in the
   index is now trusted.
5. Client downloads an individual archive, verifies SHA256 against
   the trusted index.
6. Install proceeds with verified bits.

The master GPG key is held offline, never touches the VPS, and never signs release indexes directly. Subkey [S1] (on hardware token NK#1) is the primary release signer; [S2] (on hardware token NK#2) is the backup. This topology is documented in docs/signing-key.md.

TLS is transport-only. TLS provides encryption and opportunistic authentication but is not the integrity boundary. A successful MitM with a valid Let's Encrypt cert for repo.intergenos.org cannot forge a GPG signature on the index — the signing material is on hardware tokens, not on the VPS. The MitM can deny service but cannot install untrusted bits.

Cert pinning: not required for v1.0. The integrity-chain anchor is the GPG master pubkey, shipped in /etc/pkm/trusted.gpg. TLS cert rotation (Let's Encrypt every ~60d) does not affect trust.


4 — Publish workflow

The canonical publish script is scripts/publish-repo.sh. It runs on the build VM (or any host that has the build's .igos.tar.gz archives and the release signing key available via the hardware token) and is wired into scripts/build-intergenos.sh as the publish phase.

Steps:

  1. Pre-checks. The master GPG keyring is available; the release subkey is present ([S1] on NK#1 by default, or [S2] on NK#2 via --gpg-key S2); SSH access to [email protected]:2200 works; and the archives directory exists and is non-empty.
  2. Generate index. Calls pkm.repo.generate_index(<archives_dir>) to produce InterGenOS.db (gzipped JSON in the format pkm/repo.py parses).
  3. Sign index. gpg --detach-sign --armor --output InterGenOS.db.sig --local-user <SUBKEY_FP> InterGenOS.db. The hardware token prompts for its PIN and touch confirmation.
  4. Rsync staged tree to VPS. Stages into a per-publish _staging-<TS>/ directory directly under /home/intergenos/repo/x86_64/ on the VPS, with no intermediate account and no root step.
  5. Atomic promote. ln -sfn + mv -T to swap the current/ symlink to the new staging directory, then archive the prior target to _previous/.

No httpd restart needed. Apache serves files directly from disk; the symlink update is observed on the next request.

Remaining v1.0 work. Three pieces of wiring remain, none of which require design changes: (i) the build pipeline must emit per-package .igos.tar.gz archives into /var/lib/igos/archives/; (ii) the index-generation step in publish-repo.sh must be exercised against a real build's archive set, including the hardware-token signing prompt; and (iii) the first publish plus an end-to-end pkm sync smoke test against the live mirror.


5 — Client-side config

The OS ships /etc/pkm/repos.conf via packages/core/pkm/build.sh:

[intergenos-current]
url = https://repo.intergenos.org/x86_64/current/
enabled = true
# gpg_verify = true — optional; verification is mandatory, only true is accepted

The runtime pkm/repo.py DEFAULT_REPOS dictionary encodes the same URL, so a missing or unreadable /etc/pkm/repos.conf falls back to a functional default rather than a broken one.

Repo-index signature verification is mandatory and unconditionally on (the first signed publish has long since landed). gpg_verify may be omitted (default on) or set true; an explicit gpg_verify = false is refused at config load (PKM-A21) rather than silently verifying anyway and contradicting the user — a security knob that silently does nothing is worse than no knob.

Planned config schema. The v1.x roadmap includes a per-repo signing-key-fingerprint field, an opt-in testing/ channel alongside current/, and an optional TLS-SPKI pin as defense-in-depth. None of these ship in v1.0.


6 — Security posture

Security is not first. It is only. The mirror design reflects that posture:

  • No third-party CAs in the integrity boundary. TLS uses Let's Encrypt because the only alternative — shipping a project-owned CA trust anchor in the OS for a CA that signs our own TLS certificate — buys nothing, since TLS is transport-only. The integrity boundary is the GPG signing topology, anchored on hardware-token subkeys certified by an offline-held master.
  • No standing third-party access to the publish path. The publish workflow uses a dedicated ed25519 key installed under the intergenos cPanel account. There are no webhooks, no CI runners with mirror-write access, and no SaaS in the loop. The signing material stays on hardware tokens.
  • Verifiable by the user. Every archive's path, every SHA256, and the index signature itself are reproducible by hand with curl, gpg, and sha256sum against the published master public key. There are no opaque steps.
  • Published from the canonical source, not from an installed system. The publish script takes archives from the build-output directory — the canonical producer — not from /var/lib/igos/archives/ on an installed machine.

7 — Cross-references