Skip to content

What this module does not do

A small module is easier to trust than a large one, and the things left out are as much a design decision as the things kept. Each of these was considered and placed elsewhere.

It does not choose versions

There is no "latest", no channel to track, no status to resolve against. You pass a Ref with an explicit version and get that version.

The reasoning is in Why status is not a channel.

It does not extract archives

Resolve returns a path to a .tgz. It does not unpack it, and it does not know that the file inside is a shared library you were going to dlopen.

Extraction is where a downloaded archive becomes a filesystem write with the archive's own idea of paths — the zip-slip class of problem — and it needs decisions this package has no basis for: where to extract, whether to reuse an existing extraction, what to do about permissions and symlinks.

A consumer that needs it wraps this one. That wrapper is a reasonable candidate for its own module if more than one tool needs the same behaviour.

It does not load anything

No dlopen, no LoadLibrary, no plugin registration. The result is a path.

Loading a native library is platform-specific, process-global, and effectively irreversible — the wrong place for it is a package whose job finishes when the bytes are on disk and proven.

It does not publish

Publishing is the channel's job: the artifacts project mirrors upstream releases, generates manifests, signs them with a KMS-held key via CI, and uploads them.

Keeping the consumer and publisher apart is deliberate. This module has no signing capability at all — it can verify and it cannot sign, which is the right asymmetry for something running on a user's machine.

It does not discover what exists

There is no "list all artefacts" or "list versions of this artefact". You need to know the name and version before you call it.

client.Manifest(ctx, ref) tells you what a specific version contains, which is the question that comes up in practice — usually "was my platform published?". Browsing the catalogue is a job for the inventory in the channel repository, where the statuses and licences and upstream links live in a form a human reads.

It does not decide policy about the cache

It will not clean up old versions, enforce a size budget, or expire anything. A cache directory grows until something else removes files from it.

Retention is a deployment decision — a CI runner, a developer laptop and a long-lived container want three different answers — and the layout is deliberately browsable so that rm -rf <root>/<artefact>/<version> is a complete and obvious operation.

It does not re-verify on read

Bytes are verified before they are cached, not each time they are read. The consequence — anyone who can write to the cache can substitute an artefact — is covered in Choose a cache location.

DirCache.Verify exists for a caller that wants to audit a cache it did not populate, but nothing calls it on the read path.

Why the list matters

Each of these is somewhere a "helpful" addition would cost more than it gave. A resolver that also extracted, loaded and cleaned up would be a resolver whose failure modes are hard to reason about and whose blast radius includes the filesystem and the process.

What is left is small enough to describe in a sentence: fetch by name and version, prove who published it, prove the bytes match, hand back a path.