Commit

Author:

Hash:

Timestamp:

+7989 -291 +/-26 browse

Kevin Schoon [me@kevinschoon.com]

40dc7e7d832ef744927c0895e4349c20606b5dc7

Sat, 29 Mar 2025 20:40:59 +0000 (1 month ago)

finish implementing OCI pull compliance
finish implementing OCI pull compliance

Several serious bugs remain.
1diff --git a/.gitignore b/.gitignore
2index ea8c4bf..57ac264 100644
3--- a/.gitignore
4+++ b/.gitignore
5 @@ -1 +1,2 @@
6 /target
7+ registry
8 diff --git a/Cargo.lock b/Cargo.lock
9index 8f700ae..e1762b5 100644
10--- a/Cargo.lock
11+++ b/Cargo.lock
12 @@ -38,12 +38,19 @@ dependencies = [
13 ]
14
15 [[package]]
16+ name = "autocfg"
17+ version = "1.4.0"
18+ source = "registry+https://github.com/rust-lang/crates.io-index"
19+ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
20+
21+ [[package]]
22 name = "axum"
23- version = "0.8.1"
24+ version = "0.8.3"
25 source = "registry+https://github.com/rust-lang/crates.io-index"
26- checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8"
27+ checksum = "de45108900e1f9b9242f7f2e254aa3e2c029c921c258fe9e6b4217eeebd54288"
28 dependencies = [
29 "axum-core",
30+ "axum-macros",
31 "bytes",
32 "form_urlencoded",
33 "futures-util",
34 @@ -73,12 +80,12 @@ dependencies = [
35
36 [[package]]
37 name = "axum-core"
38- version = "0.5.0"
39+ version = "0.5.2"
40 source = "registry+https://github.com/rust-lang/crates.io-index"
41- checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733"
42+ checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6"
43 dependencies = [
44 "bytes",
45- "futures-util",
46+ "futures-core",
47 "http",
48 "http-body",
49 "http-body-util",
50 @@ -92,6 +99,17 @@ dependencies = [
51 ]
52
53 [[package]]
54+ name = "axum-macros"
55+ version = "0.5.0"
56+ source = "registry+https://github.com/rust-lang/crates.io-index"
57+ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
58+ dependencies = [
59+ "proc-macro2",
60+ "quote",
61+ "syn",
62+ ]
63+
64+ [[package]]
65 name = "backtrace"
66 version = "0.3.74"
67 source = "registry+https://github.com/rust-lang/crates.io-index"
68 @@ -107,6 +125,33 @@ dependencies = [
69 ]
70
71 [[package]]
72+ name = "base16ct"
73+ version = "0.2.0"
74+ source = "registry+https://github.com/rust-lang/crates.io-index"
75+ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
76+
77+ [[package]]
78+ name = "base64"
79+ version = "0.22.1"
80+ source = "registry+https://github.com/rust-lang/crates.io-index"
81+ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
82+
83+ [[package]]
84+ name = "bitflags"
85+ version = "2.9.0"
86+ source = "registry+https://github.com/rust-lang/crates.io-index"
87+ checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
88+
89+ [[package]]
90+ name = "block-buffer"
91+ version = "0.10.4"
92+ source = "registry+https://github.com/rust-lang/crates.io-index"
93+ checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
94+ dependencies = [
95+ "generic-array",
96+ ]
97+
98+ [[package]]
99 name = "bytes"
100 version = "1.10.1"
101 source = "registry+https://github.com/rust-lang/crates.io-index"
102 @@ -119,6 +164,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
103 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
104
105 [[package]]
106+ name = "cpufeatures"
107+ version = "0.2.17"
108+ source = "registry+https://github.com/rust-lang/crates.io-index"
109+ checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
110+ dependencies = [
111+ "libc",
112+ ]
113+
114+ [[package]]
115+ name = "crypto-common"
116+ version = "0.1.6"
117+ source = "registry+https://github.com/rust-lang/crates.io-index"
118+ checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
119+ dependencies = [
120+ "generic-array",
121+ "typenum",
122+ ]
123+
124+ [[package]]
125 name = "darling"
126 version = "0.20.10"
127 source = "registry+https://github.com/rust-lang/crates.io-index"
128 @@ -185,6 +249,16 @@ dependencies = [
129 ]
130
131 [[package]]
132+ name = "digest"
133+ version = "0.10.7"
134+ source = "registry+https://github.com/rust-lang/crates.io-index"
135+ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
136+ dependencies = [
137+ "block-buffer",
138+ "crypto-common",
139+ ]
140+
141+ [[package]]
142 name = "fnv"
143 version = "1.0.7"
144 source = "registry+https://github.com/rust-lang/crates.io-index"
145 @@ -200,12 +274,28 @@ dependencies = [
146 ]
147
148 [[package]]
149+ name = "futures"
150+ version = "0.3.31"
151+ source = "registry+https://github.com/rust-lang/crates.io-index"
152+ checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
153+ dependencies = [
154+ "futures-channel",
155+ "futures-core",
156+ "futures-executor",
157+ "futures-io",
158+ "futures-sink",
159+ "futures-task",
160+ "futures-util",
161+ ]
162+
163+ [[package]]
164 name = "futures-channel"
165 version = "0.3.31"
166 source = "registry+https://github.com/rust-lang/crates.io-index"
167 checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
168 dependencies = [
169 "futures-core",
170+ "futures-sink",
171 ]
172
173 [[package]]
174 @@ -215,6 +305,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
175 checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
176
177 [[package]]
178+ name = "futures-executor"
179+ version = "0.3.31"
180+ source = "registry+https://github.com/rust-lang/crates.io-index"
181+ checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
182+ dependencies = [
183+ "futures-core",
184+ "futures-task",
185+ "futures-util",
186+ ]
187+
188+ [[package]]
189+ name = "futures-io"
190+ version = "0.3.31"
191+ source = "registry+https://github.com/rust-lang/crates.io-index"
192+ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
193+
194+ [[package]]
195+ name = "futures-macro"
196+ version = "0.3.31"
197+ source = "registry+https://github.com/rust-lang/crates.io-index"
198+ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
199+ dependencies = [
200+ "proc-macro2",
201+ "quote",
202+ "syn",
203+ ]
204+
205+ [[package]]
206+ name = "futures-sink"
207+ version = "0.3.31"
208+ source = "registry+https://github.com/rust-lang/crates.io-index"
209+ checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
210+
211+ [[package]]
212 name = "futures-task"
213 version = "0.3.31"
214 source = "registry+https://github.com/rust-lang/crates.io-index"
215 @@ -226,10 +350,38 @@ version = "0.3.31"
216 source = "registry+https://github.com/rust-lang/crates.io-index"
217 checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
218 dependencies = [
219+ "futures-channel",
220 "futures-core",
221+ "futures-io",
222+ "futures-macro",
223+ "futures-sink",
224 "futures-task",
225+ "memchr",
226 "pin-project-lite",
227 "pin-utils",
228+ "slab",
229+ ]
230+
231+ [[package]]
232+ name = "generic-array"
233+ version = "0.14.7"
234+ source = "registry+https://github.com/rust-lang/crates.io-index"
235+ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
236+ dependencies = [
237+ "typenum",
238+ "version_check",
239+ ]
240+
241+ [[package]]
242+ name = "getrandom"
243+ version = "0.3.1"
244+ source = "registry+https://github.com/rust-lang/crates.io-index"
245+ checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
246+ dependencies = [
247+ "cfg-if",
248+ "libc",
249+ "wasi 0.13.3+wasi-0.2.2",
250+ "windows-targets",
251 ]
252
253 [[package]]
254 @@ -257,6 +409,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
255 checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
256
257 [[package]]
258+ name = "hex-literal"
259+ version = "1.0.0"
260+ source = "registry+https://github.com/rust-lang/crates.io-index"
261+ checksum = "bcaaec4551594c969335c98c903c1397853d4198408ea609190f420500f6be71"
262+
263+ [[package]]
264 name = "http"
265 version = "1.3.1"
266 source = "registry+https://github.com/rust-lang/crates.io-index"
267 @@ -350,12 +508,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
268 checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
269
270 [[package]]
271+ name = "lazy_static"
272+ version = "1.5.0"
273+ source = "registry+https://github.com/rust-lang/crates.io-index"
274+ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
275+
276+ [[package]]
277 name = "libc"
278 version = "0.2.171"
279 source = "registry+https://github.com/rust-lang/crates.io-index"
280 checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
281
282 [[package]]
283+ name = "lock_api"
284+ version = "0.4.12"
285+ source = "registry+https://github.com/rust-lang/crates.io-index"
286+ checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
287+ dependencies = [
288+ "autocfg",
289+ "scopeguard",
290+ ]
291+
292+ [[package]]
293 name = "log"
294 version = "0.4.26"
295 source = "registry+https://github.com/rust-lang/crates.io-index"
296 @@ -395,11 +569,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
297 checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
298 dependencies = [
299 "libc",
300- "wasi",
301+ "wasi 0.11.0+wasi-snapshot-preview1",
302 "windows-sys",
303 ]
304
305 [[package]]
306+ name = "nu-ansi-term"
307+ version = "0.46.0"
308+ source = "registry+https://github.com/rust-lang/crates.io-index"
309+ checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
310+ dependencies = [
311+ "overload",
312+ "winapi",
313+ ]
314+
315+ [[package]]
316 name = "object"
317 version = "0.36.7"
318 source = "registry+https://github.com/rust-lang/crates.io-index"
319 @@ -431,17 +615,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
320 checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
321
322 [[package]]
323+ name = "overload"
324+ version = "0.1.1"
325+ source = "registry+https://github.com/rust-lang/crates.io-index"
326+ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
327+
328+ [[package]]
329 name = "papyri"
330 version = "0.1.0"
331 dependencies = [
332 "async-trait",
333 "axum",
334+ "base16ct",
335+ "base64",
336+ "bytes",
337+ "futures",
338+ "hex-literal",
339+ "http",
340 "oci-spec",
341 "regex",
342+ "relative-path",
343 "serde",
344 "serde_json",
345+ "sha2",
346 "thiserror",
347+ "tokio",
348+ "tokio-util",
349+ "tower",
350+ "tower-http",
351 "tracing",
352+ "tracing-subscriber",
353+ "uuid",
354+ ]
355+
356+ [[package]]
357+ name = "parking_lot"
358+ version = "0.12.3"
359+ source = "registry+https://github.com/rust-lang/crates.io-index"
360+ checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
361+ dependencies = [
362+ "lock_api",
363+ "parking_lot_core",
364+ ]
365+
366+ [[package]]
367+ name = "parking_lot_core"
368+ version = "0.9.10"
369+ source = "registry+https://github.com/rust-lang/crates.io-index"
370+ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
371+ dependencies = [
372+ "cfg-if",
373+ "libc",
374+ "redox_syscall",
375+ "smallvec",
376+ "windows-targets",
377 ]
378
379 [[package]]
380 @@ -503,6 +730,15 @@ dependencies = [
381 ]
382
383 [[package]]
384+ name = "redox_syscall"
385+ version = "0.5.10"
386+ source = "registry+https://github.com/rust-lang/crates.io-index"
387+ checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
388+ dependencies = [
389+ "bitflags",
390+ ]
391+
392+ [[package]]
393 name = "regex"
394 version = "1.11.1"
395 source = "registry+https://github.com/rust-lang/crates.io-index"
396 @@ -532,6 +768,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
397 checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
398
399 [[package]]
400+ name = "relative-path"
401+ version = "1.9.3"
402+ source = "registry+https://github.com/rust-lang/crates.io-index"
403+ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
404+
405+ [[package]]
406 name = "rustc-demangle"
407 version = "0.1.24"
408 source = "registry+https://github.com/rust-lang/crates.io-index"
409 @@ -550,6 +792,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
410 checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
411
412 [[package]]
413+ name = "scopeguard"
414+ version = "1.2.0"
415+ source = "registry+https://github.com/rust-lang/crates.io-index"
416+ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
417+
418+ [[package]]
419 name = "serde"
420 version = "1.0.219"
421 source = "registry+https://github.com/rust-lang/crates.io-index"
422 @@ -604,6 +852,44 @@ dependencies = [
423 ]
424
425 [[package]]
426+ name = "sha2"
427+ version = "0.10.8"
428+ source = "registry+https://github.com/rust-lang/crates.io-index"
429+ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
430+ dependencies = [
431+ "cfg-if",
432+ "cpufeatures",
433+ "digest",
434+ ]
435+
436+ [[package]]
437+ name = "sharded-slab"
438+ version = "0.1.7"
439+ source = "registry+https://github.com/rust-lang/crates.io-index"
440+ checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
441+ dependencies = [
442+ "lazy_static",
443+ ]
444+
445+ [[package]]
446+ name = "signal-hook-registry"
447+ version = "1.4.2"
448+ source = "registry+https://github.com/rust-lang/crates.io-index"
449+ checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
450+ dependencies = [
451+ "libc",
452+ ]
453+
454+ [[package]]
455+ name = "slab"
456+ version = "0.4.9"
457+ source = "registry+https://github.com/rust-lang/crates.io-index"
458+ checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
459+ dependencies = [
460+ "autocfg",
461+ ]
462+
463+ [[package]]
464 name = "smallvec"
465 version = "1.14.0"
466 source = "registry+https://github.com/rust-lang/crates.io-index"
467 @@ -682,15 +968,28 @@ dependencies = [
468 ]
469
470 [[package]]
471+ name = "thread_local"
472+ version = "1.1.8"
473+ source = "registry+https://github.com/rust-lang/crates.io-index"
474+ checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
475+ dependencies = [
476+ "cfg-if",
477+ "once_cell",
478+ ]
479+
480+ [[package]]
481 name = "tokio"
482 version = "1.44.1"
483 source = "registry+https://github.com/rust-lang/crates.io-index"
484 checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
485 dependencies = [
486 "backtrace",
487+ "bytes",
488 "libc",
489 "mio",
490+ "parking_lot",
491 "pin-project-lite",
492+ "signal-hook-registry",
493 "socket2",
494 "tokio-macros",
495 "windows-sys",
496 @@ -708,6 +1007,19 @@ dependencies = [
497 ]
498
499 [[package]]
500+ name = "tokio-util"
501+ version = "0.7.14"
502+ source = "registry+https://github.com/rust-lang/crates.io-index"
503+ checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034"
504+ dependencies = [
505+ "bytes",
506+ "futures-core",
507+ "futures-sink",
508+ "pin-project-lite",
509+ "tokio",
510+ ]
511+
512+ [[package]]
513 name = "tower"
514 version = "0.5.2"
515 source = "registry+https://github.com/rust-lang/crates.io-index"
516 @@ -724,6 +1036,22 @@ dependencies = [
517 ]
518
519 [[package]]
520+ name = "tower-http"
521+ version = "0.6.2"
522+ source = "registry+https://github.com/rust-lang/crates.io-index"
523+ checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697"
524+ dependencies = [
525+ "bitflags",
526+ "bytes",
527+ "http",
528+ "http-body",
529+ "pin-project-lite",
530+ "tower-layer",
531+ "tower-service",
532+ "tracing",
533+ ]
534+
535+ [[package]]
536 name = "tower-layer"
537 version = "0.3.3"
538 source = "registry+https://github.com/rust-lang/crates.io-index"
539 @@ -765,21 +1093,105 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
540 checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
541 dependencies = [
542 "once_cell",
543+ "valuable",
544 ]
545
546 [[package]]
547+ name = "tracing-log"
548+ version = "0.2.0"
549+ source = "registry+https://github.com/rust-lang/crates.io-index"
550+ checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
551+ dependencies = [
552+ "log",
553+ "once_cell",
554+ "tracing-core",
555+ ]
556+
557+ [[package]]
558+ name = "tracing-subscriber"
559+ version = "0.3.19"
560+ source = "registry+https://github.com/rust-lang/crates.io-index"
561+ checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
562+ dependencies = [
563+ "nu-ansi-term",
564+ "sharded-slab",
565+ "smallvec",
566+ "thread_local",
567+ "tracing-core",
568+ "tracing-log",
569+ ]
570+
571+ [[package]]
572+ name = "typenum"
573+ version = "1.18.0"
574+ source = "registry+https://github.com/rust-lang/crates.io-index"
575+ checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
576+
577+ [[package]]
578 name = "unicode-ident"
579 version = "1.0.18"
580 source = "registry+https://github.com/rust-lang/crates.io-index"
581 checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
582
583 [[package]]
584+ name = "uuid"
585+ version = "1.16.0"
586+ source = "registry+https://github.com/rust-lang/crates.io-index"
587+ checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
588+ dependencies = [
589+ "getrandom",
590+ ]
591+
592+ [[package]]
593+ name = "valuable"
594+ version = "0.1.1"
595+ source = "registry+https://github.com/rust-lang/crates.io-index"
596+ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
597+
598+ [[package]]
599+ name = "version_check"
600+ version = "0.9.5"
601+ source = "registry+https://github.com/rust-lang/crates.io-index"
602+ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
603+
604+ [[package]]
605 name = "wasi"
606 version = "0.11.0+wasi-snapshot-preview1"
607 source = "registry+https://github.com/rust-lang/crates.io-index"
608 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
609
610 [[package]]
611+ name = "wasi"
612+ version = "0.13.3+wasi-0.2.2"
613+ source = "registry+https://github.com/rust-lang/crates.io-index"
614+ checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
615+ dependencies = [
616+ "wit-bindgen-rt",
617+ ]
618+
619+ [[package]]
620+ name = "winapi"
621+ version = "0.3.9"
622+ source = "registry+https://github.com/rust-lang/crates.io-index"
623+ checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
624+ dependencies = [
625+ "winapi-i686-pc-windows-gnu",
626+ "winapi-x86_64-pc-windows-gnu",
627+ ]
628+
629+ [[package]]
630+ name = "winapi-i686-pc-windows-gnu"
631+ version = "0.4.0"
632+ source = "registry+https://github.com/rust-lang/crates.io-index"
633+ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
634+
635+ [[package]]
636+ name = "winapi-x86_64-pc-windows-gnu"
637+ version = "0.4.0"
638+ source = "registry+https://github.com/rust-lang/crates.io-index"
639+ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
640+
641+ [[package]]
642 name = "windows-sys"
643 version = "0.52.0"
644 source = "registry+https://github.com/rust-lang/crates.io-index"
645 @@ -851,3 +1263,12 @@ name = "windows_x86_64_msvc"
646 version = "0.52.6"
647 source = "registry+https://github.com/rust-lang/crates.io-index"
648 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
649+
650+ [[package]]
651+ name = "wit-bindgen-rt"
652+ version = "0.33.0"
653+ source = "registry+https://github.com/rust-lang/crates.io-index"
654+ checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
655+ dependencies = [
656+ "bitflags",
657+ ]
658 diff --git a/Cargo.toml b/Cargo.toml
659index 7a6e130..6d7c9c0 100644
660--- a/Cargo.toml
661+++ b/Cargo.toml
662 @@ -4,7 +4,13 @@ version = "0.1.0"
663 edition = "2024"
664
665 [dependencies]
666- axum = "0.8.1"
667+ axum = { version = "0.8.3", features = ["macros", "query", "json"], optional = true }
668+ http = { version = "1.3.1", optional = true }
669+ tower = { version = "0.5.2", features = ["util"], optional = true }
670+
671+ tokio = { version = "1.44.1", features = ["fs"], optional = true }
672+ tokio-util = { version = "0.7.14", features = ["io"], optional = true }
673+
674 oci-spec = "0.7.1"
675 serde = "1.0.219"
676 serde_json = "1.0.140"
677 @@ -12,3 +18,40 @@ async-trait = "0.1.88"
678 regex = "1.11.1"
679 tracing = { version = "0.1.41", features = ["log"] }
680 thiserror = "2.0.12"
681+ futures = "0.3.31"
682+ uuid = { version = "1.16.0", features = ["v4"] }
683+ bytes = "1.10.1"
684+ relative-path = "1.9.3"
685+ sha2 = "0.10.8"
686+ hex-literal = "1.0.0"
687+ base16ct = { version = "0.2.0", features = ["alloc"] }
688+ base64 = "0.22.1"
689+
690+ [dev-dependencies]
691+ tokio = { version = "1.44.1", features = ["full"] }
692+ tower-http = { version = "0.6.2", features = ["trace", "normalize-path"] }
693+ tracing-subscriber = "0.3.19"
694+
695+ [features]
696+ default = []
697+
698+ axum-router = [
699+ "axum",
700+ "http",
701+ "tower"
702+ ]
703+
704+ storage-fs = [
705+ "tokio",
706+ "tokio-util"
707+ ]
708+
709+ [[example]]
710+ name = "server"
711+ path = "examples/server.rs"
712+ required-features = ["axum-router", "storage-fs"]
713+
714+ [[example]]
715+ name = "custom"
716+ path = "examples/custom.rs"
717+ required-features = ["storage-fs"]
718 diff --git a/LICENSE b/LICENSE
719new file mode 100644
720index 0000000..be3f7b2
721--- /dev/null
722+++ b/LICENSE
723 @@ -0,0 +1,661 @@
724+ GNU AFFERO GENERAL PUBLIC LICENSE
725+ Version 3, 19 November 2007
726+
727+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
728+ Everyone is permitted to copy and distribute verbatim copies
729+ of this license document, but changing it is not allowed.
730+
731+ Preamble
732+
733+ The GNU Affero General Public License is a free, copyleft license for
734+ software and other kinds of works, specifically designed to ensure
735+ cooperation with the community in the case of network server software.
736+
737+ The licenses for most software and other practical works are designed
738+ to take away your freedom to share and change the works. By contrast,
739+ our General Public Licenses are intended to guarantee your freedom to
740+ share and change all versions of a program--to make sure it remains free
741+ software for all its users.
742+
743+ When we speak of free software, we are referring to freedom, not
744+ price. Our General Public Licenses are designed to make sure that you
745+ have the freedom to distribute copies of free software (and charge for
746+ them if you wish), that you receive source code or can get it if you
747+ want it, that you can change the software or use pieces of it in new
748+ free programs, and that you know you can do these things.
749+
750+ Developers that use our General Public Licenses protect your rights
751+ with two steps: (1) assert copyright on the software, and (2) offer
752+ you this License which gives you legal permission to copy, distribute
753+ and/or modify the software.
754+
755+ A secondary benefit of defending all users' freedom is that
756+ improvements made in alternate versions of the program, if they
757+ receive widespread use, become available for other developers to
758+ incorporate. Many developers of free software are heartened and
759+ encouraged by the resulting cooperation. However, in the case of
760+ software used on network servers, this result may fail to come about.
761+ The GNU General Public License permits making a modified version and
762+ letting the public access it on a server without ever releasing its
763+ source code to the public.
764+
765+ The GNU Affero General Public License is designed specifically to
766+ ensure that, in such cases, the modified source code becomes available
767+ to the community. It requires the operator of a network server to
768+ provide the source code of the modified version running there to the
769+ users of that server. Therefore, public use of a modified version, on
770+ a publicly accessible server, gives the public access to the source
771+ code of the modified version.
772+
773+ An older license, called the Affero General Public License and
774+ published by Affero, was designed to accomplish similar goals. This is
775+ a different license, not a version of the Affero GPL, but Affero has
776+ released a new version of the Affero GPL which permits relicensing under
777+ this license.
778+
779+ The precise terms and conditions for copying, distribution and
780+ modification follow.
781+
782+ TERMS AND CONDITIONS
783+
784+ 0. Definitions.
785+
786+ "This License" refers to version 3 of the GNU Affero General Public License.
787+
788+ "Copyright" also means copyright-like laws that apply to other kinds of
789+ works, such as semiconductor masks.
790+
791+ "The Program" refers to any copyrightable work licensed under this
792+ License. Each licensee is addressed as "you". "Licensees" and
793+ "recipients" may be individuals or organizations.
794+
795+ To "modify" a work means to copy from or adapt all or part of the work
796+ in a fashion requiring copyright permission, other than the making of an
797+ exact copy. The resulting work is called a "modified version" of the
798+ earlier work or a work "based on" the earlier work.
799+
800+ A "covered work" means either the unmodified Program or a work based
801+ on the Program.
802+
803+ To "propagate" a work means to do anything with it that, without
804+ permission, would make you directly or secondarily liable for
805+ infringement under applicable copyright law, except executing it on a
806+ computer or modifying a private copy. Propagation includes copying,
807+ distribution (with or without modification), making available to the
808+ public, and in some countries other activities as well.
809+
810+ To "convey" a work means any kind of propagation that enables other
811+ parties to make or receive copies. Mere interaction with a user through
812+ a computer network, with no transfer of a copy, is not conveying.
813+
814+ An interactive user interface displays "Appropriate Legal Notices"
815+ to the extent that it includes a convenient and prominently visible
816+ feature that (1) displays an appropriate copyright notice, and (2)
817+ tells the user that there is no warranty for the work (except to the
818+ extent that warranties are provided), that licensees may convey the
819+ work under this License, and how to view a copy of this License. If
820+ the interface presents a list of user commands or options, such as a
821+ menu, a prominent item in the list meets this criterion.
822+
823+ 1. Source Code.
824+
825+ The "source code" for a work means the preferred form of the work
826+ for making modifications to it. "Object code" means any non-source
827+ form of a work.
828+
829+ A "Standard Interface" means an interface that either is an official
830+ standard defined by a recognized standards body, or, in the case of
831+ interfaces specified for a particular programming language, one that
832+ is widely used among developers working in that language.
833+
834+ The "System Libraries" of an executable work include anything, other
835+ than the work as a whole, that (a) is included in the normal form of
836+ packaging a Major Component, but which is not part of that Major
837+ Component, and (b) serves only to enable use of the work with that
838+ Major Component, or to implement a Standard Interface for which an
839+ implementation is available to the public in source code form. A
840+ "Major Component", in this context, means a major essential component
841+ (kernel, window system, and so on) of the specific operating system
842+ (if any) on which the executable work runs, or a compiler used to
843+ produce the work, or an object code interpreter used to run it.
844+
845+ The "Corresponding Source" for a work in object code form means all
846+ the source code needed to generate, install, and (for an executable
847+ work) run the object code and to modify the work, including scripts to
848+ control those activities. However, it does not include the work's
849+ System Libraries, or general-purpose tools or generally available free
850+ programs which are used unmodified in performing those activities but
851+ which are not part of the work. For example, Corresponding Source
852+ includes interface definition files associated with source files for
853+ the work, and the source code for shared libraries and dynamically
854+ linked subprograms that the work is specifically designed to require,
855+ such as by intimate data communication or control flow between those
856+ subprograms and other parts of the work.
857+
858+ The Corresponding Source need not include anything that users
859+ can regenerate automatically from other parts of the Corresponding
860+ Source.
861+
862+ The Corresponding Source for a work in source code form is that
863+ same work.
864+
865+ 2. Basic Permissions.
866+
867+ All rights granted under this License are granted for the term of
868+ copyright on the Program, and are irrevocable provided the stated
869+ conditions are met. This License explicitly affirms your unlimited
870+ permission to run the unmodified Program. The output from running a
871+ covered work is covered by this License only if the output, given its
872+ content, constitutes a covered work. This License acknowledges your
873+ rights of fair use or other equivalent, as provided by copyright law.
874+
875+ You may make, run and propagate covered works that you do not
876+ convey, without conditions so long as your license otherwise remains
877+ in force. You may convey covered works to others for the sole purpose
878+ of having them make modifications exclusively for you, or provide you
879+ with facilities for running those works, provided that you comply with
880+ the terms of this License in conveying all material for which you do
881+ not control copyright. Those thus making or running the covered works
882+ for you must do so exclusively on your behalf, under your direction
883+ and control, on terms that prohibit them from making any copies of
884+ your copyrighted material outside their relationship with you.
885+
886+ Conveying under any other circumstances is permitted solely under
887+ the conditions stated below. Sublicensing is not allowed; section 10
888+ makes it unnecessary.
889+
890+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
891+
892+ No covered work shall be deemed part of an effective technological
893+ measure under any applicable law fulfilling obligations under article
894+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
895+ similar laws prohibiting or restricting circumvention of such
896+ measures.
897+
898+ When you convey a covered work, you waive any legal power to forbid
899+ circumvention of technological measures to the extent such circumvention
900+ is effected by exercising rights under this License with respect to
901+ the covered work, and you disclaim any intention to limit operation or
902+ modification of the work as a means of enforcing, against the work's
903+ users, your or third parties' legal rights to forbid circumvention of
904+ technological measures.
905+
906+ 4. Conveying Verbatim Copies.
907+
908+ You may convey verbatim copies of the Program's source code as you
909+ receive it, in any medium, provided that you conspicuously and
910+ appropriately publish on each copy an appropriate copyright notice;
911+ keep intact all notices stating that this License and any
912+ non-permissive terms added in accord with section 7 apply to the code;
913+ keep intact all notices of the absence of any warranty; and give all
914+ recipients a copy of this License along with the Program.
915+
916+ You may charge any price or no price for each copy that you convey,
917+ and you may offer support or warranty protection for a fee.
918+
919+ 5. Conveying Modified Source Versions.
920+
921+ You may convey a work based on the Program, or the modifications to
922+ produce it from the Program, in the form of source code under the
923+ terms of section 4, provided that you also meet all of these conditions:
924+
925+ a) The work must carry prominent notices stating that you modified
926+ it, and giving a relevant date.
927+
928+ b) The work must carry prominent notices stating that it is
929+ released under this License and any conditions added under section
930+ 7. This requirement modifies the requirement in section 4 to
931+ "keep intact all notices".
932+
933+ c) You must license the entire work, as a whole, under this
934+ License to anyone who comes into possession of a copy. This
935+ License will therefore apply, along with any applicable section 7
936+ additional terms, to the whole of the work, and all its parts,
937+ regardless of how they are packaged. This License gives no
938+ permission to license the work in any other way, but it does not
939+ invalidate such permission if you have separately received it.
940+
941+ d) If the work has interactive user interfaces, each must display
942+ Appropriate Legal Notices; however, if the Program has interactive
943+ interfaces that do not display Appropriate Legal Notices, your
944+ work need not make them do so.
945+
946+ A compilation of a covered work with other separate and independent
947+ works, which are not by their nature extensions of the covered work,
948+ and which are not combined with it such as to form a larger program,
949+ in or on a volume of a storage or distribution medium, is called an
950+ "aggregate" if the compilation and its resulting copyright are not
951+ used to limit the access or legal rights of the compilation's users
952+ beyond what the individual works permit. Inclusion of a covered work
953+ in an aggregate does not cause this License to apply to the other
954+ parts of the aggregate.
955+
956+ 6. Conveying Non-Source Forms.
957+
958+ You may convey a covered work in object code form under the terms
959+ of sections 4 and 5, provided that you also convey the
960+ machine-readable Corresponding Source under the terms of this License,
961+ in one of these ways:
962+
963+ a) Convey the object code in, or embodied in, a physical product
964+ (including a physical distribution medium), accompanied by the
965+ Corresponding Source fixed on a durable physical medium
966+ customarily used for software interchange.
967+
968+ b) Convey the object code in, or embodied in, a physical product
969+ (including a physical distribution medium), accompanied by a
970+ written offer, valid for at least three years and valid for as
971+ long as you offer spare parts or customer support for that product
972+ model, to give anyone who possesses the object code either (1) a
973+ copy of the Corresponding Source for all the software in the
974+ product that is covered by this License, on a durable physical
975+ medium customarily used for software interchange, for a price no
976+ more than your reasonable cost of physically performing this
977+ conveying of source, or (2) access to copy the
978+ Corresponding Source from a network server at no charge.
979+
980+ c) Convey individual copies of the object code with a copy of the
981+ written offer to provide the Corresponding Source. This
982+ alternative is allowed only occasionally and noncommercially, and
983+ only if you received the object code with such an offer, in accord
984+ with subsection 6b.
985+
986+ d) Convey the object code by offering access from a designated
987+ place (gratis or for a charge), and offer equivalent access to the
988+ Corresponding Source in the same way through the same place at no
989+ further charge. You need not require recipients to copy the
990+ Corresponding Source along with the object code. If the place to
991+ copy the object code is a network server, the Corresponding Source
992+ may be on a different server (operated by you or a third party)
993+ that supports equivalent copying facilities, provided you maintain
994+ clear directions next to the object code saying where to find the
995+ Corresponding Source. Regardless of what server hosts the
996+ Corresponding Source, you remain obligated to ensure that it is
997+ available for as long as needed to satisfy these requirements.
998+
999+ e) Convey the object code using peer-to-peer transmission, provided
1000+ you inform other peers where the object code and Corresponding
1001+ Source of the work are being offered to the general public at no
1002+ charge under subsection 6d.
1003+
1004+ A separable portion of the object code, whose source code is excluded
1005+ from the Corresponding Source as a System Library, need not be
1006+ included in conveying the object code work.
1007+
1008+ A "User Product" is either (1) a "consumer product", which means any
1009+ tangible personal property which is normally used for personal, family,
1010+ or household purposes, or (2) anything designed or sold for incorporation
1011+ into a dwelling. In determining whether a product is a consumer product,
1012+ doubtful cases shall be resolved in favor of coverage. For a particular
1013+ product received by a particular user, "normally used" refers to a
1014+ typical or common use of that class of product, regardless of the status
1015+ of the particular user or of the way in which the particular user
1016+ actually uses, or expects or is expected to use, the product. A product
1017+ is a consumer product regardless of whether the product has substantial
1018+ commercial, industrial or non-consumer uses, unless such uses represent
1019+ the only significant mode of use of the product.
1020+
1021+ "Installation Information" for a User Product means any methods,
1022+ procedures, authorization keys, or other information required to install
1023+ and execute modified versions of a covered work in that User Product from
1024+ a modified version of its Corresponding Source. The information must
1025+ suffice to ensure that the continued functioning of the modified object
1026+ code is in no case prevented or interfered with solely because
1027+ modification has been made.
1028+
1029+ If you convey an object code work under this section in, or with, or
1030+ specifically for use in, a User Product, and the conveying occurs as
1031+ part of a transaction in which the right of possession and use of the
1032+ User Product is transferred to the recipient in perpetuity or for a
1033+ fixed term (regardless of how the transaction is characterized), the
1034+ Corresponding Source conveyed under this section must be accompanied
1035+ by the Installation Information. But this requirement does not apply
1036+ if neither you nor any third party retains the ability to install
1037+ modified object code on the User Product (for example, the work has
1038+ been installed in ROM).
1039+
1040+ The requirement to provide Installation Information does not include a
1041+ requirement to continue to provide support service, warranty, or updates
1042+ for a work that has been modified or installed by the recipient, or for
1043+ the User Product in which it has been modified or installed. Access to a
1044+ network may be denied when the modification itself materially and
1045+ adversely affects the operation of the network or violates the rules and
1046+ protocols for communication across the network.
1047+
1048+ Corresponding Source conveyed, and Installation Information provided,
1049+ in accord with this section must be in a format that is publicly
1050+ documented (and with an implementation available to the public in
1051+ source code form), and must require no special password or key for
1052+ unpacking, reading or copying.
1053+
1054+ 7. Additional Terms.
1055+
1056+ "Additional permissions" are terms that supplement the terms of this
1057+ License by making exceptions from one or more of its conditions.
1058+ Additional permissions that are applicable to the entire Program shall
1059+ be treated as though they were included in this License, to the extent
1060+ that they are valid under applicable law. If additional permissions
1061+ apply only to part of the Program, that part may be used separately
1062+ under those permissions, but the entire Program remains governed by
1063+ this License without regard to the additional permissions.
1064+
1065+ When you convey a copy of a covered work, you may at your option
1066+ remove any additional permissions from that copy, or from any part of
1067+ it. (Additional permissions may be written to require their own
1068+ removal in certain cases when you modify the work.) You may place
1069+ additional permissions on material, added by you to a covered work,
1070+ for which you have or can give appropriate copyright permission.
1071+
1072+ Notwithstanding any other provision of this License, for material you
1073+ add to a covered work, you may (if authorized by the copyright holders of
1074+ that material) supplement the terms of this License with terms:
1075+
1076+ a) Disclaiming warranty or limiting liability differently from the
1077+ terms of sections 15 and 16 of this License; or
1078+
1079+ b) Requiring preservation of specified reasonable legal notices or
1080+ author attributions in that material or in the Appropriate Legal
1081+ Notices displayed by works containing it; or
1082+
1083+ c) Prohibiting misrepresentation of the origin of that material, or
1084+ requiring that modified versions of such material be marked in
1085+ reasonable ways as different from the original version; or
1086+
1087+ d) Limiting the use for publicity purposes of names of licensors or
1088+ authors of the material; or
1089+
1090+ e) Declining to grant rights under trademark law for use of some
1091+ trade names, trademarks, or service marks; or
1092+
1093+ f) Requiring indemnification of licensors and authors of that
1094+ material by anyone who conveys the material (or modified versions of
1095+ it) with contractual assumptions of liability to the recipient, for
1096+ any liability that these contractual assumptions directly impose on
1097+ those licensors and authors.
1098+
1099+ All other non-permissive additional terms are considered "further
1100+ restrictions" within the meaning of section 10. If the Program as you
1101+ received it, or any part of it, contains a notice stating that it is
1102+ governed by this License along with a term that is a further
1103+ restriction, you may remove that term. If a license document contains
1104+ a further restriction but permits relicensing or conveying under this
1105+ License, you may add to a covered work material governed by the terms
1106+ of that license document, provided that the further restriction does
1107+ not survive such relicensing or conveying.
1108+
1109+ If you add terms to a covered work in accord with this section, you
1110+ must place, in the relevant source files, a statement of the
1111+ additional terms that apply to those files, or a notice indicating
1112+ where to find the applicable terms.
1113+
1114+ Additional terms, permissive or non-permissive, may be stated in the
1115+ form of a separately written license, or stated as exceptions;
1116+ the above requirements apply either way.
1117+
1118+ 8. Termination.
1119+
1120+ You may not propagate or modify a covered work except as expressly
1121+ provided under this License. Any attempt otherwise to propagate or
1122+ modify it is void, and will automatically terminate your rights under
1123+ this License (including any patent licenses granted under the third
1124+ paragraph of section 11).
1125+
1126+ However, if you cease all violation of this License, then your
1127+ license from a particular copyright holder is reinstated (a)
1128+ provisionally, unless and until the copyright holder explicitly and
1129+ finally terminates your license, and (b) permanently, if the copyright
1130+ holder fails to notify you of the violation by some reasonable means
1131+ prior to 60 days after the cessation.
1132+
1133+ Moreover, your license from a particular copyright holder is
1134+ reinstated permanently if the copyright holder notifies you of the
1135+ violation by some reasonable means, this is the first time you have
1136+ received notice of violation of this License (for any work) from that
1137+ copyright holder, and you cure the violation prior to 30 days after
1138+ your receipt of the notice.
1139+
1140+ Termination of your rights under this section does not terminate the
1141+ licenses of parties who have received copies or rights from you under
1142+ this License. If your rights have been terminated and not permanently
1143+ reinstated, you do not qualify to receive new licenses for the same
1144+ material under section 10.
1145+
1146+ 9. Acceptance Not Required for Having Copies.
1147+
1148+ You are not required to accept this License in order to receive or
1149+ run a copy of the Program. Ancillary propagation of a covered work
1150+ occurring solely as a consequence of using peer-to-peer transmission
1151+ to receive a copy likewise does not require acceptance. However,
1152+ nothing other than this License grants you permission to propagate or
1153+ modify any covered work. These actions infringe copyright if you do
1154+ not accept this License. Therefore, by modifying or propagating a
1155+ covered work, you indicate your acceptance of this License to do so.
1156+
1157+ 10. Automatic Licensing of Downstream Recipients.
1158+
1159+ Each time you convey a covered work, the recipient automatically
1160+ receives a license from the original licensors, to run, modify and
1161+ propagate that work, subject to this License. You are not responsible
1162+ for enforcing compliance by third parties with this License.
1163+
1164+ An "entity transaction" is a transaction transferring control of an
1165+ organization, or substantially all assets of one, or subdividing an
1166+ organization, or merging organizations. If propagation of a covered
1167+ work results from an entity transaction, each party to that
1168+ transaction who receives a copy of the work also receives whatever
1169+ licenses to the work the party's predecessor in interest had or could
1170+ give under the previous paragraph, plus a right to possession of the
1171+ Corresponding Source of the work from the predecessor in interest, if
1172+ the predecessor has it or can get it with reasonable efforts.
1173+
1174+ You may not impose any further restrictions on the exercise of the
1175+ rights granted or affirmed under this License. For example, you may
1176+ not impose a license fee, royalty, or other charge for exercise of
1177+ rights granted under this License, and you may not initiate litigation
1178+ (including a cross-claim or counterclaim in a lawsuit) alleging that
1179+ any patent claim is infringed by making, using, selling, offering for
1180+ sale, or importing the Program or any portion of it.
1181+
1182+ 11. Patents.
1183+
1184+ A "contributor" is a copyright holder who authorizes use under this
1185+ License of the Program or a work on which the Program is based. The
1186+ work thus licensed is called the contributor's "contributor version".
1187+
1188+ A contributor's "essential patent claims" are all patent claims
1189+ owned or controlled by the contributor, whether already acquired or
1190+ hereafter acquired, that would be infringed by some manner, permitted
1191+ by this License, of making, using, or selling its contributor version,
1192+ but do not include claims that would be infringed only as a
1193+ consequence of further modification of the contributor version. For
1194+ purposes of this definition, "control" includes the right to grant
1195+ patent sublicenses in a manner consistent with the requirements of
1196+ this License.
1197+
1198+ Each contributor grants you a non-exclusive, worldwide, royalty-free
1199+ patent license under the contributor's essential patent claims, to
1200+ make, use, sell, offer for sale, import and otherwise run, modify and
1201+ propagate the contents of its contributor version.
1202+
1203+ In the following three paragraphs, a "patent license" is any express
1204+ agreement or commitment, however denominated, not to enforce a patent
1205+ (such as an express permission to practice a patent or covenant not to
1206+ sue for patent infringement). To "grant" such a patent license to a
1207+ party means to make such an agreement or commitment not to enforce a
1208+ patent against the party.
1209+
1210+ If you convey a covered work, knowingly relying on a patent license,
1211+ and the Corresponding Source of the work is not available for anyone
1212+ to copy, free of charge and under the terms of this License, through a
1213+ publicly available network server or other readily accessible means,
1214+ then you must either (1) cause the Corresponding Source to be so
1215+ available, or (2) arrange to deprive yourself of the benefit of the
1216+ patent license for this particular work, or (3) arrange, in a manner
1217+ consistent with the requirements of this License, to extend the patent
1218+ license to downstream recipients. "Knowingly relying" means you have
1219+ actual knowledge that, but for the patent license, your conveying the
1220+ covered work in a country, or your recipient's use of the covered work
1221+ in a country, would infringe one or more identifiable patents in that
1222+ country that you have reason to believe are valid.
1223+
1224+ If, pursuant to or in connection with a single transaction or
1225+ arrangement, you convey, or propagate by procuring conveyance of, a
1226+ covered work, and grant a patent license to some of the parties
1227+ receiving the covered work authorizing them to use, propagate, modify
1228+ or convey a specific copy of the covered work, then the patent license
1229+ you grant is automatically extended to all recipients of the covered
1230+ work and works based on it.
1231+
1232+ A patent license is "discriminatory" if it does not include within
1233+ the scope of its coverage, prohibits the exercise of, or is
1234+ conditioned on the non-exercise of one or more of the rights that are
1235+ specifically granted under this License. You may not convey a covered
1236+ work if you are a party to an arrangement with a third party that is
1237+ in the business of distributing software, under which you make payment
1238+ to the third party based on the extent of your activity of conveying
1239+ the work, and under which the third party grants, to any of the
1240+ parties who would receive the covered work from you, a discriminatory
1241+ patent license (a) in connection with copies of the covered work
1242+ conveyed by you (or copies made from those copies), or (b) primarily
1243+ for and in connection with specific products or compilations that
1244+ contain the covered work, unless you entered into that arrangement,
1245+ or that patent license was granted, prior to 28 March 2007.
1246+
1247+ Nothing in this License shall be construed as excluding or limiting
1248+ any implied license or other defenses to infringement that may
1249+ otherwise be available to you under applicable patent law.
1250+
1251+ 12. No Surrender of Others' Freedom.
1252+
1253+ If conditions are imposed on you (whether by court order, agreement or
1254+ otherwise) that contradict the conditions of this License, they do not
1255+ excuse you from the conditions of this License. If you cannot convey a
1256+ covered work so as to satisfy simultaneously your obligations under this
1257+ License and any other pertinent obligations, then as a consequence you may
1258+ not convey it at all. For example, if you agree to terms that obligate you
1259+ to collect a royalty for further conveying from those to whom you convey
1260+ the Program, the only way you could satisfy both those terms and this
1261+ License would be to refrain entirely from conveying the Program.
1262+
1263+ 13. Remote Network Interaction; Use with the GNU General Public License.
1264+
1265+ Notwithstanding any other provision of this License, if you modify the
1266+ Program, your modified version must prominently offer all users
1267+ interacting with it remotely through a computer network (if your version
1268+ supports such interaction) an opportunity to receive the Corresponding
1269+ Source of your version by providing access to the Corresponding Source
1270+ from a network server at no charge, through some standard or customary
1271+ means of facilitating copying of software. This Corresponding Source
1272+ shall include the Corresponding Source for any work covered by version 3
1273+ of the GNU General Public License that is incorporated pursuant to the
1274+ following paragraph.
1275+
1276+ Notwithstanding any other provision of this License, you have
1277+ permission to link or combine any covered work with a work licensed
1278+ under version 3 of the GNU General Public License into a single
1279+ combined work, and to convey the resulting work. The terms of this
1280+ License will continue to apply to the part which is the covered work,
1281+ but the work with which it is combined will remain governed by version
1282+ 3 of the GNU General Public License.
1283+
1284+ 14. Revised Versions of this License.
1285+
1286+ The Free Software Foundation may publish revised and/or new versions of
1287+ the GNU Affero General Public License from time to time. Such new versions
1288+ will be similar in spirit to the present version, but may differ in detail to
1289+ address new problems or concerns.
1290+
1291+ Each version is given a distinguishing version number. If the
1292+ Program specifies that a certain numbered version of the GNU Affero General
1293+ Public License "or any later version" applies to it, you have the
1294+ option of following the terms and conditions either of that numbered
1295+ version or of any later version published by the Free Software
1296+ Foundation. If the Program does not specify a version number of the
1297+ GNU Affero General Public License, you may choose any version ever published
1298+ by the Free Software Foundation.
1299+
1300+ If the Program specifies that a proxy can decide which future
1301+ versions of the GNU Affero General Public License can be used, that proxy's
1302+ public statement of acceptance of a version permanently authorizes you
1303+ to choose that version for the Program.
1304+
1305+ Later license versions may give you additional or different
1306+ permissions. However, no additional obligations are imposed on any
1307+ author or copyright holder as a result of your choosing to follow a
1308+ later version.
1309+
1310+ 15. Disclaimer of Warranty.
1311+
1312+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
1313+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
1314+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
1315+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
1316+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1317+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
1318+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
1319+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
1320+
1321+ 16. Limitation of Liability.
1322+
1323+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
1324+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
1325+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
1326+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
1327+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
1328+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
1329+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
1330+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
1331+ SUCH DAMAGES.
1332+
1333+ 17. Interpretation of Sections 15 and 16.
1334+
1335+ If the disclaimer of warranty and limitation of liability provided
1336+ above cannot be given local legal effect according to their terms,
1337+ reviewing courts shall apply local law that most closely approximates
1338+ an absolute waiver of all civil liability in connection with the
1339+ Program, unless a warranty or assumption of liability accompanies a
1340+ copy of the Program in return for a fee.
1341+
1342+ END OF TERMS AND CONDITIONS
1343+
1344+ How to Apply These Terms to Your New Programs
1345+
1346+ If you develop a new program, and you want it to be of the greatest
1347+ possible use to the public, the best way to achieve this is to make it
1348+ free software which everyone can redistribute and change under these terms.
1349+
1350+ To do so, attach the following notices to the program. It is safest
1351+ to attach them to the start of each source file to most effectively
1352+ state the exclusion of warranty; and each file should have at least
1353+ the "copyright" line and a pointer to where the full notice is found.
1354+
1355+ <one line to give the program's name and a brief idea of what it does.>
1356+ Copyright (C) <year> <name of author>
1357+
1358+ This program is free software: you can redistribute it and/or modify
1359+ it under the terms of the GNU Affero General Public License as published by
1360+ the Free Software Foundation, either version 3 of the License, or
1361+ (at your option) any later version.
1362+
1363+ This program is distributed in the hope that it will be useful,
1364+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1365+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1366+ GNU Affero General Public License for more details.
1367+
1368+ You should have received a copy of the GNU Affero General Public License
1369+ along with this program. If not, see <https://www.gnu.org/licenses/>.
1370+
1371+ Also add information on how to contact you by electronic and paper mail.
1372+
1373+ If your software can interact with users remotely through a computer
1374+ network, you should also make sure that it provides a way for users to
1375+ get its source. For example, if your program is a web application, its
1376+ interface could display a "Source" link that leads users to an archive
1377+ of the code. There are many ways you could offer source, and different
1378+ solutions will be better for different programs; see section 13 for the
1379+ specific requirements.
1380+
1381+ You should also get your employer (if you work as a programmer) or school,
1382+ if any, to sign a "copyright disclaimer" for the program, if necessary.
1383+ For more information on this, and how to apply and follow the GNU AGPL, see
1384+ <https://www.gnu.org/licenses/>.
1385 diff --git a/README.md b/README.md
1386index 98ba0f3..9b6b5be 100644
1387--- a/README.md
1388+++ b/README.md
1389 @@ -1,5 +1,34 @@
1390 # Papyri
1391
1392 Papyri is a [OCI Distribution Spec](https://github.com/opencontainers/distribution-spec)
1393- compliant container registry that is usable as a standalone application or
1394- consumable as a Rust library.
1395+ compliant container registry that is consumable as a Rust library for use with
1396+ [axum](https://github.com/tokio-rs/axum). An example server is provided for
1397+ illistrative purposes and a full-featured standalone container registry might
1398+ be implemented in the future. This library is intended to be used in
1399+ [Ayllu](https://ayllu-forge.org) but may be useful elsewhere.
1400+
1401+ Note that this code has only been tested for use with Podman.
1402+
1403+
1404+ ## Running the Example
1405+
1406+ First add a new insecure registry to your `/etc/containers/registries.conf`.
1407+
1408+ ```toml
1409+ [[registry]]
1410+ location = "localhost:8700"
1411+ insecure = true
1412+ ```
1413+
1414+ Then run the example server:
1415+
1416+ ```sh
1417+ cargo run --example=server
1418+ ```
1419+ And finally interact with the dev server:
1420+
1421+ ```sh
1422+ podman login localhost:8700
1423+ podman tag alpine:3 localhost:8700/alpine:3
1424+ podman push localhost:8700/alpine:3
1425+ ```
1426 diff --git a/examples/custom.rs b/examples/custom.rs
1427new file mode 100644
1428index 0000000..419f71c
1429--- /dev/null
1430+++ b/examples/custom.rs
1431 @@ -0,0 +1,13 @@
1432+ use std::{error::Error, path::Path};
1433+
1434+ use papyri::{oci_interface::OciInterface, storage};
1435+
1436+ #[tokio::main]
1437+ async fn main() -> Result<(), Box<dyn Error>> {
1438+ let fs = storage::Storage::FileSystem {
1439+ base: Path::new("registry").to_path_buf(),
1440+ };
1441+ fs.init()?;
1442+ let _ = OciInterface {storage: fs};
1443+ Ok(())
1444+ }
1445 diff --git a/examples/server.rs b/examples/server.rs
1446new file mode 100644
1447index 0000000..851913d
1448--- /dev/null
1449+++ b/examples/server.rs
1450 @@ -0,0 +1,52 @@
1451+ use std::{collections::HashMap, error::Error, path::Path, str::FromStr};
1452+
1453+ use axum::{Router, extract::Request};
1454+ use papyri::storage::Storage;
1455+ use tower::Layer;
1456+ use tower_http::{normalize_path::NormalizePathLayer, trace::TraceLayer};
1457+ use tracing::{event, info_span, trace, Level};
1458+
1459+ const ADDRESS: &str = "127.0.0.1:8700";
1460+
1461+ const LEVEL: &str = "DEBUG";
1462+
1463+ #[tokio::main]
1464+ async fn main() -> Result<(), Box<dyn Error>> {
1465+ tracing_subscriber::fmt()
1466+ .compact()
1467+ .with_line_number(true)
1468+ .with_max_level(Level::from_str(LEVEL).unwrap())
1469+ .init();
1470+
1471+ let listener = tokio::net::TcpListener::bind(ADDRESS).await?;
1472+ tracing::info!("listening @ {}", ADDRESS);
1473+
1474+ let fs = Storage::FileSystem {
1475+ base: Path::new("registry").to_path_buf(),
1476+ };
1477+ fs.init()?;
1478+
1479+ // Registry middleware must be wrapped with namespace extraction/rewrite.
1480+ let registry = papyri::axum::router(&fs);
1481+ let middleware = tower::util::MapRequestLayer::new(papyri::axum::extract_namespace);
1482+
1483+ let router =
1484+ Router::new()
1485+ .nest_service("/v2/", middleware.layer(registry))
1486+ .layer(TraceLayer::new_for_http().make_span_with(
1487+ |req: &Request<_>| {
1488+ let headers: Vec<(String, String)> = req.headers().iter().map(|(key, value)| (key.to_string(), value.to_str().unwrap().to_string())).collect();
1489+ let span = info_span!("http_request", method = ?req.method(), uri = req.uri().to_string());
1490+ span.in_scope(|| {
1491+ headers.iter().for_each(|(key, value)| {
1492+ event!(Level::DEBUG, key = key, value = value);
1493+ })
1494+ });
1495+ span
1496+ },
1497+ ))
1498+ .layer(NormalizePathLayer::trim_trailing_slash());
1499+
1500+ axum::serve(listener, router).await?;
1501+ Ok(())
1502+ }
1503 diff --git a/framework b/framework
1504new file mode 100644
1505index 0000000..acdd265
1506--- /dev/null
1507+++ b/framework
1508 @@ -0,0 +1,2475 @@
1509+ <html>
1510+ <head>
1511+ <title>OCI Distribution Conformance Tests</title>
1512+ <style>
1513+ body {
1514+ padding: 10px 20px 10px 20px;
1515+ font-family: -apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;
1516+ background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAG0lEQVQYV2Pce7zwv7NlPyMDFMAZGAIwlRgqAFydCAVv5m4UAAAAAElFTkSuQmCC") repeat;
1517+
1518+ }
1519+ table {
1520+ border-collapse: collapse;
1521+ width: 100%;
1522+ background-color: white;
1523+ }
1524+ th, td {
1525+ padding: 12px;
1526+ text-align: left;
1527+ border-bottom: 1px solid #ddd;
1528+ }
1529+ tr:hover {
1530+ background-color: #ffe39b;
1531+ }
1532+ .result {
1533+ padding: 1.25em 0 .25em 0.8em;
1534+ border: 1px solid #e1e1e1;
1535+ border-radius: 5px;
1536+ margin-top: 10px;
1537+ }
1538+ .red {
1539+ background: #ffc8c8;
1540+ }
1541+ pre.fail-message {
1542+ background: #f9a5a5;
1543+ padding: 20px;
1544+ margin-right: 10px;
1545+ display: inline-block;
1546+ border-radius: 4px;
1547+ font-size: 1.25em;
1548+ width: 94%;
1549+ overflow-x: auto;
1550+ max-width: 85%;
1551+ }
1552+ .green {
1553+ background: #c8ffc8;
1554+ padding: 1.25em 0 1.25em 0.8em;
1555+ }
1556+ .grey {
1557+ background: lightgrey;
1558+ padding: 1.25em 0 1.25em 0.8em;
1559+ }
1560+ .toggle {
1561+ border: 2px solid #3e3e3e;
1562+ cursor: pointer;
1563+ width: 1em;
1564+ text-align: center;
1565+ font-weight: bold;
1566+ display: inline;
1567+ font-family: monospace;
1568+ padding: 0 .25em 0 .25em;
1569+ margin: 1em 1em 1em 0;
1570+ font-size: 12pt;
1571+ color: #3e3e3e;
1572+ border-radius: 3px;
1573+ }
1574+ pre.pre-box {
1575+ background: #343a40;
1576+ color: #fff;
1577+ padding: 10px;
1578+ border: 1px solid gray;
1579+ display: inline-block;
1580+ border-radius: 4px;
1581+ width: 97%;
1582+ font-size: 1.25em;
1583+ overflow-x: auto;
1584+ max-height: 60em;
1585+ overflow-y: auto;
1586+ max-width: 85%;
1587+ }
1588+ .summary {
1589+ width: 100%;
1590+ height: auto;
1591+ padding: 0 0 .5em 0;
1592+ border-radius: 6px;
1593+ border: 1px solid #cccddd;
1594+ background: white;
1595+ }
1596+ .summary-bullet {
1597+ width: 100%;
1598+ height: auto;
1599+ display: flex;
1600+ flex-wrap: wrap;
1601+ padding: .5em .1em .1em .5em;
1602+ }
1603+ .bullet-left {
1604+ width: 25%;
1605+ font-weight: bold;
1606+ font-size: 100%;
1607+ }
1608+ .bullet-right {
1609+ width: auto;
1610+ font-family: monospace;
1611+ font-size: 110%;
1612+ }
1613+ .quick-summary {
1614+ width: 70%;
1615+ display: flex;
1616+ margin: 0 auto 0 0;
1617+ font-weight: bold;
1618+ font-size: 1.2em;
1619+ }
1620+ .darkgreen {
1621+ color: green;
1622+ }
1623+ .darkred {
1624+ color: red;
1625+ padding: 0 0 0 2em;
1626+ }
1627+ .darkgrey {
1628+ color: grey;
1629+ padding: 0 0 0 2em;
1630+ }
1631+ .meter {
1632+ border: 1px solid black;
1633+ margin: 0 .5em 0 auto;
1634+ display: flex;
1635+ height: 25px;
1636+ width: 45%;
1637+ }
1638+ @media only screen and (max-width: 600px) {
1639+ .meter {
1640+ display: none;
1641+ }
1642+ }
1643+ .meter-green {
1644+ height: 100%;
1645+ background: green;
1646+ width: 28%;
1647+ }
1648+ .meter-red {
1649+ height: 100%;
1650+ background: red;
1651+ width: 1%;
1652+ }
1653+ .meter-grey {
1654+ height: 100%;
1655+ background: grey;
1656+ width: 71%;
1657+ }
1658+ .subcategory {
1659+ background: white;
1660+ padding: 0px 20px 20px 20px;
1661+ border: 1px solid #cccddd;
1662+ border-radius: 6px;
1663+ }
1664+ h2 {
1665+ margin-top: 45px;
1666+ }
1667+ h4 {
1668+ vertical-align: bottom;
1669+ cursor: pointer;
1670+ }
1671+ </style>
1672+ <script>
1673+ function toggleOutput(id) {
1674+ var elem = document.getElementById(id);
1675+ var button = document.getElementById(id + "-button");
1676+ if (elem.style['display'] === 'block') {
1677+ button.innerHTML = "+";
1678+ elem.style['display'] = 'none';
1679+ } else {
1680+ button.innerHTML = "-";
1681+ elem.style['display'] = 'block';
1682+ }
1683+ }
1684+ </script>
1685+ </head>
1686+ <body>
1687+ <h1>OCI Distribution Conformance Tests</h1>
1688+ <table>
1689+ <tr>
1690+ </tr>
1691+ <tr>
1692+ <td class="bullet-left">Summary</td>
1693+ <td>
1694+ <div class="quick-summary"><span class="darkgreen">22 passed</span><span class="darkred">1 failed</span><span class="darkgrey">56 skipped</span><div class="meter">
1695+ <div class="meter-green"></div>
1696+ <div class="meter-red"></div>
1697+ <div class="meter-grey"></div>
1698+ </div>
1699+ </div>
1700+ </td>
1701+ </tr>
1702+ <tr>
1703+ <td class="bullet-left">Start Time</td>
1704+ <td>Apr 13 10:49:52.799 &#43;0000 UTC</td>
1705+ </tr>
1706+ <tr>
1707+ <td class="bullet-left">End Time</td>
1708+ <td>Apr 13 10:49:52.968 &#43;0000 UTC</td>
1709+ </tr>
1710+ <tr>
1711+ <td class="bullet-left">Time Elapsed</td>
1712+ <td>168.404009ms</td>
1713+ </tr>
1714+ <tr>
1715+ <td class="bullet-left">Test Version</td>
1716+ <td>unknown</td>
1717+ </tr>
1718+ <tr>
1719+ <td class="bullet-left">Configuration</td>
1720+ <td><div class="bullet-right">
1721+
1722+ OCI_ROOT_URL=http://localhost:5000<br />
1723+
1724+ OCI_NAMESPACE=myorg/myrepo/a<br />
1725+
1726+ OCI_USERNAME=*****<br />
1727+
1728+ OCI_PASSWORD=*****<br />
1729+
1730+ OCI_DEBUG=0<br />
1731+
1732+ OCI_TEST_PULL=1<br />
1733+
1734+ OCI_TEST_PUSH=0<br />
1735+
1736+ OCI_TEST_CONTENT_DISCOVERY=0<br />
1737+
1738+ OCI_TEST_CONTENT_MANAGEMENT=0<br />
1739+
1740+ OCI_HIDE_SKIPPED_WORKFLOWS=0<br />
1741+
1742+ </div></td>
1743+ </tr>
1744+ </table>
1745+
1746+ <div>
1747+
1748+
1749+
1750+
1751+
1752+
1753+ <h2>Pull</h2>
1754+ <div class="subcategory">
1755+
1756+
1757+ <h3>Setup</h3>
1758+
1759+
1760+
1761+
1762+
1763+
1764+ <div class="result green">
1765+ <div id="output-box-1-button" class="toggle" onclick="javascript:toggleOutput('output-box-1')">+</div>
1766+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-1')">Populate registry with test blob</h4>
1767+ <br>
1768+ <div id="output-box-1" style="display: none;">
1769+ <pre class="pre-box">DEBUG
1770+ ==============================================================================
1771+ ~~~ REQUEST ~~~
1772+ POST /v2/myorg/myrepo/a/blobs/uploads/ HTTP/1.1
1773+ HOST : localhost:5000
1774+ HEADERS:
1775+ User-Agent: distribution-spec-conformance-tests
1776+ BODY :
1777+ ***** NO CONTENT *****
1778+ ------------------------------------------------------------------------------
1779+ ~~~ RESPONSE ~~~
1780+ STATUS : 202 Accepted
1781+ PROTO : HTTP/1.1
1782+ RECEIVED AT : 2025-04-13T10:49:52.857954489Z
1783+ TIME DURATION: 12.910389ms
1784+ HEADERS :
1785+ Content-Length: 0
1786+ Date: Sun, 13 Apr 2025 10:49:52 GMT
1787+ Docker-Distribution-Api-Version: registry/2.0
1788+ Docker-Upload-Uuid: 8fc0b397-8d2e-44f5-924f-c841ea801c14
1789+ Location: http://localhost:5000/v2/myorg/myrepo/a/blobs/uploads/8fc0b397-8d2e-44f5-924f-c841ea801c14?_state=*****
1790+ Range: 0-0
1791+ X-Content-Type-Options: nosniff
1792+ BODY :
1793+
1794+ ==============================================================================
1795+
1796+ DEBUG
1797+ ==============================================================================
1798+ ~~~ REQUEST ~~~
1799+ PUT /v2/myorg/myrepo/a/blobs/uploads/8fc0b397-8d2e-44f5-924f-c841ea801c14?_state=*****&amp;digest=sha256%3Ab3a6fe88600709014374f837673294ff2b0890d8ce591f77c2c2824a3391e1bf HTTP/1.1
1800+ HOST : localhost:5000
1801+ HEADERS:
1802+ Content-Length: 129
1803+ Content-Type: application/octet-stream
1804+ User-Agent: distribution-spec-conformance-tests
1805+ BODY :
1806+ ***** BODY IS byte(s) (size - 129) *****
1807+ ------------------------------------------------------------------------------
1808+ ~~~ RESPONSE ~~~
1809+ STATUS : 201 Created
1810+ PROTO : HTTP/1.1
1811+ RECEIVED AT : 2025-04-13T10:49:52.877569064Z
1812+ TIME DURATION: 19.457485ms
1813+ HEADERS :
1814+ Content-Length: 0
1815+ Date: Sun, 13 Apr 2025 10:49:52 GMT
1816+ Docker-Content-Digest: sha256:b3a6fe88600709014374f837673294ff2b0890d8ce591f77c2c2824a3391e1bf
1817+ Docker-Distribution-Api-Version: registry/2.0
1818+ Location: http://localhost:5000/v2/myorg/myrepo/a/blobs/sha256:b3a6fe88600709014374f837673294ff2b0890d8ce591f77c2c2824a3391e1bf
1819+ X-Content-Type-Options: nosniff
1820+ BODY :
1821+
1822+ ==============================================================================
1823+
1824+ </pre>
1825+ </div>
1826+ </div>
1827+
1828+
1829+
1830+
1831+ <div class="result green">
1832+ <div id="output-box-1-button" class="toggle" onclick="javascript:toggleOutput('output-box-1')">+</div>
1833+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-1')">Populate registry with test blob</h4>
1834+ <br>
1835+ <div id="output-box-1" style="display: none;">
1836+ <pre class="pre-box">DEBUG
1837+ ==============================================================================
1838+ ~~~ REQUEST ~~~
1839+ POST /v2/myorg/myrepo/a/blobs/uploads/ HTTP/1.1
1840+ HOST : localhost:5000
1841+ HEADERS:
1842+ User-Agent: distribution-spec-conformance-tests
1843+ BODY :
1844+ ***** NO CONTENT *****
1845+ ------------------------------------------------------------------------------
1846+ ~~~ RESPONSE ~~~
1847+ STATUS : 202 Accepted
1848+ PROTO : HTTP/1.1
1849+ RECEIVED AT : 2025-04-13T10:49:52.857954489Z
1850+ TIME DURATION: 12.910389ms
1851+ HEADERS :
1852+ Content-Length: 0
1853+ Date: Sun, 13 Apr 2025 10:49:52 GMT
1854+ Docker-Distribution-Api-Version: registry/2.0
1855+ Docker-Upload-Uuid: 8fc0b397-8d2e-44f5-924f-c841ea801c14
1856+ Location: http://localhost:5000/v2/myorg/myrepo/a/blobs/uploads/8fc0b397-8d2e-44f5-924f-c841ea801c14?_state=*****
1857+ Range: 0-0
1858+ X-Content-Type-Options: nosniff
1859+ BODY :
1860+
1861+ ==============================================================================
1862+
1863+ DEBUG
1864+ ==============================================================================
1865+ ~~~ REQUEST ~~~
1866+ PUT /v2/myorg/myrepo/a/blobs/uploads/8fc0b397-8d2e-44f5-924f-c841ea801c14?_state=*****&amp;digest=sha256%3Ab3a6fe88600709014374f837673294ff2b0890d8ce591f77c2c2824a3391e1bf HTTP/1.1
1867+ HOST : localhost:5000
1868+ HEADERS:
1869+ Content-Length: 129
1870+ Content-Type: application/octet-stream
1871+ User-Agent: distribution-spec-conformance-tests
1872+ BODY :
1873+ ***** BODY IS byte(s) (size - 129) *****
1874+ ------------------------------------------------------------------------------
1875+ ~~~ RESPONSE ~~~
1876+ STATUS : 201 Created
1877+ PROTO : HTTP/1.1
1878+ RECEIVED AT : 2025-04-13T10:49:52.877569064Z
1879+ TIME DURATION: 19.457485ms
1880+ HEADERS :
1881+ Content-Length: 0
1882+ Date: Sun, 13 Apr 2025 10:49:52 GMT
1883+ Docker-Content-Digest: sha256:b3a6fe88600709014374f837673294ff2b0890d8ce591f77c2c2824a3391e1bf
1884+ Docker-Distribution-Api-Version: registry/2.0
1885+ Location: http://localhost:5000/v2/myorg/myrepo/a/blobs/sha256:b3a6fe88600709014374f837673294ff2b0890d8ce591f77c2c2824a3391e1bf
1886+ X-Content-Type-Options: nosniff
1887+ BODY :
1888+
1889+ ==============================================================================
1890+
1891+ </pre>
1892+ </div>
1893+ </div>
1894+
1895+
1896+
1897+
1898+ <div class="result green">
1899+ <div id="output-box-2-button" class="toggle" onclick="javascript:toggleOutput('output-box-2')">+</div>
1900+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-2')">Populate registry with test layer</h4>
1901+ <br>
1902+ <div id="output-box-2" style="display: none;">
1903+ <pre class="pre-box">DEBUG
1904+ ==============================================================================
1905+ ~~~ REQUEST ~~~
1906+ POST /v2/myorg/myrepo/a/blobs/uploads/ HTTP/1.1
1907+ HOST : localhost:5000
1908+ HEADERS:
1909+ User-Agent: distribution-spec-conformance-tests
1910+ BODY :
1911+ ***** NO CONTENT *****
1912+ ------------------------------------------------------------------------------
1913+ ~~~ RESPONSE ~~~
1914+ STATUS : 202 Accepted
1915+ PROTO : HTTP/1.1
1916+ RECEIVED AT : 2025-04-13T10:49:52.89087901Z
1917+ TIME DURATION: 12.98874ms
1918+ HEADERS :
1919+ Content-Length: 0
1920+ Date: Sun, 13 Apr 2025 10:49:52 GMT
1921+ Docker-Distribution-Api-Version: registry/2.0
1922+ Docker-Upload-Uuid: 4a5b6be7-6c6d-47f7-9c4b-4242723e9540
1923+ Location: http://localhost:5000/v2/myorg/myrepo/a/blobs/uploads/4a5b6be7-6c6d-47f7-9c4b-4242723e9540?_state=*****
1924+ Range: 0-0
1925+ X-Content-Type-Options: nosniff
1926+ BODY :
1927+
1928+ ==============================================================================
1929+
1930+ DEBUG
1931+ ==============================================================================
1932+ ~~~ REQUEST ~~~
1933+ PUT /v2/myorg/myrepo/a/blobs/uploads/4a5b6be7-6c6d-47f7-9c4b-4242723e9540?_state=*****&amp;digest=sha256%3A48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183 HTTP/1.1
1934+ HOST : localhost:5000
1935+ HEADERS:
1936+ Content-Length: 168
1937+ Content-Type: application/octet-stream
1938+ User-Agent: distribution-spec-conformance-tests
1939+ BODY :
1940+ ***** BODY IS byte(s) (size - 168) *****
1941+ ------------------------------------------------------------------------------
1942+ ~~~ RESPONSE ~~~
1943+ STATUS : 201 Created
1944+ PROTO : HTTP/1.1
1945+ RECEIVED AT : 2025-04-13T10:49:52.910012408Z
1946+ TIME DURATION: 18.985691ms
1947+ HEADERS :
1948+ Content-Length: 0
1949+ Date: Sun, 13 Apr 2025 10:49:52 GMT
1950+ Docker-Content-Digest: sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183
1951+ Docker-Distribution-Api-Version: registry/2.0
1952+ Location: http://localhost:5000/v2/myorg/myrepo/a/blobs/sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183
1953+ X-Content-Type-Options: nosniff
1954+ BODY :
1955+
1956+ ==============================================================================
1957+
1958+ </pre>
1959+ </div>
1960+ </div>
1961+
1962+
1963+
1964+
1965+ <div class="result green">
1966+ <div id="output-box-4-button" class="toggle" onclick="javascript:toggleOutput('output-box-4')">+</div>
1967+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-4')">Populate registry with test manifest</h4>
1968+ <br>
1969+ <div id="output-box-4" style="display: none;">
1970+ <pre class="pre-box">DEBUG
1971+ ==============================================================================
1972+ ~~~ REQUEST ~~~
1973+ PUT /v2/myorg/myrepo/a/manifests/sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0 HTTP/1.1
1974+ HOST : localhost:5000
1975+ HEADERS:
1976+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
1977+ User-Agent: distribution-spec-conformance-tests
1978+ BODY :
1979+ &#34;ewoJInNjaGVtYVZlcnNpb24iOiAyLAoJIm1lZGlhVHlwZSI6ICJhcHBsaWNhdGlvbi92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLAoJImNvbmZpZyI6IHsKCQkibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5vY2kuaW1hZ2UuY29uZmlnLnYxK2pzb24iLAoJCSJkaWdlc3QiOiAic2hhMjU2OmIzYTZmZTg4NjAwNzA5MDE0Mzc0ZjgzNzY3MzI5NGZmMmIwODkwZDhjZTU5MWY3N2MyYzI4MjRhMzM5MWUxYmYiLAoJCSJzaXplIjogMTI5LAoJCSJkYXRhIjogImV3b0pJbUYxZEdodmNpSTZJQ0p2UkhsWFEyOWlNVWRvU1VjM1VIYzBJaXdLQ1NKaGNtTm9hWFJsWTNSMWNtVWlPaUFpWVcxa05qUWlMQW9KSW05eklqb2dJbXhwYm5WNElpd0tDU0p5YjI5MFpuTWlPaUI3Q2drSkluUjVjR1VpT2lBaWJHRjVaWEp6SWl3S0NRa2laR2xtWmw5cFpITWlPaUJiWFFvSmZRcDkiLAoJCSJuZXdVbnNwZWNpZmllZEZpZWxkIjogImFHVnNiRzhnZDI5eWJHUT0iCgl9LAoJImxheWVycyI6IFsKCQl7CgkJCSJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLm9jaS5pbWFnZS5sYXllci52MS50YXIrZ3ppcCIsCgkJCSJkaWdlc3QiOiAic2hhMjU2OjQ4YWNmZjFkOTE3NTJlOTU3NTI3YzFiNTQxNmU3Mzc2ZDkxMGJjYWNmMDFiOTQ0MTE3NWY4YzI3MGUzNWMxODMiLAoJCQkic2l6ZSI6IDE2OCwKCQkJIm5ld1Vuc3BlY2lmaWVkRmllbGQiOiBudWxsCgkJfQoJXQp9&#34;
1980+ ------------------------------------------------------------------------------
1981+ ~~~ RESPONSE ~~~
1982+ STATUS : 201 Created
1983+ PROTO : HTTP/1.1
1984+ RECEIVED AT : 2025-04-13T10:49:52.94799338Z
1985+ TIME DURATION: 12.786291ms
1986+ HEADERS :
1987+ Content-Length: 0
1988+ Date: Sun, 13 Apr 2025 10:49:52 GMT
1989+ Docker-Content-Digest: sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0
1990+ Docker-Distribution-Api-Version: registry/2.0
1991+ Location: http://localhost:5000/v2/myorg/myrepo/a/manifests/sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0
1992+ X-Content-Type-Options: nosniff
1993+ BODY :
1994+
1995+ ==============================================================================
1996+
1997+ </pre>
1998+ </div>
1999+ </div>
2000+
2001+
2002+
2003+
2004+ <div class="result green">
2005+ <div id="output-box-4-button" class="toggle" onclick="javascript:toggleOutput('output-box-4')">+</div>
2006+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-4')">Populate registry with test manifest</h4>
2007+ <br>
2008+ <div id="output-box-4" style="display: none;">
2009+ <pre class="pre-box">DEBUG
2010+ ==============================================================================
2011+ ~~~ REQUEST ~~~
2012+ PUT /v2/myorg/myrepo/a/manifests/sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0 HTTP/1.1
2013+ HOST : localhost:5000
2014+ HEADERS:
2015+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
2016+ User-Agent: distribution-spec-conformance-tests
2017+ BODY :
2018+ &#34;ewoJInNjaGVtYVZlcnNpb24iOiAyLAoJIm1lZGlhVHlwZSI6ICJhcHBsaWNhdGlvbi92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLAoJImNvbmZpZyI6IHsKCQkibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5vY2kuaW1hZ2UuY29uZmlnLnYxK2pzb24iLAoJCSJkaWdlc3QiOiAic2hhMjU2OmIzYTZmZTg4NjAwNzA5MDE0Mzc0ZjgzNzY3MzI5NGZmMmIwODkwZDhjZTU5MWY3N2MyYzI4MjRhMzM5MWUxYmYiLAoJCSJzaXplIjogMTI5LAoJCSJkYXRhIjogImV3b0pJbUYxZEdodmNpSTZJQ0p2UkhsWFEyOWlNVWRvU1VjM1VIYzBJaXdLQ1NKaGNtTm9hWFJsWTNSMWNtVWlPaUFpWVcxa05qUWlMQW9KSW05eklqb2dJbXhwYm5WNElpd0tDU0p5YjI5MFpuTWlPaUI3Q2drSkluUjVjR1VpT2lBaWJHRjVaWEp6SWl3S0NRa2laR2xtWmw5cFpITWlPaUJiWFFvSmZRcDkiLAoJCSJuZXdVbnNwZWNpZmllZEZpZWxkIjogImFHVnNiRzhnZDI5eWJHUT0iCgl9LAoJImxheWVycyI6IFsKCQl7CgkJCSJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLm9jaS5pbWFnZS5sYXllci52MS50YXIrZ3ppcCIsCgkJCSJkaWdlc3QiOiAic2hhMjU2OjQ4YWNmZjFkOTE3NTJlOTU3NTI3YzFiNTQxNmU3Mzc2ZDkxMGJjYWNmMDFiOTQ0MTE3NWY4YzI3MGUzNWMxODMiLAoJCQkic2l6ZSI6IDE2OCwKCQkJIm5ld1Vuc3BlY2lmaWVkRmllbGQiOiBudWxsCgkJfQoJXQp9&#34;
2019+ ------------------------------------------------------------------------------
2020+ ~~~ RESPONSE ~~~
2021+ STATUS : 201 Created
2022+ PROTO : HTTP/1.1
2023+ RECEIVED AT : 2025-04-13T10:49:52.94799338Z
2024+ TIME DURATION: 12.786291ms
2025+ HEADERS :
2026+ Content-Length: 0
2027+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2028+ Docker-Content-Digest: sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0
2029+ Docker-Distribution-Api-Version: registry/2.0
2030+ Location: http://localhost:5000/v2/myorg/myrepo/a/manifests/sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0
2031+ X-Content-Type-Options: nosniff
2032+ BODY :
2033+
2034+ ==============================================================================
2035+
2036+ </pre>
2037+ </div>
2038+ </div>
2039+
2040+
2041+
2042+
2043+ <div class="result grey">
2044+ <div id="output-box-5-button" class="toggle" onclick="javascript:toggleOutput('output-box-5')">+</div>
2045+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-5')">Get tag name from environment</h4>
2046+ <br>
2047+ <div id="output-box-5" style="display: none;">
2048+ <pre class="pre-box">you have skipped this test.</pre>
2049+ </div>
2050+ </div>
2051+
2052+ <br>
2053+
2054+
2055+ <h3>Pull blobs</h3>
2056+
2057+
2058+
2059+
2060+
2061+
2062+ <div class="result green">
2063+ <div id="output-box-6-button" class="toggle" onclick="javascript:toggleOutput('output-box-6')">+</div>
2064+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-6')">HEAD request to nonexistent blob should result in 404 response</h4>
2065+ <br>
2066+ <div id="output-box-6" style="display: none;">
2067+ <pre class="pre-box">DEBUG
2068+ ==============================================================================
2069+ ~~~ REQUEST ~~~
2070+ HEAD /v2/myorg/myrepo/a/blobs/sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 HTTP/1.1
2071+ HOST : localhost:5000
2072+ HEADERS:
2073+ User-Agent: distribution-spec-conformance-tests
2074+ BODY :
2075+ ***** NO CONTENT *****
2076+ ------------------------------------------------------------------------------
2077+ ~~~ RESPONSE ~~~
2078+ STATUS : 404 Not Found
2079+ PROTO : HTTP/1.1
2080+ RECEIVED AT : 2025-04-13T10:49:52.949403031Z
2081+ TIME DURATION: 1.007217ms
2082+ HEADERS :
2083+ Content-Length: 157
2084+ Content-Type: application/json; charset=utf-8
2085+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2086+ Docker-Distribution-Api-Version: registry/2.0
2087+ X-Content-Type-Options: nosniff
2088+ BODY :
2089+ *** Error: Unable to format response body - &#34;unexpected end of JSON input&#34; ***
2090+
2091+ Log Body as-is:
2092+
2093+ ==============================================================================
2094+
2095+ </pre>
2096+ </div>
2097+ </div>
2098+
2099+
2100+
2101+
2102+ <div class="result green">
2103+ <div id="output-box-7-button" class="toggle" onclick="javascript:toggleOutput('output-box-7')">+</div>
2104+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-7')">HEAD request to existing blob should yield 200</h4>
2105+ <br>
2106+ <div id="output-box-7" style="display: none;">
2107+ <pre class="pre-box">DEBUG
2108+ ==============================================================================
2109+ ~~~ REQUEST ~~~
2110+ HEAD /v2/myorg/myrepo/a/blobs/sha256:13b7ad8050af00074dc5511427cced4f3ca332c05d6a14044a8be80966c6148b HTTP/1.1
2111+ HOST : localhost:5000
2112+ HEADERS:
2113+ User-Agent: distribution-spec-conformance-tests
2114+ BODY :
2115+ ***** NO CONTENT *****
2116+ ------------------------------------------------------------------------------
2117+ ~~~ RESPONSE ~~~
2118+ STATUS : 200 OK
2119+ PROTO : HTTP/1.1
2120+ RECEIVED AT : 2025-04-13T10:49:52.950143361Z
2121+ TIME DURATION: 567.386µs
2122+ HEADERS :
2123+ Accept-Ranges: bytes
2124+ Cache-Control: max-age=31536000
2125+ Content-Length: 129
2126+ Content-Type: application/octet-stream
2127+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2128+ Docker-Content-Digest: sha256:13b7ad8050af00074dc5511427cced4f3ca332c05d6a14044a8be80966c6148b
2129+ Docker-Distribution-Api-Version: registry/2.0
2130+ Etag: &#34;sha256:13b7ad8050af00074dc5511427cced4f3ca332c05d6a14044a8be80966c6148b&#34;
2131+ X-Content-Type-Options: nosniff
2132+ BODY :
2133+
2134+ ==============================================================================
2135+
2136+ </pre>
2137+ </div>
2138+ </div>
2139+
2140+
2141+
2142+
2143+ <div class="result green">
2144+ <div id="output-box-8-button" class="toggle" onclick="javascript:toggleOutput('output-box-8')">+</div>
2145+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-8')">GET nonexistent blob should result in 404 response</h4>
2146+ <br>
2147+ <div id="output-box-8" style="display: none;">
2148+ <pre class="pre-box">DEBUG
2149+ ==============================================================================
2150+ ~~~ REQUEST ~~~
2151+ GET /v2/myorg/myrepo/a/blobs/sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 HTTP/1.1
2152+ HOST : localhost:5000
2153+ HEADERS:
2154+ User-Agent: distribution-spec-conformance-tests
2155+ BODY :
2156+ ***** NO CONTENT *****
2157+ ------------------------------------------------------------------------------
2158+ ~~~ RESPONSE ~~~
2159+ STATUS : 404 Not Found
2160+ PROTO : HTTP/1.1
2161+ RECEIVED AT : 2025-04-13T10:49:52.950889669Z
2162+ TIME DURATION: 552.541µs
2163+ HEADERS :
2164+ Content-Length: 157
2165+ Content-Type: application/json; charset=utf-8
2166+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2167+ Docker-Distribution-Api-Version: registry/2.0
2168+ X-Content-Type-Options: nosniff
2169+ BODY :
2170+ {
2171+ &#34;errors&#34;: [
2172+ {
2173+ &#34;code&#34;: &#34;BLOB_UNKNOWN&#34;,
2174+ &#34;message&#34;: &#34;blob unknown to registry&#34;,
2175+ &#34;detail&#34;: &#34;sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9&#34;
2176+ }
2177+ ]
2178+ }
2179+
2180+ ==============================================================================
2181+
2182+ </pre>
2183+ </div>
2184+ </div>
2185+
2186+
2187+
2188+
2189+ <div class="result green">
2190+ <div id="output-box-9-button" class="toggle" onclick="javascript:toggleOutput('output-box-9')">+</div>
2191+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-9')">GET request to existing blob URL should yield 200</h4>
2192+ <br>
2193+ <div id="output-box-9" style="display: none;">
2194+ <pre class="pre-box">DEBUG
2195+ ==============================================================================
2196+ ~~~ REQUEST ~~~
2197+ GET /v2/myorg/myrepo/a/blobs/sha256:13b7ad8050af00074dc5511427cced4f3ca332c05d6a14044a8be80966c6148b HTTP/1.1
2198+ HOST : localhost:5000
2199+ HEADERS:
2200+ User-Agent: distribution-spec-conformance-tests
2201+ BODY :
2202+ ***** NO CONTENT *****
2203+ ------------------------------------------------------------------------------
2204+ ~~~ RESPONSE ~~~
2205+ STATUS : 200 OK
2206+ PROTO : HTTP/1.1
2207+ RECEIVED AT : 2025-04-13T10:49:52.952908912Z
2208+ TIME DURATION: 1.424852ms
2209+ HEADERS :
2210+ Accept-Ranges: bytes
2211+ Cache-Control: max-age=31536000
2212+ Content-Length: 129
2213+ Content-Type: application/octet-stream
2214+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2215+ Docker-Content-Digest: sha256:13b7ad8050af00074dc5511427cced4f3ca332c05d6a14044a8be80966c6148b
2216+ Docker-Distribution-Api-Version: registry/2.0
2217+ Etag: &#34;sha256:13b7ad8050af00074dc5511427cced4f3ca332c05d6a14044a8be80966c6148b&#34;
2218+ X-Content-Type-Options: nosniff
2219+ BODY :
2220+ {
2221+ &#34;author&#34;: &#34;XsgewaAE1n-nuS1n&#34;,
2222+ &#34;architecture&#34;: &#34;amd64&#34;,
2223+ &#34;os&#34;: &#34;linux&#34;,
2224+ &#34;rootfs&#34;: {
2225+ &#34;type&#34;: &#34;layers&#34;,
2226+ &#34;diff_ids&#34;: []
2227+ }
2228+ }
2229+ ==============================================================================
2230+
2231+ </pre>
2232+ </div>
2233+ </div>
2234+
2235+ <br>
2236+
2237+
2238+ <h3>Pull manifests</h3>
2239+
2240+
2241+
2242+
2243+
2244+
2245+ <div class="result green">
2246+ <div id="output-box-10-button" class="toggle" onclick="javascript:toggleOutput('output-box-10')">+</div>
2247+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-10')">HEAD request to nonexistent manifest should return 404</h4>
2248+ <br>
2249+ <div id="output-box-10" style="display: none;">
2250+ <pre class="pre-box">DEBUG
2251+ ==============================================================================
2252+ ~~~ REQUEST ~~~
2253+ HEAD /v2/myorg/myrepo/a/manifests/.INVALID_MANIFEST_NAME HTTP/1.1
2254+ HOST : localhost:5000
2255+ HEADERS:
2256+ User-Agent: distribution-spec-conformance-tests
2257+ BODY :
2258+ ***** NO CONTENT *****
2259+ ------------------------------------------------------------------------------
2260+ ~~~ RESPONSE ~~~
2261+ STATUS : 404 Not Found
2262+ PROTO : HTTP/1.1
2263+ RECEIVED AT : 2025-04-13T10:49:52.953307301Z
2264+ TIME DURATION: 134.056µs
2265+ HEADERS :
2266+ Content-Length: 19
2267+ Content-Type: text/plain; charset=utf-8
2268+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2269+ Docker-Distribution-Api-Version: registry/2.0
2270+ X-Content-Type-Options: nosniff
2271+ BODY :
2272+
2273+ ==============================================================================
2274+
2275+ </pre>
2276+ </div>
2277+ </div>
2278+
2279+
2280+
2281+
2282+ <div class="result green">
2283+ <div id="output-box-11-button" class="toggle" onclick="javascript:toggleOutput('output-box-11')">+</div>
2284+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-11')">HEAD request to manifest[0] path (digest) should yield 200 response</h4>
2285+ <br>
2286+ <div id="output-box-11" style="display: none;">
2287+ <pre class="pre-box">DEBUG
2288+ ==============================================================================
2289+ ~~~ REQUEST ~~~
2290+ HEAD /v2/myorg/myrepo/a/manifests/sha256:0d3190494f1b2b9db0a27d31e1a7a9cfd5cfd24e1c99ecb373b0306082e29896 HTTP/1.1
2291+ HOST : localhost:5000
2292+ HEADERS:
2293+ Accept: application/vnd.oci.image.manifest.v1&#43;json
2294+ User-Agent: distribution-spec-conformance-tests
2295+ BODY :
2296+ ***** NO CONTENT *****
2297+ ------------------------------------------------------------------------------
2298+ ~~~ RESPONSE ~~~
2299+ STATUS : 200 OK
2300+ PROTO : HTTP/1.1
2301+ RECEIVED AT : 2025-04-13T10:49:52.954106123Z
2302+ TIME DURATION: 620.998µs
2303+ HEADERS :
2304+ Content-Length: 714
2305+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
2306+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2307+ Docker-Content-Digest: sha256:0d3190494f1b2b9db0a27d31e1a7a9cfd5cfd24e1c99ecb373b0306082e29896
2308+ Docker-Distribution-Api-Version: registry/2.0
2309+ Etag: &#34;sha256:0d3190494f1b2b9db0a27d31e1a7a9cfd5cfd24e1c99ecb373b0306082e29896&#34;
2310+ X-Content-Type-Options: nosniff
2311+ BODY :
2312+ *** Error: Unable to format response body - &#34;unexpected end of JSON input&#34; ***
2313+
2314+ Log Body as-is:
2315+
2316+ ==============================================================================
2317+
2318+ </pre>
2319+ </div>
2320+ </div>
2321+
2322+
2323+
2324+
2325+ <div class="result green">
2326+ <div id="output-box-12-button" class="toggle" onclick="javascript:toggleOutput('output-box-12')">+</div>
2327+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-12')">HEAD request to manifest[1] path (digest) should yield 200 response</h4>
2328+ <br>
2329+ <div id="output-box-12" style="display: none;">
2330+ <pre class="pre-box">DEBUG
2331+ ==============================================================================
2332+ ~~~ REQUEST ~~~
2333+ HEAD /v2/myorg/myrepo/a/manifests/sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0 HTTP/1.1
2334+ HOST : localhost:5000
2335+ HEADERS:
2336+ Accept: application/vnd.oci.image.manifest.v1&#43;json
2337+ User-Agent: distribution-spec-conformance-tests
2338+ BODY :
2339+ ***** NO CONTENT *****
2340+ ------------------------------------------------------------------------------
2341+ ~~~ RESPONSE ~~~
2342+ STATUS : 200 OK
2343+ PROTO : HTTP/1.1
2344+ RECEIVED AT : 2025-04-13T10:49:52.95487287Z
2345+ TIME DURATION: 576.497µs
2346+ HEADERS :
2347+ Content-Length: 714
2348+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
2349+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2350+ Docker-Content-Digest: sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0
2351+ Docker-Distribution-Api-Version: registry/2.0
2352+ Etag: &#34;sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0&#34;
2353+ X-Content-Type-Options: nosniff
2354+ BODY :
2355+ *** Error: Unable to format response body - &#34;unexpected end of JSON input&#34; ***
2356+
2357+ Log Body as-is:
2358+
2359+ ==============================================================================
2360+
2361+ </pre>
2362+ </div>
2363+ </div>
2364+
2365+
2366+
2367+
2368+ <div class="result green">
2369+ <div id="output-box-13-button" class="toggle" onclick="javascript:toggleOutput('output-box-13')">+</div>
2370+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-13')">HEAD request to manifest path (tag) should yield 200 response</h4>
2371+ <br>
2372+ <div id="output-box-13" style="display: none;">
2373+ <pre class="pre-box">DEBUG
2374+ ==============================================================================
2375+ ~~~ REQUEST ~~~
2376+ HEAD /v2/myorg/myrepo/a/manifests/tagtest0 HTTP/1.1
2377+ HOST : localhost:5000
2378+ HEADERS:
2379+ Accept: application/vnd.oci.image.manifest.v1&#43;json
2380+ User-Agent: distribution-spec-conformance-tests
2381+ BODY :
2382+ ***** NO CONTENT *****
2383+ ------------------------------------------------------------------------------
2384+ ~~~ RESPONSE ~~~
2385+ STATUS : 200 OK
2386+ PROTO : HTTP/1.1
2387+ RECEIVED AT : 2025-04-13T10:49:52.95567204Z
2388+ TIME DURATION: 615.656µs
2389+ HEADERS :
2390+ Content-Length: 714
2391+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
2392+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2393+ Docker-Content-Digest: sha256:0d3190494f1b2b9db0a27d31e1a7a9cfd5cfd24e1c99ecb373b0306082e29896
2394+ Docker-Distribution-Api-Version: registry/2.0
2395+ Etag: &#34;sha256:0d3190494f1b2b9db0a27d31e1a7a9cfd5cfd24e1c99ecb373b0306082e29896&#34;
2396+ X-Content-Type-Options: nosniff
2397+ BODY :
2398+ *** Error: Unable to format response body - &#34;unexpected end of JSON input&#34; ***
2399+
2400+ Log Body as-is:
2401+
2402+ ==============================================================================
2403+
2404+ </pre>
2405+ </div>
2406+ </div>
2407+
2408+
2409+
2410+
2411+ <div class="result green">
2412+ <div id="output-box-14-button" class="toggle" onclick="javascript:toggleOutput('output-box-14')">+</div>
2413+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-14')">GET nonexistent manifest should return 404</h4>
2414+ <br>
2415+ <div id="output-box-14" style="display: none;">
2416+ <pre class="pre-box">DEBUG
2417+ ==============================================================================
2418+ ~~~ REQUEST ~~~
2419+ GET /v2/myorg/myrepo/a/manifests/.INVALID_MANIFEST_NAME HTTP/1.1
2420+ HOST : localhost:5000
2421+ HEADERS:
2422+ User-Agent: distribution-spec-conformance-tests
2423+ BODY :
2424+ ***** NO CONTENT *****
2425+ ------------------------------------------------------------------------------
2426+ ~~~ RESPONSE ~~~
2427+ STATUS : 404 Not Found
2428+ PROTO : HTTP/1.1
2429+ RECEIVED AT : 2025-04-13T10:49:52.955981367Z
2430+ TIME DURATION: 121.869µs
2431+ HEADERS :
2432+ Content-Length: 19
2433+ Content-Type: text/plain; charset=utf-8
2434+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2435+ Docker-Distribution-Api-Version: registry/2.0
2436+ X-Content-Type-Options: nosniff
2437+ BODY :
2438+ 404 page not found
2439+ ==============================================================================
2440+
2441+ </pre>
2442+ </div>
2443+ </div>
2444+
2445+
2446+
2447+
2448+ <div class="result green">
2449+ <div id="output-box-15-button" class="toggle" onclick="javascript:toggleOutput('output-box-15')">+</div>
2450+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-15')">GET request to manifest[0] path (digest) should yield 200 response</h4>
2451+ <br>
2452+ <div id="output-box-15" style="display: none;">
2453+ <pre class="pre-box">DEBUG
2454+ ==============================================================================
2455+ ~~~ REQUEST ~~~
2456+ GET /v2/myorg/myrepo/a/manifests/sha256:0d3190494f1b2b9db0a27d31e1a7a9cfd5cfd24e1c99ecb373b0306082e29896 HTTP/1.1
2457+ HOST : localhost:5000
2458+ HEADERS:
2459+ Accept: application/vnd.oci.image.manifest.v1&#43;json
2460+ User-Agent: distribution-spec-conformance-tests
2461+ BODY :
2462+ ***** NO CONTENT *****
2463+ ------------------------------------------------------------------------------
2464+ ~~~ RESPONSE ~~~
2465+ STATUS : 200 OK
2466+ PROTO : HTTP/1.1
2467+ RECEIVED AT : 2025-04-13T10:49:52.956748392Z
2468+ TIME DURATION: 607.981µs
2469+ HEADERS :
2470+ Content-Length: 714
2471+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
2472+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2473+ Docker-Content-Digest: sha256:0d3190494f1b2b9db0a27d31e1a7a9cfd5cfd24e1c99ecb373b0306082e29896
2474+ Docker-Distribution-Api-Version: registry/2.0
2475+ Etag: &#34;sha256:0d3190494f1b2b9db0a27d31e1a7a9cfd5cfd24e1c99ecb373b0306082e29896&#34;
2476+ X-Content-Type-Options: nosniff
2477+ BODY :
2478+ {
2479+ &#34;schemaVersion&#34;: 2,
2480+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.manifest.v1&#43;json&#34;,
2481+ &#34;config&#34;: {
2482+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.config.v1&#43;json&#34;,
2483+ &#34;digest&#34;: &#34;sha256:13b7ad8050af00074dc5511427cced4f3ca332c05d6a14044a8be80966c6148b&#34;,
2484+ &#34;size&#34;: 129,
2485+ &#34;data&#34;: &#34;ewoJImF1dGhvciI6ICJYc2dld2FBRTFuLW51UzFuIiwKCSJhcmNoaXRlY3R1cmUiOiAiYW1kNjQiLAoJIm9zIjogImxpbnV4IiwKCSJyb290ZnMiOiB7CgkJInR5cGUiOiAibGF5ZXJzIiwKCQkiZGlmZl9pZHMiOiBbXQoJfQp9&#34;,
2486+ &#34;newUnspecifiedField&#34;: &#34;aGVsbG8gd29ybGQ=&#34;
2487+ },
2488+ &#34;layers&#34;: [
2489+ {
2490+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.layer.v1.tar&#43;gzip&#34;,
2491+ &#34;digest&#34;: &#34;sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183&#34;,
2492+ &#34;size&#34;: 168,
2493+ &#34;newUnspecifiedField&#34;: null
2494+ }
2495+ ]
2496+ }
2497+ ==============================================================================
2498+
2499+ </pre>
2500+ </div>
2501+ </div>
2502+
2503+
2504+
2505+
2506+ <div class="result green">
2507+ <div id="output-box-16-button" class="toggle" onclick="javascript:toggleOutput('output-box-16')">+</div>
2508+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-16')">GET request to manifest[1] path (digest) should yield 200 response</h4>
2509+ <br>
2510+ <div id="output-box-16" style="display: none;">
2511+ <pre class="pre-box">DEBUG
2512+ ==============================================================================
2513+ ~~~ REQUEST ~~~
2514+ GET /v2/myorg/myrepo/a/manifests/sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0 HTTP/1.1
2515+ HOST : localhost:5000
2516+ HEADERS:
2517+ Accept: application/vnd.oci.image.manifest.v1&#43;json
2518+ User-Agent: distribution-spec-conformance-tests
2519+ BODY :
2520+ ***** NO CONTENT *****
2521+ ------------------------------------------------------------------------------
2522+ ~~~ RESPONSE ~~~
2523+ STATUS : 200 OK
2524+ PROTO : HTTP/1.1
2525+ RECEIVED AT : 2025-04-13T10:49:52.957666304Z
2526+ TIME DURATION: 618.218µs
2527+ HEADERS :
2528+ Content-Length: 714
2529+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
2530+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2531+ Docker-Content-Digest: sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0
2532+ Docker-Distribution-Api-Version: registry/2.0
2533+ Etag: &#34;sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0&#34;
2534+ X-Content-Type-Options: nosniff
2535+ BODY :
2536+ {
2537+ &#34;schemaVersion&#34;: 2,
2538+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.manifest.v1&#43;json&#34;,
2539+ &#34;config&#34;: {
2540+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.config.v1&#43;json&#34;,
2541+ &#34;digest&#34;: &#34;sha256:b3a6fe88600709014374f837673294ff2b0890d8ce591f77c2c2824a3391e1bf&#34;,
2542+ &#34;size&#34;: 129,
2543+ &#34;data&#34;: &#34;ewoJImF1dGhvciI6ICJvRHlXQ29iMUdoSUc3UHc0IiwKCSJhcmNoaXRlY3R1cmUiOiAiYW1kNjQiLAoJIm9zIjogImxpbnV4IiwKCSJyb290ZnMiOiB7CgkJInR5cGUiOiAibGF5ZXJzIiwKCQkiZGlmZl9pZHMiOiBbXQoJfQp9&#34;,
2544+ &#34;newUnspecifiedField&#34;: &#34;aGVsbG8gd29ybGQ=&#34;
2545+ },
2546+ &#34;layers&#34;: [
2547+ {
2548+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.layer.v1.tar&#43;gzip&#34;,
2549+ &#34;digest&#34;: &#34;sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183&#34;,
2550+ &#34;size&#34;: 168,
2551+ &#34;newUnspecifiedField&#34;: null
2552+ }
2553+ ]
2554+ }
2555+ ==============================================================================
2556+
2557+ </pre>
2558+ </div>
2559+ </div>
2560+
2561+
2562+
2563+
2564+ <div class="result green">
2565+ <div id="output-box-17-button" class="toggle" onclick="javascript:toggleOutput('output-box-17')">+</div>
2566+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-17')">GET request to manifest path (tag) should yield 200 response</h4>
2567+ <br>
2568+ <div id="output-box-17" style="display: none;">
2569+ <pre class="pre-box">DEBUG
2570+ ==============================================================================
2571+ ~~~ REQUEST ~~~
2572+ GET /v2/myorg/myrepo/a/manifests/tagtest0 HTTP/1.1
2573+ HOST : localhost:5000
2574+ HEADERS:
2575+ Accept: application/vnd.oci.image.manifest.v1&#43;json
2576+ User-Agent: distribution-spec-conformance-tests
2577+ BODY :
2578+ ***** NO CONTENT *****
2579+ ------------------------------------------------------------------------------
2580+ ~~~ RESPONSE ~~~
2581+ STATUS : 200 OK
2582+ PROTO : HTTP/1.1
2583+ RECEIVED AT : 2025-04-13T10:49:52.958468578Z
2584+ TIME DURATION: 537.533µs
2585+ HEADERS :
2586+ Content-Length: 714
2587+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
2588+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2589+ Docker-Content-Digest: sha256:0d3190494f1b2b9db0a27d31e1a7a9cfd5cfd24e1c99ecb373b0306082e29896
2590+ Docker-Distribution-Api-Version: registry/2.0
2591+ Etag: &#34;sha256:0d3190494f1b2b9db0a27d31e1a7a9cfd5cfd24e1c99ecb373b0306082e29896&#34;
2592+ X-Content-Type-Options: nosniff
2593+ BODY :
2594+ {
2595+ &#34;schemaVersion&#34;: 2,
2596+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.manifest.v1&#43;json&#34;,
2597+ &#34;config&#34;: {
2598+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.config.v1&#43;json&#34;,
2599+ &#34;digest&#34;: &#34;sha256:13b7ad8050af00074dc5511427cced4f3ca332c05d6a14044a8be80966c6148b&#34;,
2600+ &#34;size&#34;: 129,
2601+ &#34;data&#34;: &#34;ewoJImF1dGhvciI6ICJYc2dld2FBRTFuLW51UzFuIiwKCSJhcmNoaXRlY3R1cmUiOiAiYW1kNjQiLAoJIm9zIjogImxpbnV4IiwKCSJyb290ZnMiOiB7CgkJInR5cGUiOiAibGF5ZXJzIiwKCQkiZGlmZl9pZHMiOiBbXQoJfQp9&#34;,
2602+ &#34;newUnspecifiedField&#34;: &#34;aGVsbG8gd29ybGQ=&#34;
2603+ },
2604+ &#34;layers&#34;: [
2605+ {
2606+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.layer.v1.tar&#43;gzip&#34;,
2607+ &#34;digest&#34;: &#34;sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183&#34;,
2608+ &#34;size&#34;: 168,
2609+ &#34;newUnspecifiedField&#34;: null
2610+ }
2611+ ]
2612+ }
2613+ ==============================================================================
2614+
2615+ </pre>
2616+ </div>
2617+ </div>
2618+
2619+ <br>
2620+
2621+
2622+ <h3>Error codes</h3>
2623+
2624+
2625+
2626+
2627+
2628+
2629+ <div class="result red">
2630+ <div id="output-box-18-button" class="toggle" onclick="javascript:toggleOutput('output-box-18')">+</div>
2631+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-18')">400 response body should contain OCI-conforming JSON message</h4>
2632+ <br>
2633+ <div>
2634+ <div id="output-box-18" style="display: none;">
2635+ <pre class="pre-box">DEBUG
2636+ ==============================================================================
2637+ ~~~ REQUEST ~~~
2638+ GET /v2/myorg/myrepo/a/manifests/sha256:totallywrong HTTP/1.1
2639+ HOST : localhost:5000
2640+ HEADERS:
2641+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
2642+ User-Agent: distribution-spec-conformance-tests
2643+ BODY :
2644+ ***** NO CONTENT *****
2645+ ------------------------------------------------------------------------------
2646+ ~~~ RESPONSE ~~~
2647+ STATUS : 500 Internal Server Error
2648+ PROTO : HTTP/1.1
2649+ RECEIVED AT : 2025-04-13T10:49:52.959279296Z
2650+ TIME DURATION: 545.865µs
2651+ HEADERS :
2652+ Content-Length: 201
2653+ Content-Type: application/json; charset=utf-8
2654+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2655+ Docker-Distribution-Api-Version: registry/2.0
2656+ X-Content-Type-Options: nosniff
2657+ BODY :
2658+ {
2659+ &#34;errors&#34;: [
2660+ {
2661+ &#34;code&#34;: &#34;UNKNOWN&#34;,
2662+ &#34;message&#34;: &#34;unknown error&#34;,
2663+ &#34;detail&#34;: {
2664+ &#34;Path&#34;: &#34;/docker/registry/v2/repositories/myorg/myrepo/a/_manifests/tags/sha256:totallywrong/current/link&#34;,
2665+ &#34;DriverName&#34;: &#34;filesystem&#34;
2666+ }
2667+ }
2668+ ]
2669+ }
2670+
2671+ ==============================================================================
2672+
2673+ </pre>
2674+ </div>
2675+ </div>
2676+ <pre class="fail-message">Expected
2677+ &lt;int&gt;: 500
2678+ To satisfy at least one of these matchers: [%!s(*matchers.EqualMatcher=&amp;{400}) %!s(*matchers.EqualMatcher=&amp;{404})]</pre>
2679+ <br>
2680+ </div>
2681+
2682+ <br>
2683+
2684+
2685+ <h3>Teardown</h3>
2686+
2687+
2688+
2689+
2690+
2691+
2692+ <div class="result green">
2693+ <div id="output-box-19-button" class="toggle" onclick="javascript:toggleOutput('output-box-19')">+</div>
2694+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-19')">Delete config[0] blob created in setup</h4>
2695+ <br>
2696+ <div id="output-box-19" style="display: none;">
2697+ <pre class="pre-box">DEBUG
2698+ ==============================================================================
2699+ ~~~ REQUEST ~~~
2700+ DELETE /v2/myorg/myrepo/a/blobs/sha256:13b7ad8050af00074dc5511427cced4f3ca332c05d6a14044a8be80966c6148b HTTP/1.1
2701+ HOST : localhost:5000
2702+ HEADERS:
2703+ User-Agent: distribution-spec-conformance-tests
2704+ BODY :
2705+ ***** NO CONTENT *****
2706+ ------------------------------------------------------------------------------
2707+ ~~~ RESPONSE ~~~
2708+ STATUS : 405 Method Not Allowed
2709+ PROTO : HTTP/1.1
2710+ RECEIVED AT : 2025-04-13T10:49:52.960047618Z
2711+ TIME DURATION: 439.82µs
2712+ HEADERS :
2713+ Content-Length: 78
2714+ Content-Type: application/json; charset=utf-8
2715+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2716+ Docker-Distribution-Api-Version: registry/2.0
2717+ X-Content-Type-Options: nosniff
2718+ BODY :
2719+ {
2720+ &#34;errors&#34;: [
2721+ {
2722+ &#34;code&#34;: &#34;UNSUPPORTED&#34;,
2723+ &#34;message&#34;: &#34;The operation is unsupported.&#34;
2724+ }
2725+ ]
2726+ }
2727+
2728+ ==============================================================================
2729+
2730+ </pre>
2731+ </div>
2732+ </div>
2733+
2734+
2735+
2736+
2737+ <div class="result green">
2738+ <div id="output-box-20-button" class="toggle" onclick="javascript:toggleOutput('output-box-20')">+</div>
2739+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-20')">Delete config[1] blob created in setup</h4>
2740+ <br>
2741+ <div id="output-box-20" style="display: none;">
2742+ <pre class="pre-box">DEBUG
2743+ ==============================================================================
2744+ ~~~ REQUEST ~~~
2745+ DELETE /v2/myorg/myrepo/a/blobs/sha256:b3a6fe88600709014374f837673294ff2b0890d8ce591f77c2c2824a3391e1bf HTTP/1.1
2746+ HOST : localhost:5000
2747+ HEADERS:
2748+ User-Agent: distribution-spec-conformance-tests
2749+ BODY :
2750+ ***** NO CONTENT *****
2751+ ------------------------------------------------------------------------------
2752+ ~~~ RESPONSE ~~~
2753+ STATUS : 405 Method Not Allowed
2754+ PROTO : HTTP/1.1
2755+ RECEIVED AT : 2025-04-13T10:49:52.960663143Z
2756+ TIME DURATION: 446.135µs
2757+ HEADERS :
2758+ Content-Length: 78
2759+ Content-Type: application/json; charset=utf-8
2760+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2761+ Docker-Distribution-Api-Version: registry/2.0
2762+ X-Content-Type-Options: nosniff
2763+ BODY :
2764+ {
2765+ &#34;errors&#34;: [
2766+ {
2767+ &#34;code&#34;: &#34;UNSUPPORTED&#34;,
2768+ &#34;message&#34;: &#34;The operation is unsupported.&#34;
2769+ }
2770+ ]
2771+ }
2772+
2773+ ==============================================================================
2774+
2775+ </pre>
2776+ </div>
2777+ </div>
2778+
2779+
2780+
2781+
2782+ <div class="result green">
2783+ <div id="output-box-21-button" class="toggle" onclick="javascript:toggleOutput('output-box-21')">+</div>
2784+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-21')">Delete layer blob created in setup</h4>
2785+ <br>
2786+ <div id="output-box-21" style="display: none;">
2787+ <pre class="pre-box">DEBUG
2788+ ==============================================================================
2789+ ~~~ REQUEST ~~~
2790+ DELETE /v2/myorg/myrepo/a/blobs/sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183 HTTP/1.1
2791+ HOST : localhost:5000
2792+ HEADERS:
2793+ User-Agent: distribution-spec-conformance-tests
2794+ BODY :
2795+ ***** NO CONTENT *****
2796+ ------------------------------------------------------------------------------
2797+ ~~~ RESPONSE ~~~
2798+ STATUS : 405 Method Not Allowed
2799+ PROTO : HTTP/1.1
2800+ RECEIVED AT : 2025-04-13T10:49:52.961605544Z
2801+ TIME DURATION: 784.721µs
2802+ HEADERS :
2803+ Content-Length: 78
2804+ Content-Type: application/json; charset=utf-8
2805+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2806+ Docker-Distribution-Api-Version: registry/2.0
2807+ X-Content-Type-Options: nosniff
2808+ BODY :
2809+ {
2810+ &#34;errors&#34;: [
2811+ {
2812+ &#34;code&#34;: &#34;UNSUPPORTED&#34;,
2813+ &#34;message&#34;: &#34;The operation is unsupported.&#34;
2814+ }
2815+ ]
2816+ }
2817+
2818+ ==============================================================================
2819+
2820+ </pre>
2821+ </div>
2822+ </div>
2823+
2824+
2825+
2826+
2827+ <div class="result green">
2828+ <div id="output-box-22-button" class="toggle" onclick="javascript:toggleOutput('output-box-22')">+</div>
2829+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-22')">Delete manifest[0] created in setup</h4>
2830+ <br>
2831+ <div id="output-box-22" style="display: none;">
2832+ <pre class="pre-box">DEBUG
2833+ ==============================================================================
2834+ ~~~ REQUEST ~~~
2835+ DELETE /v2/myorg/myrepo/a/manifests/sha256:0d3190494f1b2b9db0a27d31e1a7a9cfd5cfd24e1c99ecb373b0306082e29896 HTTP/1.1
2836+ HOST : localhost:5000
2837+ HEADERS:
2838+ User-Agent: distribution-spec-conformance-tests
2839+ BODY :
2840+ ***** NO CONTENT *****
2841+ ------------------------------------------------------------------------------
2842+ ~~~ RESPONSE ~~~
2843+ STATUS : 405 Method Not Allowed
2844+ PROTO : HTTP/1.1
2845+ RECEIVED AT : 2025-04-13T10:49:52.962271415Z
2846+ TIME DURATION: 479.065µs
2847+ HEADERS :
2848+ Content-Length: 78
2849+ Content-Type: application/json; charset=utf-8
2850+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2851+ Docker-Distribution-Api-Version: registry/2.0
2852+ X-Content-Type-Options: nosniff
2853+ BODY :
2854+ {
2855+ &#34;errors&#34;: [
2856+ {
2857+ &#34;code&#34;: &#34;UNSUPPORTED&#34;,
2858+ &#34;message&#34;: &#34;The operation is unsupported.&#34;
2859+ }
2860+ ]
2861+ }
2862+
2863+ ==============================================================================
2864+
2865+ </pre>
2866+ </div>
2867+ </div>
2868+
2869+
2870+
2871+
2872+ <div class="result green">
2873+ <div id="output-box-23-button" class="toggle" onclick="javascript:toggleOutput('output-box-23')">+</div>
2874+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-23')">Delete manifest[1] created in setup</h4>
2875+ <br>
2876+ <div id="output-box-23" style="display: none;">
2877+ <pre class="pre-box">DEBUG
2878+ ==============================================================================
2879+ ~~~ REQUEST ~~~
2880+ DELETE /v2/myorg/myrepo/a/manifests/sha256:34baedb2fd45ee2a83db57722eaece9be6f5b02c61e3fbc2d2812128d080bfc0 HTTP/1.1
2881+ HOST : localhost:5000
2882+ HEADERS:
2883+ User-Agent: distribution-spec-conformance-tests
2884+ BODY :
2885+ ***** NO CONTENT *****
2886+ ------------------------------------------------------------------------------
2887+ ~~~ RESPONSE ~~~
2888+ STATUS : 405 Method Not Allowed
2889+ PROTO : HTTP/1.1
2890+ RECEIVED AT : 2025-04-13T10:49:52.962899073Z
2891+ TIME DURATION: 443.018µs
2892+ HEADERS :
2893+ Content-Length: 78
2894+ Content-Type: application/json; charset=utf-8
2895+ Date: Sun, 13 Apr 2025 10:49:52 GMT
2896+ Docker-Distribution-Api-Version: registry/2.0
2897+ X-Content-Type-Options: nosniff
2898+ BODY :
2899+ {
2900+ &#34;errors&#34;: [
2901+ {
2902+ &#34;code&#34;: &#34;UNSUPPORTED&#34;,
2903+ &#34;message&#34;: &#34;The operation is unsupported.&#34;
2904+ }
2905+ ]
2906+ }
2907+
2908+ ==============================================================================
2909+
2910+ </pre>
2911+ </div>
2912+ </div>
2913+
2914+ <br>
2915+
2916+
2917+
2918+
2919+ </div>
2920+
2921+
2922+
2923+
2924+ <h2>Push</h2>
2925+ <div class="subcategory">
2926+
2927+
2928+ <h3>Blob Upload Streamed</h3>
2929+
2930+
2931+
2932+
2933+
2934+
2935+ <div class="result grey">
2936+ <div id="output-box-24-button" class="toggle" onclick="javascript:toggleOutput('output-box-24')">+</div>
2937+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-24')">PATCH request with blob in body should yield 202 response</h4>
2938+ <br>
2939+ <div id="output-box-24" style="display: none;">
2940+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
2941+ OCI_TEST_PUSH=0
2942+ OCI_TEST_CONTENT_DISCOVERY=0
2943+ OCI_TEST_CONTENT_MANAGEMENT=0
2944+ OCI_TEST_PULL=1
2945+ </pre>
2946+ </div>
2947+ </div>
2948+
2949+
2950+
2951+
2952+ <div class="result grey">
2953+ <div id="output-box-25-button" class="toggle" onclick="javascript:toggleOutput('output-box-25')">+</div>
2954+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-25')">PUT request to session URL with digest should yield 201 response</h4>
2955+ <br>
2956+ <div id="output-box-25" style="display: none;">
2957+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
2958+ OCI_TEST_PULL=1
2959+ OCI_TEST_PUSH=0
2960+ OCI_TEST_CONTENT_DISCOVERY=0
2961+ OCI_TEST_CONTENT_MANAGEMENT=0
2962+ </pre>
2963+ </div>
2964+ </div>
2965+
2966+ <br>
2967+
2968+
2969+ <h3>Blob Upload Monolithic</h3>
2970+
2971+
2972+
2973+
2974+
2975+
2976+ <div class="result grey">
2977+ <div id="output-box-26-button" class="toggle" onclick="javascript:toggleOutput('output-box-26')">+</div>
2978+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-26')">GET nonexistent blob should result in 404 response</h4>
2979+ <br>
2980+ <div id="output-box-26" style="display: none;">
2981+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
2982+ OCI_TEST_PUSH=0
2983+ OCI_TEST_CONTENT_DISCOVERY=0
2984+ OCI_TEST_CONTENT_MANAGEMENT=0
2985+ OCI_TEST_PULL=1
2986+ </pre>
2987+ </div>
2988+ </div>
2989+
2990+
2991+
2992+
2993+ <div class="result grey">
2994+ <div id="output-box-27-button" class="toggle" onclick="javascript:toggleOutput('output-box-27')">+</div>
2995+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-27')">POST request with digest and blob should yield a 201 or 202</h4>
2996+ <br>
2997+ <div id="output-box-27" style="display: none;">
2998+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
2999+ OCI_TEST_CONTENT_MANAGEMENT=0
3000+ OCI_TEST_PULL=1
3001+ OCI_TEST_PUSH=0
3002+ OCI_TEST_CONTENT_DISCOVERY=0
3003+ </pre>
3004+ </div>
3005+ </div>
3006+
3007+
3008+
3009+
3010+ <div class="result grey">
3011+ <div id="output-box-28-button" class="toggle" onclick="javascript:toggleOutput('output-box-28')">+</div>
3012+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-28')">GET request to blob URL from prior request should yield 200 or 404 based on response code</h4>
3013+ <br>
3014+ <div id="output-box-28" style="display: none;">
3015+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3016+ OCI_TEST_PULL=1
3017+ OCI_TEST_PUSH=0
3018+ OCI_TEST_CONTENT_DISCOVERY=0
3019+ OCI_TEST_CONTENT_MANAGEMENT=0
3020+ </pre>
3021+ </div>
3022+ </div>
3023+
3024+
3025+
3026+
3027+ <div class="result grey">
3028+ <div id="output-box-29-button" class="toggle" onclick="javascript:toggleOutput('output-box-29')">+</div>
3029+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-29')">POST request should yield a session ID</h4>
3030+ <br>
3031+ <div id="output-box-29" style="display: none;">
3032+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3033+ OCI_TEST_PUSH=0
3034+ OCI_TEST_CONTENT_DISCOVERY=0
3035+ OCI_TEST_CONTENT_MANAGEMENT=0
3036+ OCI_TEST_PULL=1
3037+ </pre>
3038+ </div>
3039+ </div>
3040+
3041+
3042+
3043+
3044+ <div class="result grey">
3045+ <div id="output-box-30-button" class="toggle" onclick="javascript:toggleOutput('output-box-30')">+</div>
3046+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-30')">PUT upload of a blob should yield a 201 Response</h4>
3047+ <br>
3048+ <div id="output-box-30" style="display: none;">
3049+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3050+ OCI_TEST_PULL=1
3051+ OCI_TEST_PUSH=0
3052+ OCI_TEST_CONTENT_DISCOVERY=0
3053+ OCI_TEST_CONTENT_MANAGEMENT=0
3054+ </pre>
3055+ </div>
3056+ </div>
3057+
3058+
3059+
3060+
3061+ <div class="result grey">
3062+ <div id="output-box-31-button" class="toggle" onclick="javascript:toggleOutput('output-box-31')">+</div>
3063+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-31')">GET request to existing blob should yield 200 response</h4>
3064+ <br>
3065+ <div id="output-box-31" style="display: none;">
3066+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3067+ OCI_TEST_PULL=1
3068+ OCI_TEST_PUSH=0
3069+ OCI_TEST_CONTENT_DISCOVERY=0
3070+ OCI_TEST_CONTENT_MANAGEMENT=0
3071+ </pre>
3072+ </div>
3073+ </div>
3074+
3075+
3076+
3077+
3078+ <div class="result grey">
3079+ <div id="output-box-32-button" class="toggle" onclick="javascript:toggleOutput('output-box-32')">+</div>
3080+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-32')">PUT upload of a layer blob should yield a 201 Response</h4>
3081+ <br>
3082+ <div id="output-box-32" style="display: none;">
3083+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3084+ OCI_TEST_CONTENT_MANAGEMENT=0
3085+ OCI_TEST_PULL=1
3086+ OCI_TEST_PUSH=0
3087+ OCI_TEST_CONTENT_DISCOVERY=0
3088+ </pre>
3089+ </div>
3090+ </div>
3091+
3092+
3093+
3094+
3095+ <div class="result grey">
3096+ <div id="output-box-33-button" class="toggle" onclick="javascript:toggleOutput('output-box-33')">+</div>
3097+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-33')">GET request to existing layer should yield 200 response</h4>
3098+ <br>
3099+ <div id="output-box-33" style="display: none;">
3100+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3101+ OCI_TEST_CONTENT_MANAGEMENT=0
3102+ OCI_TEST_PULL=1
3103+ OCI_TEST_PUSH=0
3104+ OCI_TEST_CONTENT_DISCOVERY=0
3105+ </pre>
3106+ </div>
3107+ </div>
3108+
3109+ <br>
3110+
3111+
3112+ <h3>Blob Upload Chunked</h3>
3113+
3114+
3115+
3116+
3117+
3118+
3119+ <div class="result grey">
3120+ <div id="output-box-34-button" class="toggle" onclick="javascript:toggleOutput('output-box-34')">+</div>
3121+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-34')">Out-of-order blob upload should return 416</h4>
3122+ <br>
3123+ <div id="output-box-34" style="display: none;">
3124+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3125+ OCI_TEST_PULL=1
3126+ OCI_TEST_PUSH=0
3127+ OCI_TEST_CONTENT_DISCOVERY=0
3128+ OCI_TEST_CONTENT_MANAGEMENT=0
3129+ </pre>
3130+ </div>
3131+ </div>
3132+
3133+
3134+
3135+
3136+ <div class="result grey">
3137+ <div id="output-box-35-button" class="toggle" onclick="javascript:toggleOutput('output-box-35')">+</div>
3138+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-35')">PATCH request with first chunk should return 202</h4>
3139+ <br>
3140+ <div id="output-box-35" style="display: none;">
3141+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3142+ OCI_TEST_PULL=1
3143+ OCI_TEST_PUSH=0
3144+ OCI_TEST_CONTENT_DISCOVERY=0
3145+ OCI_TEST_CONTENT_MANAGEMENT=0
3146+ </pre>
3147+ </div>
3148+ </div>
3149+
3150+
3151+
3152+
3153+ <div class="result grey">
3154+ <div id="output-box-36-button" class="toggle" onclick="javascript:toggleOutput('output-box-36')">+</div>
3155+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-36')">Retry previous blob chunk should return 416</h4>
3156+ <br>
3157+ <div id="output-box-36" style="display: none;">
3158+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3159+ OCI_TEST_PULL=1
3160+ OCI_TEST_PUSH=0
3161+ OCI_TEST_CONTENT_DISCOVERY=0
3162+ OCI_TEST_CONTENT_MANAGEMENT=0
3163+ </pre>
3164+ </div>
3165+ </div>
3166+
3167+
3168+
3169+
3170+ <div class="result grey">
3171+ <div id="output-box-37-button" class="toggle" onclick="javascript:toggleOutput('output-box-37')">+</div>
3172+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-37')">Get on stale blob upload should return 204 with a range and location</h4>
3173+ <br>
3174+ <div id="output-box-37" style="display: none;">
3175+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3176+ OCI_TEST_PULL=1
3177+ OCI_TEST_PUSH=0
3178+ OCI_TEST_CONTENT_DISCOVERY=0
3179+ OCI_TEST_CONTENT_MANAGEMENT=0
3180+ </pre>
3181+ </div>
3182+ </div>
3183+
3184+
3185+
3186+
3187+ <div class="result grey">
3188+ <div id="output-box-38-button" class="toggle" onclick="javascript:toggleOutput('output-box-38')">+</div>
3189+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-38')">PATCH request with second chunk should return 202</h4>
3190+ <br>
3191+ <div id="output-box-38" style="display: none;">
3192+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3193+ OCI_TEST_PULL=1
3194+ OCI_TEST_PUSH=0
3195+ OCI_TEST_CONTENT_DISCOVERY=0
3196+ OCI_TEST_CONTENT_MANAGEMENT=0
3197+ </pre>
3198+ </div>
3199+ </div>
3200+
3201+
3202+
3203+
3204+ <div class="result grey">
3205+ <div id="output-box-39-button" class="toggle" onclick="javascript:toggleOutput('output-box-39')">+</div>
3206+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-39')">PUT request with digest should return 201</h4>
3207+ <br>
3208+ <div id="output-box-39" style="display: none;">
3209+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3210+ OCI_TEST_PULL=1
3211+ OCI_TEST_PUSH=0
3212+ OCI_TEST_CONTENT_DISCOVERY=0
3213+ OCI_TEST_CONTENT_MANAGEMENT=0
3214+ </pre>
3215+ </div>
3216+ </div>
3217+
3218+ <br>
3219+
3220+
3221+ <h3>Cross-Repository Blob Mount</h3>
3222+
3223+
3224+
3225+
3226+
3227+
3228+ <div class="result grey">
3229+ <div id="output-box-40-button" class="toggle" onclick="javascript:toggleOutput('output-box-40')">+</div>
3230+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-40')">Cross-mounting of a blob without the from argument should yield session id</h4>
3231+ <br>
3232+ <div id="output-box-40" style="display: none;">
3233+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3234+ OCI_TEST_PULL=1
3235+ OCI_TEST_PUSH=0
3236+ OCI_TEST_CONTENT_DISCOVERY=0
3237+ OCI_TEST_CONTENT_MANAGEMENT=0
3238+ </pre>
3239+ </div>
3240+ </div>
3241+
3242+
3243+
3244+
3245+ <div class="result grey">
3246+ <div id="output-box-41-button" class="toggle" onclick="javascript:toggleOutput('output-box-41')">+</div>
3247+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-41')">POST request to mount another repository&#39;s blob should return 201 or 202</h4>
3248+ <br>
3249+ <div id="output-box-41" style="display: none;">
3250+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3251+ OCI_TEST_PULL=1
3252+ OCI_TEST_PUSH=0
3253+ OCI_TEST_CONTENT_DISCOVERY=0
3254+ OCI_TEST_CONTENT_MANAGEMENT=0
3255+ </pre>
3256+ </div>
3257+ </div>
3258+
3259+
3260+
3261+
3262+ <div class="result grey">
3263+ <div id="output-box-42-button" class="toggle" onclick="javascript:toggleOutput('output-box-42')">+</div>
3264+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-42')">GET request to test digest within cross-mount namespace should return 200</h4>
3265+ <br>
3266+ <div id="output-box-42" style="display: none;">
3267+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3268+ OCI_TEST_PULL=1
3269+ OCI_TEST_PUSH=0
3270+ OCI_TEST_CONTENT_DISCOVERY=0
3271+ OCI_TEST_CONTENT_MANAGEMENT=0
3272+ </pre>
3273+ </div>
3274+ </div>
3275+
3276+
3277+
3278+
3279+ <div class="result grey">
3280+ <div id="output-box-43-button" class="toggle" onclick="javascript:toggleOutput('output-box-43')">+</div>
3281+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-43')">Cross-mounting of nonexistent blob should yield session id</h4>
3282+ <br>
3283+ <div id="output-box-43" style="display: none;">
3284+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3285+ OCI_TEST_PULL=1
3286+ OCI_TEST_PUSH=0
3287+ OCI_TEST_CONTENT_DISCOVERY=0
3288+ OCI_TEST_CONTENT_MANAGEMENT=0
3289+ </pre>
3290+ </div>
3291+ </div>
3292+
3293+
3294+
3295+
3296+ <div class="result grey">
3297+ <div id="output-box-44-button" class="toggle" onclick="javascript:toggleOutput('output-box-44')">+</div>
3298+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-44')">Cross-mounting without from, and automatic content discovery enabled should return a 201</h4>
3299+ <br>
3300+ <div id="output-box-44" style="display: none;">
3301+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3302+ OCI_TEST_PULL=1
3303+ OCI_TEST_PUSH=0
3304+ OCI_TEST_CONTENT_DISCOVERY=0
3305+ OCI_TEST_CONTENT_MANAGEMENT=0
3306+ </pre>
3307+ </div>
3308+ </div>
3309+
3310+
3311+
3312+
3313+ <div class="result grey">
3314+ <div id="output-box-45-button" class="toggle" onclick="javascript:toggleOutput('output-box-45')">+</div>
3315+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-45')">Cross-mounting without from, and automatic content discovery disabled should return a 202</h4>
3316+ <br>
3317+ <div id="output-box-45" style="display: none;">
3318+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3319+ OCI_TEST_CONTENT_MANAGEMENT=0
3320+ OCI_TEST_PULL=1
3321+ OCI_TEST_PUSH=0
3322+ OCI_TEST_CONTENT_DISCOVERY=0
3323+ </pre>
3324+ </div>
3325+ </div>
3326+
3327+ <br>
3328+
3329+
3330+ <h3>Manifest Upload</h3>
3331+
3332+
3333+
3334+
3335+
3336+
3337+ <div class="result grey">
3338+ <div id="output-box-46-button" class="toggle" onclick="javascript:toggleOutput('output-box-46')">+</div>
3339+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-46')">GET nonexistent manifest should return 404</h4>
3340+ <br>
3341+ <div id="output-box-46" style="display: none;">
3342+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3343+ OCI_TEST_PULL=1
3344+ OCI_TEST_PUSH=0
3345+ OCI_TEST_CONTENT_DISCOVERY=0
3346+ OCI_TEST_CONTENT_MANAGEMENT=0
3347+ </pre>
3348+ </div>
3349+ </div>
3350+
3351+
3352+
3353+
3354+ <div class="result grey">
3355+ <div id="output-box-47-button" class="toggle" onclick="javascript:toggleOutput('output-box-47')">+</div>
3356+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-47')">PUT should accept a manifest upload</h4>
3357+ <br>
3358+ <div id="output-box-47" style="display: none;">
3359+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3360+ OCI_TEST_PULL=1
3361+ OCI_TEST_PUSH=0
3362+ OCI_TEST_CONTENT_DISCOVERY=0
3363+ OCI_TEST_CONTENT_MANAGEMENT=0
3364+ </pre>
3365+ </div>
3366+ </div>
3367+
3368+
3369+
3370+
3371+ <div class="result grey">
3372+ <div id="output-box-48-button" class="toggle" onclick="javascript:toggleOutput('output-box-48')">+</div>
3373+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-48')">Registry should accept a manifest upload with no layers</h4>
3374+ <br>
3375+ <div id="output-box-48" style="display: none;">
3376+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3377+ OCI_TEST_PULL=1
3378+ OCI_TEST_PUSH=0
3379+ OCI_TEST_CONTENT_DISCOVERY=0
3380+ OCI_TEST_CONTENT_MANAGEMENT=0
3381+ </pre>
3382+ </div>
3383+ </div>
3384+
3385+
3386+
3387+
3388+ <div class="result grey">
3389+ <div id="output-box-49-button" class="toggle" onclick="javascript:toggleOutput('output-box-49')">+</div>
3390+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-49')">GET request to manifest URL (digest) should yield 200 response</h4>
3391+ <br>
3392+ <div id="output-box-49" style="display: none;">
3393+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3394+ OCI_TEST_PULL=1
3395+ OCI_TEST_PUSH=0
3396+ OCI_TEST_CONTENT_DISCOVERY=0
3397+ OCI_TEST_CONTENT_MANAGEMENT=0
3398+ </pre>
3399+ </div>
3400+ </div>
3401+
3402+ <br>
3403+
3404+
3405+ <h3>Teardown</h3>
3406+
3407+
3408+
3409+
3410+
3411+
3412+ <div class="result grey">
3413+ <div id="output-box-50-button" class="toggle" onclick="javascript:toggleOutput('output-box-50')">+</div>
3414+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-50')">Delete config blob created in tests</h4>
3415+ <br>
3416+ <div id="output-box-50" style="display: none;">
3417+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3418+ OCI_TEST_PULL=1
3419+ OCI_TEST_PUSH=0
3420+ OCI_TEST_CONTENT_DISCOVERY=0
3421+ OCI_TEST_CONTENT_MANAGEMENT=0
3422+ </pre>
3423+ </div>
3424+ </div>
3425+
3426+
3427+
3428+
3429+ <div class="result grey">
3430+ <div id="output-box-51-button" class="toggle" onclick="javascript:toggleOutput('output-box-51')">+</div>
3431+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-51')">Delete layer blob created in setup</h4>
3432+ <br>
3433+ <div id="output-box-51" style="display: none;">
3434+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3435+ OCI_TEST_PUSH=0
3436+ OCI_TEST_CONTENT_DISCOVERY=0
3437+ OCI_TEST_CONTENT_MANAGEMENT=0
3438+ OCI_TEST_PULL=1
3439+ </pre>
3440+ </div>
3441+ </div>
3442+
3443+
3444+
3445+
3446+ <div class="result grey">
3447+ <div id="output-box-52-button" class="toggle" onclick="javascript:toggleOutput('output-box-52')">+</div>
3448+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-52')">Delete manifest created in tests</h4>
3449+ <br>
3450+ <div id="output-box-52" style="display: none;">
3451+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3452+ OCI_TEST_PUSH=0
3453+ OCI_TEST_CONTENT_DISCOVERY=0
3454+ OCI_TEST_CONTENT_MANAGEMENT=0
3455+ OCI_TEST_PULL=1
3456+ </pre>
3457+ </div>
3458+ </div>
3459+
3460+ <br>
3461+
3462+
3463+
3464+
3465+ </div>
3466+
3467+
3468+
3469+
3470+ <h2>Content Discovery</h2>
3471+ <div class="subcategory">
3472+
3473+
3474+ <h3>Setup</h3>
3475+
3476+
3477+
3478+
3479+
3480+
3481+ <div class="result grey">
3482+ <div id="output-box-53-button" class="toggle" onclick="javascript:toggleOutput('output-box-53')">+</div>
3483+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-53')">Populate registry with test blob</h4>
3484+ <br>
3485+ <div id="output-box-53" style="display: none;">
3486+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3487+ OCI_TEST_CONTENT_MANAGEMENT=0
3488+ OCI_TEST_PULL=1
3489+ OCI_TEST_PUSH=0
3490+ OCI_TEST_CONTENT_DISCOVERY=0
3491+ </pre>
3492+ </div>
3493+ </div>
3494+
3495+
3496+
3497+
3498+ <div class="result grey">
3499+ <div id="output-box-54-button" class="toggle" onclick="javascript:toggleOutput('output-box-54')">+</div>
3500+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-54')">Populate registry with test layer</h4>
3501+ <br>
3502+ <div id="output-box-54" style="display: none;">
3503+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3504+ OCI_TEST_PULL=1
3505+ OCI_TEST_PUSH=0
3506+ OCI_TEST_CONTENT_DISCOVERY=0
3507+ OCI_TEST_CONTENT_MANAGEMENT=0
3508+ </pre>
3509+ </div>
3510+ </div>
3511+
3512+
3513+
3514+
3515+ <div class="result grey">
3516+ <div id="output-box-55-button" class="toggle" onclick="javascript:toggleOutput('output-box-55')">+</div>
3517+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-55')">Populate registry with test tags</h4>
3518+ <br>
3519+ <div id="output-box-55" style="display: none;">
3520+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3521+ OCI_TEST_PULL=1
3522+ OCI_TEST_PUSH=0
3523+ OCI_TEST_CONTENT_DISCOVERY=0
3524+ OCI_TEST_CONTENT_MANAGEMENT=0
3525+ </pre>
3526+ </div>
3527+ </div>
3528+
3529+
3530+
3531+
3532+ <div class="result grey">
3533+ <div id="output-box-56-button" class="toggle" onclick="javascript:toggleOutput('output-box-56')">+</div>
3534+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-56')">Populate registry with test tags (no push)</h4>
3535+ <br>
3536+ <div id="output-box-56" style="display: none;">
3537+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3538+ OCI_TEST_PULL=1
3539+ OCI_TEST_PUSH=0
3540+ OCI_TEST_CONTENT_DISCOVERY=0
3541+ OCI_TEST_CONTENT_MANAGEMENT=0
3542+ </pre>
3543+ </div>
3544+ </div>
3545+
3546+
3547+
3548+
3549+ <div class="result grey">
3550+ <div id="output-box-57-button" class="toggle" onclick="javascript:toggleOutput('output-box-57')">+</div>
3551+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-57')">References setup</h4>
3552+ <br>
3553+ <div id="output-box-57" style="display: none;">
3554+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3555+ OCI_TEST_PUSH=0
3556+ OCI_TEST_CONTENT_DISCOVERY=0
3557+ OCI_TEST_CONTENT_MANAGEMENT=0
3558+ OCI_TEST_PULL=1
3559+ </pre>
3560+ </div>
3561+ </div>
3562+
3563+ <br>
3564+
3565+
3566+ <h3>Test content discovery endpoints (listing tags)</h3>
3567+
3568+
3569+
3570+
3571+
3572+
3573+ <div class="result grey">
3574+ <div id="output-box-58-button" class="toggle" onclick="javascript:toggleOutput('output-box-58')">+</div>
3575+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-58')">GET request to list tags should yield 200 response</h4>
3576+ <br>
3577+ <div id="output-box-58" style="display: none;">
3578+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3579+ OCI_TEST_PUSH=0
3580+ OCI_TEST_CONTENT_DISCOVERY=0
3581+ OCI_TEST_CONTENT_MANAGEMENT=0
3582+ OCI_TEST_PULL=1
3583+ </pre>
3584+ </div>
3585+ </div>
3586+
3587+
3588+
3589+
3590+ <div class="result grey">
3591+ <div id="output-box-59-button" class="toggle" onclick="javascript:toggleOutput('output-box-59')">+</div>
3592+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-59')">GET number of tags should be limitable by `n` query parameter</h4>
3593+ <br>
3594+ <div id="output-box-59" style="display: none;">
3595+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3596+ OCI_TEST_PULL=1
3597+ OCI_TEST_PUSH=0
3598+ OCI_TEST_CONTENT_DISCOVERY=0
3599+ OCI_TEST_CONTENT_MANAGEMENT=0
3600+ </pre>
3601+ </div>
3602+ </div>
3603+
3604+
3605+
3606+
3607+ <div class="result grey">
3608+ <div id="output-box-60-button" class="toggle" onclick="javascript:toggleOutput('output-box-60')">+</div>
3609+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-60')">GET start of tag is set by `last` query parameter</h4>
3610+ <br>
3611+ <div id="output-box-60" style="display: none;">
3612+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3613+ OCI_TEST_CONTENT_MANAGEMENT=0
3614+ OCI_TEST_PULL=1
3615+ OCI_TEST_PUSH=0
3616+ OCI_TEST_CONTENT_DISCOVERY=0
3617+ </pre>
3618+ </div>
3619+ </div>
3620+
3621+ <br>
3622+
3623+
3624+ <h3>Test content discovery endpoints (listing references)</h3>
3625+
3626+
3627+
3628+
3629+
3630+
3631+ <div class="result grey">
3632+ <div id="output-box-61-button" class="toggle" onclick="javascript:toggleOutput('output-box-61')">+</div>
3633+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-61')">GET request to nonexistent blob should result in empty 200 response</h4>
3634+ <br>
3635+ <div id="output-box-61" style="display: none;">
3636+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3637+ OCI_TEST_CONTENT_DISCOVERY=0
3638+ OCI_TEST_CONTENT_MANAGEMENT=0
3639+ OCI_TEST_PULL=1
3640+ OCI_TEST_PUSH=0
3641+ </pre>
3642+ </div>
3643+ </div>
3644+
3645+
3646+
3647+
3648+ <div class="result grey">
3649+ <div id="output-box-62-button" class="toggle" onclick="javascript:toggleOutput('output-box-62')">+</div>
3650+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-62')">GET request to existing blob should yield 200</h4>
3651+ <br>
3652+ <div id="output-box-62" style="display: none;">
3653+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3654+ OCI_TEST_PULL=1
3655+ OCI_TEST_PUSH=0
3656+ OCI_TEST_CONTENT_DISCOVERY=0
3657+ OCI_TEST_CONTENT_MANAGEMENT=0
3658+ </pre>
3659+ </div>
3660+ </div>
3661+
3662+
3663+
3664+
3665+ <div class="result grey">
3666+ <div id="output-box-63-button" class="toggle" onclick="javascript:toggleOutput('output-box-63')">+</div>
3667+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-63')">GET request to existing blob with filter should yield 200</h4>
3668+ <br>
3669+ <div id="output-box-63" style="display: none;">
3670+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3671+ OCI_TEST_CONTENT_MANAGEMENT=0
3672+ OCI_TEST_PULL=1
3673+ OCI_TEST_PUSH=0
3674+ OCI_TEST_CONTENT_DISCOVERY=0
3675+ </pre>
3676+ </div>
3677+ </div>
3678+
3679+
3680+
3681+
3682+ <div class="result grey">
3683+ <div id="output-box-64-button" class="toggle" onclick="javascript:toggleOutput('output-box-64')">+</div>
3684+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-64')">GET request to missing manifest should yield 200</h4>
3685+ <br>
3686+ <div id="output-box-64" style="display: none;">
3687+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3688+ OCI_TEST_CONTENT_DISCOVERY=0
3689+ OCI_TEST_CONTENT_MANAGEMENT=0
3690+ OCI_TEST_PULL=1
3691+ OCI_TEST_PUSH=0
3692+ </pre>
3693+ </div>
3694+ </div>
3695+
3696+ <br>
3697+
3698+
3699+ <h3>Teardown</h3>
3700+
3701+
3702+
3703+
3704+
3705+
3706+ <div class="result grey">
3707+ <div id="output-box-65-button" class="toggle" onclick="javascript:toggleOutput('output-box-65')">+</div>
3708+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-65')">Delete config blob created in tests</h4>
3709+ <br>
3710+ <div id="output-box-65" style="display: none;">
3711+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3712+ OCI_TEST_PULL=1
3713+ OCI_TEST_PUSH=0
3714+ OCI_TEST_CONTENT_DISCOVERY=0
3715+ OCI_TEST_CONTENT_MANAGEMENT=0
3716+ </pre>
3717+ </div>
3718+ </div>
3719+
3720+
3721+
3722+
3723+ <div class="result grey">
3724+ <div id="output-box-66-button" class="toggle" onclick="javascript:toggleOutput('output-box-66')">+</div>
3725+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-66')">Delete layer blob created in setup</h4>
3726+ <br>
3727+ <div id="output-box-66" style="display: none;">
3728+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3729+ OCI_TEST_PULL=1
3730+ OCI_TEST_PUSH=0
3731+ OCI_TEST_CONTENT_DISCOVERY=0
3732+ OCI_TEST_CONTENT_MANAGEMENT=0
3733+ </pre>
3734+ </div>
3735+ </div>
3736+
3737+
3738+
3739+
3740+ <div class="result grey">
3741+ <div id="output-box-67-button" class="toggle" onclick="javascript:toggleOutput('output-box-67')">+</div>
3742+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-67')">Delete created manifest &amp; associated tags</h4>
3743+ <br>
3744+ <div id="output-box-67" style="display: none;">
3745+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3746+ OCI_TEST_PUSH=0
3747+ OCI_TEST_CONTENT_DISCOVERY=0
3748+ OCI_TEST_CONTENT_MANAGEMENT=0
3749+ OCI_TEST_PULL=1
3750+ </pre>
3751+ </div>
3752+ </div>
3753+
3754+
3755+
3756+
3757+ <div class="result grey">
3758+ <div id="output-box-68-button" class="toggle" onclick="javascript:toggleOutput('output-box-68')">+</div>
3759+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-68')">References teardown</h4>
3760+ <br>
3761+ <div id="output-box-68" style="display: none;">
3762+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3763+ OCI_TEST_PULL=1
3764+ OCI_TEST_PUSH=0
3765+ OCI_TEST_CONTENT_DISCOVERY=0
3766+ OCI_TEST_CONTENT_MANAGEMENT=0
3767+ </pre>
3768+ </div>
3769+ </div>
3770+
3771+ <br>
3772+
3773+
3774+
3775+
3776+ </div>
3777+
3778+
3779+
3780+
3781+ <h2>Content Management</h2>
3782+ <div class="subcategory">
3783+
3784+
3785+ <h3>Setup</h3>
3786+
3787+
3788+
3789+
3790+
3791+
3792+ <div class="result grey">
3793+ <div id="output-box-69-button" class="toggle" onclick="javascript:toggleOutput('output-box-69')">+</div>
3794+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-69')">Populate registry with test config blob</h4>
3795+ <br>
3796+ <div id="output-box-69" style="display: none;">
3797+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3798+ OCI_TEST_PUSH=0
3799+ OCI_TEST_CONTENT_DISCOVERY=0
3800+ OCI_TEST_CONTENT_MANAGEMENT=0
3801+ OCI_TEST_PULL=1
3802+ </pre>
3803+ </div>
3804+ </div>
3805+
3806+
3807+
3808+
3809+ <div class="result grey">
3810+ <div id="output-box-70-button" class="toggle" onclick="javascript:toggleOutput('output-box-70')">+</div>
3811+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-70')">Populate registry with test layer</h4>
3812+ <br>
3813+ <div id="output-box-70" style="display: none;">
3814+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3815+ OCI_TEST_PUSH=0
3816+ OCI_TEST_CONTENT_DISCOVERY=0
3817+ OCI_TEST_CONTENT_MANAGEMENT=0
3818+ OCI_TEST_PULL=1
3819+ </pre>
3820+ </div>
3821+ </div>
3822+
3823+
3824+
3825+
3826+ <div class="result grey">
3827+ <div id="output-box-71-button" class="toggle" onclick="javascript:toggleOutput('output-box-71')">+</div>
3828+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-71')">Populate registry with test tag</h4>
3829+ <br>
3830+ <div id="output-box-71" style="display: none;">
3831+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3832+ OCI_TEST_PULL=1
3833+ OCI_TEST_PUSH=0
3834+ OCI_TEST_CONTENT_DISCOVERY=0
3835+ OCI_TEST_CONTENT_MANAGEMENT=0
3836+ </pre>
3837+ </div>
3838+ </div>
3839+
3840+
3841+
3842+
3843+ <div class="result grey">
3844+ <div id="output-box-72-button" class="toggle" onclick="javascript:toggleOutput('output-box-72')">+</div>
3845+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-72')">Check how many tags there are before anything gets deleted</h4>
3846+ <br>
3847+ <div id="output-box-72" style="display: none;">
3848+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3849+ OCI_TEST_PULL=1
3850+ OCI_TEST_PUSH=0
3851+ OCI_TEST_CONTENT_DISCOVERY=0
3852+ OCI_TEST_CONTENT_MANAGEMENT=0
3853+ </pre>
3854+ </div>
3855+ </div>
3856+
3857+ <br>
3858+
3859+
3860+ <h3>Manifest delete</h3>
3861+
3862+
3863+
3864+
3865+
3866+
3867+ <div class="result grey">
3868+ <div id="output-box-73-button" class="toggle" onclick="javascript:toggleOutput('output-box-73')">+</div>
3869+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-73')">DELETE request to manifest tag should return 202, unless tag deletion is disallowed (400/405)</h4>
3870+ <br>
3871+ <div id="output-box-73" style="display: none;">
3872+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3873+ OCI_TEST_CONTENT_MANAGEMENT=0
3874+ OCI_TEST_PULL=1
3875+ OCI_TEST_PUSH=0
3876+ OCI_TEST_CONTENT_DISCOVERY=0
3877+ </pre>
3878+ </div>
3879+ </div>
3880+
3881+
3882+
3883+
3884+ <div class="result grey">
3885+ <div id="output-box-74-button" class="toggle" onclick="javascript:toggleOutput('output-box-74')">+</div>
3886+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-74')">DELETE request to manifest (digest) should yield 202 response unless already deleted</h4>
3887+ <br>
3888+ <div id="output-box-74" style="display: none;">
3889+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3890+ OCI_TEST_CONTENT_DISCOVERY=0
3891+ OCI_TEST_CONTENT_MANAGEMENT=0
3892+ OCI_TEST_PULL=1
3893+ OCI_TEST_PUSH=0
3894+ </pre>
3895+ </div>
3896+ </div>
3897+
3898+
3899+
3900+
3901+ <div class="result grey">
3902+ <div id="output-box-75-button" class="toggle" onclick="javascript:toggleOutput('output-box-75')">+</div>
3903+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-75')">GET request to deleted manifest URL should yield 404 response, unless delete is disallowed</h4>
3904+ <br>
3905+ <div id="output-box-75" style="display: none;">
3906+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3907+ OCI_TEST_PULL=1
3908+ OCI_TEST_PUSH=0
3909+ OCI_TEST_CONTENT_DISCOVERY=0
3910+ OCI_TEST_CONTENT_MANAGEMENT=0
3911+ </pre>
3912+ </div>
3913+ </div>
3914+
3915+
3916+
3917+
3918+ <div class="result grey">
3919+ <div id="output-box-76-button" class="toggle" onclick="javascript:toggleOutput('output-box-76')">+</div>
3920+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-76')">GET request to tags list should reflect manifest deletion</h4>
3921+ <br>
3922+ <div id="output-box-76" style="display: none;">
3923+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3924+ OCI_TEST_PULL=1
3925+ OCI_TEST_PUSH=0
3926+ OCI_TEST_CONTENT_DISCOVERY=0
3927+ OCI_TEST_CONTENT_MANAGEMENT=0
3928+ </pre>
3929+ </div>
3930+ </div>
3931+
3932+ <br>
3933+
3934+
3935+ <h3>Blob delete</h3>
3936+
3937+
3938+
3939+
3940+
3941+
3942+ <div class="result grey">
3943+ <div id="output-box-77-button" class="toggle" onclick="javascript:toggleOutput('output-box-77')">+</div>
3944+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-77')">DELETE request to blob URL should yield 202 response</h4>
3945+ <br>
3946+ <div id="output-box-77" style="display: none;">
3947+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3948+ OCI_TEST_PULL=1
3949+ OCI_TEST_PUSH=0
3950+ OCI_TEST_CONTENT_DISCOVERY=0
3951+ OCI_TEST_CONTENT_MANAGEMENT=0
3952+ </pre>
3953+ </div>
3954+ </div>
3955+
3956+
3957+
3958+
3959+ <div class="result grey">
3960+ <div id="output-box-78-button" class="toggle" onclick="javascript:toggleOutput('output-box-78')">+</div>
3961+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-78')">GET request to deleted blob URL should yield 404 response</h4>
3962+ <br>
3963+ <div id="output-box-78" style="display: none;">
3964+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
3965+ OCI_TEST_PULL=1
3966+ OCI_TEST_PUSH=0
3967+ OCI_TEST_CONTENT_DISCOVERY=0
3968+ OCI_TEST_CONTENT_MANAGEMENT=0
3969+ </pre>
3970+ </div>
3971+ </div>
3972+
3973+ <br>
3974+
3975+
3976+
3977+
3978+ </div>
3979+
3980+
3981+ </div>
3982+ </body>
3983+ </html>
3984 diff --git a/manifest.json b/manifest.json
3985new file mode 100644
3986index 0000000..9061278
3987--- /dev/null
3988+++ b/manifest.json
3989 @@ -0,0 +1,19 @@
3990+ {
3991+ "schemaVersion": 2,
3992+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
3993+ "config": {
3994+ "mediaType": "application/vnd.oci.image.config.v1+json",
3995+ "digest": "sha256:04d09c568ab48c342d9c33fbd598bfeb0fb4fcdb16527154ea8a23f7685f35d1",
3996+ "size": 129,
3997+ "data": "ewoJImF1dGhvciI6ICJ4VmFlQWc0V05jOENTZ2NJIiwKCSJhcmNoaXRlY3R1cmUiOiAiYW1kNjQiLAoJIm9zIjogImxpbnV4IiwKCSJyb290ZnMiOiB7CgkJInR5cGUiOiAibGF5ZXJzIiwKCQkiZGlmZl9pZHMiOiBbXQoJfQp9",
3998+ "newUnspecifiedField": "aGVsbG8gd29ybGQ="
3999+ },
4000+ "layers": [
4001+ {
4002+ "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
4003+ "digest": "sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183",
4004+ "size": 168,
4005+ "newUnspecifiedField": null
4006+ }
4007+ ]
4008+ }
4009\ No newline at end of file
4010 diff --git a/results/junit.xml b/results/junit.xml
4011new file mode 100644
4012index 0000000..b3af104
4013--- /dev/null
4014+++ b/results/junit.xml
4015 @@ -0,0 +1,321 @@
4016+ <?xml version="1.0" encoding="UTF-8"?>
4017+ <testsuites tests="80" disabled="56" errors="0" failures="1" time="0.169447691">
4018+ <testsuite name="conformance tests" package="/results" tests="80" disabled="0" skipped="56" errors="0" failures="1" time="0.169447691" timestamp="2025-04-13T12:25:02">
4019+ <properties>
4020+ <property name="SuiteSucceeded" value="false"></property>
4021+ <property name="SuiteHasProgrammaticFocus" value="false"></property>
4022+ <property name="SpecialSuiteFailureReason" value=""></property>
4023+ <property name="SuiteLabels" value="[]"></property>
4024+ <property name="RandomSeed" value="1744547102"></property>
4025+ <property name="RandomizeAllSpecs" value="false"></property>
4026+ <property name="LabelFilter" value=""></property>
4027+ <property name="FocusStrings" value=""></property>
4028+ <property name="SkipStrings" value=""></property>
4029+ <property name="FocusFiles" value=""></property>
4030+ <property name="SkipFiles" value=""></property>
4031+ <property name="FailOnPending" value="false"></property>
4032+ <property name="FailFast" value="false"></property>
4033+ <property name="FlakeAttempts" value="0"></property>
4034+ <property name="DryRun" value="false"></property>
4035+ <property name="ParallelTotal" value="1"></property>
4036+ <property name="OutputInterceptorMode" value=""></property>
4037+ </properties>
4038+ <testcase name="OCI Distribution Conformance Tests Pull Setup Populate registry with test blob" classname="conformance tests" status="passed" time="0.045084284">
4039+ <system-err>&gt; Enter [It] Populate registry with test blob - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:18 @ 04/13/25 12:25:02.902&#xA;&lt; Exit [It] Populate registry with test blob - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:18 @ 04/13/25 12:25:02.946 (45ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:02.946&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:02.946 (0s)&#xA;</system-err>
4040+ </testcase>
4041+ <testcase name="OCI Distribution Conformance Tests Pull Setup Populate registry with test blob" classname="conformance tests" status="passed" time="0.032417102">
4042+ <system-err>&gt; Enter [It] Populate registry with test blob - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:36 @ 04/13/25 12:25:02.946&#xA;&lt; Exit [It] Populate registry with test blob - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:36 @ 04/13/25 12:25:02.979 (32ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:02.979&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:02.979 (0s)&#xA;</system-err>
4043+ </testcase>
4044+ <testcase name="OCI Distribution Conformance Tests Pull Setup Populate registry with test layer" classname="conformance tests" status="passed" time="0.03232161">
4045+ <system-err>&gt; Enter [It] Populate registry with test layer - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:54 @ 04/13/25 12:25:02.979&#xA;&lt; Exit [It] Populate registry with test layer - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:54 @ 04/13/25 12:25:03.011 (32ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.011&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.011 (0s)&#xA;</system-err>
4046+ </testcase>
4047+ <testcase name="OCI Distribution Conformance Tests Pull Setup Populate registry with test manifest" classname="conformance tests" status="passed" time="0.024845792">
4048+ <system-err>&gt; Enter [It] Populate registry with test manifest - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:72 @ 04/13/25 12:25:03.011&#xA;&lt; Exit [It] Populate registry with test manifest - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:72 @ 04/13/25 12:25:03.036 (25ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.036&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.036 (0s)&#xA;</system-err>
4049+ </testcase>
4050+ <testcase name="OCI Distribution Conformance Tests Pull Setup Populate registry with test manifest" classname="conformance tests" status="passed" time="0.013175274">
4051+ <system-err>&gt; Enter [It] Populate registry with test manifest - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:87 @ 04/13/25 12:25:03.036&#xA;&lt; Exit [It] Populate registry with test manifest - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:87 @ 04/13/25 12:25:03.049 (13ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.049&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.049 (0s)&#xA;</system-err>
4052+ </testcase>
4053+ <testcase name="OCI Distribution Conformance Tests Pull Setup Get tag name from environment" classname="conformance tests" status="skipped" time="9.807e-05">
4054+ <skipped message="skipped - you have skipped this test."></skipped>
4055+ <system-err>&gt; Enter [It] Get tag name from environment - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:101 @ 04/13/25 12:25:03.049&#xA;[SKIPPED] you have skipped this test.&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:591 @ 04/13/25 12:25:03.049&#xA;&lt; Exit [It] Get tag name from environment - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:101 @ 04/13/25 12:25:03.049 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.049&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.049 (0s)&#xA;</system-err>
4056+ </testcase>
4057+ <testcase name="OCI Distribution Conformance Tests Pull Pull blobs HEAD request to nonexistent blob should result in 404 response" classname="conformance tests" status="passed" time="0.00112071">
4058+ <system-err>&gt; Enter [It] HEAD request to nonexistent blob should result in 404 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:112 @ 04/13/25 12:25:03.049&#xA;&lt; Exit [It] HEAD request to nonexistent blob should result in 404 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:112 @ 04/13/25 12:25:03.051 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.051&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.051 (0s)&#xA;</system-err>
4059+ </testcase>
4060+ <testcase name="OCI Distribution Conformance Tests Pull Pull blobs HEAD request to existing blob should yield 200" classname="conformance tests" status="passed" time="0.000762485">
4061+ <system-err>&gt; Enter [It] HEAD request to existing blob should yield 200 - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:121 @ 04/13/25 12:25:03.051&#xA;&lt; Exit [It] HEAD request to existing blob should yield 200 - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:121 @ 04/13/25 12:25:03.051 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.051&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.051 (0s)&#xA;</system-err>
4062+ </testcase>
4063+ <testcase name="OCI Distribution Conformance Tests Pull Pull blobs GET nonexistent blob should result in 404 response" classname="conformance tests" status="passed" time="0.000966695">
4064+ <system-err>&gt; Enter [It] GET nonexistent blob should result in 404 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:133 @ 04/13/25 12:25:03.051&#xA;&lt; Exit [It] GET nonexistent blob should result in 404 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:133 @ 04/13/25 12:25:03.052 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.052&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.052 (0s)&#xA;</system-err>
4065+ </testcase>
4066+ <testcase name="OCI Distribution Conformance Tests Pull Pull blobs GET request to existing blob URL should yield 200" classname="conformance tests" status="passed" time="0.001268844">
4067+ <system-err>&gt; Enter [It] GET request to existing blob URL should yield 200 - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:142 @ 04/13/25 12:25:03.052&#xA;&lt; Exit [It] GET request to existing blob URL should yield 200 - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:142 @ 04/13/25 12:25:03.054 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.054&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.054 (0s)&#xA;</system-err>
4068+ </testcase>
4069+ <testcase name="OCI Distribution Conformance Tests Pull Pull manifests HEAD request to nonexistent manifest should return 404" classname="conformance tests" status="passed" time="0.000344243">
4070+ <system-err>&gt; Enter [It] HEAD request to nonexistent manifest should return 404 - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:152 @ 04/13/25 12:25:03.054&#xA;&lt; Exit [It] HEAD request to nonexistent manifest should return 404 - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:152 @ 04/13/25 12:25:03.054 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.054&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.054 (0s)&#xA;</system-err>
4071+ </testcase>
4072+ <testcase name="OCI Distribution Conformance Tests Pull Pull manifests HEAD request to manifest[0] path (digest) should yield 200 response" classname="conformance tests" status="passed" time="0.000827058">
4073+ <system-err>&gt; Enter [It] HEAD request to manifest[0] path (digest) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:161 @ 04/13/25 12:25:03.054&#xA;&lt; Exit [It] HEAD request to manifest[0] path (digest) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:161 @ 04/13/25 12:25:03.055 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.055&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.055 (0s)&#xA;</system-err>
4074+ </testcase>
4075+ <testcase name="OCI Distribution Conformance Tests Pull Pull manifests HEAD request to manifest[1] path (digest) should yield 200 response" classname="conformance tests" status="passed" time="0.000841226">
4076+ <system-err>&gt; Enter [It] HEAD request to manifest[1] path (digest) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:173 @ 04/13/25 12:25:03.055&#xA;&lt; Exit [It] HEAD request to manifest[1] path (digest) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:173 @ 04/13/25 12:25:03.056 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.056&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.056 (0s)&#xA;</system-err>
4077+ </testcase>
4078+ <testcase name="OCI Distribution Conformance Tests Pull Pull manifests HEAD request to manifest path (tag) should yield 200 response" classname="conformance tests" status="passed" time="0.000785109">
4079+ <system-err>&gt; Enter [It] HEAD request to manifest path (tag) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:185 @ 04/13/25 12:25:03.056&#xA;&lt; Exit [It] HEAD request to manifest path (tag) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:185 @ 04/13/25 12:25:03.057 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.057&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.057 (0s)&#xA;</system-err>
4080+ </testcase>
4081+ <testcase name="OCI Distribution Conformance Tests Pull Pull manifests GET nonexistent manifest should return 404" classname="conformance tests" status="passed" time="0.000236652">
4082+ <system-err>&gt; Enter [It] GET nonexistent manifest should return 404 - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:198 @ 04/13/25 12:25:03.057&#xA;&lt; Exit [It] GET nonexistent manifest should return 404 - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:198 @ 04/13/25 12:25:03.057 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.057&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.057 (0s)&#xA;</system-err>
4083+ </testcase>
4084+ <testcase name="OCI Distribution Conformance Tests Pull Pull manifests GET request to manifest[0] path (digest) should yield 200 response" classname="conformance tests" status="passed" time="0.000830533">
4085+ <system-err>&gt; Enter [It] GET request to manifest[0] path (digest) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:207 @ 04/13/25 12:25:03.057&#xA;&lt; Exit [It] GET request to manifest[0] path (digest) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:207 @ 04/13/25 12:25:03.058 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.058&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.058 (0s)&#xA;</system-err>
4086+ </testcase>
4087+ <testcase name="OCI Distribution Conformance Tests Pull Pull manifests GET request to manifest[1] path (digest) should yield 200 response" classname="conformance tests" status="passed" time="0.000876693">
4088+ <system-err>&gt; Enter [It] GET request to manifest[1] path (digest) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:216 @ 04/13/25 12:25:03.058&#xA;&lt; Exit [It] GET request to manifest[1] path (digest) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:216 @ 04/13/25 12:25:03.059 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.059&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.059 (0s)&#xA;</system-err>
4089+ </testcase>
4090+ <testcase name="OCI Distribution Conformance Tests Pull Pull manifests GET request to manifest path (tag) should yield 200 response" classname="conformance tests" status="passed" time="0.001180002">
4091+ <system-err>&gt; Enter [It] GET request to manifest path (tag) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:225 @ 04/13/25 12:25:03.059&#xA;&lt; Exit [It] GET request to manifest path (tag) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:225 @ 04/13/25 12:25:03.06 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.06&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.06 (0s)&#xA;</system-err>
4092+ </testcase>
4093+ <testcase name="OCI Distribution Conformance Tests Pull Error codes 400 response body should contain OCI-conforming JSON message" classname="conformance tests" status="failed" time="0.000880432">
4094+ <failure message="Expected&#xA; &lt;int&gt;: 500&#xA;To satisfy at least one of these matchers: [%!s(*matchers.EqualMatcher=&amp;{400}) %!s(*matchers.EqualMatcher=&amp;{404})]" type="failed">[FAILED] Expected&#xA; &lt;int&gt;: 500&#xA;To satisfy at least one of these matchers: [%!s(*matchers.EqualMatcher=&amp;{400}) %!s(*matchers.EqualMatcher=&amp;{404})]&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:245 @ 04/13/25 12:25:03.061&#xA;</failure>
4095+ <system-err>&gt; Enter [It] 400 response body should contain OCI-conforming JSON message - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:237 @ 04/13/25 12:25:03.06&#xA;[FAILED] Expected&#xA; &lt;int&gt;: 500&#xA;To satisfy at least one of these matchers: [%!s(*matchers.EqualMatcher=&amp;{400}) %!s(*matchers.EqualMatcher=&amp;{404})]&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:245 @ 04/13/25 12:25:03.061&#xA;&lt; Exit [It] 400 response body should contain OCI-conforming JSON message - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:237 @ 04/13/25 12:25:03.061 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.061&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.061 (0s)&#xA;</system-err>
4096+ </testcase>
4097+ <testcase name="OCI Distribution Conformance Tests Pull Teardown Delete config[0] blob created in setup" classname="conformance tests" status="passed" time="0.000750107">
4098+ <system-err>&gt; Enter [It] Delete config[0] blob created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:290 @ 04/13/25 12:25:03.061&#xA;&lt; Exit [It] Delete config[0] blob created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:290 @ 04/13/25 12:25:03.062 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.062&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.062 (0s)&#xA;</system-err>
4099+ </testcase>
4100+ <testcase name="OCI Distribution Conformance Tests Pull Teardown Delete config[1] blob created in setup" classname="conformance tests" status="passed" time="0.000708235">
4101+ <system-err>&gt; Enter [It] Delete config[1] blob created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:305 @ 04/13/25 12:25:03.062&#xA;&lt; Exit [It] Delete config[1] blob created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:305 @ 04/13/25 12:25:03.062 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.062&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.062 (0s)&#xA;</system-err>
4102+ </testcase>
4103+ <testcase name="OCI Distribution Conformance Tests Pull Teardown Delete layer blob created in setup" classname="conformance tests" status="passed" time="0.000684584">
4104+ <system-err>&gt; Enter [It] Delete layer blob created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:321 @ 04/13/25 12:25:03.062&#xA;&lt; Exit [It] Delete layer blob created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:321 @ 04/13/25 12:25:03.063 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.063&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.063 (0s)&#xA;</system-err>
4105+ </testcase>
4106+ <testcase name="OCI Distribution Conformance Tests Pull Teardown Delete manifest[0] created in setup" classname="conformance tests" status="passed" time="0.000715913">
4107+ <system-err>&gt; Enter [It] Delete manifest[0] created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:338 @ 04/13/25 12:25:03.063&#xA;&lt; Exit [It] Delete manifest[0] created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:338 @ 04/13/25 12:25:03.064 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.064&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.064 (0s)&#xA;</system-err>
4108+ </testcase>
4109+ <testcase name="OCI Distribution Conformance Tests Pull Teardown Delete manifest[1] created in setup" classname="conformance tests" status="passed" time="0.001148443">
4110+ <system-err>&gt; Enter [It] Delete manifest[1] created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:352 @ 04/13/25 12:25:03.064&#xA;&lt; Exit [It] Delete manifest[1] created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/01_pull_test.go:352 @ 04/13/25 12:25:03.065 (1ms)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065 (0s)&#xA;</system-err>
4111+ </testcase>
4112+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Streamed PATCH request with blob in body should yield 202 response" classname="conformance tests" status="skipped" time="9.266e-05">
4113+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4114+ <system-err>&gt; Enter [It] PATCH request with blob in body should yield 202 response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:25 @ 04/13/25 12:25:03.065&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [It] PATCH request with blob in body should yield 202 response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:25 @ 04/13/25 12:25:03.065 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065 (0s)&#xA;</system-err>
4115+ </testcase>
4116+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Streamed PUT request to session URL with digest should yield 201 response" classname="conformance tests" status="skipped" time="8.7901e-05">
4117+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4118+ <system-err>&gt; Enter [It] PUT request to session URL with digest should yield 201 response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:42 @ 04/13/25 12:25:03.065&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [It] PUT request to session URL with digest should yield 201 response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:42 @ 04/13/25 12:25:03.065 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065 (0s)&#xA;</system-err>
4119+ </testcase>
4120+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Monolithic GET nonexistent blob should result in 404 response" classname="conformance tests" status="skipped" time="7.6757e-05">
4121+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4122+ <system-err>&gt; Enter [It] GET nonexistent blob should result in 404 response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:58 @ 04/13/25 12:25:03.065&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [It] GET nonexistent blob should result in 404 response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:58 @ 04/13/25 12:25:03.065 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065 (0s)&#xA;</system-err>
4123+ </testcase>
4124+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Monolithic POST request with digest and blob should yield a 201 or 202" classname="conformance tests" status="skipped" time="8.0309e-05">
4125+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4126+ <system-err>&gt; Enter [It] POST request with digest and blob should yield a 201 or 202 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:67 @ 04/13/25 12:25:03.065&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [It] POST request with digest and blob should yield a 201 or 202 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:67 @ 04/13/25 12:25:03.065 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065 (0s)&#xA;</system-err>
4127+ </testcase>
4128+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Monolithic GET request to blob URL from prior request should yield 200 or 404 based on response code" classname="conformance tests" status="skipped" time="8.85e-05">
4129+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;"></skipped>
4130+ <system-err>&gt; Enter [It] GET request to blob URL from prior request should yield 200 or 404 based on response code - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:85 @ 04/13/25 12:25:03.065&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [It] GET request to blob URL from prior request should yield 200 or 404 based on response code - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:85 @ 04/13/25 12:25:03.065 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065 (0s)&#xA;</system-err>
4131+ </testcase>
4132+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Monolithic POST request should yield a session ID" classname="conformance tests" status="skipped" time="7.9208e-05">
4133+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4134+ <system-err>&gt; Enter [It] POST request should yield a session ID - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:98 @ 04/13/25 12:25:03.065&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [It] POST request should yield a session ID - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:98 @ 04/13/25 12:25:03.065 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.065 (0s)&#xA;</system-err>
4135+ </testcase>
4136+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Monolithic PUT upload of a blob should yield a 201 Response" classname="conformance tests" status="skipped" time="7.5334e-05">
4137+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;"></skipped>
4138+ <system-err>&gt; Enter [It] PUT upload of a blob should yield a 201 Response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:107 @ 04/13/25 12:25:03.065&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [It] PUT upload of a blob should yield a 201 Response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:107 @ 04/13/25 12:25:03.066 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066 (0s)&#xA;</system-err>
4139+ </testcase>
4140+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Monolithic GET request to existing blob should yield 200 response" classname="conformance tests" status="skipped" time="7.5369e-05">
4141+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;"></skipped>
4142+ <system-err>&gt; Enter [It] GET request to existing blob should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:121 @ 04/13/25 12:25:03.066&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [It] GET request to existing blob should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:121 @ 04/13/25 12:25:03.066 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066 (0s)&#xA;</system-err>
4143+ </testcase>
4144+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Monolithic PUT upload of a layer blob should yield a 201 Response" classname="conformance tests" status="skipped" time="8.6792e-05">
4145+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4146+ <system-err>&gt; Enter [It] PUT upload of a layer blob should yield a 201 Response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:129 @ 04/13/25 12:25:03.066&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [It] PUT upload of a layer blob should yield a 201 Response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:129 @ 04/13/25 12:25:03.066 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066 (0s)&#xA;</system-err>
4147+ </testcase>
4148+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Monolithic GET request to existing layer should yield 200 response" classname="conformance tests" status="skipped" time="8.6753e-05">
4149+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;"></skipped>
4150+ <system-err>&gt; Enter [It] GET request to existing layer should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:146 @ 04/13/25 12:25:03.066&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [It] GET request to existing layer should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:146 @ 04/13/25 12:25:03.066 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066 (0s)&#xA;</system-err>
4151+ </testcase>
4152+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Chunked Out-of-order blob upload should return 416" classname="conformance tests" status="skipped" time="8.2734e-05">
4153+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4154+ <system-err>&gt; Enter [It] Out-of-order blob upload should return 416 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:156 @ 04/13/25 12:25:03.066&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [It] Out-of-order blob upload should return 416 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:156 @ 04/13/25 12:25:03.066 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066 (0s)&#xA;</system-err>
4155+ </testcase>
4156+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Chunked PATCH request with first chunk should return 202" classname="conformance tests" status="skipped" time="7.4307e-05">
4157+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4158+ <system-err>&gt; Enter [It] PATCH request with first chunk should return 202 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:185 @ 04/13/25 12:25:03.066&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [It] PATCH request with first chunk should return 202 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:185 @ 04/13/25 12:25:03.066 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066 (0s)&#xA;</system-err>
4159+ </testcase>
4160+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Chunked Retry previous blob chunk should return 416" classname="conformance tests" status="skipped" time="7.4338e-05">
4161+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4162+ <system-err>&gt; Enter [It] Retry previous blob chunk should return 416 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:206 @ 04/13/25 12:25:03.066&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [It] Retry previous blob chunk should return 416 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:206 @ 04/13/25 12:25:03.066 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066 (0s)&#xA;</system-err>
4163+ </testcase>
4164+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Chunked Get on stale blob upload should return 204 with a range and location" classname="conformance tests" status="skipped" time="7.831e-05">
4165+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;"></skipped>
4166+ <system-err>&gt; Enter [It] Get on stale blob upload should return 204 with a range and location - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:218 @ 04/13/25 12:25:03.066&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [It] Get on stale blob upload should return 204 with a range and location - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:218 @ 04/13/25 12:25:03.066 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066 (0s)&#xA;</system-err>
4167+ </testcase>
4168+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Chunked PATCH request with second chunk should return 202" classname="conformance tests" status="skipped" time="7.4689e-05">
4169+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4170+ <system-err>&gt; Enter [It] PATCH request with second chunk should return 202 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:229 @ 04/13/25 12:25:03.066&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [It] PATCH request with second chunk should return 202 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:229 @ 04/13/25 12:25:03.066 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066 (0s)&#xA;</system-err>
4171+ </testcase>
4172+ <testcase name="OCI Distribution Conformance Tests Push Blob Upload Chunked PUT request with digest should return 201" classname="conformance tests" status="skipped" time="7.3663e-05">
4173+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4174+ <system-err>&gt; Enter [It] PUT request with digest should return 201 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:244 @ 04/13/25 12:25:03.066&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [It] PUT request with digest should return 201 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:244 @ 04/13/25 12:25:03.066 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066 (0s)&#xA;</system-err>
4175+ </testcase>
4176+ <testcase name="OCI Distribution Conformance Tests Push Cross-Repository Blob Mount Cross-mounting of a blob without the from argument should yield session id" classname="conformance tests" status="skipped" time="7.3666e-05">
4177+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4178+ <system-err>&gt; Enter [It] Cross-mounting of a blob without the from argument should yield session id - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:259 @ 04/13/25 12:25:03.066&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [It] Cross-mounting of a blob without the from argument should yield session id - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:259 @ 04/13/25 12:25:03.066 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.066 (0s)&#xA;</system-err>
4179+ </testcase>
4180+ <testcase name="OCI Distribution Conformance Tests Push Cross-Repository Blob Mount POST request to mount another repository&#39;s blob should return 201 or 202" classname="conformance tests" status="skipped" time="7.4594e-05">
4181+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4182+ <system-err>&gt; Enter [It] POST request to mount another repository&#39;s blob should return 201 or 202 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:270 @ 04/13/25 12:25:03.066&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [It] POST request to mount another repository&#39;s blob should return 201 or 202 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:270 @ 04/13/25 12:25:03.067 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067 (0s)&#xA;</system-err>
4183+ </testcase>
4184+ <testcase name="OCI Distribution Conformance Tests Push Cross-Repository Blob Mount GET request to test digest within cross-mount namespace should return 200" classname="conformance tests" status="skipped" time="7.8032e-05">
4185+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4186+ <system-err>&gt; Enter [It] GET request to test digest within cross-mount namespace should return 200 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:285 @ 04/13/25 12:25:03.067&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [It] GET request to test digest within cross-mount namespace should return 200 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:285 @ 04/13/25 12:25:03.067 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067 (0s)&#xA;</system-err>
4187+ </testcase>
4188+ <testcase name="OCI Distribution Conformance Tests Push Cross-Repository Blob Mount Cross-mounting of nonexistent blob should yield session id" classname="conformance tests" status="skipped" time="7.422e-05">
4189+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;"></skipped>
4190+ <system-err>&gt; Enter [It] Cross-mounting of nonexistent blob should yield session id - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:295 @ 04/13/25 12:25:03.067&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [It] Cross-mounting of nonexistent blob should yield session id - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:295 @ 04/13/25 12:25:03.067 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067 (0s)&#xA;</system-err>
4191+ </testcase>
4192+ <testcase name="OCI Distribution Conformance Tests Push Cross-Repository Blob Mount Cross-mounting without from, and automatic content discovery enabled should return a 201" classname="conformance tests" status="skipped" time="7.6628e-05">
4193+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4194+ <system-err>&gt; Enter [It] Cross-mounting without from, and automatic content discovery enabled should return a 201 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:301 @ 04/13/25 12:25:03.067&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [It] Cross-mounting without from, and automatic content discovery enabled should return a 201 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:301 @ 04/13/25 12:25:03.067 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067 (0s)&#xA;</system-err>
4195+ </testcase>
4196+ <testcase name="OCI Distribution Conformance Tests Push Cross-Repository Blob Mount Cross-mounting without from, and automatic content discovery disabled should return a 202" classname="conformance tests" status="skipped" time="8.1477e-05">
4197+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4198+ <system-err>&gt; Enter [It] Cross-mounting without from, and automatic content discovery disabled should return a 202 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:314 @ 04/13/25 12:25:03.067&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [It] Cross-mounting without from, and automatic content discovery disabled should return a 202 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:314 @ 04/13/25 12:25:03.067 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067 (0s)&#xA;</system-err>
4199+ </testcase>
4200+ <testcase name="OCI Distribution Conformance Tests Push Manifest Upload GET nonexistent manifest should return 404" classname="conformance tests" status="skipped" time="7.5157e-05">
4201+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;"></skipped>
4202+ <system-err>&gt; Enter [It] GET nonexistent manifest should return 404 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:329 @ 04/13/25 12:25:03.067&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [It] GET nonexistent manifest should return 404 - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:329 @ 04/13/25 12:25:03.067 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067 (0s)&#xA;</system-err>
4203+ </testcase>
4204+ <testcase name="OCI Distribution Conformance Tests Push Manifest Upload PUT should accept a manifest upload" classname="conformance tests" status="skipped" time="7.7056e-05">
4205+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;"></skipped>
4206+ <system-err>&gt; Enter [It] PUT should accept a manifest upload - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:338 @ 04/13/25 12:25:03.067&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [It] PUT should accept a manifest upload - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:338 @ 04/13/25 12:25:03.067 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067 (0s)&#xA;</system-err>
4207+ </testcase>
4208+ <testcase name="OCI Distribution Conformance Tests Push Manifest Upload Registry should accept a manifest upload with no layers" classname="conformance tests" status="skipped" time="7.3088e-05">
4209+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4210+ <system-err>&gt; Enter [It] Registry should accept a manifest upload with no layers - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:354 @ 04/13/25 12:25:03.067&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [It] Registry should accept a manifest upload with no layers - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:354 @ 04/13/25 12:25:03.067 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067 (0s)&#xA;</system-err>
4211+ </testcase>
4212+ <testcase name="OCI Distribution Conformance Tests Push Manifest Upload GET request to manifest URL (digest) should yield 200 response" classname="conformance tests" status="skipped" time="7.4208e-05">
4213+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4214+ <system-err>&gt; Enter [It] GET request to manifest URL (digest) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:372 @ 04/13/25 12:25:03.067&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [It] GET request to manifest URL (digest) should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:372 @ 04/13/25 12:25:03.067 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067 (0s)&#xA;</system-err>
4215+ </testcase>
4216+ <testcase name="OCI Distribution Conformance Tests Push Teardown Delete config blob created in tests" classname="conformance tests" status="skipped" time="7.352e-05">
4217+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4218+ <system-err>&gt; Enter [It] Delete config blob created in tests - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:412 @ 04/13/25 12:25:03.067&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [It] Delete config blob created in tests - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:412 @ 04/13/25 12:25:03.067 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067 (0s)&#xA;</system-err>
4219+ </testcase>
4220+ <testcase name="OCI Distribution Conformance Tests Push Teardown Delete layer blob created in setup" classname="conformance tests" status="skipped" time="7.2372e-05">
4221+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4222+ <system-err>&gt; Enter [It] Delete layer blob created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:428 @ 04/13/25 12:25:03.067&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [It] Delete layer blob created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:428 @ 04/13/25 12:25:03.067 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.067 (0s)&#xA;</system-err>
4223+ </testcase>
4224+ <testcase name="OCI Distribution Conformance Tests Push Teardown Delete manifest created in tests" classname="conformance tests" status="skipped" time="7.6509e-05">
4225+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;"></skipped>
4226+ <system-err>&gt; Enter [It] Delete manifest created in tests - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:445 @ 04/13/25 12:25:03.067&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [It] Delete manifest created in tests - /go/src/github.com/opencontainers/distribution-spec/conformance/02_push_test.go:445 @ 04/13/25 12:25:03.068 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068 (0s)&#xA;</system-err>
4227+ </testcase>
4228+ <testcase name="OCI Distribution Conformance Tests Content Discovery Setup Populate registry with test blob" classname="conformance tests" status="skipped" time="7.602e-05">
4229+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4230+ <system-err>&gt; Enter [It] Populate registry with test blob - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:24 @ 04/13/25 12:25:03.068&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [It] Populate registry with test blob - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:24 @ 04/13/25 12:25:03.068 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068 (0s)&#xA;</system-err>
4231+ </testcase>
4232+ <testcase name="OCI Distribution Conformance Tests Content Discovery Setup Populate registry with test layer" classname="conformance tests" status="skipped" time="7.4066e-05">
4233+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4234+ <system-err>&gt; Enter [It] Populate registry with test layer - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:42 @ 04/13/25 12:25:03.068&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [It] Populate registry with test layer - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:42 @ 04/13/25 12:25:03.068 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068 (0s)&#xA;</system-err>
4235+ </testcase>
4236+ <testcase name="OCI Distribution Conformance Tests Content Discovery Setup Populate registry with test tags" classname="conformance tests" status="skipped" time="7.4151e-05">
4237+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;"></skipped>
4238+ <system-err>&gt; Enter [It] Populate registry with test tags - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:60 @ 04/13/25 12:25:03.068&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [It] Populate registry with test tags - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:60 @ 04/13/25 12:25:03.068 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068 (0s)&#xA;</system-err>
4239+ </testcase>
4240+ <testcase name="OCI Distribution Conformance Tests Content Discovery Setup Populate registry with test tags (no push)" classname="conformance tests" status="skipped" time="8.1358e-05">
4241+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4242+ <system-err>&gt; Enter [It] Populate registry with test tags (no push) - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:82 @ 04/13/25 12:25:03.068&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [It] Populate registry with test tags (no push) - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:82 @ 04/13/25 12:25:03.068 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068 (0s)&#xA;</system-err>
4243+ </testcase>
4244+ <testcase name="OCI Distribution Conformance Tests Content Discovery Setup References setup" classname="conformance tests" status="skipped" time="7.0082e-05">
4245+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4246+ <system-err>&gt; Enter [It] References setup - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:88 @ 04/13/25 12:25:03.068&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [It] References setup - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:88 @ 04/13/25 12:25:03.068 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068 (0s)&#xA;</system-err>
4247+ </testcase>
4248+ <testcase name="OCI Distribution Conformance Tests Content Discovery Test content discovery endpoints (listing tags) GET request to list tags should yield 200 response" classname="conformance tests" status="skipped" time="0.000171825">
4249+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4250+ <system-err>&gt; Enter [It] GET request to list tags should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:256 @ 04/13/25 12:25:03.068&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [It] GET request to list tags should yield 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:256 @ 04/13/25 12:25:03.068 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068 (0s)&#xA;</system-err>
4251+ </testcase>
4252+ <testcase name="OCI Distribution Conformance Tests Content Discovery Test content discovery endpoints (listing tags) GET number of tags should be limitable by `n` query parameter" classname="conformance tests" status="skipped" time="0.000215793">
4253+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4254+ <system-err>&gt; Enter [It] GET number of tags should be limitable by `n` query parameter - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:266 @ 04/13/25 12:25:03.068&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [It] GET number of tags should be limitable by `n` query parameter - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:266 @ 04/13/25 12:25:03.068 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.068 (0s)&#xA;</system-err>
4255+ </testcase>
4256+ <testcase name="OCI Distribution Conformance Tests Content Discovery Test content discovery endpoints (listing tags) GET start of tag is set by `last` query parameter" classname="conformance tests" status="skipped" time="8.5116e-05">
4257+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;"></skipped>
4258+ <system-err>&gt; Enter [It] GET start of tag is set by `last` query parameter - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:279 @ 04/13/25 12:25:03.068&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [It] GET start of tag is set by `last` query parameter - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:279 @ 04/13/25 12:25:03.069 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069 (0s)&#xA;</system-err>
4259+ </testcase>
4260+ <testcase name="OCI Distribution Conformance Tests Content Discovery Test content discovery endpoints (listing references) GET request to nonexistent blob should result in empty 200 response" classname="conformance tests" status="skipped" time="7.9876e-05">
4261+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4262+ <system-err>&gt; Enter [It] GET request to nonexistent blob should result in empty 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:300 @ 04/13/25 12:25:03.069&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [It] GET request to nonexistent blob should result in empty 200 response - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:300 @ 04/13/25 12:25:03.069 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069 (0s)&#xA;</system-err>
4263+ </testcase>
4264+ <testcase name="OCI Distribution Conformance Tests Content Discovery Test content discovery endpoints (listing references) GET request to existing blob should yield 200" classname="conformance tests" status="skipped" time="7.7027e-05">
4265+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4266+ <system-err>&gt; Enter [It] GET request to existing blob should yield 200 - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:315 @ 04/13/25 12:25:03.069&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [It] GET request to existing blob should yield 200 - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:315 @ 04/13/25 12:25:03.069 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069 (0s)&#xA;</system-err>
4267+ </testcase>
4268+ <testcase name="OCI Distribution Conformance Tests Content Discovery Test content discovery endpoints (listing references) GET request to existing blob with filter should yield 200" classname="conformance tests" status="skipped" time="7.4983e-05">
4269+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4270+ <system-err>&gt; Enter [It] GET request to existing blob with filter should yield 200 - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:335 @ 04/13/25 12:25:03.069&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [It] GET request to existing blob with filter should yield 200 - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:335 @ 04/13/25 12:25:03.069 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069 (0s)&#xA;</system-err>
4271+ </testcase>
4272+ <testcase name="OCI Distribution Conformance Tests Content Discovery Test content discovery endpoints (listing references) GET request to missing manifest should yield 200" classname="conformance tests" status="skipped" time="8.3686e-05">
4273+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4274+ <system-err>&gt; Enter [It] GET request to missing manifest should yield 200 - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:367 @ 04/13/25 12:25:03.069&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [It] GET request to missing manifest should yield 200 - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:367 @ 04/13/25 12:25:03.069 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069 (0s)&#xA;</system-err>
4275+ </testcase>
4276+ <testcase name="OCI Distribution Conformance Tests Content Discovery Teardown Delete config blob created in tests" classname="conformance tests" status="skipped" time="7.6191e-05">
4277+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4278+ <system-err>&gt; Enter [It] Delete config blob created in tests - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:415 @ 04/13/25 12:25:03.069&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [It] Delete config blob created in tests - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:415 @ 04/13/25 12:25:03.069 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069 (0s)&#xA;</system-err>
4279+ </testcase>
4280+ <testcase name="OCI Distribution Conformance Tests Content Discovery Teardown Delete layer blob created in setup" classname="conformance tests" status="skipped" time="7.5933e-05">
4281+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4282+ <system-err>&gt; Enter [It] Delete layer blob created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:431 @ 04/13/25 12:25:03.069&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [It] Delete layer blob created in setup - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:431 @ 04/13/25 12:25:03.069 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069 (0s)&#xA;</system-err>
4283+ </testcase>
4284+ <testcase name="OCI Distribution Conformance Tests Content Discovery Teardown Delete created manifest &amp; associated tags" classname="conformance tests" status="skipped" time="7.6856e-05">
4285+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4286+ <system-err>&gt; Enter [It] Delete created manifest &amp; associated tags - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:448 @ 04/13/25 12:25:03.069&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [It] Delete created manifest &amp; associated tags - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:448 @ 04/13/25 12:25:03.069 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069 (0s)&#xA;</system-err>
4287+ </testcase>
4288+ <testcase name="OCI Distribution Conformance Tests Content Discovery Teardown References teardown" classname="conformance tests" status="skipped" time="8.2358e-05">
4289+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4290+ <system-err>&gt; Enter [It] References teardown - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:477 @ 04/13/25 12:25:03.069&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [It] References teardown - /go/src/github.com/opencontainers/distribution-spec/conformance/03_discovery_test.go:477 @ 04/13/25 12:25:03.069 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069 (0s)&#xA;</system-err>
4291+ </testcase>
4292+ <testcase name="OCI Distribution Conformance Tests Content Management Setup Populate registry with test config blob" classname="conformance tests" status="skipped" time="8.6666e-05">
4293+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4294+ <system-err>&gt; Enter [It] Populate registry with test config blob - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:21 @ 04/13/25 12:25:03.069&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [It] Populate registry with test config blob - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:21 @ 04/13/25 12:25:03.069 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069 (0s)&#xA;</system-err>
4295+ </testcase>
4296+ <testcase name="OCI Distribution Conformance Tests Content Management Setup Populate registry with test layer" classname="conformance tests" status="skipped" time="7.811e-05">
4297+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4298+ <system-err>&gt; Enter [It] Populate registry with test layer - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:39 @ 04/13/25 12:25:03.069&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [It] Populate registry with test layer - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:39 @ 04/13/25 12:25:03.069 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.069 (0s)&#xA;</system-err>
4299+ </testcase>
4300+ <testcase name="OCI Distribution Conformance Tests Content Management Setup Populate registry with test tag" classname="conformance tests" status="skipped" time="8.2355e-05">
4301+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;"></skipped>
4302+ <system-err>&gt; Enter [It] Populate registry with test tag - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:57 @ 04/13/25 12:25:03.069&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [It] Populate registry with test tag - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:57 @ 04/13/25 12:25:03.07 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07 (0s)&#xA;</system-err>
4303+ </testcase>
4304+ <testcase name="OCI Distribution Conformance Tests Content Management Setup Check how many tags there are before anything gets deleted" classname="conformance tests" status="skipped" time="7.7407e-05">
4305+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4306+ <system-err>&gt; Enter [It] Check how many tags there are before anything gets deleted - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:72 @ 04/13/25 12:25:03.07&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [It] Check how many tags there are before anything gets deleted - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:72 @ 04/13/25 12:25:03.07 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07 (0s)&#xA;</system-err>
4307+ </testcase>
4308+ <testcase name="OCI Distribution Conformance Tests Content Management Manifest delete DELETE request to manifest tag should return 202, unless tag deletion is disallowed (400/405)" classname="conformance tests" status="skipped" time="8.1127e-05">
4309+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;"></skipped>
4310+ <system-err>&gt; Enter [It] DELETE request to manifest tag should return 202, unless tag deletion is disallowed (400/405) - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:88 @ 04/13/25 12:25:03.07&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [It] DELETE request to manifest tag should return 202, unless tag deletion is disallowed (400/405) - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:88 @ 04/13/25 12:25:03.07 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07 (0s)&#xA;</system-err>
4311+ </testcase>
4312+ <testcase name="OCI Distribution Conformance Tests Content Management Manifest delete DELETE request to manifest (digest) should yield 202 response unless already deleted" classname="conformance tests" status="skipped" time="7.6632e-05">
4313+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;"></skipped>
4314+ <system-err>&gt; Enter [It] DELETE request to manifest (digest) should yield 202 response unless already deleted - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:106 @ 04/13/25 12:25:03.07&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;&#x9;OCI_TEST_PULL=1&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [It] DELETE request to manifest (digest) should yield 202 response unless already deleted - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:106 @ 04/13/25 12:25:03.07 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07 (0s)&#xA;</system-err>
4315+ </testcase>
4316+ <testcase name="OCI Distribution Conformance Tests Content Management Manifest delete GET request to deleted manifest URL should yield 404 response, unless delete is disallowed" classname="conformance tests" status="skipped" time="8.0156e-05">
4317+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4318+ <system-err>&gt; Enter [It] GET request to deleted manifest URL should yield 404 response, unless delete is disallowed - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:118 @ 04/13/25 12:25:03.07&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [It] GET request to deleted manifest URL should yield 404 response, unless delete is disallowed - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:118 @ 04/13/25 12:25:03.07 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07 (0s)&#xA;</system-err>
4319+ </testcase>
4320+ <testcase name="OCI Distribution Conformance Tests Content Management Manifest delete GET request to tags list should reflect manifest deletion" classname="conformance tests" status="skipped" time="7.5152e-05">
4321+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4322+ <system-err>&gt; Enter [It] GET request to tags list should reflect manifest deletion - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:129 @ 04/13/25 12:25:03.07&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [It] GET request to tags list should reflect manifest deletion - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:129 @ 04/13/25 12:25:03.07 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07 (0s)&#xA;</system-err>
4323+ </testcase>
4324+ <testcase name="OCI Distribution Conformance Tests Content Management Blob delete DELETE request to blob URL should yield 202 response" classname="conformance tests" status="skipped" time="8.1684e-05">
4325+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4326+ <system-err>&gt; Enter [It] DELETE request to blob URL should yield 202 response - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:153 @ 04/13/25 12:25:03.07&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [It] DELETE request to blob URL should yield 202 response - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:153 @ 04/13/25 12:25:03.07 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07 (0s)&#xA;</system-err>
4327+ </testcase>
4328+ <testcase name="OCI Distribution Conformance Tests Content Management Blob delete GET request to deleted blob URL should yield 404 response" classname="conformance tests" status="skipped" time="7.5496e-05">
4329+ <skipped message="skipped - you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;"></skipped>
4330+ <system-err>&gt; Enter [It] GET request to deleted blob URL should yield 404 response - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:180 @ 04/13/25 12:25:03.07&#xA;[SKIPPED] you have skipped this test; if this is an error, check your environment variable settings:&#xA;&#x9;OCI_TEST_PULL=1&#xA;&#x9;OCI_TEST_PUSH=0&#xA;&#x9;OCI_TEST_CONTENT_DISCOVERY=0&#xA;&#x9;OCI_TEST_CONTENT_MANAGEMENT=0&#xA;In [It] at: /go/src/github.com/opencontainers/distribution-spec/conformance/setup.go:579 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [It] GET request to deleted blob URL should yield 404 response - /go/src/github.com/opencontainers/distribution-spec/conformance/04_management_test.go:180 @ 04/13/25 12:25:03.07 (0s)&#xA;&gt; Enter [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [ReportAfterEach] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:23 @ 04/13/25 12:25:03.07 (0s)&#xA;</system-err>
4331+ </testcase>
4332+ <testcase name="html custom reporter" classname="conformance tests" status="passed" time="0.004703533">
4333+ <system-err>&gt; Enter [ReportAfterSuite] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:24 @ 04/13/25 12:25:03.07&#xA;&lt; Exit [ReportAfterSuite] TOP-LEVEL - /go/src/github.com/opencontainers/distribution-spec/conformance/00_conformance_suite_test.go:24 @ 04/13/25 12:25:03.075 (5ms)&#xA;</system-err>
4334+ </testcase>
4335+ </testsuite>
4336+ </testsuites>
4337\ No newline at end of file
4338 diff --git a/results/report.html b/results/report.html
4339new file mode 100644
4340index 0000000..45dfcb5
4341--- /dev/null
4342+++ b/results/report.html
4343 @@ -0,0 +1,2475 @@
4344+ <html>
4345+ <head>
4346+ <title>OCI Distribution Conformance Tests</title>
4347+ <style>
4348+ body {
4349+ padding: 10px 20px 10px 20px;
4350+ font-family: -apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;
4351+ background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAG0lEQVQYV2Pce7zwv7NlPyMDFMAZGAIwlRgqAFydCAVv5m4UAAAAAElFTkSuQmCC") repeat;
4352+
4353+ }
4354+ table {
4355+ border-collapse: collapse;
4356+ width: 100%;
4357+ background-color: white;
4358+ }
4359+ th, td {
4360+ padding: 12px;
4361+ text-align: left;
4362+ border-bottom: 1px solid #ddd;
4363+ }
4364+ tr:hover {
4365+ background-color: #ffe39b;
4366+ }
4367+ .result {
4368+ padding: 1.25em 0 .25em 0.8em;
4369+ border: 1px solid #e1e1e1;
4370+ border-radius: 5px;
4371+ margin-top: 10px;
4372+ }
4373+ .red {
4374+ background: #ffc8c8;
4375+ }
4376+ pre.fail-message {
4377+ background: #f9a5a5;
4378+ padding: 20px;
4379+ margin-right: 10px;
4380+ display: inline-block;
4381+ border-radius: 4px;
4382+ font-size: 1.25em;
4383+ width: 94%;
4384+ overflow-x: auto;
4385+ max-width: 85%;
4386+ }
4387+ .green {
4388+ background: #c8ffc8;
4389+ padding: 1.25em 0 1.25em 0.8em;
4390+ }
4391+ .grey {
4392+ background: lightgrey;
4393+ padding: 1.25em 0 1.25em 0.8em;
4394+ }
4395+ .toggle {
4396+ border: 2px solid #3e3e3e;
4397+ cursor: pointer;
4398+ width: 1em;
4399+ text-align: center;
4400+ font-weight: bold;
4401+ display: inline;
4402+ font-family: monospace;
4403+ padding: 0 .25em 0 .25em;
4404+ margin: 1em 1em 1em 0;
4405+ font-size: 12pt;
4406+ color: #3e3e3e;
4407+ border-radius: 3px;
4408+ }
4409+ pre.pre-box {
4410+ background: #343a40;
4411+ color: #fff;
4412+ padding: 10px;
4413+ border: 1px solid gray;
4414+ display: inline-block;
4415+ border-radius: 4px;
4416+ width: 97%;
4417+ font-size: 1.25em;
4418+ overflow-x: auto;
4419+ max-height: 60em;
4420+ overflow-y: auto;
4421+ max-width: 85%;
4422+ }
4423+ .summary {
4424+ width: 100%;
4425+ height: auto;
4426+ padding: 0 0 .5em 0;
4427+ border-radius: 6px;
4428+ border: 1px solid #cccddd;
4429+ background: white;
4430+ }
4431+ .summary-bullet {
4432+ width: 100%;
4433+ height: auto;
4434+ display: flex;
4435+ flex-wrap: wrap;
4436+ padding: .5em .1em .1em .5em;
4437+ }
4438+ .bullet-left {
4439+ width: 25%;
4440+ font-weight: bold;
4441+ font-size: 100%;
4442+ }
4443+ .bullet-right {
4444+ width: auto;
4445+ font-family: monospace;
4446+ font-size: 110%;
4447+ }
4448+ .quick-summary {
4449+ width: 70%;
4450+ display: flex;
4451+ margin: 0 auto 0 0;
4452+ font-weight: bold;
4453+ font-size: 1.2em;
4454+ }
4455+ .darkgreen {
4456+ color: green;
4457+ }
4458+ .darkred {
4459+ color: red;
4460+ padding: 0 0 0 2em;
4461+ }
4462+ .darkgrey {
4463+ color: grey;
4464+ padding: 0 0 0 2em;
4465+ }
4466+ .meter {
4467+ border: 1px solid black;
4468+ margin: 0 .5em 0 auto;
4469+ display: flex;
4470+ height: 25px;
4471+ width: 45%;
4472+ }
4473+ @media only screen and (max-width: 600px) {
4474+ .meter {
4475+ display: none;
4476+ }
4477+ }
4478+ .meter-green {
4479+ height: 100%;
4480+ background: green;
4481+ width: 28%;
4482+ }
4483+ .meter-red {
4484+ height: 100%;
4485+ background: red;
4486+ width: 1%;
4487+ }
4488+ .meter-grey {
4489+ height: 100%;
4490+ background: grey;
4491+ width: 71%;
4492+ }
4493+ .subcategory {
4494+ background: white;
4495+ padding: 0px 20px 20px 20px;
4496+ border: 1px solid #cccddd;
4497+ border-radius: 6px;
4498+ }
4499+ h2 {
4500+ margin-top: 45px;
4501+ }
4502+ h4 {
4503+ vertical-align: bottom;
4504+ cursor: pointer;
4505+ }
4506+ </style>
4507+ <script>
4508+ function toggleOutput(id) {
4509+ var elem = document.getElementById(id);
4510+ var button = document.getElementById(id + "-button");
4511+ if (elem.style['display'] === 'block') {
4512+ button.innerHTML = "+";
4513+ elem.style['display'] = 'none';
4514+ } else {
4515+ button.innerHTML = "-";
4516+ elem.style['display'] = 'block';
4517+ }
4518+ }
4519+ </script>
4520+ </head>
4521+ <body>
4522+ <h1>OCI Distribution Conformance Tests</h1>
4523+ <table>
4524+ <tr>
4525+ </tr>
4526+ <tr>
4527+ <td class="bullet-left">Summary</td>
4528+ <td>
4529+ <div class="quick-summary"><span class="darkgreen">22 passed</span><span class="darkred">1 failed</span><span class="darkgrey">56 skipped</span><div class="meter">
4530+ <div class="meter-green"></div>
4531+ <div class="meter-red"></div>
4532+ <div class="meter-grey"></div>
4533+ </div>
4534+ </div>
4535+ </td>
4536+ </tr>
4537+ <tr>
4538+ <td class="bullet-left">Start Time</td>
4539+ <td>Apr 13 12:25:02.900 &#43;0000 UTC</td>
4540+ </tr>
4541+ <tr>
4542+ <td class="bullet-left">End Time</td>
4543+ <td>Apr 13 12:25:03.070 &#43;0000 UTC</td>
4544+ </tr>
4545+ <tr>
4546+ <td class="bullet-left">Time Elapsed</td>
4547+ <td>169.993402ms</td>
4548+ </tr>
4549+ <tr>
4550+ <td class="bullet-left">Test Version</td>
4551+ <td>unknown</td>
4552+ </tr>
4553+ <tr>
4554+ <td class="bullet-left">Configuration</td>
4555+ <td><div class="bullet-right">
4556+
4557+ OCI_ROOT_URL=http://localhost:5000<br />
4558+
4559+ OCI_NAMESPACE=myorg/myrepo/a<br />
4560+
4561+ OCI_USERNAME=*****<br />
4562+
4563+ OCI_PASSWORD=*****<br />
4564+
4565+ OCI_DEBUG=0<br />
4566+
4567+ OCI_TEST_PULL=1<br />
4568+
4569+ OCI_TEST_PUSH=0<br />
4570+
4571+ OCI_TEST_CONTENT_DISCOVERY=0<br />
4572+
4573+ OCI_TEST_CONTENT_MANAGEMENT=0<br />
4574+
4575+ OCI_HIDE_SKIPPED_WORKFLOWS=0<br />
4576+
4577+ </div></td>
4578+ </tr>
4579+ </table>
4580+
4581+ <div>
4582+
4583+
4584+
4585+
4586+
4587+
4588+ <h2>Pull</h2>
4589+ <div class="subcategory">
4590+
4591+
4592+ <h3>Setup</h3>
4593+
4594+
4595+
4596+
4597+
4598+
4599+ <div class="result green">
4600+ <div id="output-box-1-button" class="toggle" onclick="javascript:toggleOutput('output-box-1')">+</div>
4601+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-1')">Populate registry with test blob</h4>
4602+ <br>
4603+ <div id="output-box-1" style="display: none;">
4604+ <pre class="pre-box">DEBUG
4605+ ==============================================================================
4606+ ~~~ REQUEST ~~~
4607+ POST /v2/myorg/myrepo/a/blobs/uploads/ HTTP/1.1
4608+ HOST : localhost:5000
4609+ HEADERS:
4610+ User-Agent: distribution-spec-conformance-tests
4611+ BODY :
4612+ ***** NO CONTENT *****
4613+ ------------------------------------------------------------------------------
4614+ ~~~ RESPONSE ~~~
4615+ STATUS : 202 Accepted
4616+ PROTO : HTTP/1.1
4617+ RECEIVED AT : 2025-04-13T12:25:02.960113525Z
4618+ TIME DURATION: 13.109557ms
4619+ HEADERS :
4620+ Content-Length: 0
4621+ Date: Sun, 13 Apr 2025 12:25:02 GMT
4622+ Docker-Distribution-Api-Version: registry/2.0
4623+ Docker-Upload-Uuid: 0884ac30-9538-4d0b-8ed9-99548c0b901a
4624+ Location: http://localhost:5000/v2/myorg/myrepo/a/blobs/uploads/0884ac30-9538-4d0b-8ed9-99548c0b901a?_state=*****
4625+ Range: 0-0
4626+ X-Content-Type-Options: nosniff
4627+ BODY :
4628+
4629+ ==============================================================================
4630+
4631+ DEBUG
4632+ ==============================================================================
4633+ ~~~ REQUEST ~~~
4634+ PUT /v2/myorg/myrepo/a/blobs/uploads/0884ac30-9538-4d0b-8ed9-99548c0b901a?_state=*****&amp;digest=sha256%3A91ebe32a31a708da89e098c1053ba39ce65b98bc33542e5a588e7bf5b2693ef5 HTTP/1.1
4635+ HOST : localhost:5000
4636+ HEADERS:
4637+ Content-Length: 129
4638+ Content-Type: application/octet-stream
4639+ User-Agent: distribution-spec-conformance-tests
4640+ BODY :
4641+ ***** BODY IS byte(s) (size - 129) *****
4642+ ------------------------------------------------------------------------------
4643+ ~~~ RESPONSE ~~~
4644+ STATUS : 201 Created
4645+ PROTO : HTTP/1.1
4646+ RECEIVED AT : 2025-04-13T12:25:02.979243777Z
4647+ TIME DURATION: 18.98139ms
4648+ HEADERS :
4649+ Content-Length: 0
4650+ Date: Sun, 13 Apr 2025 12:25:02 GMT
4651+ Docker-Content-Digest: sha256:91ebe32a31a708da89e098c1053ba39ce65b98bc33542e5a588e7bf5b2693ef5
4652+ Docker-Distribution-Api-Version: registry/2.0
4653+ Location: http://localhost:5000/v2/myorg/myrepo/a/blobs/sha256:91ebe32a31a708da89e098c1053ba39ce65b98bc33542e5a588e7bf5b2693ef5
4654+ X-Content-Type-Options: nosniff
4655+ BODY :
4656+
4657+ ==============================================================================
4658+
4659+ </pre>
4660+ </div>
4661+ </div>
4662+
4663+
4664+
4665+
4666+ <div class="result green">
4667+ <div id="output-box-1-button" class="toggle" onclick="javascript:toggleOutput('output-box-1')">+</div>
4668+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-1')">Populate registry with test blob</h4>
4669+ <br>
4670+ <div id="output-box-1" style="display: none;">
4671+ <pre class="pre-box">DEBUG
4672+ ==============================================================================
4673+ ~~~ REQUEST ~~~
4674+ POST /v2/myorg/myrepo/a/blobs/uploads/ HTTP/1.1
4675+ HOST : localhost:5000
4676+ HEADERS:
4677+ User-Agent: distribution-spec-conformance-tests
4678+ BODY :
4679+ ***** NO CONTENT *****
4680+ ------------------------------------------------------------------------------
4681+ ~~~ RESPONSE ~~~
4682+ STATUS : 202 Accepted
4683+ PROTO : HTTP/1.1
4684+ RECEIVED AT : 2025-04-13T12:25:02.960113525Z
4685+ TIME DURATION: 13.109557ms
4686+ HEADERS :
4687+ Content-Length: 0
4688+ Date: Sun, 13 Apr 2025 12:25:02 GMT
4689+ Docker-Distribution-Api-Version: registry/2.0
4690+ Docker-Upload-Uuid: 0884ac30-9538-4d0b-8ed9-99548c0b901a
4691+ Location: http://localhost:5000/v2/myorg/myrepo/a/blobs/uploads/0884ac30-9538-4d0b-8ed9-99548c0b901a?_state=*****
4692+ Range: 0-0
4693+ X-Content-Type-Options: nosniff
4694+ BODY :
4695+
4696+ ==============================================================================
4697+
4698+ DEBUG
4699+ ==============================================================================
4700+ ~~~ REQUEST ~~~
4701+ PUT /v2/myorg/myrepo/a/blobs/uploads/0884ac30-9538-4d0b-8ed9-99548c0b901a?_state=*****&amp;digest=sha256%3A91ebe32a31a708da89e098c1053ba39ce65b98bc33542e5a588e7bf5b2693ef5 HTTP/1.1
4702+ HOST : localhost:5000
4703+ HEADERS:
4704+ Content-Length: 129
4705+ Content-Type: application/octet-stream
4706+ User-Agent: distribution-spec-conformance-tests
4707+ BODY :
4708+ ***** BODY IS byte(s) (size - 129) *****
4709+ ------------------------------------------------------------------------------
4710+ ~~~ RESPONSE ~~~
4711+ STATUS : 201 Created
4712+ PROTO : HTTP/1.1
4713+ RECEIVED AT : 2025-04-13T12:25:02.979243777Z
4714+ TIME DURATION: 18.98139ms
4715+ HEADERS :
4716+ Content-Length: 0
4717+ Date: Sun, 13 Apr 2025 12:25:02 GMT
4718+ Docker-Content-Digest: sha256:91ebe32a31a708da89e098c1053ba39ce65b98bc33542e5a588e7bf5b2693ef5
4719+ Docker-Distribution-Api-Version: registry/2.0
4720+ Location: http://localhost:5000/v2/myorg/myrepo/a/blobs/sha256:91ebe32a31a708da89e098c1053ba39ce65b98bc33542e5a588e7bf5b2693ef5
4721+ X-Content-Type-Options: nosniff
4722+ BODY :
4723+
4724+ ==============================================================================
4725+
4726+ </pre>
4727+ </div>
4728+ </div>
4729+
4730+
4731+
4732+
4733+ <div class="result green">
4734+ <div id="output-box-2-button" class="toggle" onclick="javascript:toggleOutput('output-box-2')">+</div>
4735+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-2')">Populate registry with test layer</h4>
4736+ <br>
4737+ <div id="output-box-2" style="display: none;">
4738+ <pre class="pre-box">DEBUG
4739+ ==============================================================================
4740+ ~~~ REQUEST ~~~
4741+ POST /v2/myorg/myrepo/a/blobs/uploads/ HTTP/1.1
4742+ HOST : localhost:5000
4743+ HEADERS:
4744+ User-Agent: distribution-spec-conformance-tests
4745+ BODY :
4746+ ***** NO CONTENT *****
4747+ ------------------------------------------------------------------------------
4748+ ~~~ RESPONSE ~~~
4749+ STATUS : 202 Accepted
4750+ PROTO : HTTP/1.1
4751+ RECEIVED AT : 2025-04-13T12:25:02.992416017Z
4752+ TIME DURATION: 12.970237ms
4753+ HEADERS :
4754+ Content-Length: 0
4755+ Date: Sun, 13 Apr 2025 12:25:02 GMT
4756+ Docker-Distribution-Api-Version: registry/2.0
4757+ Docker-Upload-Uuid: 0295b7cf-e728-47c0-b8a2-81bd70d0dfd9
4758+ Location: http://localhost:5000/v2/myorg/myrepo/a/blobs/uploads/0295b7cf-e728-47c0-b8a2-81bd70d0dfd9?_state=*****
4759+ Range: 0-0
4760+ X-Content-Type-Options: nosniff
4761+ BODY :
4762+
4763+ ==============================================================================
4764+
4765+ DEBUG
4766+ ==============================================================================
4767+ ~~~ REQUEST ~~~
4768+ PUT /v2/myorg/myrepo/a/blobs/uploads/0295b7cf-e728-47c0-b8a2-81bd70d0dfd9?_state=*****&amp;digest=sha256%3A48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183 HTTP/1.1
4769+ HOST : localhost:5000
4770+ HEADERS:
4771+ Content-Length: 168
4772+ Content-Type: application/octet-stream
4773+ User-Agent: distribution-spec-conformance-tests
4774+ BODY :
4775+ ***** BODY IS byte(s) (size - 168) *****
4776+ ------------------------------------------------------------------------------
4777+ ~~~ RESPONSE ~~~
4778+ STATUS : 201 Created
4779+ PROTO : HTTP/1.1
4780+ RECEIVED AT : 2025-04-13T12:25:03.011600451Z
4781+ TIME DURATION: 18.992823ms
4782+ HEADERS :
4783+ Content-Length: 0
4784+ Date: Sun, 13 Apr 2025 12:25:03 GMT
4785+ Docker-Content-Digest: sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183
4786+ Docker-Distribution-Api-Version: registry/2.0
4787+ Location: http://localhost:5000/v2/myorg/myrepo/a/blobs/sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183
4788+ X-Content-Type-Options: nosniff
4789+ BODY :
4790+
4791+ ==============================================================================
4792+
4793+ </pre>
4794+ </div>
4795+ </div>
4796+
4797+
4798+
4799+
4800+ <div class="result green">
4801+ <div id="output-box-4-button" class="toggle" onclick="javascript:toggleOutput('output-box-4')">+</div>
4802+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-4')">Populate registry with test manifest</h4>
4803+ <br>
4804+ <div id="output-box-4" style="display: none;">
4805+ <pre class="pre-box">DEBUG
4806+ ==============================================================================
4807+ ~~~ REQUEST ~~~
4808+ PUT /v2/myorg/myrepo/a/manifests/sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9 HTTP/1.1
4809+ HOST : localhost:5000
4810+ HEADERS:
4811+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
4812+ User-Agent: distribution-spec-conformance-tests
4813+ BODY :
4814+ &#34;ewoJInNjaGVtYVZlcnNpb24iOiAyLAoJIm1lZGlhVHlwZSI6ICJhcHBsaWNhdGlvbi92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLAoJImNvbmZpZyI6IHsKCQkibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5vY2kuaW1hZ2UuY29uZmlnLnYxK2pzb24iLAoJCSJkaWdlc3QiOiAic2hhMjU2OjkxZWJlMzJhMzFhNzA4ZGE4OWUwOThjMTA1M2JhMzljZTY1Yjk4YmMzMzU0MmU1YTU4OGU3YmY1YjI2OTNlZjUiLAoJCSJzaXplIjogMTI5LAoJCSJkYXRhIjogImV3b0pJbUYxZEdodmNpSTZJQ0owUkdSeVZFSndVelJIVERFM05sVkhJaXdLQ1NKaGNtTm9hWFJsWTNSMWNtVWlPaUFpWVcxa05qUWlMQW9KSW05eklqb2dJbXhwYm5WNElpd0tDU0p5YjI5MFpuTWlPaUI3Q2drSkluUjVjR1VpT2lBaWJHRjVaWEp6SWl3S0NRa2laR2xtWmw5cFpITWlPaUJiWFFvSmZRcDkiLAoJCSJuZXdVbnNwZWNpZmllZEZpZWxkIjogImFHVnNiRzhnZDI5eWJHUT0iCgl9LAoJImxheWVycyI6IFsKCQl7CgkJCSJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLm9jaS5pbWFnZS5sYXllci52MS50YXIrZ3ppcCIsCgkJCSJkaWdlc3QiOiAic2hhMjU2OjQ4YWNmZjFkOTE3NTJlOTU3NTI3YzFiNTQxNmU3Mzc2ZDkxMGJjYWNmMDFiOTQ0MTE3NWY4YzI3MGUzNWMxODMiLAoJCQkic2l6ZSI6IDE2OCwKCQkJIm5ld1Vuc3BlY2lmaWVkRmllbGQiOiBudWxsCgkJfQoJXQp9&#34;
4815+ ------------------------------------------------------------------------------
4816+ ~~~ RESPONSE ~~~
4817+ STATUS : 201 Created
4818+ PROTO : HTTP/1.1
4819+ RECEIVED AT : 2025-04-13T12:25:03.049599671Z
4820+ TIME DURATION: 12.901323ms
4821+ HEADERS :
4822+ Content-Length: 0
4823+ Date: Sun, 13 Apr 2025 12:25:03 GMT
4824+ Docker-Content-Digest: sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9
4825+ Docker-Distribution-Api-Version: registry/2.0
4826+ Location: http://localhost:5000/v2/myorg/myrepo/a/manifests/sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9
4827+ X-Content-Type-Options: nosniff
4828+ BODY :
4829+
4830+ ==============================================================================
4831+
4832+ </pre>
4833+ </div>
4834+ </div>
4835+
4836+
4837+
4838+
4839+ <div class="result green">
4840+ <div id="output-box-4-button" class="toggle" onclick="javascript:toggleOutput('output-box-4')">+</div>
4841+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-4')">Populate registry with test manifest</h4>
4842+ <br>
4843+ <div id="output-box-4" style="display: none;">
4844+ <pre class="pre-box">DEBUG
4845+ ==============================================================================
4846+ ~~~ REQUEST ~~~
4847+ PUT /v2/myorg/myrepo/a/manifests/sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9 HTTP/1.1
4848+ HOST : localhost:5000
4849+ HEADERS:
4850+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
4851+ User-Agent: distribution-spec-conformance-tests
4852+ BODY :
4853+ &#34;ewoJInNjaGVtYVZlcnNpb24iOiAyLAoJIm1lZGlhVHlwZSI6ICJhcHBsaWNhdGlvbi92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLAoJImNvbmZpZyI6IHsKCQkibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5vY2kuaW1hZ2UuY29uZmlnLnYxK2pzb24iLAoJCSJkaWdlc3QiOiAic2hhMjU2OjkxZWJlMzJhMzFhNzA4ZGE4OWUwOThjMTA1M2JhMzljZTY1Yjk4YmMzMzU0MmU1YTU4OGU3YmY1YjI2OTNlZjUiLAoJCSJzaXplIjogMTI5LAoJCSJkYXRhIjogImV3b0pJbUYxZEdodmNpSTZJQ0owUkdSeVZFSndVelJIVERFM05sVkhJaXdLQ1NKaGNtTm9hWFJsWTNSMWNtVWlPaUFpWVcxa05qUWlMQW9KSW05eklqb2dJbXhwYm5WNElpd0tDU0p5YjI5MFpuTWlPaUI3Q2drSkluUjVjR1VpT2lBaWJHRjVaWEp6SWl3S0NRa2laR2xtWmw5cFpITWlPaUJiWFFvSmZRcDkiLAoJCSJuZXdVbnNwZWNpZmllZEZpZWxkIjogImFHVnNiRzhnZDI5eWJHUT0iCgl9LAoJImxheWVycyI6IFsKCQl7CgkJCSJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLm9jaS5pbWFnZS5sYXllci52MS50YXIrZ3ppcCIsCgkJCSJkaWdlc3QiOiAic2hhMjU2OjQ4YWNmZjFkOTE3NTJlOTU3NTI3YzFiNTQxNmU3Mzc2ZDkxMGJjYWNmMDFiOTQ0MTE3NWY4YzI3MGUzNWMxODMiLAoJCQkic2l6ZSI6IDE2OCwKCQkJIm5ld1Vuc3BlY2lmaWVkRmllbGQiOiBudWxsCgkJfQoJXQp9&#34;
4854+ ------------------------------------------------------------------------------
4855+ ~~~ RESPONSE ~~~
4856+ STATUS : 201 Created
4857+ PROTO : HTTP/1.1
4858+ RECEIVED AT : 2025-04-13T12:25:03.049599671Z
4859+ TIME DURATION: 12.901323ms
4860+ HEADERS :
4861+ Content-Length: 0
4862+ Date: Sun, 13 Apr 2025 12:25:03 GMT
4863+ Docker-Content-Digest: sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9
4864+ Docker-Distribution-Api-Version: registry/2.0
4865+ Location: http://localhost:5000/v2/myorg/myrepo/a/manifests/sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9
4866+ X-Content-Type-Options: nosniff
4867+ BODY :
4868+
4869+ ==============================================================================
4870+
4871+ </pre>
4872+ </div>
4873+ </div>
4874+
4875+
4876+
4877+
4878+ <div class="result grey">
4879+ <div id="output-box-5-button" class="toggle" onclick="javascript:toggleOutput('output-box-5')">+</div>
4880+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-5')">Get tag name from environment</h4>
4881+ <br>
4882+ <div id="output-box-5" style="display: none;">
4883+ <pre class="pre-box">you have skipped this test.</pre>
4884+ </div>
4885+ </div>
4886+
4887+ <br>
4888+
4889+
4890+ <h3>Pull blobs</h3>
4891+
4892+
4893+
4894+
4895+
4896+
4897+ <div class="result green">
4898+ <div id="output-box-6-button" class="toggle" onclick="javascript:toggleOutput('output-box-6')">+</div>
4899+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-6')">HEAD request to nonexistent blob should result in 404 response</h4>
4900+ <br>
4901+ <div id="output-box-6" style="display: none;">
4902+ <pre class="pre-box">DEBUG
4903+ ==============================================================================
4904+ ~~~ REQUEST ~~~
4905+ HEAD /v2/myorg/myrepo/a/blobs/sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 HTTP/1.1
4906+ HOST : localhost:5000
4907+ HEADERS:
4908+ User-Agent: distribution-spec-conformance-tests
4909+ BODY :
4910+ ***** NO CONTENT *****
4911+ ------------------------------------------------------------------------------
4912+ ~~~ RESPONSE ~~~
4913+ STATUS : 404 Not Found
4914+ PROTO : HTTP/1.1
4915+ RECEIVED AT : 2025-04-13T12:25:03.05095233Z
4916+ TIME DURATION: 955.473µs
4917+ HEADERS :
4918+ Content-Length: 157
4919+ Content-Type: application/json; charset=utf-8
4920+ Date: Sun, 13 Apr 2025 12:25:03 GMT
4921+ Docker-Distribution-Api-Version: registry/2.0
4922+ X-Content-Type-Options: nosniff
4923+ BODY :
4924+ *** Error: Unable to format response body - &#34;unexpected end of JSON input&#34; ***
4925+
4926+ Log Body as-is:
4927+
4928+ ==============================================================================
4929+
4930+ </pre>
4931+ </div>
4932+ </div>
4933+
4934+
4935+
4936+
4937+ <div class="result green">
4938+ <div id="output-box-7-button" class="toggle" onclick="javascript:toggleOutput('output-box-7')">+</div>
4939+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-7')">HEAD request to existing blob should yield 200</h4>
4940+ <br>
4941+ <div id="output-box-7" style="display: none;">
4942+ <pre class="pre-box">DEBUG
4943+ ==============================================================================
4944+ ~~~ REQUEST ~~~
4945+ HEAD /v2/myorg/myrepo/a/blobs/sha256:4ff4c7e8f8cd0ece3cd6a91d2e8eb83d06b1d0f9f1caa06a82d7fe1d6acde544 HTTP/1.1
4946+ HOST : localhost:5000
4947+ HEADERS:
4948+ User-Agent: distribution-spec-conformance-tests
4949+ BODY :
4950+ ***** NO CONTENT *****
4951+ ------------------------------------------------------------------------------
4952+ ~~~ RESPONSE ~~~
4953+ STATUS : 200 OK
4954+ PROTO : HTTP/1.1
4955+ RECEIVED AT : 2025-04-13T12:25:03.051732952Z
4956+ TIME DURATION: 600.012µs
4957+ HEADERS :
4958+ Accept-Ranges: bytes
4959+ Cache-Control: max-age=31536000
4960+ Content-Length: 129
4961+ Content-Type: application/octet-stream
4962+ Date: Sun, 13 Apr 2025 12:25:03 GMT
4963+ Docker-Content-Digest: sha256:4ff4c7e8f8cd0ece3cd6a91d2e8eb83d06b1d0f9f1caa06a82d7fe1d6acde544
4964+ Docker-Distribution-Api-Version: registry/2.0
4965+ Etag: &#34;sha256:4ff4c7e8f8cd0ece3cd6a91d2e8eb83d06b1d0f9f1caa06a82d7fe1d6acde544&#34;
4966+ X-Content-Type-Options: nosniff
4967+ BODY :
4968+
4969+ ==============================================================================
4970+
4971+ </pre>
4972+ </div>
4973+ </div>
4974+
4975+
4976+
4977+
4978+ <div class="result green">
4979+ <div id="output-box-8-button" class="toggle" onclick="javascript:toggleOutput('output-box-8')">+</div>
4980+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-8')">GET nonexistent blob should result in 404 response</h4>
4981+ <br>
4982+ <div id="output-box-8" style="display: none;">
4983+ <pre class="pre-box">DEBUG
4984+ ==============================================================================
4985+ ~~~ REQUEST ~~~
4986+ GET /v2/myorg/myrepo/a/blobs/sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 HTTP/1.1
4987+ HOST : localhost:5000
4988+ HEADERS:
4989+ User-Agent: distribution-spec-conformance-tests
4990+ BODY :
4991+ ***** NO CONTENT *****
4992+ ------------------------------------------------------------------------------
4993+ ~~~ RESPONSE ~~~
4994+ STATUS : 404 Not Found
4995+ PROTO : HTTP/1.1
4996+ RECEIVED AT : 2025-04-13T12:25:03.052717209Z
4997+ TIME DURATION: 799.041µs
4998+ HEADERS :
4999+ Content-Length: 157
5000+ Content-Type: application/json; charset=utf-8
5001+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5002+ Docker-Distribution-Api-Version: registry/2.0
5003+ X-Content-Type-Options: nosniff
5004+ BODY :
5005+ {
5006+ &#34;errors&#34;: [
5007+ {
5008+ &#34;code&#34;: &#34;BLOB_UNKNOWN&#34;,
5009+ &#34;message&#34;: &#34;blob unknown to registry&#34;,
5010+ &#34;detail&#34;: &#34;sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9&#34;
5011+ }
5012+ ]
5013+ }
5014+
5015+ ==============================================================================
5016+
5017+ </pre>
5018+ </div>
5019+ </div>
5020+
5021+
5022+
5023+
5024+ <div class="result green">
5025+ <div id="output-box-9-button" class="toggle" onclick="javascript:toggleOutput('output-box-9')">+</div>
5026+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-9')">GET request to existing blob URL should yield 200</h4>
5027+ <br>
5028+ <div id="output-box-9" style="display: none;">
5029+ <pre class="pre-box">DEBUG
5030+ ==============================================================================
5031+ ~~~ REQUEST ~~~
5032+ GET /v2/myorg/myrepo/a/blobs/sha256:4ff4c7e8f8cd0ece3cd6a91d2e8eb83d06b1d0f9f1caa06a82d7fe1d6acde544 HTTP/1.1
5033+ HOST : localhost:5000
5034+ HEADERS:
5035+ User-Agent: distribution-spec-conformance-tests
5036+ BODY :
5037+ ***** NO CONTENT *****
5038+ ------------------------------------------------------------------------------
5039+ ~~~ RESPONSE ~~~
5040+ STATUS : 200 OK
5041+ PROTO : HTTP/1.1
5042+ RECEIVED AT : 2025-04-13T12:25:03.053997891Z
5043+ TIME DURATION: 1.092002ms
5044+ HEADERS :
5045+ Accept-Ranges: bytes
5046+ Cache-Control: max-age=31536000
5047+ Content-Length: 129
5048+ Content-Type: application/octet-stream
5049+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5050+ Docker-Content-Digest: sha256:4ff4c7e8f8cd0ece3cd6a91d2e8eb83d06b1d0f9f1caa06a82d7fe1d6acde544
5051+ Docker-Distribution-Api-Version: registry/2.0
5052+ Etag: &#34;sha256:4ff4c7e8f8cd0ece3cd6a91d2e8eb83d06b1d0f9f1caa06a82d7fe1d6acde544&#34;
5053+ X-Content-Type-Options: nosniff
5054+ BODY :
5055+ {
5056+ &#34;author&#34;: &#34;HMjYvZz4L8VkAAjl&#34;,
5057+ &#34;architecture&#34;: &#34;amd64&#34;,
5058+ &#34;os&#34;: &#34;linux&#34;,
5059+ &#34;rootfs&#34;: {
5060+ &#34;type&#34;: &#34;layers&#34;,
5061+ &#34;diff_ids&#34;: []
5062+ }
5063+ }
5064+ ==============================================================================
5065+
5066+ </pre>
5067+ </div>
5068+ </div>
5069+
5070+ <br>
5071+
5072+
5073+ <h3>Pull manifests</h3>
5074+
5075+
5076+
5077+
5078+
5079+
5080+ <div class="result green">
5081+ <div id="output-box-10-button" class="toggle" onclick="javascript:toggleOutput('output-box-10')">+</div>
5082+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-10')">HEAD request to nonexistent manifest should return 404</h4>
5083+ <br>
5084+ <div id="output-box-10" style="display: none;">
5085+ <pre class="pre-box">DEBUG
5086+ ==============================================================================
5087+ ~~~ REQUEST ~~~
5088+ HEAD /v2/myorg/myrepo/a/manifests/.INVALID_MANIFEST_NAME HTTP/1.1
5089+ HOST : localhost:5000
5090+ HEADERS:
5091+ User-Agent: distribution-spec-conformance-tests
5092+ BODY :
5093+ ***** NO CONTENT *****
5094+ ------------------------------------------------------------------------------
5095+ ~~~ RESPONSE ~~~
5096+ STATUS : 404 Not Found
5097+ PROTO : HTTP/1.1
5098+ RECEIVED AT : 2025-04-13T12:25:03.054407305Z
5099+ TIME DURATION: 206.948µs
5100+ HEADERS :
5101+ Content-Length: 19
5102+ Content-Type: text/plain; charset=utf-8
5103+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5104+ Docker-Distribution-Api-Version: registry/2.0
5105+ X-Content-Type-Options: nosniff
5106+ BODY :
5107+
5108+ ==============================================================================
5109+
5110+ </pre>
5111+ </div>
5112+ </div>
5113+
5114+
5115+
5116+
5117+ <div class="result green">
5118+ <div id="output-box-11-button" class="toggle" onclick="javascript:toggleOutput('output-box-11')">+</div>
5119+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-11')">HEAD request to manifest[0] path (digest) should yield 200 response</h4>
5120+ <br>
5121+ <div id="output-box-11" style="display: none;">
5122+ <pre class="pre-box">DEBUG
5123+ ==============================================================================
5124+ ~~~ REQUEST ~~~
5125+ HEAD /v2/myorg/myrepo/a/manifests/sha256:d0154f9c047c63a137a3827d30c53c5a09d50c3ce8385f1eb543603ab5271590 HTTP/1.1
5126+ HOST : localhost:5000
5127+ HEADERS:
5128+ Accept: application/vnd.oci.image.manifest.v1&#43;json
5129+ User-Agent: distribution-spec-conformance-tests
5130+ BODY :
5131+ ***** NO CONTENT *****
5132+ ------------------------------------------------------------------------------
5133+ ~~~ RESPONSE ~~~
5134+ STATUS : 200 OK
5135+ PROTO : HTTP/1.1
5136+ RECEIVED AT : 2025-04-13T12:25:03.055219281Z
5137+ TIME DURATION: 645.464µs
5138+ HEADERS :
5139+ Content-Length: 714
5140+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
5141+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5142+ Docker-Content-Digest: sha256:d0154f9c047c63a137a3827d30c53c5a09d50c3ce8385f1eb543603ab5271590
5143+ Docker-Distribution-Api-Version: registry/2.0
5144+ Etag: &#34;sha256:d0154f9c047c63a137a3827d30c53c5a09d50c3ce8385f1eb543603ab5271590&#34;
5145+ X-Content-Type-Options: nosniff
5146+ BODY :
5147+ *** Error: Unable to format response body - &#34;unexpected end of JSON input&#34; ***
5148+
5149+ Log Body as-is:
5150+
5151+ ==============================================================================
5152+
5153+ </pre>
5154+ </div>
5155+ </div>
5156+
5157+
5158+
5159+
5160+ <div class="result green">
5161+ <div id="output-box-12-button" class="toggle" onclick="javascript:toggleOutput('output-box-12')">+</div>
5162+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-12')">HEAD request to manifest[1] path (digest) should yield 200 response</h4>
5163+ <br>
5164+ <div id="output-box-12" style="display: none;">
5165+ <pre class="pre-box">DEBUG
5166+ ==============================================================================
5167+ ~~~ REQUEST ~~~
5168+ HEAD /v2/myorg/myrepo/a/manifests/sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9 HTTP/1.1
5169+ HOST : localhost:5000
5170+ HEADERS:
5171+ Accept: application/vnd.oci.image.manifest.v1&#43;json
5172+ User-Agent: distribution-spec-conformance-tests
5173+ BODY :
5174+ ***** NO CONTENT *****
5175+ ------------------------------------------------------------------------------
5176+ ~~~ RESPONSE ~~~
5177+ STATUS : 200 OK
5178+ PROTO : HTTP/1.1
5179+ RECEIVED AT : 2025-04-13T12:25:03.05608927Z
5180+ TIME DURATION: 661.816µs
5181+ HEADERS :
5182+ Content-Length: 714
5183+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
5184+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5185+ Docker-Content-Digest: sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9
5186+ Docker-Distribution-Api-Version: registry/2.0
5187+ Etag: &#34;sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9&#34;
5188+ X-Content-Type-Options: nosniff
5189+ BODY :
5190+ *** Error: Unable to format response body - &#34;unexpected end of JSON input&#34; ***
5191+
5192+ Log Body as-is:
5193+
5194+ ==============================================================================
5195+
5196+ </pre>
5197+ </div>
5198+ </div>
5199+
5200+
5201+
5202+
5203+ <div class="result green">
5204+ <div id="output-box-13-button" class="toggle" onclick="javascript:toggleOutput('output-box-13')">+</div>
5205+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-13')">HEAD request to manifest path (tag) should yield 200 response</h4>
5206+ <br>
5207+ <div id="output-box-13" style="display: none;">
5208+ <pre class="pre-box">DEBUG
5209+ ==============================================================================
5210+ ~~~ REQUEST ~~~
5211+ HEAD /v2/myorg/myrepo/a/manifests/tagtest0 HTTP/1.1
5212+ HOST : localhost:5000
5213+ HEADERS:
5214+ Accept: application/vnd.oci.image.manifest.v1&#43;json
5215+ User-Agent: distribution-spec-conformance-tests
5216+ BODY :
5217+ ***** NO CONTENT *****
5218+ ------------------------------------------------------------------------------
5219+ ~~~ RESPONSE ~~~
5220+ STATUS : 200 OK
5221+ PROTO : HTTP/1.1
5222+ RECEIVED AT : 2025-04-13T12:25:03.056902383Z
5223+ TIME DURATION: 622.226µs
5224+ HEADERS :
5225+ Content-Length: 714
5226+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
5227+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5228+ Docker-Content-Digest: sha256:d0154f9c047c63a137a3827d30c53c5a09d50c3ce8385f1eb543603ab5271590
5229+ Docker-Distribution-Api-Version: registry/2.0
5230+ Etag: &#34;sha256:d0154f9c047c63a137a3827d30c53c5a09d50c3ce8385f1eb543603ab5271590&#34;
5231+ X-Content-Type-Options: nosniff
5232+ BODY :
5233+ *** Error: Unable to format response body - &#34;unexpected end of JSON input&#34; ***
5234+
5235+ Log Body as-is:
5236+
5237+ ==============================================================================
5238+
5239+ </pre>
5240+ </div>
5241+ </div>
5242+
5243+
5244+
5245+
5246+ <div class="result green">
5247+ <div id="output-box-14-button" class="toggle" onclick="javascript:toggleOutput('output-box-14')">+</div>
5248+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-14')">GET nonexistent manifest should return 404</h4>
5249+ <br>
5250+ <div id="output-box-14" style="display: none;">
5251+ <pre class="pre-box">DEBUG
5252+ ==============================================================================
5253+ ~~~ REQUEST ~~~
5254+ GET /v2/myorg/myrepo/a/manifests/.INVALID_MANIFEST_NAME HTTP/1.1
5255+ HOST : localhost:5000
5256+ HEADERS:
5257+ User-Agent: distribution-spec-conformance-tests
5258+ BODY :
5259+ ***** NO CONTENT *****
5260+ ------------------------------------------------------------------------------
5261+ ~~~ RESPONSE ~~~
5262+ STATUS : 404 Not Found
5263+ PROTO : HTTP/1.1
5264+ RECEIVED AT : 2025-04-13T12:25:03.057189187Z
5265+ TIME DURATION: 106.368µs
5266+ HEADERS :
5267+ Content-Length: 19
5268+ Content-Type: text/plain; charset=utf-8
5269+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5270+ Docker-Distribution-Api-Version: registry/2.0
5271+ X-Content-Type-Options: nosniff
5272+ BODY :
5273+ 404 page not found
5274+ ==============================================================================
5275+
5276+ </pre>
5277+ </div>
5278+ </div>
5279+
5280+
5281+
5282+
5283+ <div class="result green">
5284+ <div id="output-box-15-button" class="toggle" onclick="javascript:toggleOutput('output-box-15')">+</div>
5285+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-15')">GET request to manifest[0] path (digest) should yield 200 response</h4>
5286+ <br>
5287+ <div id="output-box-15" style="display: none;">
5288+ <pre class="pre-box">DEBUG
5289+ ==============================================================================
5290+ ~~~ REQUEST ~~~
5291+ GET /v2/myorg/myrepo/a/manifests/sha256:d0154f9c047c63a137a3827d30c53c5a09d50c3ce8385f1eb543603ab5271590 HTTP/1.1
5292+ HOST : localhost:5000
5293+ HEADERS:
5294+ Accept: application/vnd.oci.image.manifest.v1&#43;json
5295+ User-Agent: distribution-spec-conformance-tests
5296+ BODY :
5297+ ***** NO CONTENT *****
5298+ ------------------------------------------------------------------------------
5299+ ~~~ RESPONSE ~~~
5300+ STATUS : 200 OK
5301+ PROTO : HTTP/1.1
5302+ RECEIVED AT : 2025-04-13T12:25:03.0579284Z
5303+ TIME DURATION: 581.057µs
5304+ HEADERS :
5305+ Content-Length: 714
5306+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
5307+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5308+ Docker-Content-Digest: sha256:d0154f9c047c63a137a3827d30c53c5a09d50c3ce8385f1eb543603ab5271590
5309+ Docker-Distribution-Api-Version: registry/2.0
5310+ Etag: &#34;sha256:d0154f9c047c63a137a3827d30c53c5a09d50c3ce8385f1eb543603ab5271590&#34;
5311+ X-Content-Type-Options: nosniff
5312+ BODY :
5313+ {
5314+ &#34;schemaVersion&#34;: 2,
5315+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.manifest.v1&#43;json&#34;,
5316+ &#34;config&#34;: {
5317+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.config.v1&#43;json&#34;,
5318+ &#34;digest&#34;: &#34;sha256:4ff4c7e8f8cd0ece3cd6a91d2e8eb83d06b1d0f9f1caa06a82d7fe1d6acde544&#34;,
5319+ &#34;size&#34;: 129,
5320+ &#34;data&#34;: &#34;ewoJImF1dGhvciI6ICJITWpZdlp6NEw4VmtBQWpsIiwKCSJhcmNoaXRlY3R1cmUiOiAiYW1kNjQiLAoJIm9zIjogImxpbnV4IiwKCSJyb290ZnMiOiB7CgkJInR5cGUiOiAibGF5ZXJzIiwKCQkiZGlmZl9pZHMiOiBbXQoJfQp9&#34;,
5321+ &#34;newUnspecifiedField&#34;: &#34;aGVsbG8gd29ybGQ=&#34;
5322+ },
5323+ &#34;layers&#34;: [
5324+ {
5325+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.layer.v1.tar&#43;gzip&#34;,
5326+ &#34;digest&#34;: &#34;sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183&#34;,
5327+ &#34;size&#34;: 168,
5328+ &#34;newUnspecifiedField&#34;: null
5329+ }
5330+ ]
5331+ }
5332+ ==============================================================================
5333+
5334+ </pre>
5335+ </div>
5336+ </div>
5337+
5338+
5339+
5340+
5341+ <div class="result green">
5342+ <div id="output-box-16-button" class="toggle" onclick="javascript:toggleOutput('output-box-16')">+</div>
5343+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-16')">GET request to manifest[1] path (digest) should yield 200 response</h4>
5344+ <br>
5345+ <div id="output-box-16" style="display: none;">
5346+ <pre class="pre-box">DEBUG
5347+ ==============================================================================
5348+ ~~~ REQUEST ~~~
5349+ GET /v2/myorg/myrepo/a/manifests/sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9 HTTP/1.1
5350+ HOST : localhost:5000
5351+ HEADERS:
5352+ Accept: application/vnd.oci.image.manifest.v1&#43;json
5353+ User-Agent: distribution-spec-conformance-tests
5354+ BODY :
5355+ ***** NO CONTENT *****
5356+ ------------------------------------------------------------------------------
5357+ ~~~ RESPONSE ~~~
5358+ STATUS : 200 OK
5359+ PROTO : HTTP/1.1
5360+ RECEIVED AT : 2025-04-13T12:25:03.058825064Z
5361+ TIME DURATION: 635.452µs
5362+ HEADERS :
5363+ Content-Length: 714
5364+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
5365+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5366+ Docker-Content-Digest: sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9
5367+ Docker-Distribution-Api-Version: registry/2.0
5368+ Etag: &#34;sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9&#34;
5369+ X-Content-Type-Options: nosniff
5370+ BODY :
5371+ {
5372+ &#34;schemaVersion&#34;: 2,
5373+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.manifest.v1&#43;json&#34;,
5374+ &#34;config&#34;: {
5375+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.config.v1&#43;json&#34;,
5376+ &#34;digest&#34;: &#34;sha256:91ebe32a31a708da89e098c1053ba39ce65b98bc33542e5a588e7bf5b2693ef5&#34;,
5377+ &#34;size&#34;: 129,
5378+ &#34;data&#34;: &#34;ewoJImF1dGhvciI6ICJ0RGRyVEJwUzRHTDE3NlVHIiwKCSJhcmNoaXRlY3R1cmUiOiAiYW1kNjQiLAoJIm9zIjogImxpbnV4IiwKCSJyb290ZnMiOiB7CgkJInR5cGUiOiAibGF5ZXJzIiwKCQkiZGlmZl9pZHMiOiBbXQoJfQp9&#34;,
5379+ &#34;newUnspecifiedField&#34;: &#34;aGVsbG8gd29ybGQ=&#34;
5380+ },
5381+ &#34;layers&#34;: [
5382+ {
5383+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.layer.v1.tar&#43;gzip&#34;,
5384+ &#34;digest&#34;: &#34;sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183&#34;,
5385+ &#34;size&#34;: 168,
5386+ &#34;newUnspecifiedField&#34;: null
5387+ }
5388+ ]
5389+ }
5390+ ==============================================================================
5391+
5392+ </pre>
5393+ </div>
5394+ </div>
5395+
5396+
5397+
5398+
5399+ <div class="result green">
5400+ <div id="output-box-17-button" class="toggle" onclick="javascript:toggleOutput('output-box-17')">+</div>
5401+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-17')">GET request to manifest path (tag) should yield 200 response</h4>
5402+ <br>
5403+ <div id="output-box-17" style="display: none;">
5404+ <pre class="pre-box">DEBUG
5405+ ==============================================================================
5406+ ~~~ REQUEST ~~~
5407+ GET /v2/myorg/myrepo/a/manifests/tagtest0 HTTP/1.1
5408+ HOST : localhost:5000
5409+ HEADERS:
5410+ Accept: application/vnd.oci.image.manifest.v1&#43;json
5411+ User-Agent: distribution-spec-conformance-tests
5412+ BODY :
5413+ ***** NO CONTENT *****
5414+ ------------------------------------------------------------------------------
5415+ ~~~ RESPONSE ~~~
5416+ STATUS : 200 OK
5417+ PROTO : HTTP/1.1
5418+ RECEIVED AT : 2025-04-13T12:25:03.060105139Z
5419+ TIME DURATION: 660.603µs
5420+ HEADERS :
5421+ Content-Length: 714
5422+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
5423+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5424+ Docker-Content-Digest: sha256:d0154f9c047c63a137a3827d30c53c5a09d50c3ce8385f1eb543603ab5271590
5425+ Docker-Distribution-Api-Version: registry/2.0
5426+ Etag: &#34;sha256:d0154f9c047c63a137a3827d30c53c5a09d50c3ce8385f1eb543603ab5271590&#34;
5427+ X-Content-Type-Options: nosniff
5428+ BODY :
5429+ {
5430+ &#34;schemaVersion&#34;: 2,
5431+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.manifest.v1&#43;json&#34;,
5432+ &#34;config&#34;: {
5433+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.config.v1&#43;json&#34;,
5434+ &#34;digest&#34;: &#34;sha256:4ff4c7e8f8cd0ece3cd6a91d2e8eb83d06b1d0f9f1caa06a82d7fe1d6acde544&#34;,
5435+ &#34;size&#34;: 129,
5436+ &#34;data&#34;: &#34;ewoJImF1dGhvciI6ICJITWpZdlp6NEw4VmtBQWpsIiwKCSJhcmNoaXRlY3R1cmUiOiAiYW1kNjQiLAoJIm9zIjogImxpbnV4IiwKCSJyb290ZnMiOiB7CgkJInR5cGUiOiAibGF5ZXJzIiwKCQkiZGlmZl9pZHMiOiBbXQoJfQp9&#34;,
5437+ &#34;newUnspecifiedField&#34;: &#34;aGVsbG8gd29ybGQ=&#34;
5438+ },
5439+ &#34;layers&#34;: [
5440+ {
5441+ &#34;mediaType&#34;: &#34;application/vnd.oci.image.layer.v1.tar&#43;gzip&#34;,
5442+ &#34;digest&#34;: &#34;sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183&#34;,
5443+ &#34;size&#34;: 168,
5444+ &#34;newUnspecifiedField&#34;: null
5445+ }
5446+ ]
5447+ }
5448+ ==============================================================================
5449+
5450+ </pre>
5451+ </div>
5452+ </div>
5453+
5454+ <br>
5455+
5456+
5457+ <h3>Error codes</h3>
5458+
5459+
5460+
5461+
5462+
5463+
5464+ <div class="result red">
5465+ <div id="output-box-18-button" class="toggle" onclick="javascript:toggleOutput('output-box-18')">+</div>
5466+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-18')">400 response body should contain OCI-conforming JSON message</h4>
5467+ <br>
5468+ <div>
5469+ <div id="output-box-18" style="display: none;">
5470+ <pre class="pre-box">DEBUG
5471+ ==============================================================================
5472+ ~~~ REQUEST ~~~
5473+ GET /v2/myorg/myrepo/a/manifests/sha256:totallywrong HTTP/1.1
5474+ HOST : localhost:5000
5475+ HEADERS:
5476+ Content-Type: application/vnd.oci.image.manifest.v1&#43;json
5477+ User-Agent: distribution-spec-conformance-tests
5478+ BODY :
5479+ ***** NO CONTENT *****
5480+ ------------------------------------------------------------------------------
5481+ ~~~ RESPONSE ~~~
5482+ STATUS : 500 Internal Server Error
5483+ PROTO : HTTP/1.1
5484+ RECEIVED AT : 2025-04-13T12:25:03.060978042Z
5485+ TIME DURATION: 609.932µs
5486+ HEADERS :
5487+ Content-Length: 201
5488+ Content-Type: application/json; charset=utf-8
5489+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5490+ Docker-Distribution-Api-Version: registry/2.0
5491+ X-Content-Type-Options: nosniff
5492+ BODY :
5493+ {
5494+ &#34;errors&#34;: [
5495+ {
5496+ &#34;code&#34;: &#34;UNKNOWN&#34;,
5497+ &#34;message&#34;: &#34;unknown error&#34;,
5498+ &#34;detail&#34;: {
5499+ &#34;Path&#34;: &#34;/docker/registry/v2/repositories/myorg/myrepo/a/_manifests/tags/sha256:totallywrong/current/link&#34;,
5500+ &#34;DriverName&#34;: &#34;filesystem&#34;
5501+ }
5502+ }
5503+ ]
5504+ }
5505+
5506+ ==============================================================================
5507+
5508+ </pre>
5509+ </div>
5510+ </div>
5511+ <pre class="fail-message">Expected
5512+ &lt;int&gt;: 500
5513+ To satisfy at least one of these matchers: [%!s(*matchers.EqualMatcher=&amp;{400}) %!s(*matchers.EqualMatcher=&amp;{404})]</pre>
5514+ <br>
5515+ </div>
5516+
5517+ <br>
5518+
5519+
5520+ <h3>Teardown</h3>
5521+
5522+
5523+
5524+
5525+
5526+
5527+ <div class="result green">
5528+ <div id="output-box-19-button" class="toggle" onclick="javascript:toggleOutput('output-box-19')">+</div>
5529+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-19')">Delete config[0] blob created in setup</h4>
5530+ <br>
5531+ <div id="output-box-19" style="display: none;">
5532+ <pre class="pre-box">DEBUG
5533+ ==============================================================================
5534+ ~~~ REQUEST ~~~
5535+ DELETE /v2/myorg/myrepo/a/blobs/sha256:4ff4c7e8f8cd0ece3cd6a91d2e8eb83d06b1d0f9f1caa06a82d7fe1d6acde544 HTTP/1.1
5536+ HOST : localhost:5000
5537+ HEADERS:
5538+ User-Agent: distribution-spec-conformance-tests
5539+ BODY :
5540+ ***** NO CONTENT *****
5541+ ------------------------------------------------------------------------------
5542+ ~~~ RESPONSE ~~~
5543+ STATUS : 405 Method Not Allowed
5544+ PROTO : HTTP/1.1
5545+ RECEIVED AT : 2025-04-13T12:25:03.06184978Z
5546+ TIME DURATION: 550.29µs
5547+ HEADERS :
5548+ Content-Length: 78
5549+ Content-Type: application/json; charset=utf-8
5550+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5551+ Docker-Distribution-Api-Version: registry/2.0
5552+ X-Content-Type-Options: nosniff
5553+ BODY :
5554+ {
5555+ &#34;errors&#34;: [
5556+ {
5557+ &#34;code&#34;: &#34;UNSUPPORTED&#34;,
5558+ &#34;message&#34;: &#34;The operation is unsupported.&#34;
5559+ }
5560+ ]
5561+ }
5562+
5563+ ==============================================================================
5564+
5565+ </pre>
5566+ </div>
5567+ </div>
5568+
5569+
5570+
5571+
5572+ <div class="result green">
5573+ <div id="output-box-20-button" class="toggle" onclick="javascript:toggleOutput('output-box-20')">+</div>
5574+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-20')">Delete config[1] blob created in setup</h4>
5575+ <br>
5576+ <div id="output-box-20" style="display: none;">
5577+ <pre class="pre-box">DEBUG
5578+ ==============================================================================
5579+ ~~~ REQUEST ~~~
5580+ DELETE /v2/myorg/myrepo/a/blobs/sha256:91ebe32a31a708da89e098c1053ba39ce65b98bc33542e5a588e7bf5b2693ef5 HTTP/1.1
5581+ HOST : localhost:5000
5582+ HEADERS:
5583+ User-Agent: distribution-spec-conformance-tests
5584+ BODY :
5585+ ***** NO CONTENT *****
5586+ ------------------------------------------------------------------------------
5587+ ~~~ RESPONSE ~~~
5588+ STATUS : 405 Method Not Allowed
5589+ PROTO : HTTP/1.1
5590+ RECEIVED AT : 2025-04-13T12:25:03.062620919Z
5591+ TIME DURATION: 554.119µs
5592+ HEADERS :
5593+ Content-Length: 78
5594+ Content-Type: application/json; charset=utf-8
5595+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5596+ Docker-Distribution-Api-Version: registry/2.0
5597+ X-Content-Type-Options: nosniff
5598+ BODY :
5599+ {
5600+ &#34;errors&#34;: [
5601+ {
5602+ &#34;code&#34;: &#34;UNSUPPORTED&#34;,
5603+ &#34;message&#34;: &#34;The operation is unsupported.&#34;
5604+ }
5605+ ]
5606+ }
5607+
5608+ ==============================================================================
5609+
5610+ </pre>
5611+ </div>
5612+ </div>
5613+
5614+
5615+
5616+
5617+ <div class="result green">
5618+ <div id="output-box-21-button" class="toggle" onclick="javascript:toggleOutput('output-box-21')">+</div>
5619+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-21')">Delete layer blob created in setup</h4>
5620+ <br>
5621+ <div id="output-box-21" style="display: none;">
5622+ <pre class="pre-box">DEBUG
5623+ ==============================================================================
5624+ ~~~ REQUEST ~~~
5625+ DELETE /v2/myorg/myrepo/a/blobs/sha256:48acff1d91752e957527c1b5416e7376d910bcacf01b9441175f8c270e35c183 HTTP/1.1
5626+ HOST : localhost:5000
5627+ HEADERS:
5628+ User-Agent: distribution-spec-conformance-tests
5629+ BODY :
5630+ ***** NO CONTENT *****
5631+ ------------------------------------------------------------------------------
5632+ ~~~ RESPONSE ~~~
5633+ STATUS : 405 Method Not Allowed
5634+ PROTO : HTTP/1.1
5635+ RECEIVED AT : 2025-04-13T12:25:03.063325816Z
5636+ TIME DURATION: 530.477µs
5637+ HEADERS :
5638+ Content-Length: 78
5639+ Content-Type: application/json; charset=utf-8
5640+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5641+ Docker-Distribution-Api-Version: registry/2.0
5642+ X-Content-Type-Options: nosniff
5643+ BODY :
5644+ {
5645+ &#34;errors&#34;: [
5646+ {
5647+ &#34;code&#34;: &#34;UNSUPPORTED&#34;,
5648+ &#34;message&#34;: &#34;The operation is unsupported.&#34;
5649+ }
5650+ ]
5651+ }
5652+
5653+ ==============================================================================
5654+
5655+ </pre>
5656+ </div>
5657+ </div>
5658+
5659+
5660+
5661+
5662+ <div class="result green">
5663+ <div id="output-box-22-button" class="toggle" onclick="javascript:toggleOutput('output-box-22')">+</div>
5664+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-22')">Delete manifest[0] created in setup</h4>
5665+ <br>
5666+ <div id="output-box-22" style="display: none;">
5667+ <pre class="pre-box">DEBUG
5668+ ==============================================================================
5669+ ~~~ REQUEST ~~~
5670+ DELETE /v2/myorg/myrepo/a/manifests/sha256:d0154f9c047c63a137a3827d30c53c5a09d50c3ce8385f1eb543603ab5271590 HTTP/1.1
5671+ HOST : localhost:5000
5672+ HEADERS:
5673+ User-Agent: distribution-spec-conformance-tests
5674+ BODY :
5675+ ***** NO CONTENT *****
5676+ ------------------------------------------------------------------------------
5677+ ~~~ RESPONSE ~~~
5678+ STATUS : 405 Method Not Allowed
5679+ PROTO : HTTP/1.1
5680+ RECEIVED AT : 2025-04-13T12:25:03.0640344Z
5681+ TIME DURATION: 535.02µs
5682+ HEADERS :
5683+ Content-Length: 78
5684+ Content-Type: application/json; charset=utf-8
5685+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5686+ Docker-Distribution-Api-Version: registry/2.0
5687+ X-Content-Type-Options: nosniff
5688+ BODY :
5689+ {
5690+ &#34;errors&#34;: [
5691+ {
5692+ &#34;code&#34;: &#34;UNSUPPORTED&#34;,
5693+ &#34;message&#34;: &#34;The operation is unsupported.&#34;
5694+ }
5695+ ]
5696+ }
5697+
5698+ ==============================================================================
5699+
5700+ </pre>
5701+ </div>
5702+ </div>
5703+
5704+
5705+
5706+
5707+ <div class="result green">
5708+ <div id="output-box-23-button" class="toggle" onclick="javascript:toggleOutput('output-box-23')">+</div>
5709+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-23')">Delete manifest[1] created in setup</h4>
5710+ <br>
5711+ <div id="output-box-23" style="display: none;">
5712+ <pre class="pre-box">DEBUG
5713+ ==============================================================================
5714+ ~~~ REQUEST ~~~
5715+ DELETE /v2/myorg/myrepo/a/manifests/sha256:0b10c41d8ddd03ca72c3cbe84912f8262908325bd5efae9fb8d61c3221751ce9 HTTP/1.1
5716+ HOST : localhost:5000
5717+ HEADERS:
5718+ User-Agent: distribution-spec-conformance-tests
5719+ BODY :
5720+ ***** NO CONTENT *****
5721+ ------------------------------------------------------------------------------
5722+ ~~~ RESPONSE ~~~
5723+ STATUS : 405 Method Not Allowed
5724+ PROTO : HTTP/1.1
5725+ RECEIVED AT : 2025-04-13T12:25:03.065226499Z
5726+ TIME DURATION: 984.506µs
5727+ HEADERS :
5728+ Content-Length: 78
5729+ Content-Type: application/json; charset=utf-8
5730+ Date: Sun, 13 Apr 2025 12:25:03 GMT
5731+ Docker-Distribution-Api-Version: registry/2.0
5732+ X-Content-Type-Options: nosniff
5733+ BODY :
5734+ {
5735+ &#34;errors&#34;: [
5736+ {
5737+ &#34;code&#34;: &#34;UNSUPPORTED&#34;,
5738+ &#34;message&#34;: &#34;The operation is unsupported.&#34;
5739+ }
5740+ ]
5741+ }
5742+
5743+ ==============================================================================
5744+
5745+ </pre>
5746+ </div>
5747+ </div>
5748+
5749+ <br>
5750+
5751+
5752+
5753+
5754+ </div>
5755+
5756+
5757+
5758+
5759+ <h2>Push</h2>
5760+ <div class="subcategory">
5761+
5762+
5763+ <h3>Blob Upload Streamed</h3>
5764+
5765+
5766+
5767+
5768+
5769+
5770+ <div class="result grey">
5771+ <div id="output-box-24-button" class="toggle" onclick="javascript:toggleOutput('output-box-24')">+</div>
5772+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-24')">PATCH request with blob in body should yield 202 response</h4>
5773+ <br>
5774+ <div id="output-box-24" style="display: none;">
5775+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5776+ OCI_TEST_PULL=1
5777+ OCI_TEST_PUSH=0
5778+ OCI_TEST_CONTENT_DISCOVERY=0
5779+ OCI_TEST_CONTENT_MANAGEMENT=0
5780+ </pre>
5781+ </div>
5782+ </div>
5783+
5784+
5785+
5786+
5787+ <div class="result grey">
5788+ <div id="output-box-25-button" class="toggle" onclick="javascript:toggleOutput('output-box-25')">+</div>
5789+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-25')">PUT request to session URL with digest should yield 201 response</h4>
5790+ <br>
5791+ <div id="output-box-25" style="display: none;">
5792+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5793+ OCI_TEST_PULL=1
5794+ OCI_TEST_PUSH=0
5795+ OCI_TEST_CONTENT_DISCOVERY=0
5796+ OCI_TEST_CONTENT_MANAGEMENT=0
5797+ </pre>
5798+ </div>
5799+ </div>
5800+
5801+ <br>
5802+
5803+
5804+ <h3>Blob Upload Monolithic</h3>
5805+
5806+
5807+
5808+
5809+
5810+
5811+ <div class="result grey">
5812+ <div id="output-box-26-button" class="toggle" onclick="javascript:toggleOutput('output-box-26')">+</div>
5813+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-26')">GET nonexistent blob should result in 404 response</h4>
5814+ <br>
5815+ <div id="output-box-26" style="display: none;">
5816+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5817+ OCI_TEST_PULL=1
5818+ OCI_TEST_PUSH=0
5819+ OCI_TEST_CONTENT_DISCOVERY=0
5820+ OCI_TEST_CONTENT_MANAGEMENT=0
5821+ </pre>
5822+ </div>
5823+ </div>
5824+
5825+
5826+
5827+
5828+ <div class="result grey">
5829+ <div id="output-box-27-button" class="toggle" onclick="javascript:toggleOutput('output-box-27')">+</div>
5830+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-27')">POST request with digest and blob should yield a 201 or 202</h4>
5831+ <br>
5832+ <div id="output-box-27" style="display: none;">
5833+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5834+ OCI_TEST_PULL=1
5835+ OCI_TEST_PUSH=0
5836+ OCI_TEST_CONTENT_DISCOVERY=0
5837+ OCI_TEST_CONTENT_MANAGEMENT=0
5838+ </pre>
5839+ </div>
5840+ </div>
5841+
5842+
5843+
5844+
5845+ <div class="result grey">
5846+ <div id="output-box-28-button" class="toggle" onclick="javascript:toggleOutput('output-box-28')">+</div>
5847+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-28')">GET request to blob URL from prior request should yield 200 or 404 based on response code</h4>
5848+ <br>
5849+ <div id="output-box-28" style="display: none;">
5850+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5851+ OCI_TEST_CONTENT_MANAGEMENT=0
5852+ OCI_TEST_PULL=1
5853+ OCI_TEST_PUSH=0
5854+ OCI_TEST_CONTENT_DISCOVERY=0
5855+ </pre>
5856+ </div>
5857+ </div>
5858+
5859+
5860+
5861+
5862+ <div class="result grey">
5863+ <div id="output-box-29-button" class="toggle" onclick="javascript:toggleOutput('output-box-29')">+</div>
5864+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-29')">POST request should yield a session ID</h4>
5865+ <br>
5866+ <div id="output-box-29" style="display: none;">
5867+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5868+ OCI_TEST_PULL=1
5869+ OCI_TEST_PUSH=0
5870+ OCI_TEST_CONTENT_DISCOVERY=0
5871+ OCI_TEST_CONTENT_MANAGEMENT=0
5872+ </pre>
5873+ </div>
5874+ </div>
5875+
5876+
5877+
5878+
5879+ <div class="result grey">
5880+ <div id="output-box-30-button" class="toggle" onclick="javascript:toggleOutput('output-box-30')">+</div>
5881+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-30')">PUT upload of a blob should yield a 201 Response</h4>
5882+ <br>
5883+ <div id="output-box-30" style="display: none;">
5884+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5885+ OCI_TEST_CONTENT_DISCOVERY=0
5886+ OCI_TEST_CONTENT_MANAGEMENT=0
5887+ OCI_TEST_PULL=1
5888+ OCI_TEST_PUSH=0
5889+ </pre>
5890+ </div>
5891+ </div>
5892+
5893+
5894+
5895+
5896+ <div class="result grey">
5897+ <div id="output-box-31-button" class="toggle" onclick="javascript:toggleOutput('output-box-31')">+</div>
5898+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-31')">GET request to existing blob should yield 200 response</h4>
5899+ <br>
5900+ <div id="output-box-31" style="display: none;">
5901+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5902+ OCI_TEST_CONTENT_DISCOVERY=0
5903+ OCI_TEST_CONTENT_MANAGEMENT=0
5904+ OCI_TEST_PULL=1
5905+ OCI_TEST_PUSH=0
5906+ </pre>
5907+ </div>
5908+ </div>
5909+
5910+
5911+
5912+
5913+ <div class="result grey">
5914+ <div id="output-box-32-button" class="toggle" onclick="javascript:toggleOutput('output-box-32')">+</div>
5915+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-32')">PUT upload of a layer blob should yield a 201 Response</h4>
5916+ <br>
5917+ <div id="output-box-32" style="display: none;">
5918+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5919+ OCI_TEST_PULL=1
5920+ OCI_TEST_PUSH=0
5921+ OCI_TEST_CONTENT_DISCOVERY=0
5922+ OCI_TEST_CONTENT_MANAGEMENT=0
5923+ </pre>
5924+ </div>
5925+ </div>
5926+
5927+
5928+
5929+
5930+ <div class="result grey">
5931+ <div id="output-box-33-button" class="toggle" onclick="javascript:toggleOutput('output-box-33')">+</div>
5932+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-33')">GET request to existing layer should yield 200 response</h4>
5933+ <br>
5934+ <div id="output-box-33" style="display: none;">
5935+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5936+ OCI_TEST_CONTENT_DISCOVERY=0
5937+ OCI_TEST_CONTENT_MANAGEMENT=0
5938+ OCI_TEST_PULL=1
5939+ OCI_TEST_PUSH=0
5940+ </pre>
5941+ </div>
5942+ </div>
5943+
5944+ <br>
5945+
5946+
5947+ <h3>Blob Upload Chunked</h3>
5948+
5949+
5950+
5951+
5952+
5953+
5954+ <div class="result grey">
5955+ <div id="output-box-34-button" class="toggle" onclick="javascript:toggleOutput('output-box-34')">+</div>
5956+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-34')">Out-of-order blob upload should return 416</h4>
5957+ <br>
5958+ <div id="output-box-34" style="display: none;">
5959+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5960+ OCI_TEST_PULL=1
5961+ OCI_TEST_PUSH=0
5962+ OCI_TEST_CONTENT_DISCOVERY=0
5963+ OCI_TEST_CONTENT_MANAGEMENT=0
5964+ </pre>
5965+ </div>
5966+ </div>
5967+
5968+
5969+
5970+
5971+ <div class="result grey">
5972+ <div id="output-box-35-button" class="toggle" onclick="javascript:toggleOutput('output-box-35')">+</div>
5973+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-35')">PATCH request with first chunk should return 202</h4>
5974+ <br>
5975+ <div id="output-box-35" style="display: none;">
5976+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5977+ OCI_TEST_PULL=1
5978+ OCI_TEST_PUSH=0
5979+ OCI_TEST_CONTENT_DISCOVERY=0
5980+ OCI_TEST_CONTENT_MANAGEMENT=0
5981+ </pre>
5982+ </div>
5983+ </div>
5984+
5985+
5986+
5987+
5988+ <div class="result grey">
5989+ <div id="output-box-36-button" class="toggle" onclick="javascript:toggleOutput('output-box-36')">+</div>
5990+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-36')">Retry previous blob chunk should return 416</h4>
5991+ <br>
5992+ <div id="output-box-36" style="display: none;">
5993+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
5994+ OCI_TEST_PULL=1
5995+ OCI_TEST_PUSH=0
5996+ OCI_TEST_CONTENT_DISCOVERY=0
5997+ OCI_TEST_CONTENT_MANAGEMENT=0
5998+ </pre>
5999+ </div>
6000+ </div>
6001+
6002+
6003+
6004+
6005+ <div class="result grey">
6006+ <div id="output-box-37-button" class="toggle" onclick="javascript:toggleOutput('output-box-37')">+</div>
6007+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-37')">Get on stale blob upload should return 204 with a range and location</h4>
6008+ <br>
6009+ <div id="output-box-37" style="display: none;">
6010+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6011+ OCI_TEST_CONTENT_DISCOVERY=0
6012+ OCI_TEST_CONTENT_MANAGEMENT=0
6013+ OCI_TEST_PULL=1
6014+ OCI_TEST_PUSH=0
6015+ </pre>
6016+ </div>
6017+ </div>
6018+
6019+
6020+
6021+
6022+ <div class="result grey">
6023+ <div id="output-box-38-button" class="toggle" onclick="javascript:toggleOutput('output-box-38')">+</div>
6024+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-38')">PATCH request with second chunk should return 202</h4>
6025+ <br>
6026+ <div id="output-box-38" style="display: none;">
6027+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6028+ OCI_TEST_PULL=1
6029+ OCI_TEST_PUSH=0
6030+ OCI_TEST_CONTENT_DISCOVERY=0
6031+ OCI_TEST_CONTENT_MANAGEMENT=0
6032+ </pre>
6033+ </div>
6034+ </div>
6035+
6036+
6037+
6038+
6039+ <div class="result grey">
6040+ <div id="output-box-39-button" class="toggle" onclick="javascript:toggleOutput('output-box-39')">+</div>
6041+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-39')">PUT request with digest should return 201</h4>
6042+ <br>
6043+ <div id="output-box-39" style="display: none;">
6044+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6045+ OCI_TEST_PULL=1
6046+ OCI_TEST_PUSH=0
6047+ OCI_TEST_CONTENT_DISCOVERY=0
6048+ OCI_TEST_CONTENT_MANAGEMENT=0
6049+ </pre>
6050+ </div>
6051+ </div>
6052+
6053+ <br>
6054+
6055+
6056+ <h3>Cross-Repository Blob Mount</h3>
6057+
6058+
6059+
6060+
6061+
6062+
6063+ <div class="result grey">
6064+ <div id="output-box-40-button" class="toggle" onclick="javascript:toggleOutput('output-box-40')">+</div>
6065+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-40')">Cross-mounting of a blob without the from argument should yield session id</h4>
6066+ <br>
6067+ <div id="output-box-40" style="display: none;">
6068+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6069+ OCI_TEST_PULL=1
6070+ OCI_TEST_PUSH=0
6071+ OCI_TEST_CONTENT_DISCOVERY=0
6072+ OCI_TEST_CONTENT_MANAGEMENT=0
6073+ </pre>
6074+ </div>
6075+ </div>
6076+
6077+
6078+
6079+
6080+ <div class="result grey">
6081+ <div id="output-box-41-button" class="toggle" onclick="javascript:toggleOutput('output-box-41')">+</div>
6082+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-41')">POST request to mount another repository&#39;s blob should return 201 or 202</h4>
6083+ <br>
6084+ <div id="output-box-41" style="display: none;">
6085+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6086+ OCI_TEST_PULL=1
6087+ OCI_TEST_PUSH=0
6088+ OCI_TEST_CONTENT_DISCOVERY=0
6089+ OCI_TEST_CONTENT_MANAGEMENT=0
6090+ </pre>
6091+ </div>
6092+ </div>
6093+
6094+
6095+
6096+
6097+ <div class="result grey">
6098+ <div id="output-box-42-button" class="toggle" onclick="javascript:toggleOutput('output-box-42')">+</div>
6099+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-42')">GET request to test digest within cross-mount namespace should return 200</h4>
6100+ <br>
6101+ <div id="output-box-42" style="display: none;">
6102+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6103+ OCI_TEST_PULL=1
6104+ OCI_TEST_PUSH=0
6105+ OCI_TEST_CONTENT_DISCOVERY=0
6106+ OCI_TEST_CONTENT_MANAGEMENT=0
6107+ </pre>
6108+ </div>
6109+ </div>
6110+
6111+
6112+
6113+
6114+ <div class="result grey">
6115+ <div id="output-box-43-button" class="toggle" onclick="javascript:toggleOutput('output-box-43')">+</div>
6116+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-43')">Cross-mounting of nonexistent blob should yield session id</h4>
6117+ <br>
6118+ <div id="output-box-43" style="display: none;">
6119+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6120+ OCI_TEST_CONTENT_MANAGEMENT=0
6121+ OCI_TEST_PULL=1
6122+ OCI_TEST_PUSH=0
6123+ OCI_TEST_CONTENT_DISCOVERY=0
6124+ </pre>
6125+ </div>
6126+ </div>
6127+
6128+
6129+
6130+
6131+ <div class="result grey">
6132+ <div id="output-box-44-button" class="toggle" onclick="javascript:toggleOutput('output-box-44')">+</div>
6133+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-44')">Cross-mounting without from, and automatic content discovery enabled should return a 201</h4>
6134+ <br>
6135+ <div id="output-box-44" style="display: none;">
6136+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6137+ OCI_TEST_PULL=1
6138+ OCI_TEST_PUSH=0
6139+ OCI_TEST_CONTENT_DISCOVERY=0
6140+ OCI_TEST_CONTENT_MANAGEMENT=0
6141+ </pre>
6142+ </div>
6143+ </div>
6144+
6145+
6146+
6147+
6148+ <div class="result grey">
6149+ <div id="output-box-45-button" class="toggle" onclick="javascript:toggleOutput('output-box-45')">+</div>
6150+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-45')">Cross-mounting without from, and automatic content discovery disabled should return a 202</h4>
6151+ <br>
6152+ <div id="output-box-45" style="display: none;">
6153+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6154+ OCI_TEST_PULL=1
6155+ OCI_TEST_PUSH=0
6156+ OCI_TEST_CONTENT_DISCOVERY=0
6157+ OCI_TEST_CONTENT_MANAGEMENT=0
6158+ </pre>
6159+ </div>
6160+ </div>
6161+
6162+ <br>
6163+
6164+
6165+ <h3>Manifest Upload</h3>
6166+
6167+
6168+
6169+
6170+
6171+
6172+ <div class="result grey">
6173+ <div id="output-box-46-button" class="toggle" onclick="javascript:toggleOutput('output-box-46')">+</div>
6174+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-46')">GET nonexistent manifest should return 404</h4>
6175+ <br>
6176+ <div id="output-box-46" style="display: none;">
6177+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6178+ OCI_TEST_CONTENT_MANAGEMENT=0
6179+ OCI_TEST_PULL=1
6180+ OCI_TEST_PUSH=0
6181+ OCI_TEST_CONTENT_DISCOVERY=0
6182+ </pre>
6183+ </div>
6184+ </div>
6185+
6186+
6187+
6188+
6189+ <div class="result grey">
6190+ <div id="output-box-47-button" class="toggle" onclick="javascript:toggleOutput('output-box-47')">+</div>
6191+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-47')">PUT should accept a manifest upload</h4>
6192+ <br>
6193+ <div id="output-box-47" style="display: none;">
6194+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6195+ OCI_TEST_CONTENT_DISCOVERY=0
6196+ OCI_TEST_CONTENT_MANAGEMENT=0
6197+ OCI_TEST_PULL=1
6198+ OCI_TEST_PUSH=0
6199+ </pre>
6200+ </div>
6201+ </div>
6202+
6203+
6204+
6205+
6206+ <div class="result grey">
6207+ <div id="output-box-48-button" class="toggle" onclick="javascript:toggleOutput('output-box-48')">+</div>
6208+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-48')">Registry should accept a manifest upload with no layers</h4>
6209+ <br>
6210+ <div id="output-box-48" style="display: none;">
6211+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6212+ OCI_TEST_PULL=1
6213+ OCI_TEST_PUSH=0
6214+ OCI_TEST_CONTENT_DISCOVERY=0
6215+ OCI_TEST_CONTENT_MANAGEMENT=0
6216+ </pre>
6217+ </div>
6218+ </div>
6219+
6220+
6221+
6222+
6223+ <div class="result grey">
6224+ <div id="output-box-49-button" class="toggle" onclick="javascript:toggleOutput('output-box-49')">+</div>
6225+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-49')">GET request to manifest URL (digest) should yield 200 response</h4>
6226+ <br>
6227+ <div id="output-box-49" style="display: none;">
6228+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6229+ OCI_TEST_PULL=1
6230+ OCI_TEST_PUSH=0
6231+ OCI_TEST_CONTENT_DISCOVERY=0
6232+ OCI_TEST_CONTENT_MANAGEMENT=0
6233+ </pre>
6234+ </div>
6235+ </div>
6236+
6237+ <br>
6238+
6239+
6240+ <h3>Teardown</h3>
6241+
6242+
6243+
6244+
6245+
6246+
6247+ <div class="result grey">
6248+ <div id="output-box-50-button" class="toggle" onclick="javascript:toggleOutput('output-box-50')">+</div>
6249+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-50')">Delete config blob created in tests</h4>
6250+ <br>
6251+ <div id="output-box-50" style="display: none;">
6252+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6253+ OCI_TEST_PULL=1
6254+ OCI_TEST_PUSH=0
6255+ OCI_TEST_CONTENT_DISCOVERY=0
6256+ OCI_TEST_CONTENT_MANAGEMENT=0
6257+ </pre>
6258+ </div>
6259+ </div>
6260+
6261+
6262+
6263+
6264+ <div class="result grey">
6265+ <div id="output-box-51-button" class="toggle" onclick="javascript:toggleOutput('output-box-51')">+</div>
6266+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-51')">Delete layer blob created in setup</h4>
6267+ <br>
6268+ <div id="output-box-51" style="display: none;">
6269+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6270+ OCI_TEST_PULL=1
6271+ OCI_TEST_PUSH=0
6272+ OCI_TEST_CONTENT_DISCOVERY=0
6273+ OCI_TEST_CONTENT_MANAGEMENT=0
6274+ </pre>
6275+ </div>
6276+ </div>
6277+
6278+
6279+
6280+
6281+ <div class="result grey">
6282+ <div id="output-box-52-button" class="toggle" onclick="javascript:toggleOutput('output-box-52')">+</div>
6283+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-52')">Delete manifest created in tests</h4>
6284+ <br>
6285+ <div id="output-box-52" style="display: none;">
6286+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6287+ OCI_TEST_PUSH=0
6288+ OCI_TEST_CONTENT_DISCOVERY=0
6289+ OCI_TEST_CONTENT_MANAGEMENT=0
6290+ OCI_TEST_PULL=1
6291+ </pre>
6292+ </div>
6293+ </div>
6294+
6295+ <br>
6296+
6297+
6298+
6299+
6300+ </div>
6301+
6302+
6303+
6304+
6305+ <h2>Content Discovery</h2>
6306+ <div class="subcategory">
6307+
6308+
6309+ <h3>Setup</h3>
6310+
6311+
6312+
6313+
6314+
6315+
6316+ <div class="result grey">
6317+ <div id="output-box-53-button" class="toggle" onclick="javascript:toggleOutput('output-box-53')">+</div>
6318+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-53')">Populate registry with test blob</h4>
6319+ <br>
6320+ <div id="output-box-53" style="display: none;">
6321+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6322+ OCI_TEST_PULL=1
6323+ OCI_TEST_PUSH=0
6324+ OCI_TEST_CONTENT_DISCOVERY=0
6325+ OCI_TEST_CONTENT_MANAGEMENT=0
6326+ </pre>
6327+ </div>
6328+ </div>
6329+
6330+
6331+
6332+
6333+ <div class="result grey">
6334+ <div id="output-box-54-button" class="toggle" onclick="javascript:toggleOutput('output-box-54')">+</div>
6335+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-54')">Populate registry with test layer</h4>
6336+ <br>
6337+ <div id="output-box-54" style="display: none;">
6338+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6339+ OCI_TEST_PULL=1
6340+ OCI_TEST_PUSH=0
6341+ OCI_TEST_CONTENT_DISCOVERY=0
6342+ OCI_TEST_CONTENT_MANAGEMENT=0
6343+ </pre>
6344+ </div>
6345+ </div>
6346+
6347+
6348+
6349+
6350+ <div class="result grey">
6351+ <div id="output-box-55-button" class="toggle" onclick="javascript:toggleOutput('output-box-55')">+</div>
6352+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-55')">Populate registry with test tags</h4>
6353+ <br>
6354+ <div id="output-box-55" style="display: none;">
6355+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6356+ OCI_TEST_PUSH=0
6357+ OCI_TEST_CONTENT_DISCOVERY=0
6358+ OCI_TEST_CONTENT_MANAGEMENT=0
6359+ OCI_TEST_PULL=1
6360+ </pre>
6361+ </div>
6362+ </div>
6363+
6364+
6365+
6366+
6367+ <div class="result grey">
6368+ <div id="output-box-56-button" class="toggle" onclick="javascript:toggleOutput('output-box-56')">+</div>
6369+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-56')">Populate registry with test tags (no push)</h4>
6370+ <br>
6371+ <div id="output-box-56" style="display: none;">
6372+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6373+ OCI_TEST_PULL=1
6374+ OCI_TEST_PUSH=0
6375+ OCI_TEST_CONTENT_DISCOVERY=0
6376+ OCI_TEST_CONTENT_MANAGEMENT=0
6377+ </pre>
6378+ </div>
6379+ </div>
6380+
6381+
6382+
6383+
6384+ <div class="result grey">
6385+ <div id="output-box-57-button" class="toggle" onclick="javascript:toggleOutput('output-box-57')">+</div>
6386+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-57')">References setup</h4>
6387+ <br>
6388+ <div id="output-box-57" style="display: none;">
6389+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6390+ OCI_TEST_PULL=1
6391+ OCI_TEST_PUSH=0
6392+ OCI_TEST_CONTENT_DISCOVERY=0
6393+ OCI_TEST_CONTENT_MANAGEMENT=0
6394+ </pre>
6395+ </div>
6396+ </div>
6397+
6398+ <br>
6399+
6400+
6401+ <h3>Test content discovery endpoints (listing tags)</h3>
6402+
6403+
6404+
6405+
6406+
6407+
6408+ <div class="result grey">
6409+ <div id="output-box-58-button" class="toggle" onclick="javascript:toggleOutput('output-box-58')">+</div>
6410+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-58')">GET request to list tags should yield 200 response</h4>
6411+ <br>
6412+ <div id="output-box-58" style="display: none;">
6413+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6414+ OCI_TEST_PULL=1
6415+ OCI_TEST_PUSH=0
6416+ OCI_TEST_CONTENT_DISCOVERY=0
6417+ OCI_TEST_CONTENT_MANAGEMENT=0
6418+ </pre>
6419+ </div>
6420+ </div>
6421+
6422+
6423+
6424+
6425+ <div class="result grey">
6426+ <div id="output-box-59-button" class="toggle" onclick="javascript:toggleOutput('output-box-59')">+</div>
6427+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-59')">GET number of tags should be limitable by `n` query parameter</h4>
6428+ <br>
6429+ <div id="output-box-59" style="display: none;">
6430+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6431+ OCI_TEST_PULL=1
6432+ OCI_TEST_PUSH=0
6433+ OCI_TEST_CONTENT_DISCOVERY=0
6434+ OCI_TEST_CONTENT_MANAGEMENT=0
6435+ </pre>
6436+ </div>
6437+ </div>
6438+
6439+
6440+
6441+
6442+ <div class="result grey">
6443+ <div id="output-box-60-button" class="toggle" onclick="javascript:toggleOutput('output-box-60')">+</div>
6444+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-60')">GET start of tag is set by `last` query parameter</h4>
6445+ <br>
6446+ <div id="output-box-60" style="display: none;">
6447+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6448+ OCI_TEST_PUSH=0
6449+ OCI_TEST_CONTENT_DISCOVERY=0
6450+ OCI_TEST_CONTENT_MANAGEMENT=0
6451+ OCI_TEST_PULL=1
6452+ </pre>
6453+ </div>
6454+ </div>
6455+
6456+ <br>
6457+
6458+
6459+ <h3>Test content discovery endpoints (listing references)</h3>
6460+
6461+
6462+
6463+
6464+
6465+
6466+ <div class="result grey">
6467+ <div id="output-box-61-button" class="toggle" onclick="javascript:toggleOutput('output-box-61')">+</div>
6468+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-61')">GET request to nonexistent blob should result in empty 200 response</h4>
6469+ <br>
6470+ <div id="output-box-61" style="display: none;">
6471+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6472+ OCI_TEST_PULL=1
6473+ OCI_TEST_PUSH=0
6474+ OCI_TEST_CONTENT_DISCOVERY=0
6475+ OCI_TEST_CONTENT_MANAGEMENT=0
6476+ </pre>
6477+ </div>
6478+ </div>
6479+
6480+
6481+
6482+
6483+ <div class="result grey">
6484+ <div id="output-box-62-button" class="toggle" onclick="javascript:toggleOutput('output-box-62')">+</div>
6485+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-62')">GET request to existing blob should yield 200</h4>
6486+ <br>
6487+ <div id="output-box-62" style="display: none;">
6488+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6489+ OCI_TEST_PULL=1
6490+ OCI_TEST_PUSH=0
6491+ OCI_TEST_CONTENT_DISCOVERY=0
6492+ OCI_TEST_CONTENT_MANAGEMENT=0
6493+ </pre>
6494+ </div>
6495+ </div>
6496+
6497+
6498+
6499+
6500+ <div class="result grey">
6501+ <div id="output-box-63-button" class="toggle" onclick="javascript:toggleOutput('output-box-63')">+</div>
6502+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-63')">GET request to existing blob with filter should yield 200</h4>
6503+ <br>
6504+ <div id="output-box-63" style="display: none;">
6505+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6506+ OCI_TEST_PULL=1
6507+ OCI_TEST_PUSH=0
6508+ OCI_TEST_CONTENT_DISCOVERY=0
6509+ OCI_TEST_CONTENT_MANAGEMENT=0
6510+ </pre>
6511+ </div>
6512+ </div>
6513+
6514+
6515+
6516+
6517+ <div class="result grey">
6518+ <div id="output-box-64-button" class="toggle" onclick="javascript:toggleOutput('output-box-64')">+</div>
6519+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-64')">GET request to missing manifest should yield 200</h4>
6520+ <br>
6521+ <div id="output-box-64" style="display: none;">
6522+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6523+ OCI_TEST_PULL=1
6524+ OCI_TEST_PUSH=0
6525+ OCI_TEST_CONTENT_DISCOVERY=0
6526+ OCI_TEST_CONTENT_MANAGEMENT=0
6527+ </pre>
6528+ </div>
6529+ </div>
6530+
6531+ <br>
6532+
6533+
6534+ <h3>Teardown</h3>
6535+
6536+
6537+
6538+
6539+
6540+
6541+ <div class="result grey">
6542+ <div id="output-box-65-button" class="toggle" onclick="javascript:toggleOutput('output-box-65')">+</div>
6543+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-65')">Delete config blob created in tests</h4>
6544+ <br>
6545+ <div id="output-box-65" style="display: none;">
6546+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6547+ OCI_TEST_PULL=1
6548+ OCI_TEST_PUSH=0
6549+ OCI_TEST_CONTENT_DISCOVERY=0
6550+ OCI_TEST_CONTENT_MANAGEMENT=0
6551+ </pre>
6552+ </div>
6553+ </div>
6554+
6555+
6556+
6557+
6558+ <div class="result grey">
6559+ <div id="output-box-66-button" class="toggle" onclick="javascript:toggleOutput('output-box-66')">+</div>
6560+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-66')">Delete layer blob created in setup</h4>
6561+ <br>
6562+ <div id="output-box-66" style="display: none;">
6563+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6564+ OCI_TEST_PULL=1
6565+ OCI_TEST_PUSH=0
6566+ OCI_TEST_CONTENT_DISCOVERY=0
6567+ OCI_TEST_CONTENT_MANAGEMENT=0
6568+ </pre>
6569+ </div>
6570+ </div>
6571+
6572+
6573+
6574+
6575+ <div class="result grey">
6576+ <div id="output-box-67-button" class="toggle" onclick="javascript:toggleOutput('output-box-67')">+</div>
6577+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-67')">Delete created manifest &amp; associated tags</h4>
6578+ <br>
6579+ <div id="output-box-67" style="display: none;">
6580+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6581+ OCI_TEST_PULL=1
6582+ OCI_TEST_PUSH=0
6583+ OCI_TEST_CONTENT_DISCOVERY=0
6584+ OCI_TEST_CONTENT_MANAGEMENT=0
6585+ </pre>
6586+ </div>
6587+ </div>
6588+
6589+
6590+
6591+
6592+ <div class="result grey">
6593+ <div id="output-box-68-button" class="toggle" onclick="javascript:toggleOutput('output-box-68')">+</div>
6594+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-68')">References teardown</h4>
6595+ <br>
6596+ <div id="output-box-68" style="display: none;">
6597+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6598+ OCI_TEST_PULL=1
6599+ OCI_TEST_PUSH=0
6600+ OCI_TEST_CONTENT_DISCOVERY=0
6601+ OCI_TEST_CONTENT_MANAGEMENT=0
6602+ </pre>
6603+ </div>
6604+ </div>
6605+
6606+ <br>
6607+
6608+
6609+
6610+
6611+ </div>
6612+
6613+
6614+
6615+
6616+ <h2>Content Management</h2>
6617+ <div class="subcategory">
6618+
6619+
6620+ <h3>Setup</h3>
6621+
6622+
6623+
6624+
6625+
6626+
6627+ <div class="result grey">
6628+ <div id="output-box-69-button" class="toggle" onclick="javascript:toggleOutput('output-box-69')">+</div>
6629+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-69')">Populate registry with test config blob</h4>
6630+ <br>
6631+ <div id="output-box-69" style="display: none;">
6632+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6633+ OCI_TEST_PULL=1
6634+ OCI_TEST_PUSH=0
6635+ OCI_TEST_CONTENT_DISCOVERY=0
6636+ OCI_TEST_CONTENT_MANAGEMENT=0
6637+ </pre>
6638+ </div>
6639+ </div>
6640+
6641+
6642+
6643+
6644+ <div class="result grey">
6645+ <div id="output-box-70-button" class="toggle" onclick="javascript:toggleOutput('output-box-70')">+</div>
6646+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-70')">Populate registry with test layer</h4>
6647+ <br>
6648+ <div id="output-box-70" style="display: none;">
6649+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6650+ OCI_TEST_PULL=1
6651+ OCI_TEST_PUSH=0
6652+ OCI_TEST_CONTENT_DISCOVERY=0
6653+ OCI_TEST_CONTENT_MANAGEMENT=0
6654+ </pre>
6655+ </div>
6656+ </div>
6657+
6658+
6659+
6660+
6661+ <div class="result grey">
6662+ <div id="output-box-71-button" class="toggle" onclick="javascript:toggleOutput('output-box-71')">+</div>
6663+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-71')">Populate registry with test tag</h4>
6664+ <br>
6665+ <div id="output-box-71" style="display: none;">
6666+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6667+ OCI_TEST_PUSH=0
6668+ OCI_TEST_CONTENT_DISCOVERY=0
6669+ OCI_TEST_CONTENT_MANAGEMENT=0
6670+ OCI_TEST_PULL=1
6671+ </pre>
6672+ </div>
6673+ </div>
6674+
6675+
6676+
6677+
6678+ <div class="result grey">
6679+ <div id="output-box-72-button" class="toggle" onclick="javascript:toggleOutput('output-box-72')">+</div>
6680+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-72')">Check how many tags there are before anything gets deleted</h4>
6681+ <br>
6682+ <div id="output-box-72" style="display: none;">
6683+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6684+ OCI_TEST_PULL=1
6685+ OCI_TEST_PUSH=0
6686+ OCI_TEST_CONTENT_DISCOVERY=0
6687+ OCI_TEST_CONTENT_MANAGEMENT=0
6688+ </pre>
6689+ </div>
6690+ </div>
6691+
6692+ <br>
6693+
6694+
6695+ <h3>Manifest delete</h3>
6696+
6697+
6698+
6699+
6700+
6701+
6702+ <div class="result grey">
6703+ <div id="output-box-73-button" class="toggle" onclick="javascript:toggleOutput('output-box-73')">+</div>
6704+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-73')">DELETE request to manifest tag should return 202, unless tag deletion is disallowed (400/405)</h4>
6705+ <br>
6706+ <div id="output-box-73" style="display: none;">
6707+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6708+ OCI_TEST_CONTENT_DISCOVERY=0
6709+ OCI_TEST_CONTENT_MANAGEMENT=0
6710+ OCI_TEST_PULL=1
6711+ OCI_TEST_PUSH=0
6712+ </pre>
6713+ </div>
6714+ </div>
6715+
6716+
6717+
6718+
6719+ <div class="result grey">
6720+ <div id="output-box-74-button" class="toggle" onclick="javascript:toggleOutput('output-box-74')">+</div>
6721+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-74')">DELETE request to manifest (digest) should yield 202 response unless already deleted</h4>
6722+ <br>
6723+ <div id="output-box-74" style="display: none;">
6724+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6725+ OCI_TEST_PUSH=0
6726+ OCI_TEST_CONTENT_DISCOVERY=0
6727+ OCI_TEST_CONTENT_MANAGEMENT=0
6728+ OCI_TEST_PULL=1
6729+ </pre>
6730+ </div>
6731+ </div>
6732+
6733+
6734+
6735+
6736+ <div class="result grey">
6737+ <div id="output-box-75-button" class="toggle" onclick="javascript:toggleOutput('output-box-75')">+</div>
6738+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-75')">GET request to deleted manifest URL should yield 404 response, unless delete is disallowed</h4>
6739+ <br>
6740+ <div id="output-box-75" style="display: none;">
6741+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6742+ OCI_TEST_PULL=1
6743+ OCI_TEST_PUSH=0
6744+ OCI_TEST_CONTENT_DISCOVERY=0
6745+ OCI_TEST_CONTENT_MANAGEMENT=0
6746+ </pre>
6747+ </div>
6748+ </div>
6749+
6750+
6751+
6752+
6753+ <div class="result grey">
6754+ <div id="output-box-76-button" class="toggle" onclick="javascript:toggleOutput('output-box-76')">+</div>
6755+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-76')">GET request to tags list should reflect manifest deletion</h4>
6756+ <br>
6757+ <div id="output-box-76" style="display: none;">
6758+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6759+ OCI_TEST_PULL=1
6760+ OCI_TEST_PUSH=0
6761+ OCI_TEST_CONTENT_DISCOVERY=0
6762+ OCI_TEST_CONTENT_MANAGEMENT=0
6763+ </pre>
6764+ </div>
6765+ </div>
6766+
6767+ <br>
6768+
6769+
6770+ <h3>Blob delete</h3>
6771+
6772+
6773+
6774+
6775+
6776+
6777+ <div class="result grey">
6778+ <div id="output-box-77-button" class="toggle" onclick="javascript:toggleOutput('output-box-77')">+</div>
6779+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-77')">DELETE request to blob URL should yield 202 response</h4>
6780+ <br>
6781+ <div id="output-box-77" style="display: none;">
6782+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6783+ OCI_TEST_PULL=1
6784+ OCI_TEST_PUSH=0
6785+ OCI_TEST_CONTENT_DISCOVERY=0
6786+ OCI_TEST_CONTENT_MANAGEMENT=0
6787+ </pre>
6788+ </div>
6789+ </div>
6790+
6791+
6792+
6793+
6794+ <div class="result grey">
6795+ <div id="output-box-78-button" class="toggle" onclick="javascript:toggleOutput('output-box-78')">+</div>
6796+ <h4 style="display: inline;" onclick="javascript:toggleOutput('output-box-78')">GET request to deleted blob URL should yield 404 response</h4>
6797+ <br>
6798+ <div id="output-box-78" style="display: none;">
6799+ <pre class="pre-box">you have skipped this test; if this is an error, check your environment variable settings:
6800+ OCI_TEST_PULL=1
6801+ OCI_TEST_PUSH=0
6802+ OCI_TEST_CONTENT_DISCOVERY=0
6803+ OCI_TEST_CONTENT_MANAGEMENT=0
6804+ </pre>
6805+ </div>
6806+ </div>
6807+
6808+ <br>
6809+
6810+
6811+
6812+
6813+ </div>
6814+
6815+
6816+ </div>
6817+ </body>
6818+ </html>
6819 diff --git a/scripts/conformance_test.sh b/scripts/conformance_test.sh
6820new file mode 100755
6821index 0000000..edcc388
6822--- /dev/null
6823+++ b/scripts/conformance_test.sh
6824 @@ -0,0 +1,24 @@
6825+ #!/bin/sh
6826+ # Build a container from https://github.com/opencontainers/distribution-spec/tree/main/conformance first
6827+
6828+ IMAGE_NAME="conformance:latest"
6829+ HOSTNAME="http://localhost:8700"
6830+
6831+ mkdir -p results
6832+
6833+ podman run --rm \
6834+ --net=host \
6835+ -v $(pwd)/results:/results \
6836+ -w /results \
6837+ -e OCI_ROOT_URL="$HOSTNAME" \
6838+ -e OCI_NAMESPACE="myorg/myrepo/a" \
6839+ -e OCI_USERNAME="myuser" \
6840+ -e OCI_PASSWORD="mypass" \
6841+ -e OCI_TEST_PULL=1 \
6842+ -e OCI_TEST_PUSH=0 \
6843+ -e OCI_TEST_CONTENT_DISCOVERY=0 \
6844+ -e OCI_TEST_CONTENT_MANAGEMENT=0 \
6845+ -e OCI_HIDE_SKIPPED_WORKFLOWS=0 \
6846+ -e OCI_DEBUG=0 \
6847+ -e OCI_DELETE_MANIFEST_BEFORE_BLOBS=0 \
6848+ "$IMAGE_NAME"
6849 diff --git a/src/address.rs b/src/address.rs
6850new file mode 100644
6851index 0000000..bd34217
6852--- /dev/null
6853+++ b/src/address.rs
6854 @@ -0,0 +1,258 @@
6855+ use std::{
6856+ fmt::Display,
6857+ path::{Path, PathBuf},
6858+ };
6859+
6860+ use oci_spec::image::Digest;
6861+ use relative_path::RelativePath;
6862+ use uuid::Uuid;
6863+
6864+ use crate::Namespace;
6865+
6866+ const SEPARATOR: &str = "/";
6867+
6868+ fn digest_prefix(digest: &Digest) -> &str {
6869+ match digest.algorithm() {
6870+ oci_spec::image::DigestAlgorithm::Sha256 => "sha256",
6871+ oci_spec::image::DigestAlgorithm::Sha384 => "sha384",
6872+ oci_spec::image::DigestAlgorithm::Sha512 => "sha512",
6873+ oci_spec::image::DigestAlgorithm::Other(_) => todo!(),
6874+ _ => todo!(),
6875+ }
6876+ }
6877+
6878+ pub trait Addressable {
6879+ fn address(&self) -> Address;
6880+ }
6881+
6882+ /// Address is a path-like object for addressing OCI objects. The design of
6883+ /// this basically copies the file system layout used by the Docker
6884+ /// distribution registry. https://github.com/distribution/distribution
6885+ #[derive(Debug, Clone)]
6886+ pub struct Address {
6887+ parts: Vec<String>,
6888+ }
6889+
6890+ impl Address {
6891+ pub fn as_path(&self, base_dir: &Path) -> PathBuf {
6892+ let parts = self.parts.join(SEPARATOR);
6893+ RelativePath::new(&parts).to_path(base_dir)
6894+ }
6895+
6896+ pub fn is_link(&self) -> bool {
6897+ self.parts.last().is_some_and(|part| part == "link")
6898+ }
6899+
6900+ pub fn is_data(&self) -> bool {
6901+ self.parts.last().is_some_and(|part| part == "data")
6902+ }
6903+
6904+ pub fn name(&self) -> String {
6905+ self.parts.last().cloned().unwrap()
6906+ }
6907+
6908+ // /// Create an addressable link
6909+ // pub fn link(addr: &impl Addressable) -> Self {
6910+ // let mut parts = addr.parts();
6911+ // parts.push(String::from("link"));
6912+ // Address { parts }
6913+ // }
6914+
6915+ // /// create an addressable data path
6916+ // pub fn data(addr: &impl Addressable) -> Self {
6917+ // let mut parts = addr.parts();
6918+ // parts.push(String::from("data"));
6919+ // Address { parts }
6920+ // }
6921+ }
6922+
6923+ impl Display for Address {
6924+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6925+ f.write_str(&self.parts.join(SEPARATOR))
6926+ }
6927+ }
6928+
6929+ impl Addressable for Address {
6930+ fn address(&self) -> Address {
6931+ self.clone()
6932+ }
6933+ }
6934+
6935+ impl From<&Vec<&str>> for Address {
6936+ fn from(value: &Vec<&str>) -> Self {
6937+ Address {
6938+ parts: value.iter().map(|part| part.to_string()).collect(),
6939+ }
6940+ }
6941+ }
6942+
6943+ /// The directory that contains all tags for a certian namespace
6944+ pub struct TagDirectory<'a> {
6945+ pub namespace: &'a Namespace,
6946+ }
6947+
6948+ impl<'a> From<&'a Namespace> for TagDirectory<'a> {
6949+ fn from(value: &'a Namespace) -> Self {
6950+ TagDirectory { namespace: value }
6951+ }
6952+ }
6953+
6954+ impl Addressable for TagDirectory<'_> {
6955+ fn address(&self) -> Address {
6956+ (&vec![&self.namespace.as_ref(), "tags"]).into()
6957+ }
6958+ }
6959+
6960+ /// Path to a tag within a repository namespace
6961+ pub struct Tag<'a> {
6962+ pub namespace: &'a Namespace,
6963+ pub name: &'a str,
6964+ }
6965+
6966+ impl Addressable for Tag<'_> {
6967+ fn address(&self) -> Address {
6968+ (&vec![
6969+ "repositories",
6970+ &self.namespace.as_ref(),
6971+ "tags",
6972+ self.name,
6973+ "current",
6974+ "link",
6975+ ])
6976+ .into()
6977+ }
6978+ }
6979+
6980+ pub struct Reference<'a> {
6981+ pub namespace: &'a Namespace,
6982+ pub digest: &'a Digest,
6983+ }
6984+
6985+ impl Addressable for Reference<'_> {
6986+ fn address(&self) -> Address {
6987+ (&vec![
6988+ "repositories",
6989+ &self.namespace.as_ref(),
6990+ "manifests",
6991+ "revisions",
6992+ digest_prefix(self.digest),
6993+ self.digest.digest(),
6994+ "link",
6995+ ])
6996+ .into()
6997+ }
6998+ }
6999+
7000+ /// Path to a temporary blob used during uploads
7001+ pub struct TempBlob<'a> {
7002+ pub uuid: &'a Uuid,
7003+ pub namespace: &'a Namespace,
7004+ }
7005+
7006+ impl Addressable for TempBlob<'_> {
7007+ fn address(&self) -> Address {
7008+ (&vec!["repositories", &self.namespace.as_ref(), "tmp", &self.uuid.to_string()]).into()
7009+ }
7010+ }
7011+
7012+ /// Path to a blob file on disk
7013+ pub struct Blob<'a> {
7014+ pub digest: &'a Digest,
7015+ }
7016+
7017+ impl<'a> From<&'a Digest> for Blob<'a> {
7018+ fn from(value: &'a Digest) -> Self {
7019+ Blob { digest: value }
7020+ }
7021+ }
7022+
7023+ impl Addressable for Blob<'_> {
7024+ fn address(&self) -> Address {
7025+ let digest_str = self.digest.digest();
7026+ let first_two: String = digest_str.chars().take(2).collect();
7027+ (&vec!["blobs", digest_prefix(self.digest), &first_two, digest_str]).into()
7028+ }
7029+ }
7030+
7031+ /// ManifestRevision is a link to a blob on disk
7032+ pub struct ManifestRevision<'a> {
7033+ pub namespace: &'a Namespace,
7034+ pub digest: &'a Digest,
7035+ }
7036+
7037+ impl Addressable for ManifestRevision<'_> {
7038+ fn address(&self) -> Address {
7039+ let digest_str = self.digest.digest();
7040+ (&vec![
7041+ "repositories",
7042+ &self.namespace.as_ref(),
7043+ "manifests",
7044+ "revisions",
7045+ digest_prefix(self.digest),
7046+ &digest_str,
7047+ "link",
7048+ ])
7049+ .into()
7050+ }
7051+ }
7052+
7053+ pub struct LayerLink<'a> {
7054+ pub namespace: &'a Namespace,
7055+ pub digest: &'a Digest,
7056+ }
7057+
7058+ impl Addressable for LayerLink<'_> {
7059+ fn address(&self) -> Address {
7060+ let digest_str = self.digest.digest();
7061+ (&vec![
7062+ "repositories",
7063+ self.namespace.as_ref(),
7064+ "layers",
7065+ digest_prefix(self.digest),
7066+ &digest_str,
7067+ "link",
7068+ ])
7069+ .into()
7070+ }
7071+ }
7072+
7073+ #[cfg(test)]
7074+ mod test {
7075+ use std::str::FromStr;
7076+
7077+ use super::*;
7078+
7079+ #[test]
7080+ pub fn addresses() {
7081+ let namespace = Namespace::from_str("hello/world").unwrap();
7082+ assert!(&TagDirectory::from(&namespace).address().to_string() == "hello/world/tags");
7083+ assert!(
7084+ &Tag {
7085+ namespace: &namespace,
7086+ name: "latest"
7087+ }
7088+ .address()
7089+ .to_string()
7090+ == "repositories/hello/world/tags/latest/current/link"
7091+ );
7092+ let uuid = Uuid::new_v4();
7093+ assert!(TempBlob{uuid: &uuid, namespace: &namespace}.address().to_string() == format!("repositories/hello/world/tmp/{}", uuid));
7094+ let digest = Digest::from_str(
7095+ "sha256:57f2ae062b76cff6f5a511fe6f907decfdefd6495e6afa31c44e0a6a1eca146f",
7096+ )
7097+ .unwrap();
7098+ assert!(
7099+ Blob { digest: &digest }.address().to_string()
7100+ == "blobs/sha256/57/57f2ae062b76cff6f5a511fe6f907decfdefd6495e6afa31c44e0a6a1eca146f"
7101+ );
7102+ assert!(
7103+ ManifestRevision {
7104+ namespace: &namespace,
7105+ digest: &digest
7106+ }
7107+ .address()
7108+ .to_string()
7109+ == "repositories/hello/world/manifests/revisions/sha256/57f2ae062b76cff6f5a511fe6f907decfdefd6495e6afa31c44e0a6a1eca146f/link"
7110+ )
7111+ }
7112+ }
7113 diff --git a/src/axum/error.rs b/src/axum/error.rs
7114new file mode 100644
7115index 0000000..3c137e8
7116--- /dev/null
7117+++ b/src/axum/error.rs
7118 @@ -0,0 +1,161 @@
7119+ use std::fmt::Display;
7120+
7121+ use axum::{
7122+ Json,
7123+ extract::rejection::BytesRejection,
7124+ response::{IntoResponse, Response},
7125+ };
7126+ use http::StatusCode;
7127+
7128+ use crate::error::Error as PapyriError;
7129+
7130+ const INTERNAL_SERVER_ERROR: &str = "INTERNAL_SERVER_ERROR";
7131+
7132+ #[derive(thiserror::Error, Debug)]
7133+ pub enum Error {
7134+ #[error("Papyri: {0}")]
7135+ Papyri(#[from] PapyriError),
7136+ #[error("Connection: {0}")]
7137+ Connection(#[from] BytesRejection),
7138+ #[error("Distribution Error: {{0:?}}")]
7139+ Code(Code, Option<String>),
7140+ #[error("Cannot parse UUID: {0}")]
7141+ Uuid(#[from] uuid::Error),
7142+ #[error("OCI Parsing: {0}")]
7143+ OciParsing(#[from] oci_spec::OciSpecError),
7144+ }
7145+
7146+ #[derive(serde::Serialize, Debug)]
7147+ pub struct Message {
7148+ pub code: String,
7149+ pub message: String,
7150+ pub detail: Option<String>,
7151+ }
7152+
7153+ impl From<&Error> for Message {
7154+ fn from(value: &Error) -> Self {
7155+ match value {
7156+ Error::Papyri(error) => Message {
7157+ code: INTERNAL_SERVER_ERROR.to_string(),
7158+ message: String::from("papyri internal error"),
7159+ detail: Some(error.to_string()),
7160+ },
7161+ Error::Connection(bytes_rejection) => Message {
7162+ code: INTERNAL_SERVER_ERROR.to_string(),
7163+ message: String::from("could not read message"),
7164+ detail: Some(bytes_rejection.to_string()),
7165+ },
7166+ Error::Code(code, details) => {
7167+ let (code_str, message) = match code {
7168+ Code::BlobUnknown => ("BLOB_UNKNOWN", "blob unknown to registry"),
7169+ Code::BlobUploadInvalid => ("BLOB_UPLOAD_INVALID", "blob upload invalid"),
7170+ Code::BlobUploadUnknown => {
7171+ ("BLOB_UPLOAD_UNKNOWN", "blob upload unknown to registry")
7172+ }
7173+ Code::DigestInvalid => (
7174+ "DIGEST_INVALID",
7175+ "provided digest did not match uploaded content",
7176+ ),
7177+ Code::ManifestBlobUnknown => (
7178+ "MANIFEST_BLOB_UNKNOWN",
7179+ "manifest references a manifest or blob unknown to registry",
7180+ ),
7181+ Code::ManifestInvalid => ("MANIFEST_INVALID", "manifest invalid"),
7182+ Code::ManifestUnknown => ("MANIFEST_UNKNOWN", "manifest unknown to registry"),
7183+ Code::NameInvalid => ("NAME_INVALID", "invalid repository name"),
7184+ Code::NameUnknown => ("NAME_UNKNOWN", "repository name not known to registry"),
7185+ Code::SizeInvalid => (
7186+ "SIZE_INVALID",
7187+ "provided length did not match content length",
7188+ ),
7189+ Code::Unathorized => ("UNAUTHORIZED", "authorization required"),
7190+ Code::Denied => ("DENIED", "requested access to the resource is denied"),
7191+ Code::Unsupported => ("UNSUPPORTED", "the operation is unsupported"),
7192+ Code::TooManyRequests => ("TOO_MANY_REQUESTS", "too many reuqests"),
7193+ };
7194+ Message {
7195+ code: code_str.to_string(),
7196+ message: message.to_string(),
7197+ detail: details.clone(),
7198+ }
7199+ }
7200+ Error::Uuid(error) => Message {
7201+ code: INTERNAL_SERVER_ERROR.to_string(),
7202+ message: String::from("Cannot parse UUID"),
7203+ detail: Some(error.to_string()),
7204+ },
7205+ Error::OciParsing(oci_spec_error) => Message {
7206+ code: INTERNAL_SERVER_ERROR.to_string(),
7207+ message: String::from("Failed to parse OCI specification"),
7208+ detail: Some(oci_spec_error.to_string()),
7209+ },
7210+ }
7211+ }
7212+ }
7213+
7214+ // | ID | Code | Description |
7215+ // |-------- | ------------------------|------------------------------------------------------------|
7216+ // | code-1 | `BLOB_UNKNOWN` | blob unknown to registry |
7217+ // | code-2 | `BLOB_UPLOAD_INVALID` | blob upload invalid |
7218+ // | code-3 | `BLOB_UPLOAD_UNKNOWN` | blob upload unknown to registry |
7219+ // | code-4 | `DIGEST_INVALID` | provided digest did not match uploaded content |
7220+ // | code-5 | `MANIFEST_BLOB_UNKNOWN` | manifest references a manifest or blob unknown to registry |
7221+ // | code-6 | `MANIFEST_INVALID` | manifest invalid |
7222+ // | code-7 | `MANIFEST_UNKNOWN` | manifest unknown to registry |
7223+ // | code-8 | `NAME_INVALID` | invalid repository name |
7224+ // | code-9 | `NAME_UNKNOWN` | repository name not known to registry |
7225+ // | code-10 | `SIZE_INVALID` | provided length did not match content length |
7226+ // | code-11 | `UNAUTHORIZED` | authentication required |
7227+ // | code-12 | `DENIED` | requested access to the resource is denied |
7228+ // | code-13 | `UNSUPPORTED` | the operation is unsupported |
7229+ // | code-14 | `TOOMANYREQUESTS` | too many requests |
7230+ #[derive(Debug)]
7231+ pub enum Code {
7232+ BlobUnknown,
7233+ BlobUploadInvalid,
7234+ BlobUploadUnknown,
7235+ DigestInvalid,
7236+ ManifestBlobUnknown,
7237+ ManifestInvalid,
7238+ ManifestUnknown,
7239+ NameInvalid,
7240+ NameUnknown,
7241+ SizeInvalid,
7242+ Unathorized,
7243+ Denied,
7244+ Unsupported,
7245+ TooManyRequests,
7246+ }
7247+
7248+ impl Display for Code {
7249+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7250+ write!(f, "{:?}", self)
7251+ }
7252+ }
7253+
7254+ impl std::error::Error for Code {}
7255+
7256+ impl IntoResponse for Error {
7257+ fn into_response(self) -> Response {
7258+ let message = Message::from(&self);
7259+ let message = Json(message);
7260+ let mut res = message.into_response();
7261+ let status_code = res.status_mut();
7262+ if status_code.as_u16() < 400 {
7263+ *status_code = StatusCode::INTERNAL_SERVER_ERROR;
7264+ }
7265+ if let Error::Papyri(PapyriError::Storage(crate::storage::Error::NotFound)) = self {
7266+ *status_code = StatusCode::NOT_FOUND
7267+ }
7268+ if let Error::Code(Code::BlobUnknown, _) = self {
7269+ *status_code = StatusCode::NOT_FOUND
7270+ }
7271+ if let Error::Code(Code::ManifestUnknown, _) = self {
7272+ *status_code = StatusCode::NOT_FOUND
7273+ }
7274+ if let Error::Code(Code::NameUnknown, _) = self {
7275+ *status_code = StatusCode::NOT_FOUND
7276+ }
7277+ res
7278+ }
7279+ }
7280 diff --git a/src/axum/extractors.rs b/src/axum/extractors.rs
7281new file mode 100644
7282index 0000000..8b13789
7283--- /dev/null
7284+++ b/src/axum/extractors.rs
7285 @@ -0,0 +1 @@
7286+
7287 diff --git a/src/axum/handlers.rs b/src/axum/handlers.rs
7288new file mode 100644
7289index 0000000..3fa69bc
7290--- /dev/null
7291+++ b/src/axum/handlers.rs
7292 @@ -0,0 +1,34 @@
7293+ // use std::{str::FromStr, sync::Arc};
7294+ //
7295+ // use super::{AppState, error::Error};
7296+ // use crate::Namespace;
7297+ // use axum::{
7298+ // Extension, Json,
7299+ // body::HttpBody,
7300+ // extract::{FromRequest, Path, Query, Request, State},
7301+ // http::StatusCode,
7302+ // response::{IntoResponse, Response},
7303+ // };
7304+ // use bytes::{Buf, Bytes};
7305+ // use futures::TryStreamExt;
7306+ // use oci_spec::distribution::TagList;
7307+ // use serde_json::json;
7308+ //
7309+ // pub async fn index() -> Result<Json<serde_json::Value>, Error> {
7310+ // Ok(Json(json!({})))
7311+ // }
7312+ //
7313+ // pub(crate) async fn read_tags(
7314+ // State(state): State<Arc<AppState>>,
7315+ // Path(name): Path<String>,
7316+ // ) -> Result<Json<TagList>, Error> {
7317+ // let namespace = Namespace::from_str(&name)?;
7318+ // let tags = state.oci.list_tags(&namespace).await?;
7319+ // Ok(Json(tags))
7320+ // }
7321+ //
7322+ // pub async fn read_referrers() {}
7323+ //
7324+ // pub async fn delete_manifest() {}
7325+ // pub async fn delete_tag() {}
7326+ // pub async fn delete_blob() {}
7327 diff --git a/src/axum/handlers_blob.rs b/src/axum/handlers_blob.rs
7328new file mode 100644
7329index 0000000..53732e2
7330--- /dev/null
7331+++ b/src/axum/handlers_blob.rs
7332 @@ -0,0 +1,158 @@
7333+ use std::{str::FromStr, sync::Arc};
7334+
7335+ use axum::{
7336+ Extension,
7337+ extract::{Path, Query, Request, State},
7338+ response::Response,
7339+ };
7340+ use futures::TryStreamExt;
7341+ use http::{HeaderValue, StatusCode, header::CONTENT_LENGTH};
7342+ use oci_spec::image::Digest;
7343+ use serde::Deserialize;
7344+ use uuid::Uuid;
7345+
7346+ use crate::Namespace;
7347+
7348+ use super::{AppState, error::Error, paths::DigestPath};
7349+
7350+ const OCI_CHUNK_MIN_LENGTH: usize = 10_000_000;
7351+
7352+ fn upload_path(namespace: &Namespace, uuid: &Uuid) -> String {
7353+ format!(
7354+ "/v2/{}/blobs/uploads/{}",
7355+ namespace.to_string().trim_start_matches("/"),
7356+ uuid
7357+ )
7358+ }
7359+
7360+ #[derive(Deserialize)]
7361+ pub struct UploadQuery {
7362+ pub digest: Digest,
7363+ }
7364+
7365+ /// Initiate a blob upload
7366+ /// FIXME: Per the spec for chunked uploads a header of Content-Length: 0
7367+ /// MUST be present (for some reason).
7368+ pub async fn initiate(
7369+ State(state): State<Arc<AppState>>,
7370+ Extension(namespace): Extension<Namespace>,
7371+ ) -> Result<Response, Error> {
7372+ let uuid = state.oci.new_blob(&namespace).await?;
7373+ let mut res = Response::new(axum::body::Body::empty());
7374+ let status = res.status_mut();
7375+ *status = StatusCode::ACCEPTED;
7376+ let headers = res.headers_mut();
7377+ headers.insert("Location", upload_path(&namespace, &uuid).parse().unwrap());
7378+ // FIXME: make configurable
7379+ headers.insert(
7380+ "OCI-Chunk-Min-Length",
7381+ HeaderValue::from_str(&OCI_CHUNK_MIN_LENGTH.to_string()).unwrap(),
7382+ );
7383+ Ok(res)
7384+ }
7385+
7386+ pub async fn read(
7387+ State(state): State<Arc<AppState>>,
7388+ Extension(_namespace): Extension<Namespace>,
7389+ DigestPath(digest): DigestPath,
7390+ ) -> Result<Response, Error> {
7391+ let handle = state.oci.read_blob(&digest).await.map_err(|e| {
7392+ if let crate::error::Error::Storage(crate::storage::Error::NotFound) = e {
7393+ return Error::Code(
7394+ super::error::Code::BlobUnknown,
7395+ Some(format!("No blob with digest {} exists", digest)),
7396+ );
7397+ };
7398+ Error::Papyri(e)
7399+ })?;
7400+ let body = axum::body::Body::from_stream(handle);
7401+ let res = Response::new(body);
7402+ Ok(res)
7403+ }
7404+
7405+ pub async fn stat(
7406+ State(state): State<Arc<AppState>>,
7407+ DigestPath(digest): DigestPath,
7408+ ) -> Result<StatusCode, Error> {
7409+ if !state.oci.has_blob(&digest).await? {
7410+ Err(Error::Code(super::error::Code::BlobUnknown, None))
7411+ } else {
7412+ Ok(StatusCode::OK)
7413+ }
7414+ }
7415+
7416+ pub async fn write_chunk(
7417+ State(state): State<Arc<AppState>>,
7418+ Path(upload_uuid): Path<String>,
7419+ Extension(namespace): Extension<Namespace>,
7420+ req: Request,
7421+ ) -> Result<Response, Error> {
7422+ let uuid = Uuid::from_str(&upload_uuid)?;
7423+ let stream = req.into_body().into_data_stream();
7424+ let stream = stream.map_err(|e| crate::Error::Stream(e.to_string()));
7425+ state
7426+ .oci
7427+ .write_chunk(Box::pin(stream), &namespace, &uuid)
7428+ .await?;
7429+ let mut res = Response::new(axum::body::Body::empty());
7430+ let status = res.status_mut();
7431+ *status = StatusCode::ACCEPTED;
7432+ let headers = res.headers_mut();
7433+ headers.insert("Location", upload_path(&namespace, &uuid).parse().unwrap());
7434+ Ok(res)
7435+ }
7436+
7437+ /// Write a complete blob in one request
7438+ pub async fn write(
7439+ State(state): State<Arc<AppState>>,
7440+ Path(upload_uuid): Path<String>,
7441+ Extension(namespace): Extension<Namespace>,
7442+ Query(query): Query<UploadQuery>,
7443+ req: Request,
7444+ ) -> Result<StatusCode, Error> {
7445+ let uuid = Uuid::from_str(&upload_uuid)?;
7446+ let stream = req.into_body().into_data_stream();
7447+ let stream = stream.map_err(|e| crate::error::Error::Stream(e.to_string()));
7448+ state
7449+ .oci
7450+ .write_chunk(Box::pin(stream), &namespace, &uuid)
7451+ .await?;
7452+ state
7453+ .oci
7454+ .commit_blob(&namespace, &uuid, &query.digest)
7455+ .await?;
7456+ Ok(StatusCode::OK)
7457+ }
7458+
7459+ pub async fn close(
7460+ State(state): State<Arc<AppState>>,
7461+ Path(upload_uuid): Path<String>,
7462+ Extension(namespace): Extension<Namespace>,
7463+ Query(query): Query<UploadQuery>,
7464+ req: Request,
7465+ ) -> Result<StatusCode, Error> {
7466+ let uuid = Uuid::from_str(&upload_uuid)?;
7467+ let headers = req.headers();
7468+ if headers.get(CONTENT_LENGTH).is_some() {
7469+ let stream = req.into_body().into_data_stream();
7470+ let stream = stream.map_err(|e| crate::error::Error::Stream(e.to_string()));
7471+ state
7472+ .oci
7473+ .write_chunk(Box::pin(stream), &namespace, &uuid)
7474+ .await?;
7475+ }
7476+ state
7477+ .oci
7478+ .commit_blob(&namespace, &uuid, &query.digest)
7479+ .await?;
7480+ Ok(StatusCode::CREATED)
7481+ }
7482+
7483+ pub async fn delete(
7484+ State(state): State<Arc<AppState>>,
7485+ Extension(namespace): Extension<Namespace>,
7486+ DigestPath(digest): DigestPath,
7487+ ) -> Result<(), Error> {
7488+ state.oci.delete_blob(&namespace, &digest).await?;
7489+ Ok(())
7490+ }
7491 diff --git a/src/axum/handlers_manifest.rs b/src/axum/handlers_manifest.rs
7492new file mode 100644
7493index 0000000..13fefb5
7494--- /dev/null
7495+++ b/src/axum/handlers_manifest.rs
7496 @@ -0,0 +1,97 @@
7497+ use std::{str::FromStr, sync::Arc};
7498+
7499+ use axum::{
7500+ Extension, Json,
7501+ extract::{FromRequest, Path, Request, State},
7502+ response::{IntoResponse, Response},
7503+ };
7504+ use bytes::{Buf, Bytes};
7505+ use http::{StatusCode, header::CONTENT_TYPE};
7506+ use oci_spec::{
7507+ distribution::Reference,
7508+ image::{ImageManifest, MediaType},
7509+ };
7510+
7511+ use crate::Namespace;
7512+
7513+ use super::{AppState, error::Error, paths::TagPath};
7514+
7515+ /// Extracts the manifest but also retains the exact byte specification of the
7516+ /// client manifest input.
7517+ pub struct ManifestExtractor((Bytes, ImageManifest));
7518+
7519+ impl<S> FromRequest<S> for ManifestExtractor
7520+ where
7521+ S: Send + Sync,
7522+ {
7523+ type Rejection = super::error::Error;
7524+
7525+ async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
7526+ let headers = req.headers();
7527+ let Some(content_type) = headers.get(CONTENT_TYPE) else {
7528+ todo!()
7529+ };
7530+ let content_type_str = content_type.to_str().unwrap();
7531+ let media_type = MediaType::from(content_type_str);
7532+ if !matches!(media_type, MediaType::ImageManifest) {
7533+ todo!()
7534+ }
7535+ let body = Bytes::from_request(req, state).await?;
7536+
7537+ let buf = body.as_ref().reader();
7538+ let manifest = ImageManifest::from_reader(buf)?;
7539+ Ok(ManifestExtractor((body, manifest)))
7540+ }
7541+ }
7542+
7543+ pub async fn stat(
7544+ State(state): State<Arc<AppState>>,
7545+ Extension(namespace): Extension<Namespace>,
7546+ TagPath(tag_or_digest): TagPath,
7547+ ) -> Result<StatusCode, Error> {
7548+ println!("start");
7549+ if !state.oci.has_manifest(&namespace, &tag_or_digest).await? {
7550+ Err(Error::Code(super::error::Code::ManifestUnknown, None))
7551+ } else {
7552+ Ok(StatusCode::OK)
7553+ }
7554+ }
7555+
7556+ pub async fn read(
7557+ State(state): State<Arc<AppState>>,
7558+ Extension(namespace): Extension<Namespace>,
7559+ TagPath(tag_or_digest): TagPath,
7560+ ) -> Result<Response, Error> {
7561+ let manifest = state
7562+ .oci
7563+ .read_manifest(&namespace, &tag_or_digest)
7564+ .await
7565+ .map_err(|e| {
7566+ if let crate::error::Error::Storage(crate::storage::Error::NotFound) = e {
7567+ return Error::Code(super::error::Code::ManifestUnknown, None);
7568+ };
7569+ Error::Papyri(e)
7570+ })?;
7571+ let media_type = manifest
7572+ .media_type()
7573+ .as_ref()
7574+ .map(|mt| mt.to_string())
7575+ .unwrap();
7576+ let mut res = Json(manifest).into_response();
7577+ res.headers_mut()
7578+ .insert(CONTENT_TYPE, media_type.parse().unwrap());
7579+ Ok(res)
7580+ }
7581+
7582+ pub async fn write(
7583+ Extension(namespace): Extension<Namespace>,
7584+ State(state): State<Arc<AppState>>,
7585+ TagPath(tag_or_digest): TagPath,
7586+ ManifestExtractor((manifest_bytes, manifest)): ManifestExtractor,
7587+ ) -> Result<StatusCode, Error> {
7588+ state
7589+ .oci
7590+ .write_manifest(&namespace, &tag_or_digest, &manifest, &manifest_bytes)
7591+ .await?;
7592+ Ok(StatusCode::OK)
7593+ }
7594 diff --git a/src/axum/mod.rs b/src/axum/mod.rs
7595new file mode 100644
7596index 0000000..3ef0c9a
7597--- /dev/null
7598+++ b/src/axum/mod.rs
7599 @@ -0,0 +1,137 @@
7600+ use std::str::FromStr;
7601+ use std::sync::Arc;
7602+
7603+ use axum::Json;
7604+ use axum::extract::{DefaultBodyLimit, Request};
7605+ use axum::middleware::{Next, from_fn};
7606+ use axum::response::Response;
7607+ use axum::routing::{delete, head, patch, post, put};
7608+ use axum::{Router, routing::get};
7609+ use http::Uri;
7610+ use serde_json::json;
7611+
7612+ use crate::Namespace;
7613+ use crate::oci_interface::OciInterface;
7614+ use crate::storage::Storage;
7615+
7616+ mod error;
7617+ mod extractors;
7618+ mod handlers;
7619+ mod handlers_blob;
7620+ mod handlers_manifest;
7621+ mod paths;
7622+
7623+ #[derive(Clone)]
7624+ pub(crate) struct AppState {
7625+ pub oci: OciInterface,
7626+ }
7627+
7628+ pub fn read_ns(uri: &str) -> Option<(Namespace, String)> {
7629+ let mut components: Vec<String> = uri.split("/").map(|cmp| cmp.to_string()).collect();
7630+ components.reverse();
7631+ let stop = components.iter().enumerate().find_map(|(i, entry)| {
7632+ if *entry == "blobs" || *entry == "manifests" || *entry == "tags" {
7633+ Some(i + 1)
7634+ } else {
7635+ None
7636+ }
7637+ });
7638+ if let Some(stop) = stop {
7639+ let (route, ns) = components.split_at(stop);
7640+ let mut ns: Vec<String> = ns.iter().map(String::from).collect();
7641+ ns.reverse();
7642+ let ns = ns.join("/");
7643+ let mut route: Vec<String> = route.iter().map(String::from).collect();
7644+ route.reverse();
7645+ let route = format!("/{}", route.join("/"));
7646+ Some((Namespace::from_str(&ns).unwrap(), route))
7647+ } else {
7648+ None
7649+ }
7650+ }
7651+
7652+ /// Due to the registry spec allowing "namespacing", e.g. fuu/bar/baz/blobs/...
7653+ /// it is required that we rewrite the URI extacting any namespace if it is
7654+ /// specified.
7655+ pub fn extract_namespace(mut req: Request<axum::body::Body>) -> Request<axum::body::Body> {
7656+ let uri_str = req.uri().to_string();
7657+ if let Some((namespace, route)) = read_ns(&uri_str) {
7658+ let extensions = req.extensions_mut();
7659+ extensions.insert(namespace);
7660+ let uri = req.uri_mut();
7661+ *uri = Uri::from_str(&route).unwrap();
7662+ }
7663+ req
7664+ }
7665+
7666+ // async fn propagate_header<B>(req: Request<B>, next: Next<B>) -> Response {
7667+ async fn global_headers(req: Request, next: Next) -> Response {
7668+ let mut res = next.run(req).await;
7669+ // Docker-Distribution-Api-Version: registry/2.0
7670+ res.headers_mut().insert(
7671+ "Docker-Distribution-Api-Version",
7672+ "registry/2.0".try_into().unwrap(),
7673+ );
7674+ res
7675+ }
7676+
7677+ #[axum::debug_handler]
7678+ pub async fn index() -> Result<Json<serde_json::Value>, error::Error> {
7679+ Ok(Json(json!({})))
7680+ }
7681+
7682+ const MAXIMUM_MANIFEST_SIZE: usize = 5_000_000;
7683+
7684+ pub fn router(storage: &Storage) -> Router {
7685+ Router::new()
7686+ .route("/v2", get(index))
7687+ .route(
7688+ "/blobs/uploads/{reference}",
7689+ patch(handlers_blob::write_chunk),
7690+ )
7691+ .route("/blobs/uploads/{reference}", post(handlers_blob::write))
7692+ .route("/blobs/uploads/{reference}", put(handlers_blob::close))
7693+ .route("/blobs/uploads", post(handlers_blob::initiate))
7694+ .route("/blobs/{digest}", head(handlers_blob::stat))
7695+ .route("/blobs/{digest}", get(handlers_blob::read))
7696+ .route("/blobs/{digest}", delete(handlers_blob::delete))
7697+ .route(
7698+ "/manifests/{digest_or_tag}",
7699+ put(handlers_manifest::write).layer(DefaultBodyLimit::max(MAXIMUM_MANIFEST_SIZE)),
7700+ )
7701+ .route("/manifests/{digest_or_tag}", get(handlers_manifest::read))
7702+ .route("/manifests/{digest_or_tag}", head(handlers_manifest::stat))
7703+ // // .route("/{name}/blobs/{digest}", head(crate::handlers::stat_blob))
7704+ // // .route(
7705+ // // "/{name}/manifests/{reference}",
7706+ // // get(crate::handlers::read_manifest),
7707+ // // )
7708+ // // .route(
7709+ // // "/{name}/manifests/{reference}",
7710+ // // head(crate::handlers::read_manifest),
7711+ // // )
7712+ // // .route("/{name}/blobs/uploads", post(crate::handlers::initiate_blob))
7713+ // // .route(
7714+ // // "/{name}/blobs/uploads/{reference}",
7715+ // // patch(crate::handlers::write_blob),
7716+ // // )
7717+ // // .route(
7718+ // // "/{name}/manifests/{reference}",
7719+ // // put(crate::handlers::write_manifest),
7720+ // // )
7721+ // // .route("/{name}/tags/list", get(crate::handlers::read_tags))
7722+ // // .route(
7723+ // // "/{name}/manifests/{reference}",
7724+ // // delete(crate::handlers::delete_manifest),
7725+ // // )
7726+ // // .route(
7727+ // // "/{name}/blobs/{digest}",
7728+ // // delete(crate::handlers::delete_blob),
7729+ // // )
7730+ .layer(from_fn(global_headers))
7731+ .with_state(Arc::new(AppState {
7732+ oci: OciInterface {
7733+ storage: storage.clone(),
7734+ },
7735+ }))
7736+ }
7737 diff --git a/src/axum/paths.rs b/src/axum/paths.rs
7738new file mode 100644
7739index 0000000..da82db5
7740--- /dev/null
7741+++ b/src/axum/paths.rs
7742 @@ -0,0 +1,47 @@
7743+ use std::str::FromStr;
7744+
7745+ use axum::extract::FromRequestParts;
7746+ use http::request::Parts;
7747+ use oci_spec::image::Digest;
7748+
7749+ use crate::TagOrDigest;
7750+
7751+ use super::error::{Code, Error};
7752+
7753+ pub struct DigestPath(pub Digest);
7754+
7755+ impl<S> FromRequestParts<S> for DigestPath
7756+ where
7757+ S: Send + Sync,
7758+ {
7759+ type Rejection = Error;
7760+ async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
7761+ match axum::extract::Path::<Digest>::from_request_parts(parts, state).await {
7762+ Ok(value) => Ok(Self(value.0)),
7763+ Err(_) => Err(Error::Code(Code::DigestInvalid, None)),
7764+ }
7765+ }
7766+ }
7767+
7768+ pub struct TagPath(pub TagOrDigest);
7769+
7770+ impl<S> FromRequestParts<S> for TagPath
7771+ where
7772+ S: Send + Sync,
7773+ {
7774+ type Rejection = Error;
7775+
7776+ async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
7777+ match axum::extract::Path::<String>::from_request_parts(parts, state).await {
7778+ Ok(value) => {
7779+ if let Ok(digest) = Digest::from_str(&value.0) {
7780+ Ok(Self(TagOrDigest::Digest(digest)))
7781+ } else {
7782+ // TODO: We can't use Reference here and I'm unsure what a valid tag is
7783+ Ok(Self(TagOrDigest::Tag(value.0.clone())))
7784+ }
7785+ }
7786+ Err(_) => todo!(),
7787+ }
7788+ }
7789+ }
7790 diff --git a/src/error.rs b/src/error.rs
7791index 45f1daa..9f746eb 100644
7792--- a/src/error.rs
7793+++ b/src/error.rs
7794 @@ -1,98 +1,13 @@
7795- use axum::{Json, response::IntoResponse};
7796-
7797 use crate::storage::Error as StorageError;
7798
7799- // | ID | Code | Description |
7800- // |-------- | ------------------------|------------------------------------------------------------|
7801- // | code-1 | `BLOB_UNKNOWN` | blob unknown to registry |
7802- // | code-2 | `BLOB_UPLOAD_INVALID` | blob upload invalid |
7803- // | code-3 | `BLOB_UPLOAD_UNKNOWN` | blob upload unknown to registry |
7804- // | code-4 | `DIGEST_INVALID` | provided digest did not match uploaded content |
7805- // | code-5 | `MANIFEST_BLOB_UNKNOWN` | manifest references a manifest or blob unknown to registry |
7806- // | code-6 | `MANIFEST_INVALID` | manifest invalid |
7807- // | code-7 | `MANIFEST_UNKNOWN` | manifest unknown to registry |
7808- // | code-8 | `NAME_INVALID` | invalid repository name |
7809- // | code-9 | `NAME_UNKNOWN` | repository name not known to registry |
7810- // | code-10 | `SIZE_INVALID` | provided length did not match content length |
7811- // | code-11 | `UNAUTHORIZED` | authentication required |
7812- // | code-12 | `DENIED` | requested access to the resource is denied |
7813- // | code-13 | `UNSUPPORTED` | the operation is unsupported |
7814- // | code-14 | `TOOMANYREQUESTS` | too many requests |
7815- #[derive(Debug)]
7816- pub enum Code {
7817- BlobUnknown,
7818- BlobUploadInvalid,
7819- BlobUploadUnknown,
7820- DigestInvalid,
7821- ManifestBlobUnknown,
7822- ManifestInvalid,
7823- ManifestUnknown,
7824- NameInvalid,
7825- NameUnknown,
7826- SizeInvalid,
7827- Unathorized,
7828- Denied,
7829- Unsupported,
7830- TooManyRequests,
7831- }
7832-
7833- #[derive(serde::Serialize, Debug)]
7834- pub struct Message {
7835- pub code: String,
7836- pub message: String,
7837- pub detail: Option<String>,
7838- }
7839-
7840 #[derive(thiserror::Error, Debug)]
7841 pub enum Error {
7842- Code(Code),
7843+ #[error("IO Failure: {0}")]
7844 Storage(StorageError),
7845- }
7846-
7847- impl std::fmt::Display for Error {
7848- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7849- let msg: Message = self.into();
7850- f.write_str(&format!("{:?}", msg))
7851- }
7852- }
7853-
7854- impl From<&Error> for Message {
7855- fn from(val: &Error) -> Self {
7856- match val {
7857- Error::Code(code) => match code {
7858- Code::BlobUnknown => Message {
7859- code: String::from("BLOB_UNKNOWN"),
7860- message: String::from("blob unknown to registry"),
7861- detail: None,
7862- },
7863- Code::BlobUploadInvalid => todo!(),
7864- Code::BlobUploadUnknown => todo!(),
7865- Code::DigestInvalid => todo!(),
7866- Code::ManifestBlobUnknown => todo!(),
7867- Code::ManifestInvalid => todo!(),
7868- Code::ManifestUnknown => todo!(),
7869- Code::NameInvalid => todo!(),
7870- Code::NameUnknown => todo!(),
7871- Code::SizeInvalid => todo!(),
7872- Code::Unathorized => todo!(),
7873- Code::Denied => todo!(),
7874- Code::Unsupported => todo!(),
7875- Code::TooManyRequests => todo!(),
7876- },
7877- Error::Storage(error) => {
7878- match error {
7879- StorageError::Unspecified => todo!(),
7880- StorageError::IO => todo!(),
7881- StorageError::NotFound => todo!(),
7882- }
7883- },
7884- }
7885- }
7886- }
7887-
7888- impl IntoResponse for Error {
7889- fn into_response(self) -> axum::response::Response {
7890- let message = Message::from(&self);
7891- Json(message).into_response()
7892- }
7893+ #[error("Streaming error: {0}")]
7894+ Stream(String),
7895+ #[error("Namespace Invalid: {0}")]
7896+ Namespace(String),
7897+ #[error("Error parsing OCI Specification: {0}")]
7898+ OciSpec(#[from] oci_spec::OciSpecError)
7899 }
7900 diff --git a/src/lib.rs b/src/lib.rs
7901index c3e1100..7ab9579 100644
7902--- a/src/lib.rs
7903+++ b/src/lib.rs
7904 @@ -1,3 +1,74 @@
7905- pub mod routes;
7906+ use std::{fmt::Display, str::FromStr};
7907+
7908+ use error::Error;
7909+ use oci_spec::image::Digest;
7910+ use regex::Regex;
7911+ use relative_path::RelativePath;
7912+
7913+ pub mod address;
7914 pub mod error;
7915+ pub mod oci_interface;
7916 pub mod storage;
7917+
7918+ #[cfg(feature = "axum")]
7919+ pub mod axum;
7920+
7921+ #[cfg(feature = "storage-fs")]
7922+ pub mod storage_fs;
7923+
7924+ const NAME_REGEXP_MATCH: &str =
7925+ r"[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*(\/[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*)*";
7926+
7927+ #[derive(Clone, Debug)]
7928+ pub enum TagOrDigest {
7929+ Tag(String),
7930+ Digest(Digest)
7931+ }
7932+
7933+ // TODO: Consider 255 char namespace limit - hostname length per spec docs
7934+ #[derive(Clone)]
7935+ pub struct Namespace(String);
7936+
7937+ impl Namespace {
7938+ pub fn path(&self) -> &RelativePath {
7939+ RelativePath::new(&self.0)
7940+ }
7941+ }
7942+
7943+ impl FromStr for Namespace {
7944+ type Err = Error;
7945+
7946+ fn from_str(s: &str) -> Result<Self, Self::Err> {
7947+ let regexp = Regex::new(NAME_REGEXP_MATCH).unwrap();
7948+ if regexp.is_match(s) {
7949+ Ok(Namespace(s.to_string()))
7950+ } else {
7951+ Err(Error::Namespace(s.to_string()))
7952+ }
7953+ }
7954+ }
7955+
7956+ impl Display for Namespace {
7957+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7958+ write!(f, "{}", self.0)
7959+ }
7960+ }
7961+
7962+ impl AsRef<str> for Namespace {
7963+ fn as_ref(&self) -> &str {
7964+ &self.0
7965+ }
7966+ }
7967+
7968+ #[cfg(test)]
7969+ mod test {
7970+ use super::*;
7971+
7972+ #[test]
7973+ fn namespace() {
7974+ Namespace::from_str("fuu").unwrap();
7975+ Namespace::from_str("fuu/bar").unwrap();
7976+ Namespace::from_str("fuu/bar/baz/").unwrap();
7977+ Namespace::from_str("fuu/bar/baz/qux").unwrap();
7978+ }
7979+ }
7980 diff --git a/src/oci_interface.rs b/src/oci_interface.rs
7981new file mode 100644
7982index 0000000..9c63cb3
7983--- /dev/null
7984+++ b/src/oci_interface.rs
7985 @@ -0,0 +1,245 @@
7986+ use std::{pin::Pin, str::FromStr};
7987+
7988+ use bytes::Bytes;
7989+ use futures::{Stream, StreamExt};
7990+ use oci_spec::{
7991+ distribution::TagList,
7992+ image::{Digest, ImageManifest},
7993+ };
7994+ use sha2::{Digest as HashDigest, Sha256};
7995+ use uuid::Uuid;
7996+
7997+ use crate::{
7998+ Namespace, TagOrDigest,
7999+ address::{Address, Addressable, Blob, LayerLink, Reference, Tag, TempBlob},
8000+ error::Error,
8001+ storage::{InnerStream, Storage, StorageIface},
8002+ };
8003+
8004+ use base64::prelude::*;
8005+
8006+ pub mod paths {
8007+ pub const REPOSITORIES: &str = "/repositories";
8008+ }
8009+
8010+ #[derive(Clone)]
8011+ pub struct OciInterface {
8012+ pub storage: Storage,
8013+ }
8014+
8015+ impl OciInterface {
8016+ fn store(&self) -> impl StorageIface {
8017+ self.storage.inner()
8018+ }
8019+
8020+ async fn resolve_link<A>(&self, link: &A) -> Result<Address, Error>
8021+ where
8022+ A: Addressable + Send + Sync,
8023+ {
8024+ let digest_bytes = self
8025+ .store()
8026+ .read_bytes(link)
8027+ .await
8028+ .map_err(Error::Storage)?
8029+ .to_vec();
8030+ let digest_str = String::from_utf8_lossy(digest_bytes.as_slice());
8031+ let digest = Digest::from_str(&digest_str)?;
8032+ let blob_addr = Blob::from(&digest);
8033+ Ok(blob_addr.address())
8034+ }
8035+
8036+ pub async fn new_blob(&self, namespace: &Namespace) -> Result<Uuid, Error> {
8037+ let uuid = Uuid::new_v4();
8038+ self.store()
8039+ .write_all(
8040+ &TempBlob {
8041+ uuid: &uuid,
8042+ namespace,
8043+ },
8044+ &[],
8045+ )
8046+ .await
8047+ .map_err(Error::Storage)?;
8048+ Ok(uuid)
8049+ }
8050+
8051+ pub async fn commit_blob(
8052+ &self,
8053+ namespace: &Namespace,
8054+ uuid: &Uuid,
8055+ digest: &Digest,
8056+ ) -> Result<(), Error> {
8057+ self.store()
8058+ .mv(&TempBlob { uuid, namespace }, &Blob::from(digest))
8059+ .await
8060+ .map_err(Error::Storage)?;
8061+ Ok(())
8062+ }
8063+
8064+ pub async fn delete_blob(&self, namespace: &Namespace, digest: &Digest) -> Result<(), Error> {
8065+ self.store()
8066+ .delete(&LayerLink { namespace, digest })
8067+ .await
8068+ .map_err(Error::Storage)?;
8069+ Ok(())
8070+ }
8071+
8072+ pub async fn write_chunk<S>(
8073+ &self,
8074+ mut stream: Pin<Box<S>>,
8075+ namespace: &Namespace,
8076+ uuid: &Uuid,
8077+ ) -> Result<(), Error>
8078+ where
8079+ S: Stream<Item = Result<Bytes, Error>>,
8080+ {
8081+ let tmp_blob_addr = &TempBlob { namespace, uuid };
8082+ while let Some(item) = stream.next().await {
8083+ let chunk = item?.to_vec();
8084+ self.store()
8085+ .write(tmp_blob_addr, chunk.as_slice())
8086+ .await
8087+ .map_err(Error::Storage)?;
8088+ }
8089+ Ok(())
8090+ }
8091+
8092+ pub async fn write_manifest(
8093+ &self,
8094+ namespace: &Namespace,
8095+ tag_or_digest: &TagOrDigest,
8096+ manifest: &ImageManifest,
8097+ manifest_bytes: &Bytes,
8098+ ) -> Result<(), Error> {
8099+ let uuid = Uuid::new_v4();
8100+ let tmp_blob_addr = TempBlob {
8101+ uuid: &uuid,
8102+ namespace,
8103+ };
8104+ self.storage
8105+ .inner()
8106+ .write_all(&tmp_blob_addr, manifest_bytes.to_vec().as_slice())
8107+ .await
8108+ .map_err(Error::Storage)?;
8109+ // TODO: Generalize in storage.rs
8110+ let hashed = Sha256::digest(manifest_bytes);
8111+ let hash_str = base16ct::lower::encode_string(&hashed);
8112+ let digest = Digest::from_str(&format!("sha256:{}", hash_str)).unwrap();
8113+ let blob_address = &Blob::from(&digest);
8114+ self.store()
8115+ .mv(&tmp_blob_addr, blob_address)
8116+ .await
8117+ .map_err(Error::Storage)?;
8118+ self.store()
8119+ .write_all(
8120+ &Reference {
8121+ namespace,
8122+ digest: &digest,
8123+ },
8124+ digest.to_string().as_bytes(),
8125+ )
8126+ .await
8127+ .map_err(Error::Storage)?;
8128+
8129+ for layer in manifest.layers() {
8130+ // FIXME: iirc each blob needs to be resolved
8131+ let digest = layer.digest();
8132+ let digest_str = digest.to_string();
8133+ let digest_bytes = digest_str.as_bytes();
8134+ let layer_addr = LayerLink { namespace, digest };
8135+ self.storage
8136+ .inner()
8137+ .write_all(&layer_addr, digest_bytes)
8138+ .await
8139+ .map_err(Error::Storage)?;
8140+ }
8141+ let oci_config_digest = manifest.config().digest();
8142+ let manifest_embedded_data = manifest.config().data();
8143+ if let Some(manifest_embedded_data) = manifest_embedded_data {
8144+ // let manifest_str = manifest.to_string_pretty().unwrap();
8145+ let decoded = BASE64_STANDARD.decode(manifest_embedded_data).unwrap();
8146+ self.storage
8147+ .inner()
8148+ .write_all(
8149+ &Blob {
8150+ digest: oci_config_digest,
8151+ },
8152+ decoded.as_slice(),
8153+ )
8154+ .await
8155+ .map_err(Error::Storage)?;
8156+ self.storage
8157+ .inner()
8158+ .write_all(
8159+ &LayerLink {
8160+ namespace,
8161+ digest: oci_config_digest,
8162+ },
8163+ decoded.as_slice(),
8164+ )
8165+ .await
8166+ .map_err(Error::Storage)?;
8167+ }
8168+
8169+ if let TagOrDigest::Tag(name) = tag_or_digest {
8170+ self.store()
8171+ .write_all(&Tag { namespace, name }, digest.to_string().as_bytes())
8172+ .await
8173+ .map_err(Error::Storage)?;
8174+ }
8175+
8176+ Ok(())
8177+ }
8178+
8179+ pub async fn read_manifest(
8180+ &self,
8181+ namespace: &Namespace,
8182+ tag_or_digest: &TagOrDigest,
8183+ ) -> Result<ImageManifest, Error> {
8184+ let blob_addr = match tag_or_digest {
8185+ TagOrDigest::Tag(name) => self.resolve_link(&Tag { namespace, name }).await?,
8186+ TagOrDigest::Digest(digest) => {
8187+ self.resolve_link(&Reference { namespace, digest }).await?
8188+ }
8189+ };
8190+ let manifest_bytes = self
8191+ .storage
8192+ .inner()
8193+ .read_bytes(&blob_addr)
8194+ .await
8195+ .map_err(Error::Storage)?;
8196+ let manifest: ImageManifest =
8197+ serde_json::de::from_slice(manifest_bytes.iter().as_slice()).expect("manifest invalid");
8198+ Ok(manifest)
8199+ }
8200+
8201+ pub async fn has_blob(&self, digest: &Digest) -> Result<bool, Error> {
8202+ let blob_addr = Blob::from(digest);
8203+ self.store()
8204+ .exists(&blob_addr)
8205+ .await
8206+ .map_err(Error::Storage)
8207+ }
8208+
8209+ pub async fn has_manifest(
8210+ &self,
8211+ namespace: &Namespace,
8212+ tag_or_digest: &TagOrDigest,
8213+ ) -> Result<bool, Error> {
8214+ let blob_addr = match tag_or_digest {
8215+ TagOrDigest::Tag(name) => self.resolve_link(&Tag { namespace, name }).await?,
8216+ TagOrDigest::Digest(digest) => {
8217+ self.resolve_link(&Reference { namespace, digest }).await?
8218+ }
8219+ };
8220+ self.store()
8221+ .exists(&blob_addr)
8222+ .await
8223+ .map_err(Error::Storage)
8224+ }
8225+
8226+ pub async fn read_blob(&self, digest: &Digest) -> Result<InnerStream, Error> {
8227+ let blob_addr = Blob::from(digest);
8228+ self.store().read(&blob_addr).await.map_err(Error::Storage)
8229+ }
8230+ }
8231 diff --git a/src/routes.rs b/src/routes.rs
8232deleted file mode 100644
8233index acc33b5..0000000
8234--- a/src/routes.rs
8235+++ /dev/null
8236 @@ -1,179 +0,0 @@
8237- use std::cell::OnceCell;
8238- use std::str::FromStr;
8239-
8240- use axum::Json;
8241- use axum::extract::{MatchedPath, Path, Request};
8242- use axum::response::IntoResponse;
8243- use axum::routing::{delete, head, patch, post, put};
8244- use axum::{Router, routing::get};
8245- use core::result::Result as StdResult;
8246- use oci_spec::image::{ImageIndexBuilder, ImageManifest};
8247- use regex::Regex;
8248- use serde::Deserialize;
8249- use serde_json::json;
8250- use tracing::info_span;
8251-
8252- use crate::error::Error;
8253-
8254- pub type Result<T = Json<serde_json::Value>, E = Error> = std::result::Result<T, E>;
8255-
8256- const NAME_REGEXP_MATCH: &str =
8257- r"[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*(\/[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*)*";
8258-
8259- #[derive(Deserialize)]
8260- pub struct Namespace(String);
8261-
8262- impl Namespace {
8263- pub fn validate(&self) -> Result<(), Error> {
8264- let regexp = Regex::new(NAME_REGEXP_MATCH).unwrap();
8265- if regexp.is_match(&self.0) {
8266- Ok(())
8267- } else {
8268- Err(Error::Code(crate::error::Code::NameInvalid))
8269- }
8270- }
8271- }
8272-
8273- // Registry conformance applies to the following workflow categories:
8274- //
8275- // 1. **Pull** - Clients are able to pull from the registry
8276- // 2. **Push** - Clients are able to push to the registry
8277- // 3. **Content Discovery** - Clients are able to list or otherwise query the content stored in the registry
8278- // 4. **Content Management** - Clients are able to control the full life-cycle of the content stored in the registry
8279- //
8280-
8281- pub async fn index() -> Result {
8282- Ok(Json(json!({})))
8283- }
8284-
8285- pub mod pull {
8286- pub async fn read_manifest() {}
8287- pub async fn read_blob() {}
8288- }
8289-
8290- pub mod push {
8291- pub async fn write_manifest() {}
8292- pub async fn write_blob() {}
8293- }
8294-
8295- pub mod discovery {
8296- use super::*;
8297-
8298- pub async fn read_tags(Path(name): Path<Namespace>) -> Result {
8299- name.validate()?;
8300- todo!()
8301- }
8302-
8303- pub async fn read_referrers() {}
8304- }
8305-
8306- pub mod management {
8307- pub async fn delete_manifest() {}
8308- pub async fn delete_tag() {}
8309- pub async fn delete_blob() {}
8310- }
8311-
8312- pub fn router() -> Router {
8313- Router::new()
8314- .route("/v2", get(index))
8315- .route("/v2/", get(index))
8316- .route("/v2/:name/blobs/:digest", get(pull::read_blob))
8317- .route("/v2/:name/blobs/:digest", head(pull::read_blob))
8318- .route("/v2/:name/manifests/:reference", get(pull::read_manifest))
8319- .route("/v2/:name/manifests/:reference", head(pull::read_manifest))
8320- .route("/v2/:name/blobs/uploads", post(push::write_blob))
8321- .route(
8322- "/v2/:name/blobs/uploads/:reference",
8323- patch(push::write_blob),
8324- )
8325- .route("/v2/:name/manifests/:reference", put(push::write_manifest))
8326- .route("/v2/:name/tags/list", get(discovery::read_tags))
8327- .route(
8328- "/v2/:name/manifests/:reference",
8329- delete(management::delete_manifest),
8330- )
8331- .route("/v2/:name/blobs/:digest", delete(management::delete_blob))
8332- // .route("/v2/:name/blobs/uploads", post())
8333- }
8334-
8335- // pub async fn handler_index(req: Request) -> Json<serde_json::Value> {
8336- // req.headers().iter().for_each(|h| {
8337- // let header_value = h.1.to_str().ok();
8338- // tracing::info!(key = h.0.as_str(), value = header_value);
8339- // });
8340- // Json(json!({}))
8341- // }
8342- //
8343- // pub async fn handler_manifest_index() -> Json<serde_json::Value> {
8344- // }
8345-
8346- // async fn serve() {
8347- // let app = Router::new()
8348- // .route("/", get(|| async { "Hello, World!" }))
8349- // .route("/v2", get(handler_index))
8350- // .route("/v2/", get(handler_index))
8351- // .layer(
8352- // TraceLayer::new_for_http().make_span_with(|request: &Request<_>| {
8353- // // Log the matched route's path (with placeholders not filled in).
8354- // // Use request.uri() or OriginalUri if you want the real path.
8355- // let matched_path = request
8356- // .extensions()
8357- // .get::<MatchedPath>()
8358- // .map(MatchedPath::as_str);
8359- //
8360- // let actual_path = request.uri().path();
8361- //
8362- // info_span!(
8363- // "http_request",
8364- // method = ?request.method(),
8365- // matched_path,
8366- // actual_path,
8367- // some_other_field = tracing::field::Empty,
8368- // )
8369- // }), // .on_request(|_request: &Request<_>, _span: &Span| {
8370- // // // You can use `_span.record("some_other_field", value)` in one of these
8371- // // // closures to attach a value to the initially empty field in the info_span
8372- // // // created above.
8373- // // })
8374- // // .on_response(|_response: &Response, _latency: Duration, _span: &Span| {
8375- // // // ...
8376- // // })
8377- // // .on_body_chunk(|_chunk: &Bytes, _latency: Duration, _span: &Span| {
8378- // // // ...
8379- // // })
8380- // // .on_eos(
8381- // // |_trailers: Option<&HeaderMap>, _stream_duration: Duration, _span: &Span| {
8382- // // // ...
8383- // // },
8384- // // )
8385- // // .on_failure(
8386- // // |_error: ServerErrorsFailureClass, _latency: Duration, _span: &Span| {
8387- // // // ...
8388- // // },
8389- // // ),
8390- // );
8391- //
8392- // // run our app with hyper, listening globally on port 3000
8393- // tracing::info!("Listening @ 0.0.0.0:3000");
8394- // let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
8395- // axum::serve(listener, app).await.unwrap();
8396- // }
8397- //
8398- // #[tokio::main]
8399- // async fn main() {
8400- // tracing_subscriber::registry()
8401- // .with(
8402- // tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
8403- // // axum logs rejections from built-in extractors with the `axum::rejection`
8404- // // target, at `TRACE` level. `axum::rejection=trace` enables showing those events
8405- // format!(
8406- // "{}=debug,tower_http=debug,axum::rejection=trace",
8407- // env!("CARGO_CRATE_NAME")
8408- // )
8409- // .into()
8410- // }),
8411- // )
8412- // .with(tracing_subscriber::fmt::layer())
8413- // .init();
8414- // serve().await;
8415- // }
8416 diff --git a/src/storage.rs b/src/storage.rs
8417index 65cb4c0..e97ad41 100644
8418--- a/src/storage.rs
8419+++ b/src/storage.rs
8420 @@ -1,21 +1,103 @@
8421+ use std::{io::Error as IoError, path::PathBuf, pin::Pin};
8422+
8423+ use bytes::Bytes;
8424+ use futures::{Stream, stream::BoxStream};
8425+
8426+ use crate::{
8427+ address::Addressable,
8428+ storage_fs::FileSystem,
8429+ };
8430+
8431 #[derive(thiserror::Error, Debug)]
8432 pub enum Error {
8433+ #[error("Unspecified Storage Error")]
8434 Unspecified,
8435- IO,
8436+ #[error("Storage IO: {0}")]
8437+ Io(#[from] IoError),
8438+ #[error("Object Not Found")]
8439 NotFound,
8440 }
8441
8442- impl std::fmt::Display for Error {
8443- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8444+ pub struct InnerStream {
8445+ stream: BoxStream<'static, Result<Bytes, std::io::Error>>,
8446+ }
8447+
8448+ impl InnerStream {
8449+ pub fn new(stream: BoxStream<'static, Result<Bytes, std::io::Error>>) -> Self {
8450+ InnerStream { stream }
8451+ }
8452+ }
8453+
8454+ impl Stream for InnerStream {
8455+ type Item = Result<Bytes, std::io::Error>;
8456+
8457+ fn poll_next(
8458+ self: Pin<&mut Self>,
8459+ cx: &mut std::task::Context<'_>,
8460+ ) -> std::task::Poll<Option<Self::Item>> {
8461+ Pin::new(&mut self.get_mut().stream).poll_next(cx)
8462+ }
8463+ }
8464+
8465+ /// The storage trait needs to be implemented for accessing objects from the
8466+ /// platform. This API is based on registry/storage/driver/storagedriver.go in
8467+ /// the distribution codebase.
8468+ pub trait StorageIface: Sync + Send {
8469+ /// List a single directory of objects
8470+ // async fn list(&self, addr: &Address) -> Result<Vec<Object>, Error>;
8471+ // async fn stat(&self, addr: &Address) -> Result<Option<Object>, Error>;
8472+ // async fn read_bytes(&self, addr: &Address) -> Result<Option<Vec<u8>>, Error>;
8473+ /// Check if an object exists at the given address
8474+ fn exists<A>(&self, path: &A) -> impl Future<Output = Result<bool, Error>> + Send
8475+ where
8476+ A: Addressable + Send + Sync;
8477+ /// Write bytes to the address, truncating any existing object
8478+ fn write_all<A>(
8479+ &self,
8480+ path: &A,
8481+ bytes: &[u8],
8482+ ) -> impl Future<Output = Result<(), Error>> + Send
8483+ where
8484+ A: Addressable + Send + Sync;
8485+
8486+ /// write bytes to a file that has already been created
8487+ fn write<A>(&self, path: &A, bytes: &[u8]) -> impl Future<Output = Result<(), Error>> + Send
8488+ where
8489+ A: Addressable + Send + Sync;
8490+
8491+ fn mv<A, B>(&self, src: &A, dst: &B) -> impl Future<Output = Result<(), Error>> + Send
8492+ where
8493+ A: Addressable + Send + Sync,
8494+ B: Addressable + Send + Sync;
8495+ // fn mv (&self, )std::future::Future<Output = ()> + Send
8496+ fn read<A>(&self, src: &A) -> impl Future<Output = Result<InnerStream, Error>> + Send
8497+ where
8498+ A: Addressable + Send + Sync;
8499+
8500+ fn read_bytes<A>(&self, src: &A) -> impl Future<Output = Result<Bytes, Error>> + Send
8501+ where
8502+ A: Addressable + Send + Sync;
8503+
8504+ fn delete<A>(&self, src: &A) -> impl Future<Output = Result<(), Error>> + Send
8505+ where
8506+ A: Addressable + Send + Sync;
8507+ }
8508+
8509+ #[derive(Debug, Clone)]
8510+ pub enum Storage {
8511+ FileSystem { base: PathBuf },
8512+ }
8513+
8514+ impl Storage {
8515+ pub fn init(&self) -> Result<(), Error> {
8516 match self {
8517- Error::Unspecified => f.write_str("An unspecified storage error occurred"),
8518- Error::IO => f.write_str("A storage IO error occurred"),
8519- Error::NotFound => f.write_str("Storage resource not found"),
8520+ Storage::FileSystem { base } => FileSystem { base: base.clone() }.init(),
8521 }
8522 }
8523- }
8524
8525- #[async_trait::async_trait]
8526- pub trait Storage: Sync + Send {
8527- async fn read_tags() -> Result<Vec<String>, Error>;
8528+ pub fn inner(&self) -> impl StorageIface {
8529+ match self {
8530+ Storage::FileSystem { base } => FileSystem { base: base.clone() },
8531+ }
8532+ }
8533 }
8534 diff --git a/src/storage_fs.rs b/src/storage_fs.rs
8535index e69de29..6b5ec11 100644
8536--- a/src/storage_fs.rs
8537+++ b/src/storage_fs.rs
8538 @@ -0,0 +1,137 @@
8539+ use std::{
8540+ io::Cursor,
8541+ path::{Path, PathBuf},
8542+ };
8543+
8544+ use bytes::Bytes;
8545+ use futures::StreamExt;
8546+ use tokio::io::AsyncWriteExt;
8547+
8548+ use crate::{
8549+ address::Addressable,
8550+ storage::{Error, InnerStream, StorageIface},
8551+ };
8552+
8553+ #[derive(Clone)]
8554+ pub struct FileSystem {
8555+ pub base: PathBuf,
8556+ }
8557+
8558+ impl FileSystem {
8559+ pub fn init(&self) -> Result<(), Error> {
8560+ std::fs::create_dir_all(self.base.as_path())?;
8561+ Ok(())
8562+ }
8563+
8564+ pub async fn ensure_dir(&self, path: &Path) -> Result<(), Error> {
8565+ let parent = path.parent().unwrap();
8566+ tokio::fs::create_dir_all(parent).await?;
8567+ Ok(())
8568+ }
8569+ }
8570+
8571+ impl StorageIface for FileSystem {
8572+ async fn exists<A>(&self, addr: &A) -> Result<bool, Error>
8573+ where
8574+ A: Addressable + Send + Sync,
8575+ {
8576+ let path = addr.address().as_path(&self.base);
8577+ if tokio::fs::try_exists(&path)
8578+ .await
8579+ .is_ok_and(|exists| exists)
8580+ {
8581+ let md = tokio::fs::metadata(path).await?;
8582+ if md.is_file() { Ok(true) } else { Ok(false) }
8583+ } else {
8584+ Ok(false)
8585+ }
8586+ }
8587+
8588+ async fn write_all<A>(&self, addr: &A, bytes: &[u8]) -> Result<(), Error>
8589+ where
8590+ A: Addressable + Send + Sync,
8591+ {
8592+ let path = addr.address().as_path(&self.base);
8593+ self.ensure_dir(&path).await?;
8594+ let mut fp = tokio::fs::OpenOptions::new()
8595+ .create(true)
8596+ .truncate(true)
8597+ .write(true)
8598+ .open(&path)
8599+ .await?;
8600+ let mut cursor = Cursor::new(bytes);
8601+ fp.write_buf(&mut cursor).await?;
8602+ fp.flush().await?;
8603+ fp.sync_all().await?;
8604+ Ok(())
8605+ }
8606+
8607+ async fn write<A>(&self, addr: &A, bytes: &[u8]) -> Result<(), Error>
8608+ where
8609+ A: Addressable + Send + Sync,
8610+ {
8611+ let path = addr.address().as_path(&self.base);
8612+ let mut fp = tokio::fs::OpenOptions::new()
8613+ .create(false)
8614+ .truncate(false)
8615+ .write(true)
8616+ .open(path)
8617+ .await?;
8618+ let mut cursor = Cursor::new(bytes);
8619+ fp.write_buf(&mut cursor).await?;
8620+ fp.flush().await?;
8621+ fp.sync_all().await?;
8622+ Ok(())
8623+ }
8624+
8625+ async fn mv<A, B>(&self, src: &A, dst: &B) -> Result<(), Error>
8626+ where
8627+ A: Addressable + Send + Sync,
8628+ B: Addressable + Send + Sync,
8629+ {
8630+ let src_path = src.address().as_path(&self.base);
8631+ let dst_path = dst.address().as_path(&self.base);
8632+ self.ensure_dir(&dst_path).await?;
8633+ tracing::info!("mv {:?} -> {:?}", src_path, dst_path);
8634+ tokio::fs::rename(src_path, dst_path).await?;
8635+ Ok(())
8636+ }
8637+
8638+ async fn read<A>(&self, src: &A) -> Result<InnerStream, Error>
8639+ where
8640+ A: Addressable + Send + Sync,
8641+ {
8642+ let path = src.address().as_path(&self.base);
8643+ let fp = tokio::fs::File::open(path.as_path())
8644+ .await
8645+ .map_err(|e| match e.kind() {
8646+ std::io::ErrorKind::NotFound => Error::NotFound,
8647+ _ => Error::Io(e),
8648+ })?;
8649+ let stream = tokio_util::io::ReaderStream::new(fp);
8650+ Ok(InnerStream::new(stream.boxed()))
8651+ }
8652+
8653+ async fn read_bytes<A>(&self, src: &A) -> Result<Bytes, Error>
8654+ where
8655+ A: Addressable + Send + Sync,
8656+ {
8657+ let path = src.address().as_path(&self.base);
8658+ let payload = tokio::fs::read(path.as_path())
8659+ .await
8660+ .map_err(|e| match e.kind() {
8661+ std::io::ErrorKind::NotFound => Error::NotFound,
8662+ _ => Error::Io(e),
8663+ })?;
8664+ Ok(Bytes::from(payload))
8665+ }
8666+
8667+ async fn delete<A>(&self, src: &A) -> Result<(), Error>
8668+ where
8669+ A: Addressable + Send + Sync
8670+ {
8671+ let path = src.address().as_path(&self.base);
8672+ tokio::fs::remove_file(path.as_path()).await?;
8673+ Ok(())
8674+ }
8675+ }