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, and 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 guard the file after handing it back¶
A cache hit is re-hashed against a digest from the manifest verified in the same
call, so an entry edited on disk is caught and fetched again. What Resolve
cannot do is protect the file once it has returned the path: anyone who can
write to the cache between that check and your open can still substitute it.
Choose a cache location covers what that
means for where the cache should live.
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.