From cd6618e3ff0c4079fbcfd883b32cca27ff2e6b61 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Fri, 8 Aug 2025 16:07:49 +0800 Subject: [PATCH 1/4] first version Signed-off-by: Xiaoxuan Wang --- docs/proposals/check-design.md | 71 ++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 docs/proposals/check-design.md diff --git a/docs/proposals/check-design.md b/docs/proposals/check-design.md new file mode 100644 index 000000000..11d0af8fc --- /dev/null +++ b/docs/proposals/check-design.md @@ -0,0 +1,71 @@ +# oras check draft design + +This is a draft design for the `oras check` command. + +## UX + +Command: + +``` +oras check [flags] {:|@} + +Example - validate a single image referenced by tag: + oras check localhost:5000/hello:v1 + +Example - validate multiple images referenced by tags: + oras check localhost:5000/hello:v1,v2,v3 + +Example - validate a single image referenced by digest: + oras check localhost:5000/hello@sha256:fd6ed2f36b5465244d5dc86cb4e7df0ab8a9d24adc57825099f522fe009a22bb + +``` + +Flags: + +`--oci-layout` / `--oci-layout-path` :OCI Layout validation + +`--include-referrers`: include validation of the referrers (Note: this is predecessor validation, only enabled by flag) + +`--concurrency`: set concurrency level + +## Validation behaviors (For manifest only, not index yet) + +**Step 1: Resolve the reference given by the user** + +Returns an error if the reference fails to resolve, or resolves to a blob instead of a manifest. + +**Step 2: Validate the manifest against the resolved descriptor** + +Fetch the manifest content by descriptor, and check if the **MediaType**, **Size** and **Digest** are consistent with the descriptor. + +**Step 3: Validate the blobs (config and layers) against the descriptors in the manifest** + +Fetch the blobs (config and layers) by descriptors in the manifest, and check if the **Size** and **Digest** are consistent with the descriptors. + + +```mermaid +graph TD; + A[referrer of v1] -- subject --> B[manifest v1] +``` + +**Step 4: If the subject field is not empty, validate the subject manifest** + +(Note: this is successor validation, enabled by default) + +Do step 2 with the descriptor in the subject field. Then do step 3. + +**Step 5: If --include-referrers flag is used, validate the referrers** + +(Note: this is predecessor validation, only enabled by flag) + +Resolve the referrer descriptors, then do step 2 and 3. + +Verify that the subject descriptor of the referrers is consistent with the manifest. + +## PoC implementation +https://github.com/oras-project/oras/pull/1801 + +## Questions for discussion +1. Should we support reference by digest? +2. Should we support validating index? What should the behavior be? +3. Should we support validating an entire repository? (`oras check localhost:5000/hello`, no image reference is given) \ No newline at end of file From 9ebef4748d5e236db15af490e59d9b3e9162acd4 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Mon, 11 Aug 2025 17:38:15 +0800 Subject: [PATCH 2/4] added more sections Signed-off-by: Xiaoxuan Wang --- docs/proposals/check-design.md | 59 +++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/docs/proposals/check-design.md b/docs/proposals/check-design.md index 11d0af8fc..7fae43de5 100644 --- a/docs/proposals/check-design.md +++ b/docs/proposals/check-design.md @@ -4,7 +4,7 @@ This is a draft design for the `oras check` command. ## UX -Command: +### Command: ``` oras check [flags] {:|@} @@ -17,10 +17,9 @@ Example - validate multiple images referenced by tags: Example - validate a single image referenced by digest: oras check localhost:5000/hello@sha256:fd6ed2f36b5465244d5dc86cb4e7df0ab8a9d24adc57825099f522fe009a22bb - ``` -Flags: +### Flags: `--oci-layout` / `--oci-layout-path` :OCI Layout validation @@ -28,17 +27,61 @@ Flags: `--concurrency`: set concurrency level +### Progress output: + +The command should display progress output similar to the output of `oras cp`, showing the status of each component of the checked image. Both `tty` and `no-tty` modes should be supported. + +``` +oras check localhost:5000/hello:v1 --no-tty +Checking f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip +Checking aded1e1a5b37 application/vnd.oci.image.config.v1+json +Checked [succeeded] aded1e1a5b37 application/vnd.oci.image.config.v1+json +Checked [failed] f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip +Checking 1c4eef651f65 application/vnd.oci.image.manifest.v1+json +Checked [succeeded] 1c4eef651f65 application/vnd.oci.image.manifest.v1+json +Checked [failed] [registry] localhost:5000/hello:v1 + +Checked localhost:5000/hello:v1 in 15s. 1 check failed. +[Failed] +Error: oras check failed on f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip: layer size mismatch: expect 257, got 233 +``` + +``` +oras check localhost:5000/hello:v1 +✓ Checked [failed] application/vnd.oci.image.layer.v1.tar+gzip 3.47/3.47 MB 100.00% 2s + └─ sha256:f18232174bc91741fdf3da96d85011092101a032a93a388b79e99e69c2d5c870 +✓ Checked [succeeded] application/vnd.oci.image.config.v1+json 581/581 B 100.00% 463ms + └─ sha256:aded1e1a5b3705116fa0a92ba074a5e0b0031647d9c315983ccba2ee5428ec8b +✓ Checked [succeeded] application/vnd.oci.image.manifest.v1+json 1022/1022 B 100.00% 437ms + └─ sha256:1c4eef651f65e2f7daee7ee785882ac164b02b78fb74503052a26dc061c90474 +Checked [failed] [registry] localhost:5000/hello:v1 + +Checked localhost:5000/hello:v1 in 15s. 1 check failed. +[Failed] +Error: oras check failed on f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip: layer size mismatch: expect 257, got 233 +``` +### Error messages: + +The `oras check` command should return refined error messages for failed checks. For example: +``` +[Failed] +Error: oras check failed on f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip: layer size mismatch: expect 257, got 233 +``` + + ## Validation behaviors (For manifest only, not index yet) -**Step 1: Resolve the reference given by the user** +When validating an image, the `oras check` command verifies the integrity of the manifest and all associated blobs. If the manifest includes a subject field, the referenced subject image is also validated recursively using the same process. The check proceeds through all components, reporting any failures, but does not stop at any failed check; instead, it continues until every component has been checked. + +* Step 1: Resolve the reference given by the user Returns an error if the reference fails to resolve, or resolves to a blob instead of a manifest. -**Step 2: Validate the manifest against the resolved descriptor** +* Step 2: Validate the manifest against the resolved descriptor Fetch the manifest content by descriptor, and check if the **MediaType**, **Size** and **Digest** are consistent with the descriptor. -**Step 3: Validate the blobs (config and layers) against the descriptors in the manifest** +* Step 3: Validate the blobs (config and layers) against the descriptors in the manifest Fetch the blobs (config and layers) by descriptors in the manifest, and check if the **Size** and **Digest** are consistent with the descriptors. @@ -48,13 +91,13 @@ graph TD; A[referrer of v1] -- subject --> B[manifest v1] ``` -**Step 4: If the subject field is not empty, validate the subject manifest** +* Step 4: If the subject field is not empty, validate the subject manifest (Note: this is successor validation, enabled by default) Do step 2 with the descriptor in the subject field. Then do step 3. -**Step 5: If --include-referrers flag is used, validate the referrers** +* Step 5: If --include-referrers flag is used, validate the referrers (Note: this is predecessor validation, only enabled by flag) From 8276d84f0c6f1a144775e08b1ec5a532c7f66dc2 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Tue, 19 Aug 2025 16:59:57 +0800 Subject: [PATCH 3/4] updated design docs Signed-off-by: Xiaoxuan Wang --- docs/proposals/check-design.md | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/docs/proposals/check-design.md b/docs/proposals/check-design.md index 7fae43de5..0b08cac0e 100644 --- a/docs/proposals/check-design.md +++ b/docs/proposals/check-design.md @@ -23,6 +23,8 @@ Example - validate a single image referenced by digest: `--oci-layout` / `--oci-layout-path` :OCI Layout validation +`--platform`: check specific platform for multi-arch image index + `--include-referrers`: include validation of the referrers (Note: this is predecessor validation, only enabled by flag) `--concurrency`: set concurrency level @@ -69,15 +71,21 @@ Error: oras check failed on f18232174bc9 application/vnd.oci.image.layer.v1.tar+ ``` -## Validation behaviors (For manifest only, not index yet) +## Validation behaviors + +When validating an image, the `oras check` command verifies the integrity of the manifest and all referenced blobs. If the manifest includes a subject field, the referenced subject image is also validated recursively using the same process. + +If an error is found during validating the manifest, the check process stops and the reference blobs will not be checked. But if an error is found during validating a blob, the check continues until all blobs of the manifests are checked. A more formal description about when the check process fails is in the next section (Implementation with graph modeling). -When validating an image, the `oras check` command verifies the integrity of the manifest and all associated blobs. If the manifest includes a subject field, the referenced subject image is also validated recursively using the same process. The check proceeds through all components, reporting any failures, but does not stop at any failed check; instead, it continues until every component has been checked. +When validating an index, the `oras check` command verifies the integrity of the index and all the referenced manifests. + +Step by step description of the validation process: * Step 1: Resolve the reference given by the user -Returns an error if the reference fails to resolve, or resolves to a blob instead of a manifest. +Returns an error if the reference fails to resolve. -* Step 2: Validate the manifest against the resolved descriptor +* Step 2: Validate the manifest (including index) against the resolved descriptor Fetch the manifest content by descriptor, and check if the **MediaType**, **Size** and **Digest** are consistent with the descriptor. @@ -105,10 +113,12 @@ Resolve the referrer descriptors, then do step 2 and 3. Verify that the subject descriptor of the referrers is consistent with the manifest. +## Implementation with graph modeling +Similar to the `oras cp` command, the `oras check` command models an OCI artifact as a graph, and runs the check by checking the subgraph of each node. + ## PoC implementation https://github.com/oras-project/oras/pull/1801 ## Questions for discussion -1. Should we support reference by digest? -2. Should we support validating index? What should the behavior be? -3. Should we support validating an entire repository? (`oras check localhost:5000/hello`, no image reference is given) \ No newline at end of file +1. Should we run the check if user gives a blob digest? (Why not?) +2. Should we check if a manifest misses a config or schema value (not conformant to OCI spec)? Currently we are only checking if the media type, size and digest matches the descriptor resolved by the server. \ No newline at end of file From a261341390abc3273c6c6197bc9f7998a49a2803 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Wed, 20 Aug 2025 11:02:36 +0800 Subject: [PATCH 4/4] updated Signed-off-by: Xiaoxuan Wang --- docs/proposals/check-design.md | 57 ++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/docs/proposals/check-design.md b/docs/proposals/check-design.md index 0b08cac0e..1bb46ab8d 100644 --- a/docs/proposals/check-design.md +++ b/docs/proposals/check-design.md @@ -35,39 +35,38 @@ The command should display progress output similar to the output of `oras cp`, s ``` oras check localhost:5000/hello:v1 --no-tty -Checking f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip -Checking aded1e1a5b37 application/vnd.oci.image.config.v1+json -Checked [succeeded] aded1e1a5b37 application/vnd.oci.image.config.v1+json -Checked [failed] f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip Checking 1c4eef651f65 application/vnd.oci.image.manifest.v1+json -Checked [succeeded] 1c4eef651f65 application/vnd.oci.image.manifest.v1+json -Checked [failed] [registry] localhost:5000/hello:v1 +Checked [Pass] 1c4eef651f65 application/vnd.oci.image.manifest.v1+json +Checking aded1e1a5b37 application/vnd.oci.image.config.v1+json +Checked [Failed] aded1e1a5b37 application/vnd.oci.image.config.v1+json +Checking f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip +Checked [Pass] f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip Checked localhost:5000/hello:v1 in 15s. 1 check failed. [Failed] -Error: oras check failed on f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip: layer size mismatch: expect 257, got 233 +Error: oras check failed on aded1e1a5b37 application/vnd.oci.image.config.v1+json: blob size mismatch: expect 257, got 233 ``` ``` oras check localhost:5000/hello:v1 -✓ Checked [failed] application/vnd.oci.image.layer.v1.tar+gzip 3.47/3.47 MB 100.00% 2s - └─ sha256:f18232174bc91741fdf3da96d85011092101a032a93a388b79e99e69c2d5c870 -✓ Checked [succeeded] application/vnd.oci.image.config.v1+json 581/581 B 100.00% 463ms - └─ sha256:aded1e1a5b3705116fa0a92ba074a5e0b0031647d9c315983ccba2ee5428ec8b -✓ Checked [succeeded] application/vnd.oci.image.manifest.v1+json 1022/1022 B 100.00% 437ms +✓ Checked [Pass] application/vnd.oci.image.manifest.v1+json 1022/1022 B 100.00% 437ms └─ sha256:1c4eef651f65e2f7daee7ee785882ac164b02b78fb74503052a26dc061c90474 -Checked [failed] [registry] localhost:5000/hello:v1 +✓ Checked [Failed] application/vnd.oci.image.config.v1+json 581/581 B 100.00% 463ms + └─ sha256:aded1e1a5b3705116fa0a92ba074a5e0b0031647d9c315983ccba2ee5428ec8b +✓ Checked [Pass] application/vnd.oci.image.layer.v1.tar+gzip 3.47/3.47 MB 100.00% 2s + └─ sha256:f18232174bc91741fdf3da96d85011092101a032a93a388b79e99e69c2d5c870 Checked localhost:5000/hello:v1 in 15s. 1 check failed. [Failed] -Error: oras check failed on f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip: layer size mismatch: expect 257, got 233 +Error: oras check failed on aded1e1a5b37 application/vnd.oci.image.config.v1+json: blob size mismatch: expect 257, got 233 ``` + ### Error messages: The `oras check` command should return refined error messages for failed checks. For example: ``` [Failed] -Error: oras check failed on f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip: layer size mismatch: expect 257, got 233 +Error: oras check failed on f18232174bc9 application/vnd.oci.image.layer.v1.tar+gzip: blob size mismatch: expect 257, got 233 ``` @@ -75,7 +74,7 @@ Error: oras check failed on f18232174bc9 application/vnd.oci.image.layer.v1.tar+ When validating an image, the `oras check` command verifies the integrity of the manifest and all referenced blobs. If the manifest includes a subject field, the referenced subject image is also validated recursively using the same process. -If an error is found during validating the manifest, the check process stops and the reference blobs will not be checked. But if an error is found during validating a blob, the check continues until all blobs of the manifests are checked. A more formal description about when the check process fails is in the next section (Implementation with graph modeling). +If an error is found during validating the manifest, the check process stops and the reference blobs will not be checked. But if an error is found during validating a blob, the check continues until all blobs of the manifests are checked. This is because that if a manifest fails the validation, the information in the manifest should not be trusted, and there's no point to continue checking the blobs referenced in the manifest. When validating an index, the `oras check` command verifies the integrity of the index and all the referenced manifests. @@ -99,6 +98,27 @@ graph TD; A[referrer of v1] -- subject --> B[manifest v1] ``` +``` +# referrer of v1 +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + ... + }, + "layers": [ + { + ... + } + ], + "Subject": { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:aded1e1a5b3705116fa0a92ba074a5e0b0031647d9c315983ccba2ee5428ec8b", + "size": 581 + } +} +``` + * Step 4: If the subject field is not empty, validate the subject manifest (Note: this is successor validation, enabled by default) @@ -114,11 +134,10 @@ Resolve the referrer descriptors, then do step 2 and 3. Verify that the subject descriptor of the referrers is consistent with the manifest. ## Implementation with graph modeling -Similar to the `oras cp` command, the `oras check` command models an OCI artifact as a graph, and runs the check by checking the subgraph of each node. +Similar to the `oras cp` command, the `oras check` command models an OCI artifact as a graph, and runs the check by checking the subgraph of each node recursively. ## PoC implementation https://github.com/oras-project/oras/pull/1801 ## Questions for discussion -1. Should we run the check if user gives a blob digest? (Why not?) -2. Should we check if a manifest misses a config or schema value (not conformant to OCI spec)? Currently we are only checking if the media type, size and digest matches the descriptor resolved by the server. \ No newline at end of file +1. Should we check if a manifest misses a config or schema value (not conformant to OCI spec)? Currently we are only checking if the media type, size and digest matches the descriptor resolved by the server. Similar question for image config. \ No newline at end of file