d0016e22 Andy McCall 23 days ago ↶
1
# Cylinder: artifacts, the Oxygen way
2
82739cfb Andy McCall 23 days ago ↶
3
Status: Draft 0.3 (proposal revision 3), 2026-10-12. Draft 0.2 added the
d0016e22 Andy McCall 23 days ago ↶
4
object model, deployment leases, inverted vulnerability indexing,
82739cfb Andy McCall 23 days ago ↶
5
multi-party consensus, agent scopes and revset queries; 0.3 corrects the
6
MicroVM mount path, the reach of the file index, revocation, encryption,
7
leases and upstream quarantine, and keeps §7 open. C0 is built; the rest
8
is not. "Cylinder" is a working name (the artifact-repository idea parked
9
on 2026-10-02); nothing here is decided until Andy says so.
d0016e22 Andy McCall 23 days ago ↶
10
11
** Cylinder** keeps and moves everything a build produces: runner images,
12
container images, packages, binaries, SBOMs and reports. It would be a
13
service of its own, embedded in OxygenHub by default and shown through
14
the hub's UI, the same pattern as Jetstream. It is meant to be better
15
than what exists, not compatible with it; compatibility is an edge we add
16
for adoption, never the core.
17
18
## 1. What exists today
19
20
21
22
| ** Docker Hub** | The default namespace; huge public catalogue; official images; scanning (Scout). | Pull limits since April 2025: 10 an hour anonymous, 100 an hour on a free account. SaaS only. Tags are mutable. Signatures and provenance are separate artifacts; referrers are still in beta. Nothing links an image to the source it came from. |
23
| ** GitHub** (GHCR, Packages) | Next to the code and Actions; free container storage for now; the best Sigstore integration; artifact attestations. | Storage billing for private images deferred, not settled. One silo per package format. Auth by personal access tokens. Tags are mutable: the tj-actions attack (March 2025, CVE-2025-30066) moved every tag of a popular action to a malicious commit at once. No self-hosting outside Enterprise Server. |
24
| ** GitLab** | A registry per project; many package formats; a dependency proxy; self-hostable, so it can be sovereign. | Cleanup policies delete tags only; layers stay until an administrator runs garbage collection. The registry is a separate service to run and scale. Signing means bringing cosign yourself. |
25
| ** Bitbucket** (Packages) | GA since December 2025; permissions inherited from the repository; garbage collection runs by itself; Maven and npm since April 2026. | Young; Cloud only; few formats; no provenance story. |
26
| ** Artifactory, Nexus** | Every format; proxies and caches; enterprise features. | Costly; heavy JVM operations; slow UIs. A second system beside the forge, with its own identities and permissions. Provenance and scanning are add-on products. |
27
| ** Harbor, Quay** | Self-hosted OCI with signing (cosign, Notation), replication and scanning. | Many components to run. A central bottleneck: peer-to-peer means adding Dragonfly. |
28
| ** ECR, Artifact Registry, ACR** | Cloud IAM; regional; scanning; lazy pulling on AWS (SOCI). | Lock-in; egress costs; not sovereign. |
29
30
And the bolt-ons each of them needs:
31
32
- ** Distribution:** Dragonfly, Kraken or Spegel, run beside the registry.
33
- ** Lazy pulling:** eStargz, SOCI, Nydus or zstd:chunked, each a format
34
plus a snapshotter. It matters: pulling took 76% of container start time
35
while only 6.4% of the pulled data was read (Slacker, FAST '16).
36
- ** Signing and provenance:** cosign and Rekor, SLSA generators,
37
in-toto, Notation, attached afterwards through the OCI referrers API.
38
- ** Retention:** cleanup policies plus a separate garbage collection.
39
40
## 2. The pattern behind the weaknesses
41
42
1. ** The unit is the tarball layer.** One changed file re-pushes and
43
re-pulls a whole layer; layers share nothing below their own size; and a
44
layer has two digests (compressed and not), so tools disagree on what
45
it is called.
46
2. ** Names are mutable pointers.** A tag moves silently and leaves no
47
history. Pinning by digest is safe but unreadable, so most people
48
don't.
49
3. ** Trust is bolted on afterwards.** The registry stores bytes; a
50
separate tool signs them, a third says how they were built, and each
51
brings its own keys and identities. Nothing stops an unsigned image
52
from being pushed, and most pulls never verify anything.
53
4. ** Distribution is someone else's problem.** Every registry is a
54
central server; peer-to-peer and lazy loading are extra products.
55
5. ** The forge and the registry are strangers.** Permissions, identity,
56
retention and "which commit is this?" are kept twice and drift apart.
57
58
## 3. What Oxygen already has
59
60
Every piece Cylinder needs exists in some form:
61
62
- ** Content-defined chunks with BLAKE3** (FastCDC, 32 to 256 KiB), shared
63
by repositories, release assets, and runner images: deduplication below
64
file level, across everything.
65
- ** Hybrid post-quantum signatures** (Ed25519 with ML-DSA-65), identities
66
with delegation chains, and rotation recorded in the repository.
67
- ** Signed Flow receipts:** a runner signs what it built, from which
68
state, with which pipeline and environment, producing which outputs.
69
That is provenance by construction, not a statement added later.
70
- ** flow-casfs:** a content-addressed tree mounted lazily over FUSE or
71
virtio-fs. Lazy pulling is native, not a format bolted on.
72
- ** The Jetstream swarm:** peer-to-peer chunks, rarest first, TLS pinned
73
by the hub, tickets that only the hub signs.
74
- ** Strata:** storage on disk, S3, GCS or Azure, with no server in between,
75
sovereign keys and client-side hash verification.
76
- ** OxygenHub:** one identity and permission model, checks, proposals and
77
reports.
78
- ** Scoped delegation:** key scopes (` changes` , ` refs` , ` seal` ) allowing
79
principals and AI agents to act within strict cryptographic boundaries.
80
81
## 4. The design
82
83
### 4.1 One kind of thing: a tree of chunks
84
85
An ** artifact** is an immutable, content-addressed object in the Oxygen
86
store naming a file tree:
87
88
```
89
Artifact {
90
version [0]: 1
91
kind [1]: "container" | "runner-image" | "package" | "archive" | "report"
92
arch [2]: text | null // "x86_64", "riscv64", "aarch64"
93
os [3]: text | null // "linux", "darwin", "none"
94
tree [4]: ObjectRef // DirTree blob: paths, modes, blobs, sizes
95
entrypoint [5]: [text] | null // default exec argv
96
env [6]: map<text, text> | null // environment variables
97
labels [7]: map<text, text> | null // metadata / OCI labels
98
total_size [8]: u64 // uncompressed bytes
99
receipt [9]: ObjectRef | null // Receipt object that produced it
100
}
101
```
102
103
Files in the ` DirTree` are ordinary Oxygen ` blob` objects composed of
104
FastCDC BLAKE3 ` chunk` s. So:
105
106
- An image rebuilt with one changed file moves only that file's changed
107
chunks: no layers.
108
- A release tarball, an npm package, and the container image containing
109
the same binary share its chunks verbatim. If a 100 MB model or library
110
is committed in the repo and then packaged, zero new chunk bytes are
111
written to Strata.
112
- A single file can be fetched independently: a container or job starts
113
after fetching only the files it reads.
114
- Every artifact has exactly one name for its content: the BLAKE3 of its
115
canonical CBOR encoding.
82739cfb Andy McCall 23 days ago ↶
116
- ** MicroVMs:** Flow's MicroVM tier runs on Firecracker, which has no
117
virtio-fs, so a microVM gets the artifact as a block device: an ext4
118
image served on the fly from the chunk tree (a userspace block device,
119
ublk, or an NBD server), fetching blocks as the guest reads them and
120
duplicating no bytes. That removes copying whole images onto each
121
runner's disk without changing hypervisor. The syscall tier and
122
containers mount the tree directly over ` flow-casfs` ; mounting it with
123
virtio-fs would need Cloud Hypervisor or QEMU instead of Firecracker.
d0016e22 Andy McCall 23 days ago ↶
124
125
### 4.2 Names are signed histories, not pointers
126
127
A ** channel** (` app:stable` , ` runner-image:rust` , ` pkg:cargo/my-crate` ) is an
128
append-only log of signed moves, recorded as an attestation of kind
129
` channel` :
130
131
```
132
Attest (kind = "channel") {
133
channel [0]: text // e.g. "app:stable"
134
old_art [1]: ObjectRef | null // previous artifact hash (CAS check)
135
new_art [2]: ObjectRef // target artifact hash
136
serial [3]: u64 // monotonically increasing
137
receipt [4]: ObjectRef | null // Receipt that built new_art
138
reason [5]: text // commit message or promotion note
139
}
140
```
141
142
A move needs policy: signed by an authorized key under the repository's
143
trust policy (` spec.md §14.5` ), from an approved bookmark, after
144
required checks or human approvals pass. Clients follow a channel and
145
verify each step:
146
147
- A tag cannot move silently. The tj-actions attack needed one stolen
148
token; here it needs a move signed by an authorized key, and the move
149
is logged in the append-only history.
150
- Rolling back is a move to an earlier artifact, recorded and attested
151
like any other move.
152
- Pinning stays readable and tamper-evident: ` app:stable@42` names the
153
42nd entry of an audited log.
154
- On Strata stores, updates use compare-and-swap on the channel record
155
(` old_art` and ` serial` ), matching how bookmark ` refs` operate.
156
157
### 4.3 Provenance by construction and multi-party consensus
158
159
An artifact is published by a Flow job, and its record is the unbroken
160
chain:
161
162
> source state → pipeline → runner (identity, tier, image) → signed
163
> receipt → artifact
164
165
Each link is a hash or signature verifiable offline. Beyond what
166
attestations give today:
167
168
- ** Assurance levels:** a MicroVM job on a registered runner is worth
169
more than a syscall-tier job, which is worth more than a signed local
170
build. Trust policies can enforce minimum assurance floors for
171
sensitive channels.
172
- ** Multi-party consensus (` reproduced` ):** when multiple independent
173
runners on disjoint machines or architectures build the same artifact
174
hash from the same state, each signs a receipt. A policy rule can
175
require threshold consensus:
176
` require: "reproduced(2)"` demands two independent runner receipts
177
before an artifact can be promoted to a production channel.
178
- ** Upstream lineage:** an artifact built from other artifacts (a base
179
image, a package) names their hashes in its receipt inputs, so the chain
180
reaches back transitively to their sources.
82739cfb Andy McCall 23 days ago ↶
181
- ** An SBOM with every artifact:** the job that publishes an artifact also
182
records what it contains by package and version (an SBOM, itself an
183
artifact named in the receipt's outputs), so "which artifacts hold a
184
vulnerable version of this package" is a lookup, not a scan (§4.6).
d0016e22 Andy McCall 23 days ago ↶
185
186
### 4.4 Distribution is built in
187
188
- ** The store is the seed; the swarm delivers.** Jetstream's swarm,
189
generalized: any runner, cluster node or developer machine in a site
190
shares the chunks it has, over TLS pinned by the hub, admitted by
191
hub-signed tickets.
192
- ** Lazy by default:** artifacts are mounted via ` flow-casfs` and fetched
193
on demand.
194
- ** Learned prefetch:** each run records which chunks were accessed
195
during its initial execution window; subsequent pulls request those
196
chunks first.
197
- ** Sites and air gaps:** a site syncs chunks and channel logs from
198
another hub as a signed bundle, so a disconnected network gets
199
verified artifacts with no live connection.
200
201
### 4.5 Sovereign storage, and our own transparency
202
203
- Bytes live on any Strata store: local disk, S3, GCS or Azure, in the
82739cfb Andy McCall 23 days ago ↶
204
customer's own account and region, encrypted at rest by the store with
205
customer-managed keys (for example S3 with a KMS key). Chunks stay named
206
by the hash of their plain bytes: encrypting them on the client with
207
separate keys would stop them deduplicating and stop peers checking them
208
by hash.
d0016e22 Andy McCall 23 days ago ↶
209
- Channel moves and signatures are recorded in the hub's append-only
210
Merkle log. Auditing requires no dependence on public ledgers like
211
Rekor, though Cylinder can bridge to them when desired.
212
213
### 4.6 Policy at point of use, and the inverted vulnerability index
214
215
Verification happens where the artifact is used, not only where it is
216
stored:
217
218
- A runner checks the job's image against policy before execution.
219
- A Kubernetes admission hook checks pod images against channel policies
220
and assurance levels.
221
- ` oxy` and ` flow` verify what they fetch.
222
82739cfb Andy McCall 23 days ago ↶
223
** The inverted file index:** Because artifacts are trees of
224
content-addressed files rather than opaque tarballs, Cylinder keeps an
225
index from each file's hash to the artifacts that contain it:
d0016e22 Andy McCall 23 days ago ↶
226
227
$$\text{FileHash} \longrightarrow [\text{ArtifactHash}]$$
228
82739cfb Andy McCall 23 days ago ↶
229
- ** Exact files, at once.** Given a known-bad file (a compromised binary,
230
a leaked key, the exact ` libcrypto.so.3` an advisory names), one lookup
231
lists every container image, runner image and package across the fleet
232
holding it, with no layers to unpack.
233
- ** Not versions.** A patched or rebuilt library is a different file with
234
a different hash, so this index does not answer "which images have a
235
vulnerable version of OpenSSL". That comes from package identity: the
236
SBOM each artifact carries (§4.3), indexed by package and version. The
237
two together answer both questions; the file index alone answers the
238
first.
239
- ** Revocation without an outage.** When an artifact, base image or file
240
is revoked in policy, admission hooks refuse new pods that use it at
241
once. Pods already running are not touched by admission; a controller
242
marks them, then replaces or evicts them within a grace period the
243
policy sets, so one policy change cannot take production down.
d0016e22 Andy McCall 23 days ago ↶
244
245
### 4.7 Retention by reachability and deployment leases
246
247
What a channel, a release, a pinned pipeline or an active deployment
248
reaches is kept; unreferenced chunks are collected by ` oxy gc` .
249
250
** Deployment leases:** Container registries often suffer from garbage
251
collection deleting images still running on long-lived cluster pods.
252
To prevent this, nodes or Kubernetes operators register periodic
253
** deployment leases** :
254
255
```
256
Attest (kind = "lease") {
257
artifact [0]: ObjectRef // artifact hash currently running
258
scope [1]: text // e.g. "k8s:cluster-lon/ns/workload"
259
expires [2]: u64 // timestamp
260
}
261
```
262
263
Active leases act as garbage collection roots. If a workload terminates
264
or a cluster is decommissioned, the lease expires naturally, enabling
82739cfb Andy McCall 23 days ago ↶
265
safe automated retention without operational risk. A lease is signed by
266
a key scoped to leases and to its ` scope` , and has a maximum length (a
267
day, renewed while the workload runs), so a compromised node cannot hold
268
storage forever or pin artifacts outside its own scope.
d0016e22 Andy McCall 23 days ago ↶
269
270
### 4.8 Compatibility at the edge
271
272
- ** An OCI registry façade:** ` docker pull` and Kubernetes work
273
unchanged. Manifests and layers are assembled on the fly from chunks.
274
` docker push` is accepted and chunked via FastCDC, applying
275
deduplication to legacy images.
276
- ** A containerd snapshotter** speaking the native protocol, mounting
277
file trees via ` flow-casfs` for instant sub-second container starts
278
and P2P delivery on Kubernetes.
279
- ** Package façades (Cargo, npm, PyPI):** Served from the same chunk
280
store. Façade endpoints synthesize package metadata (Cargo sparse
281
indexes, npm packuments, PyPI simple indexes) dynamically from artifact
282
manifests.
283
- ** Upstream dependency quarantine:** When Flow builds fetch third-party
82739cfb Andy McCall 23 days ago ↶
284
packages from crates.io or npm, Cylinder proxies them into the
285
organization's Strata store, locking the hashes into internal mirror
286
channels. Upstream outages or deletions cannot break builds. Packages
287
arrive compressed (` .crate` and ` .tgz` are gzip), which chunks poorly,
288
so the original archive is kept for clients that check its hash and its
289
unpacked files are chunked as an artifact tree, where they deduplicate
290
with everything else.
d0016e22 Andy McCall 23 days ago ↶
291
292
### 4.9 AI-native agent integration
293
294
Extending Oxygen's scoped delegation model (` ai_native_agent_workflows.md §2` ),
295
agent keys can hold artifact-specific scopes:
296
297
```
298
delegates [8]: [{ key: KeyId, scope: ["changes" | "refs" | "seal" | "artifacts" | "channels"], expires: u64? }]
299
```
300
301
- An AI agent (e.g. Aider, Claude Code) working autonomously can be
302
granted ` --scope artifacts` and restricted channel rights:
303
- Permitted: building artifacts and moving ` agents/NAME/**` channels.
304
- Forbidden: moving production channels (` app:stable` , ` release/*` ).
305
- Agents can test containerized workloads end-to-end in isolated
306
channels, while production promotion remains guarded by human landing
307
rules or multi-party consensus.
308
309
### 4.10 Revset query integration
310
311
Oxygen's revset language (` revset_query_language.md` ) bridges source
312
changes and deployed artifacts:
313
314
315
316
| ` artifact(CHANNEL)` | Changes contained within the artifact currently at ` CHANNEL` |
317
| ` deployed(ENV)` | Changes currently active in environment ` ENV` (via active leases) |
318
| ` unshipped()` | Equivalent to ` main ~ artifact(app:stable)` (changes on ` main` that have not reached production) |
319
| ` reproduced()` | Changes whose built artifacts have 2+ independent runner receipts |
320
| ` vulnerable(CVE)` | Changes that touch or introduced files present in an artifact flagged with ` CVE` |
321
322
Running ` oxy log -r 'main ~ artifact(app:stable)'` immediately shows all
323
changes pending deployment.
324
325
### 4.11 The UI (inside the hub)
326
327
- ** Per repository, an Artifacts tab:** published artifacts, channel
328
histories, and the provenance graph from commit to run, artifact, and
329
deployment lease.
330
- ** Site-wide:** chunk distribution across hubs and runners, active
331
swarm transfers, deduplication savings, and the global CVE inverted index.
332
- ** Runner images** are listed as standard artifacts with their build
333
receipts and hardware architecture badges.
334
335
``` mermaid
336
flowchart LR
337
subgraph Build
338
S[Source state] --> P[Pipeline]
339
P --> R1[Runner 1: microvm]
340
P --> R2[Runner 2: disjoint host]
341
R1 -->|receipt 1| A[Artifact: tree of chunks]
342
R2 -->|receipt 2| A
343
end
344
A -->|consensus move| C[Channel log: app:stable@42]
345
A --> ST[(Strata store)]
346
ST -->|seed| SW{{Swarm}}
347
SW --> N1[Runner]
348
SW --> N2[K8s node: containerd snapshotter]
349
SW --> N3[Developer]
350
N2 -->|deployment lease| DL[Active Leases: GC Roots]
351
C -->|policy check| N2
352
OCI[OCI façade] --- ST
353
PKG[Package façades: cargo/npm/pypi] --- ST
354
H[OxygenHub UI & CVE Index] --- C
355
H --- A
356
```
357
358
### 4.12 Where it stands among the services
359
360
- ** OxygenHub** owns repositories, proposals, checks, user identity,
361
and the UI.
362
- ** Jetstream** owns the fleet: queue, placement, and runner swarms. It
363
fetches runner images from Cylinder by artifact hash.
364
- ** Flow** executes pipelines and produces signed execution receipts.
365
- ** Cylinder** owns artifacts: manifests, channel logs, provenance
366
chains, distribution, package façades, and deployment leases.
367
- ** Strata** provides the underlying content-addressed chunk storage.
368
369
Each service runs embedded in OxygenHub by default, or standalone for
370
distributed scale.
371
372
## 5. Better how, in one table
373
374
375
376
| Rebuild with one changed file | Re-push and re-pull the layer | Only that file's changed chunks |
377
| Dedupe | Whole identical layers | FastCDC chunks across repos, images and packages |
378
| Names | Mutable tags; digests nobody reads | Signed, append-only channels (` app:stable@42` ) |
379
| Provenance | Attestations added later, if at all | The build's signed receipt is the record |
380
| Signing | A separate tool and keys | Native Ed25519 + ML-DSA-65 composite signatures |
381
| Consensus | Single-builder attestation | Multi-party consensus receipts (` reproduced(N)` ) |
382
| Lazy start | Bolted-on snapshotter (SOCI, Nydus) | Native: file trees mounted via ` flow-casfs` |
383
| Peer to peer | Separate mesh daemon (Dragonfly) | Built-in Jetstream swarm, TLS-pinned |
82739cfb Andy McCall 23 days ago ↶
384
| Vulnerability search | Unpack and scan every layer | Exact files by one index lookup; versions by SBOM package index |
d0016e22 Andy McCall 23 days ago ↶
385
| Retention | Tag rules + manual GC | Reachability + active deployment leases |
386
| AI workflows | Uncontrolled service tokens | Scoped delegation (` artifacts` , ` channels` ) |
387
| Querying | Disconnected CI/CD dashboards | Unified revsets (` main ~ artifact(app:stable)` ) |
388
| Sovereignty | Complex multi-tier server stack | Single binary; customer KMS and Strata bucket |
389
390
## 6. How we could build it
391
82739cfb Andy McCall 23 days ago ↶
392
- ** C0. Images in the hub (built 2026-10-12, oxygenhub #146).** Admin ›
393
Runners › Images: every runner image, its size and architecture, where
394
it is (the hub, each runner, swarm fetches in progress), the
395
repositories whose jobs used it, and an image held nowhere marked.
d0016e22 Andy McCall 23 days ago ↶
396
- ** C1. The service boundary and artifact model.** Implement the
397
` Artifact` CBOR object type and FastCDC chunk engine in ` cylinder` ;
398
unify runner images with artifacts.
642da263 Andy McCall 7 days ago ↶
399
* Started 2026-10-28 (oxygen#108):* ` crates/cylinder` has the
400
` Artifact` and ` DirTree` encodings of §4.1 (canonical CBOR; a name is
401
the BLAKE3 of the encoding; ` env` and ` labels` as sorted pairs, since
402
the profile's maps take integer keys), packing a directory into the
403
repository's own blobs and chunks, verifying and unpacking, and the
404
roots garbage collection keeps; ` oxy artifact pack | list | show |
6c3dbe20 Andy McCall 7 days ago ↶
405
unpack | verify` . The artifact is an object type of its own
406
(` artifact` , in oxy-core's ` artifact` module, checked by ` oxy fsck` ),
407
named by its object hash like every object; its tree is a blob, and
408
` .oxy/artifacts/NAME` records the artifacts a repository keeps. Next:
409
runner images as artifacts, then moving them between repositories (C2).
d0016e22 Andy McCall 23 days ago ↶
410
- ** C2. Channels, provenance and consensus.** Flow publishes artifacts;
411
signed channel move attestations; multi-party ` reproduced(N)` consensus;
412
revset predicates.
413
- ** C3. The OCI façade and containerd snapshotter.** OCI pull/push
414
translation; ` containerd` snapshotter over ` flow-casfs` .
82739cfb Andy McCall 23 days ago ↶
415
- ** C4. Leases and the indexes.** Kubernetes deployment lease operator
416
for safe GC; the inverted file index and the SBOM package index; the
417
controller that replaces revoked running workloads within their grace
418
period.
d0016e22 Andy McCall 23 days ago ↶
419
- ** C5. Reach and package façades.** Package façades for Cargo, npm,
420
and PyPI; upstream dependency quarantine mirroring.
421
422
## 7. Open questions
423
82739cfb Andy McCall 23 days ago ↶
424
These are Andy's decisions. Each carries the position proposed in review,
425
not an answer.
d0016e22 Andy McCall 23 days ago ↶
426
82739cfb Andy McCall 23 days ago ↶
427
- ** The name.** Proposed: keep ** Cylinder** . It fits the elemental
428
progression: * Oxygen* (VCS) is carried in * Cylinders* (artifacts) by
429
* Jetstream* (the fleet), driven by * Flow* (pipelines).
430
- ** Where it lives.** Proposed: first in ` oxygenflow` as
431
` crates/oxygen-cylinder` , beside ` jet` and ` flow` , to share ` flow-casfs`
432
and the chunking code; its own repository from C3.
433
- ** Local builds.** Proposed: allowed, at the lowest assurance level
434
(` local` ); production channels require more (` tier-microvm` and
435
` reproduced(2)` ).
436
- ** A public catalogue and federation.** Proposed: public hubs federate
437
by publishing signed Strata bundles of channels and artifacts, checked
438
offline with no central intermediary.
439
- ** Its place in the queue.** Proposed: C1 alongside Jetstream's service
440
boundary, so Jetstream's image store is built on Cylinder from the
441
start rather than on a temporary mechanism. Against: the core work of
442
2026-10-03 (Strata's remaining stores, agents, hub polish) waits
443
longer.
444
d0016e22 Andy McCall 23 days ago ↶
445
## Sources
446
447
- Docker Hub pull limits: [ docs.docker.com, pull usage and limits ] ( https://docs.docker.com/docker-hub/usage/pulls/ ) ; [ heise, "only 10 pulls per hour" ] ( https://heise.de/-10329047 )
448
- GHCR billing: [ GitHub community discussion #183054 ] ( https://github.com/orgs/community/discussions/183054 )
449
- GitLab cleanup policies and garbage collection: [ GitLab docs, reduce container registry storage ] ( https://docs.gitlab.com/user/packages/container_registry/reduce_container_registry_storage/ )
450
- Bitbucket Packages: [ Atlassian blog, Bitbucket Packages ] ( https://www.atlassian.com/blog/bitbucket/bitbucket-packages-container-registry ) ; [ GA announcement ] ( https://www.atlassian.com/blog/bitbucket/open-beta-introducing-packages-native-container-registry-in-bitbucket-cloud )
451
- Pull time versus data read: [ SOCI paper (Amazon), citing Slacker ] ( https://cdn.amazon.science/84/96/51ea2e0d40fca8cfaee9328278b9/soci-paper.pdf ) ; [ Grab engineering, lazy loading ] ( https://engineering.grab.com/docker-lazy-loading )
452
- zstd:chunked: [ Red Hat, faster container image pulls ] ( https://www.redhat.com/sysadmin/faster-container-image-pulls )
453
- Peer-to-peer meshes: [ Spegel vs Kraken vs Dragonfly ] ( https://www.pistack.xyz/posts/2026-04-28-spegel-vs-kraken-vs-dragonfly-self-hosted-p2p-container-image-distribution-guide-2026/ )
454
- Sigstore in registries: [ Sigstore in image registries: adoption and reality ] ( https://jacar.es/en/sigstore-in-image-registries-adoption-and-reality/ ) ; [ cosign and the referrers API ] ( https://oneuptime.com/blog/post/2026-08-11-cosign-signature-storage-oci-referrers-separate-repositories/markdown )
455
- tj-actions tag attack: [ CVE-2025-30066 ] ( https://inventivehq.com/tools/security/cve-lookup/cve-2025-30066 ) ; [ Legit Security, immutable tags ] ( https://legitsecurity.com/blog/what-are-immutable-tags-and-can-they-protect-you-from-supply-chain-attacks )
456
- Artifactory and Nexus: [ Codefresh, Artifactory alternatives ] ( https://codefresh.io/learn/jfrog-artifactory/top-8-artifactory-alternatives-in-2025 ) ; [ PeerSpot, Artifactory improvements ] ( https://origin.peerspot.com/questions/what-needs-improvement-with-jfrog-artifactory )