Limits and defaults¶
Every bound here exists because the unbounded version is a fault waiting for a bad day. None is configurable unless a column says so.
HTTP¶
| Value | Configurable | |
|---|---|---|
| Request timeout | 5 minutes | artifacts.WithHTTPClient |
| Channel base | DefaultChannel |
artifacts.WithChannel |
The default client is &http.Client{Timeout: 5 * time.Minute}. An artefact is
tens of megabytes, so a transfer that stalls is a fault rather than slowness, and
a resolver that hangs takes the tool down with it.
Supplying your own client replaces the timeout entirely — set one.
Download ceilings¶
| Fetch | Ceiling |
|---|---|
| Manifest and signature | 1 MiB |
| Artefact | the publisher's signed length, capped at 1 GiB |
A manifest is a few hundred bytes; 1 MiB is generous. The artefact ceiling is generous but finite — the largest artefact mirrored today is around 40 MB, and the bound exists so a compromised or confused channel cannot stream forever.
Reads are truncated at the ceiling rather than erroring, so an oversized artefact fails at the digest check. It fails, which is what matters.
Cache¶
| Value | |
|---|---|
| Conventional root | <os.UserCacheDir()>/phpboyscout/artifacts |
| Layout | <root>/<artefact>/<version>/<file> |
| Directory mode | 0755 |
| File mode | 0600 |
| Write strategy | stream to a quarantine file, hash in flight, then rename |
| Read strategy | re-hashed against the signed digest on every hit |
Directories are 0755 — readable by all, writable only by the owner. An artefact
is public data, fetched from a public channel, but a world-writable cache would
let any local user swap verified bytes for their own after verification has
happened.
Files land at 0600, inherited from the temporary file the atomic write creates.
The practical consequence is that a cache is shared between one user's tools, not
between users — see
Choose a cache location.
Path components from the manifest are sanitised before use: separators and
traversal are stripped, so a manifest naming ../../.ssh/authorized_keys lands
inside the cache or nowhere. A signature proves who published a name, not that
the name is harmless.
Trust¶
| Value | Configurable | |
|---|---|---|
| Release identity | artifacts-release@phpboyscout.uk |
no — it is the key |
| Anchors | embedded key and WKD, must agree | no |
| Failure mode | fail closed | no |
| WKD fetch client | go/signing default, 30s timeout |
trust.WithHTTPClient |
| Key set caching | resolved once, on success only | no |
The failure mode is deliberately not an option. go/signing's composite resolver
defaults to fail-open — a WKD outage falls back to the embedded key with a
warning — which suits self-update and not artefact resolution. See
The trust model.
A failed resolution is not cached, so a transient WKD outage does not poison the verifier for the lifetime of the process.
Dependencies¶
The root package links no cryptographic implementation, enforced by a test.
OpenPGP arrives through artifacts/trust, so importing that subpackage is the
point at which a consumer opts into cryptography — and until then go-crypto and
its curve implementations are not in the binary.
Its full dependency set is github.com/spf13/afero (the filesystem seam behind
WithFS) and afero's own golang.org/x/text. A second test names that set, so
an addition is a decision somebody recorded rather than something that arrived.
Requires Go 1.26.6 or newer.