Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/Skidbladnir

.nornir/upstream-registry-federation.md

Upstream-registry federation — the ship between harbours

Status: BUILT. skidbladnir::federation (feature federation, + upstream-azure / upstream-aws) ships the UpstreamRegistry trait and five harbour clients — Artifactory, Nexus, Azure Artifacts, AWS CodeArtifact, and OCI Distribution (GHCR/Harbor/Quay/Docker Hub) — proven by offline tests (cargo test --features federation,upstream-azure,upstream-aws). This doc is the architecture decision: where the federation lives and who consumes it.

The metaphor — Skíðblaðnir is the ship

In the myth Skíðblaðnir is Freyr's expert vessel: it always finds a fair wind and folds away when not in use. Here it is the ship that sails between harbours.

            hires the ship for a voyage
 holger  ───────────────────────────────▶  Skíðblaðnir (the ship)
 (harbour / consumer)                        skidbladnir::federation
   • which feeds, scheduling                   • UpstreamRegistry trait
   • pull-through cache, dedup-on-store         • auth · list · fetch · mirror
   • compression via znippy                     │
                                                ▼   sails between harbours
              ┌──────────┬────────┬───────────────┬────────────────┬──────────────────┐
           Artifactory  Nexus   Azure Artifacts  AWS CodeArtifact  OCI Distribution
                                                                   (GHCR/Harbor/Quay)

The contract — UpstreamRegistry

One trait (src/federation/mod.rs), five impls. The shared vocabulary (UpstreamAuth, ArtifactMeta, ArtifactCoord, RegistryFormat, upstream_path) lives once in the module so every harbour shares one auth enum, one metadata shape, and one coordinate→layout mapping.

method purpose
name / base_url / auth / format harbour identity + credentials + ecosystem
list() enumerate available artifacts — an honest Err for these content-addressed HTTP registries (no uniform cross-vendor "list everything" API); a consumer drives mirror with an explicit coordinate set instead
fetch(id) one artifact's bytes; Ok(None) on a clean 404; verified against the upstream sha256 when advertised (cache-poisoning guard)
metadata(id) cheap HEAD probe (size · sha256 · content-type)
mirror(ids, sink) the voyage: fetch each coordinate, hand the bytes to the consumer's sink, skip the 404s, report the count

The impls: ArtifactoryRegistry, NexusRegistry, AzureArtifactsRegistry (feature upstream-azure), AwsCodeArtifactRegistry (feature upstream-aws), and OciDistributionRegistry (base federation).

The OCI Distribution harbour (a different protocol, not a twin)

The four file-path harbours GET a per-ecosystem artifact path (upstream_path). OciDistributionRegistry speaks the OCI Distribution Spec v2 instead — a content-addressed image store, so it is genuinely non-twin coverage:

The mock server can emit response headers

The federation test mock (testutil::MockServer) gained start_with — a responder that sees the whole request (so it can branch on Authorization) and returns a MockResponse with arbitrary response headers. start is a thin wrapper (header-less fixtures unchanged, L2). This unblocked two things that were previously untestable: the OCI token handshake above (fixture emits the WWW-Authenticate challenge + serves its own /token), and HEAD-checksum assertions — the shared head_meta now has a test proving it reads X-Checksum-Sha256 + Content-Type (covering all four file-path harbours, which share it), OCI's metadata reads Docker-Content-Digest, and Artifactory has an end-to-end test that a mismatched advertised checksum makes fetch hard-error (the cache-poisoning guard, proven end-to-end).

Pure-Rust by charter — no async cloud SDK, no C toolchain

Every harbour speaks its documented HTTP endpoint over a shared SYNC ureq client (rustls/ring). We deliberately do not vendor aws-sdk-codeartifact, aws-config, or the async azure_* crates:

So no AWS/Azure crypto is hand-rolled here — the ship is a faithful HTTP client of each harbour's package-manager-compatible endpoint. This keeps full-tier holger green with zero C dependencies (verified: cargo tree shows no aws-lc, aws-sdk, azure_*, or openssl).

The boundary (the architecture decision)

Cross-reference — the nordisk constellation dedup law

This split is the constellation dedup law applied: a capability's mechanism lives in exactly ONE repo, and every other repo depends on it rather than re-implementing it (the same law that moves korp's lineage/segmentation into skade, and jera's job handler into edda — "no dup code"). Registry-client code has one home: Skidbladnir. holger (and any future consumer — nornir, tunnr) hires the ship; it does not build its own.

Feature map

feature pulls harbours enabled
federation ureq, base64 (pure-Rust) Artifactory, Nexus, OCI Distribution (GHCR/Harbor/Quay/Docker Hub)
upstream-azure → federation + Azure Artifacts
upstream-aws → federation + AWS CodeArtifact
(none) nothing the lean airgap core links no HTTP client for this