WIP: CLID-290: feat: Add sparse manifest platform filtering for multi-arch images#1435
WIP: CLID-290: feat: Add sparse manifest platform filtering for multi-arch images#1435aguidirh wants to merge 1 commit into
Conversation
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: aguidirh The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
@aguidirh: This pull request references CLID-290 which is a valid jira issue. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: openshift/coderabbit/.coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (15)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (11)
WalkthroughThis PR introduces per-image platform filtering across the oc-mirror pipeline. A new ChangesPer-image platform filtering across oc-mirror
Sequence Diagram(s)sequenceDiagram
participant Collector as Collector (Release/Helm/Operator/Additional)
participant RelatedImage as RelatedImage
participant BatchWorker as ChannelConcurrentBatch.Worker
participant MirrorEngine as mirror.copy()
participant determinePlatformSelection as determinePlatformSelection
participant parseMultiArch as parseMultiArch
Collector->>RelatedImage: sets Platforms *[]string from ConvertPlatformsToStringSlice
Collector->>BatchWorker: enqueues CopyImageSchema with Platforms
BatchWorker->>MirrorEngine: sets options.InstancePlatforms from img.Platforms
MirrorEngine->>determinePlatformSelection: opts.InstancePlatforms or MultiArch/All
determinePlatformSelection->>parseMultiArch: comma-separated OS/ARCH or legacy mode
parseMultiArch-->>determinePlatformSelection: ImageListSelection + []InstancePlatformFilter
determinePlatformSelection-->>MirrorEngine: imageListSelection + instancePlatforms
MirrorEngine->>MirrorEngine: copy.Options{InstancePlatforms: instancePlatforms}
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 13 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (13 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/pkg/api/v2alpha1/type_config.go (1)
116-130:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
Platform.DeepCopy()drops scalar fields and returns an incomplete copy.Line 117 only seeds
Graph;ReleaseandKubeVirtContainerare lost in the copied struct. That can silently alter mirroring behavior when callers depend onDeepCopy().Proposed fix
func (p Platform) DeepCopy() Platform { platformCopy := Platform{ - Graph: p.Graph, + Graph: p.Graph, + Release: p.Release, + KubeVirtContainer: p.KubeVirtContainer, }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/pkg/api/v2alpha1/type_config.go` around lines 116 - 130, Platform.DeepCopy() currently initializes platformCopy with only Graph, causing scalar fields like Release and KubeVirtContainer to be lost; update Platform.DeepCopy to copy all scalar and value fields from the receiver (e.g., set platformCopy.Release = p.Release and platformCopy.KubeVirtContainer = p.KubeVirtContainer) in addition to the existing deep copies of slices (Channels, Architectures, Platforms) so the returned copy is complete; locate the DeepCopy method on type Platform and add assignments for any other scalar/value fields to mirror the source struct.
🧹 Nitpick comments (2)
internal/pkg/operator/filtered_collector_test.go (1)
1052-1061: ⚡ Quick winMake the mock validate the forwarded
platformsargument.The new parameter is currently ignored, so these tests won’t detect broken propagation from operator config to catalog handler calls.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/pkg/operator/filtered_collector_test.go` around lines 1052 - 1061, The mock getRelatedImagesFromCatalog in MockHandler ignores the new platforms parameter; update it to validate the forwarded platforms pointer (the platforms *[]string argument) before returning results — e.g., check platforms is not nil and that *platforms matches the expected slice (or contains required entries) and return an error (or fail) when it does not so tests detect propagation failures; keep the existing relatedImages behavior otherwise and leave copyImageSchemaMap untouched.internal/pkg/operator/catalog_handler_test.go (1)
43-43: ⚡ Quick winAdd one non-nil
platformscase to validate propagation in returned related images.Current update only checks the
nilpath, so the new behavior can regress without test failure.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/pkg/operator/catalog_handler_test.go` at line 43, Add a test entry in catalog_handler_test.go that calls handler.getRelatedImagesFromCatalog with a non-nil platforms argument (e.g., a slice like []string{"linux/amd64"}) in addition to the existing nil-case; call the same function used in the diff (getRelatedImagesFromCatalog) with that non-nil platforms and copyImageSchemaMap, assert err == nil, and verify that each returned related image in res has its Platforms (or equivalent field) set to the same non-nil slice (or contains the provided platforms), thereby validating propagation of the platforms parameter through the function.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@go.mod`:
- Line 8: Update the pinned module version for
github.com/distribution/distribution/v3 in go.mod from v3.0.0 to a patched
release (>= v3.1.1) to address the listed GHSA advisories; after editing the
version string, run the appropriate Go module commands (e.g., go get
github.com/distribution/distribution/v3@v3.1.1 and go mod tidy) to update go.sum
and ensure build/test pass, and verify no other transitive constraints (e.g.,
from github.com/containerd/containerd or github.com/moby/spdystream) prevent the
upgrade.
- Line 138: The project currently pins github.com/moby/spdystream v0.5.0; update
the dependency to v0.5.1+ by bumping the parent module that pulls it (or
directly requesting the newer version) so the vulnerable transitive dependency
is resolved, then run go mod tidy to refresh go.sum; locate references to
github.com/moby/spdystream in go.mod (and the parent module that requires it)
and run a go get or otherwise update that parent to force
github.com/moby/spdystream@v0.5.1 (or later), followed by go mod tidy to update
go.sum.
- Line 63: Update the indirect dependency github.com/containerd/containerd from
v1.7.29 to at least v1.7.32 in go.mod to address GHSA-fqw6-gf59-qr4w; edit the
require directive for "github.com/containerd/containerd" to "v1.7.32" or a newer
compatible v1.7.x+ version, run "go get
github.com/containerd/containerd@v1.7.32" (or higher) and then "go mod tidy" to
refresh go.sum and ensure the indirect upgrade is applied across the module
graph.
In `@internal/pkg/archive/image-blob-gatherer_test.go`:
- Line 293: The test currently hard-codes the full transport error string in the
assert.Equal call (the assert.Equal(t, "...", err.Error()) in
image-blob-gatherer_test.go), which is brittle across environments; change it to
use substring/contains assertions (e.g., assert.Contains or strings.Contains on
err.Error()) to check key phrases such as "error when creating a new image
source", "fetching manifest latest", and "connection refused" (or "pinging
container registry") instead of the full message so the test is robust to
platform-specific network wording.
In `@internal/pkg/mirror/mirror.go`:
- Around line 359-368: The loop that parses multiArch tokens (using variable
multiArch and splitting into parts) currently only checks len(parts)==2 and can
accept empty or whitespace OS/ARCH; update the validation in that block (the
code that builds copy.InstancePlatformFilter) to trim and reject empty parts and
enforce an allow-list pattern for OS and Architecture (e.g., only
letters/numbers, '-', '_' and dots) before appending to platforms; on invalid
tokens return the same error path (the fmt.Errorf currently returned alongside
copy.CopySystemImage) so malformed tokens are rejected at this trust boundary.
In `@internal/pkg/operator/filtered_collector.go`:
- Around line 251-255: The computed platforms slice is passed into
getRelatedImagesFromCatalog but not applied to the operator catalog image copy,
so the catalog copy ends up unfiltered; update the code that assembles or
creates the operator catalog image later in this function to accept and use the
platforms filter (e.g., pass the platforms variable into the catalog image
creation call or set the Platforms field on the catalog image struct before
invoking the copy), ensuring the same platforms value used with
o.ctlgHandler.getRelatedImagesFromCatalog(result.DeclConfig, platforms,
copyImageSchemaMap) is also applied to the operator catalog image copy.
In `@internal/pkg/release/local_stored_collector.go`:
- Around line 56-73: getPlatformFilters in LocalStorageCollector currently
returns nil when both o.Config.Mirror.Platform.Platforms and Architectures are
empty, causing "mirror all" behavior; change it to return a pointer to a slice
containing the default "linux/amd64" string instead. Specifically, in
getPlatformFilters (and where it falls back from Architectures), replace the
final "return nil" with creation of a []string{"linux/amd64"} and return &slice
so callers expecting *[]string receive the documented default platform.
---
Outside diff comments:
In `@internal/pkg/api/v2alpha1/type_config.go`:
- Around line 116-130: Platform.DeepCopy() currently initializes platformCopy
with only Graph, causing scalar fields like Release and KubeVirtContainer to be
lost; update Platform.DeepCopy to copy all scalar and value fields from the
receiver (e.g., set platformCopy.Release = p.Release and
platformCopy.KubeVirtContainer = p.KubeVirtContainer) in addition to the
existing deep copies of slices (Channels, Architectures, Platforms) so the
returned copy is complete; locate the DeepCopy method on type Platform and add
assignments for any other scalar/value fields to mirror the source struct.
---
Nitpick comments:
In `@internal/pkg/operator/catalog_handler_test.go`:
- Line 43: Add a test entry in catalog_handler_test.go that calls
handler.getRelatedImagesFromCatalog with a non-nil platforms argument (e.g., a
slice like []string{"linux/amd64"}) in addition to the existing nil-case; call
the same function used in the diff (getRelatedImagesFromCatalog) with that
non-nil platforms and copyImageSchemaMap, assert err == nil, and verify that
each returned related image in res has its Platforms (or equivalent field) set
to the same non-nil slice (or contains the provided platforms), thereby
validating propagation of the platforms parameter through the function.
In `@internal/pkg/operator/filtered_collector_test.go`:
- Around line 1052-1061: The mock getRelatedImagesFromCatalog in MockHandler
ignores the new platforms parameter; update it to validate the forwarded
platforms pointer (the platforms *[]string argument) before returning results —
e.g., check platforms is not nil and that *platforms matches the expected slice
(or contains required entries) and return an error (or fail) when it does not so
tests detect propagation failures; keep the existing relatedImages behavior
otherwise and leave copyImageSchemaMap untouched.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 1c8d1649-2c7f-439b-a8ae-62be25a36dee
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (17)
go.modinternal/pkg/additional/local_stored_collector.gointernal/pkg/api/v2alpha1/type_config.gointernal/pkg/api/v2alpha1/type_internal.gointernal/pkg/api/v2alpha1/type_platform.gointernal/pkg/archive/image-blob-gatherer_test.gointernal/pkg/batch/concurrent_chan_worker.gointernal/pkg/helm/local_stored_collector.gointernal/pkg/mirror/mirror.gointernal/pkg/mirror/mirror_test.gointernal/pkg/mirror/options.gointernal/pkg/operator/catalog_handler.gointernal/pkg/operator/catalog_handler_test.gointernal/pkg/operator/filtered_collector.gointernal/pkg/operator/filtered_collector_test.gointernal/pkg/operator/interface.gointernal/pkg/release/local_stored_collector.go
| for _, platform := range strings.Split(multiArch, ",") { | ||
| platform = strings.TrimSpace(platform) | ||
| parts := strings.Split(platform, "/") | ||
| if len(parts) != 2 { | ||
| return copy.CopySystemImage, nil, fmt.Errorf("unknown multi-arch option %q. Choose one of the supported options: 'system', 'all', 'index-only', or a comma-separated platform list like 'linux/amd64,linux/arm64'", multiArch) | ||
| } | ||
| platforms = append(platforms, copy.InstancePlatformFilter{ | ||
| OS: parts[0], | ||
| Architecture: parts[1], | ||
| }) |
There was a problem hiding this comment.
Harden platform token validation before constructing filters.
Line 362 only validates len(parts) == 2; empty or whitespace OS/ARCH values still pass. Reject invalid tokens at this boundary to avoid propagating malformed platform filters.
Proposed fix
- for _, platform := range strings.Split(multiArch, ",") {
+ for _, platform := range strings.Split(multiArch, ",") {
platform = strings.TrimSpace(platform)
- parts := strings.Split(platform, "/")
- if len(parts) != 2 {
+ parts := strings.SplitN(platform, "/", 2)
+ if len(parts) != 2 {
return copy.CopySystemImage, nil, fmt.Errorf("unknown multi-arch option %q. Choose one of the supported options: 'system', 'all', 'index-only', or a comma-separated platform list like 'linux/amd64,linux/arm64'", multiArch)
}
+ osPart := strings.TrimSpace(parts[0])
+ archPart := strings.TrimSpace(parts[1])
+ if osPart == "" || archPart == "" {
+ return copy.CopySystemImage, nil, fmt.Errorf("invalid platform %q: expected non-empty os/architecture", platform)
+ }
platforms = append(platforms, copy.InstancePlatformFilter{
- OS: parts[0],
- Architecture: parts[1],
+ OS: osPart,
+ Architecture: archPart,
})
}As per coding guidelines, “Validate at trust boundaries with allow-lists, not deny-lists.”
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for _, platform := range strings.Split(multiArch, ",") { | |
| platform = strings.TrimSpace(platform) | |
| parts := strings.Split(platform, "/") | |
| if len(parts) != 2 { | |
| return copy.CopySystemImage, nil, fmt.Errorf("unknown multi-arch option %q. Choose one of the supported options: 'system', 'all', 'index-only', or a comma-separated platform list like 'linux/amd64,linux/arm64'", multiArch) | |
| } | |
| platforms = append(platforms, copy.InstancePlatformFilter{ | |
| OS: parts[0], | |
| Architecture: parts[1], | |
| }) | |
| for _, platform := range strings.Split(multiArch, ",") { | |
| platform = strings.TrimSpace(platform) | |
| parts := strings.SplitN(platform, "/", 2) | |
| if len(parts) != 2 { | |
| return copy.CopySystemImage, nil, fmt.Errorf("unknown multi-arch option %q. Choose one of the supported options: 'system', 'all', 'index-only', or a comma-separated platform list like 'linux/amd64,linux/arm64'", multiArch) | |
| } | |
| osPart := strings.TrimSpace(parts[0]) | |
| archPart := strings.TrimSpace(parts[1]) | |
| if osPart == "" || archPart == "" { | |
| return copy.CopySystemImage, nil, fmt.Errorf("invalid platform %q: expected non-empty os/architecture", platform) | |
| } | |
| platforms = append(platforms, copy.InstancePlatformFilter{ | |
| OS: osPart, | |
| Architecture: archPart, | |
| }) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/pkg/mirror/mirror.go` around lines 359 - 368, The loop that parses
multiArch tokens (using variable multiArch and splitting into parts) currently
only checks len(parts)==2 and can accept empty or whitespace OS/ARCH; update the
validation in that block (the code that builds copy.InstancePlatformFilter) to
trim and reject empty parts and enforce an allow-list pattern for OS and
Architecture (e.g., only letters/numbers, '-', '_' and dots) before appending to
platforms; on invalid tokens return the same error path (the fmt.Errorf
currently returned alongside copy.CopySystemImage) so malformed tokens are
rejected at this trust boundary.
Source: Coding guidelines
| func (o LocalStorageCollector) getPlatformFilters() *[]string { | ||
| // Use new Platforms field if available | ||
| if len(o.Config.Mirror.Platform.Platforms) > 0 { | ||
| return v2alpha1.ConvertPlatformsToStringSlice(o.Config.Mirror.Platform.Platforms) | ||
| } | ||
|
|
||
| // Fall back to deprecated Architectures field (assume linux) | ||
| if len(o.Config.Mirror.Platform.Architectures) > 0 { | ||
| platformStrs := make([]string, len(o.Config.Mirror.Platform.Architectures)) | ||
| for i, arch := range o.Config.Mirror.Platform.Architectures { | ||
| platformStrs[i] = "linux/" + arch | ||
| } | ||
| return &platformStrs | ||
| } | ||
|
|
||
| // No platforms specified - mirror all | ||
| return nil | ||
| } |
There was a problem hiding this comment.
Default platform behavior conflicts with config contract.
When both Platforms and Architectures are empty, Line 72 returns nil (mirror all). But Platform docs declare the default should be linux/amd64. This mismatch can unexpectedly mirror every platform.
Proposed fix
func (o LocalStorageCollector) getPlatformFilters() *[]string {
@@
// No platforms specified - mirror all
- return nil
+ defaultPlatform := []string{"linux/" + v2alpha1.DefaultPlatformArchitecture}
+ return &defaultPlatform
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func (o LocalStorageCollector) getPlatformFilters() *[]string { | |
| // Use new Platforms field if available | |
| if len(o.Config.Mirror.Platform.Platforms) > 0 { | |
| return v2alpha1.ConvertPlatformsToStringSlice(o.Config.Mirror.Platform.Platforms) | |
| } | |
| // Fall back to deprecated Architectures field (assume linux) | |
| if len(o.Config.Mirror.Platform.Architectures) > 0 { | |
| platformStrs := make([]string, len(o.Config.Mirror.Platform.Architectures)) | |
| for i, arch := range o.Config.Mirror.Platform.Architectures { | |
| platformStrs[i] = "linux/" + arch | |
| } | |
| return &platformStrs | |
| } | |
| // No platforms specified - mirror all | |
| return nil | |
| } | |
| func (o LocalStorageCollector) getPlatformFilters() *[]string { | |
| // Use new Platforms field if available | |
| if len(o.Config.Mirror.Platform.Platforms) > 0 { | |
| return v2alpha1.ConvertPlatformsToStringSlice(o.Config.Mirror.Platform.Platforms) | |
| } | |
| // Fall back to deprecated Architectures field (assume linux) | |
| if len(o.Config.Mirror.Platform.Architectures) > 0 { | |
| platformStrs := make([]string, len(o.Config.Mirror.Platform.Architectures)) | |
| for i, arch := range o.Config.Mirror.Platform.Architectures { | |
| platformStrs[i] = "linux/" + arch | |
| } | |
| return &platformStrs | |
| } | |
| // No platforms specified - mirror all | |
| defaultPlatform := []string{"linux/" + v2alpha1.DefaultPlatformArchitecture} | |
| return &defaultPlatform | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/pkg/release/local_stored_collector.go` around lines 56 - 73,
getPlatformFilters in LocalStorageCollector currently returns nil when both
o.Config.Mirror.Platform.Platforms and Architectures are empty, causing "mirror
all" behavior; change it to return a pointer to a slice containing the default
"linux/amd64" string instead. Specifically, in getPlatformFilters (and where it
falls back from Architectures), replace the final "return nil" with creation of
a []string{"linux/amd64"} and return &slice so callers expecting *[]string
receive the documented default platform.
3219c3e to
74ce905
Compare
There was a problem hiding this comment.
♻️ Duplicate comments (1)
internal/pkg/mirror/mirror.go (1)
368-377:⚠️ Potential issue | 🟠 Major | ⚡ Quick winStrengthen platform token validation at this trust boundary.
The current validation only checks
len(parts) == 2and doesn't validate the content of OS/Architecture tokens after splitting. Empty or whitespace-only values (e.g.," / ","linux/ ") can pass validation and create malformed platform filters. As per coding guidelines, input validation at trust boundaries should use allow-lists, not just structural checks.🛡️ Proposed fix to validate and sanitize platform tokens
for _, platform := range strings.Split(multiArch, ",") { platform = strings.TrimSpace(platform) - parts := strings.Split(platform, "/") + parts := strings.SplitN(platform, "/", 2) if len(parts) != 2 { return copy.CopySystemImage, nil, fmt.Errorf("unknown multi-arch option %q. Choose one of the supported options: 'system', 'all', 'index-only', or a comma-separated platform list like 'linux/amd64,linux/arm64'", multiArch) } + osPart := strings.TrimSpace(parts[0]) + archPart := strings.TrimSpace(parts[1]) + if osPart == "" || archPart == "" { + return copy.CopySystemImage, nil, fmt.Errorf("invalid platform %q: OS and architecture must be non-empty", platform) + } + // Validate against allow-list: alphanumeric, hyphen, underscore, dot + validPattern := regexp.MustCompile(`^[a-zA-Z0-9._-]+$`) + if !validPattern.MatchString(osPart) || !validPattern.MatchString(archPart) { + return copy.CopySystemImage, nil, fmt.Errorf("invalid platform %q: OS and architecture must contain only letters, numbers, hyphens, underscores, and dots", platform) + } platforms = append(platforms, copy.InstancePlatformFilter{ - OS: parts[0], - Architecture: parts[1], + OS: osPart, + Architecture: archPart, }) }Note: You'll need to import
"regexp"at the top of the file.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/pkg/mirror/mirror.go` around lines 368 - 377, The loop that parses multiArch platforms accepts tokens with only a structural check (len(parts)==2) which allows empty or whitespace OS/Architecture values; update the logic in the function containing this loop (the multi-arch platform parsing block in mirror.go) to (1) Trim and validate each token and each part after splitting, (2) enforce an allow-list/regex for OS and Architecture (e.g., permit only lowercase letters, digits and hyphens/underscores) and reject empty strings, and (3) return a clear error when a token fails validation; add the required import ("regexp") and use the validated parts when building copy.InstancePlatformFilter to prevent malformed platform filters.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@internal/pkg/mirror/mirror.go`:
- Around line 368-377: The loop that parses multiArch platforms accepts tokens
with only a structural check (len(parts)==2) which allows empty or whitespace
OS/Architecture values; update the logic in the function containing this loop
(the multi-arch platform parsing block in mirror.go) to (1) Trim and validate
each token and each part after splitting, (2) enforce an allow-list/regex for OS
and Architecture (e.g., permit only lowercase letters, digits and
hyphens/underscores) and reject empty strings, and (3) return a clear error when
a token fails validation; add the required import ("regexp") and use the
validated parts when building copy.InstancePlatformFilter to prevent malformed
platform filters.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 6601800d-c8a5-472a-8855-b3444425902e
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (17)
go.modinternal/pkg/additional/local_stored_collector.gointernal/pkg/api/v2alpha1/type_config.gointernal/pkg/api/v2alpha1/type_internal.gointernal/pkg/api/v2alpha1/type_platform.gointernal/pkg/archive/image-blob-gatherer_test.gointernal/pkg/batch/concurrent_chan_worker.gointernal/pkg/helm/local_stored_collector.gointernal/pkg/mirror/mirror.gointernal/pkg/mirror/mirror_test.gointernal/pkg/mirror/options.gointernal/pkg/operator/catalog_handler.gointernal/pkg/operator/catalog_handler_test.gointernal/pkg/operator/filtered_collector.gointernal/pkg/operator/filtered_collector_test.gointernal/pkg/operator/interface.gointernal/pkg/release/local_stored_collector.go
✅ Files skipped from review due to trivial changes (1)
- internal/pkg/archive/image-blob-gatherer_test.go
🚧 Files skipped from review as they are similar to previous changes (12)
- internal/pkg/operator/filtered_collector_test.go
- internal/pkg/operator/interface.go
- internal/pkg/operator/catalog_handler.go
- internal/pkg/api/v2alpha1/type_platform.go
- internal/pkg/operator/catalog_handler_test.go
- internal/pkg/batch/concurrent_chan_worker.go
- internal/pkg/additional/local_stored_collector.go
- internal/pkg/operator/filtered_collector.go
- internal/pkg/helm/local_stored_collector.go
- internal/pkg/api/v2alpha1/type_internal.go
- internal/pkg/api/v2alpha1/type_config.go
- internal/pkg/release/local_stored_collector.go
There was a problem hiding this comment.
♻️ Duplicate comments (1)
go.mod (1)
8-8:⚠️ Potential issue | 🟠 Major | ⚡ Quick winResolve known vulnerable pinned modules before merge.
go.modstill pins versions flagged as HIGH severity:
- Line 8:
github.com/distribution/distribution/v3 v3.0.0- Line 63:
github.com/containerd/containerd v1.7.29- Line 138:
github.com/moby/spdystream v0.5.0Please bump to patched releases and refresh
go.sum(go get ... && go mod tidy) to satisfy the repo’s dependency security policy.#!/bin/bash set -euo pipefail echo "== Current versions in go.mod ==" rg -n 'github.com/distribution/distribution/v3|github.com/containerd/containerd|github.com/moby/spdystream' go.mod echo echo "== OSV check: distribution/v3 ==" curl -s https://api.osv.dev/v1/query -H 'Content-Type: application/json' \ -d '{"package":{"ecosystem":"Go","name":"github.com/distribution/distribution/v3"}}' \ | jq '.vulns[]? | {id: .id, summary: .summary, affected: .affected[0].ranges}' echo echo "== OSV check: containerd ==" curl -s https://api.osv.dev/v1/query -H 'Content-Type: application/json' \ -d '{"package":{"ecosystem":"Go","name":"github.com/containerd/containerd"}}' \ | jq '.vulns[]? | {id: .id, summary: .summary, affected: .affected[0].ranges}' echo echo "== OSV check: moby/spdystream ==" curl -s https://api.osv.dev/v1/query -H 'Content-Type: application/json' \ -d '{"package":{"ecosystem":"Go","name":"github.com/moby/spdystream"}}' \ | jq '.vulns[]? | {id: .id, summary: .summary, affected: .affected[0].ranges}'Also applies to: 63-63, 138-138
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@go.mod` at line 8, go.mod pins vulnerable module versions for github.com/distribution/distribution/v3, github.com/containerd/containerd and github.com/moby/spdystream; update each to the latest patched release, run “go get github.com/distribution/distribution/v3@<patched> github.com/containerd/containerd@<patched> github.com/moby/spdystream@<patched>” (replace <patched> with the secure versions) and then run “go mod tidy” to refresh go.sum; ensure the updated module lines (github.com/distribution/distribution/v3, github.com/containerd/containerd, github.com/moby/spdystream) in go.mod reflect the new versions and commit the resulting go.mod and go.sum changes.Sources: Coding guidelines, Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@go.mod`:
- Line 8: go.mod pins vulnerable module versions for
github.com/distribution/distribution/v3, github.com/containerd/containerd and
github.com/moby/spdystream; update each to the latest patched release, run “go
get github.com/distribution/distribution/v3@<patched>
github.com/containerd/containerd@<patched> github.com/moby/spdystream@<patched>”
(replace <patched> with the secure versions) and then run “go mod tidy” to
refresh go.sum; ensure the updated module lines
(github.com/distribution/distribution/v3, github.com/containerd/containerd,
github.com/moby/spdystream) in go.mod reflect the new versions and commit the
resulting go.mod and go.sum changes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: fc19da77-8286-4674-9b7f-072db74d31b2
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (17)
go.modinternal/pkg/additional/local_stored_collector.gointernal/pkg/api/v2alpha1/type_config.gointernal/pkg/api/v2alpha1/type_internal.gointernal/pkg/api/v2alpha1/type_platform.gointernal/pkg/archive/image-blob-gatherer_test.gointernal/pkg/batch/concurrent_chan_worker.gointernal/pkg/helm/local_stored_collector.gointernal/pkg/mirror/mirror.gointernal/pkg/mirror/mirror_test.gointernal/pkg/mirror/options.gointernal/pkg/operator/catalog_handler.gointernal/pkg/operator/catalog_handler_test.gointernal/pkg/operator/filtered_collector.gointernal/pkg/operator/filtered_collector_test.gointernal/pkg/operator/interface.gointernal/pkg/release/local_stored_collector.go
✅ Files skipped from review due to trivial changes (1)
- internal/pkg/archive/image-blob-gatherer_test.go
🚧 Files skipped from review as they are similar to previous changes (15)
- internal/pkg/operator/catalog_handler_test.go
- internal/pkg/operator/interface.go
- internal/pkg/mirror/options.go
- internal/pkg/operator/filtered_collector.go
- internal/pkg/additional/local_stored_collector.go
- internal/pkg/batch/concurrent_chan_worker.go
- internal/pkg/mirror/mirror_test.go
- internal/pkg/operator/filtered_collector_test.go
- internal/pkg/api/v2alpha1/type_platform.go
- internal/pkg/api/v2alpha1/type_config.go
- internal/pkg/release/local_stored_collector.go
- internal/pkg/helm/local_stored_collector.go
- internal/pkg/api/v2alpha1/type_internal.go
- internal/pkg/operator/catalog_handler.go
- internal/pkg/mirror/mirror.go
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
internal/pkg/operator/filtered_collector.go (1)
251-255:⚠️ Potential issue | 🟠 Major | ⚡ Quick winCatalog image misses platform filter propagation
Line 306 builds the catalog
RelatedImagewithoutPlatforms, so the catalog copy path can still mirror all architectures even though Line 254 now filters related images.Suggested patch
relatedImages[componentName] = []v2alpha1.RelatedImage{ { Name: catalogName, Image: catalogImage, Type: v2alpha1.TypeOperatorCatalog, TargetTag: targetTag, TargetCatalog: op.TargetCatalog, RebuiltTag: rebuiltTag, FullCatalog: isFullCatalog(op), + Platforms: platforms, }, }Also applies to: 306-315
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/pkg/operator/filtered_collector.go` around lines 251 - 255, The catalog-related image construction is missing propagation of platform filters: after you call o.ctlgHandler.getRelatedImagesFromCatalog(result.DeclConfig, platforms, copyImageSchemaMap) (where platforms := v2alpha1.ConvertPlatformsToStringSlice(op.Platforms)), ensure that each RelatedImage created for the catalog copy path includes the same Platforms value (set RelatedImage.Platforms = platforms or equivalent) so the catalog copy honors op.Platforms; update the code paths that build RelatedImage instances (the block referenced around getRelatedImagesFromCatalog and the construction in the 306–315 region) to copy/set the platforms slice from the platforms variable into the RelatedImage before returning or appending.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@go.mod`:
- Line 3: The go.mod specifies Go 1.25.6 but the build sandbox uses
GO_VERSION=go1.23.5 causing mismatched toolchains; update the hack/build.sh,
hack/e2e.sh and the Dockerfile (local/go-toolset) to either install/use Go
1.25.6 (set GO_VERSION=go1.25.6 and ensure the local/go-toolset image installs
that toolchain) or make the scripts export GOTOOLCHAIN=auto so the runtime
respects the go.mod directive; change occurrences of GO_VERSION and any image
build steps that pull the older toolset, and verify createToolchain/install
steps in local/go-toolset use the 1.25.6 installer to keep builds consistent
with go.mod.
---
Duplicate comments:
In `@internal/pkg/operator/filtered_collector.go`:
- Around line 251-255: The catalog-related image construction is missing
propagation of platform filters: after you call
o.ctlgHandler.getRelatedImagesFromCatalog(result.DeclConfig, platforms,
copyImageSchemaMap) (where platforms :=
v2alpha1.ConvertPlatformsToStringSlice(op.Platforms)), ensure that each
RelatedImage created for the catalog copy path includes the same Platforms value
(set RelatedImage.Platforms = platforms or equivalent) so the catalog copy
honors op.Platforms; update the code paths that build RelatedImage instances
(the block referenced around getRelatedImagesFromCatalog and the construction in
the 306–315 region) to copy/set the platforms slice from the platforms variable
into the RelatedImage before returning or appending.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 3d59dc56-7672-41f8-a6be-eaf1d8c7f04a
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (17)
go.modinternal/pkg/additional/local_stored_collector.gointernal/pkg/api/v2alpha1/type_config.gointernal/pkg/api/v2alpha1/type_internal.gointernal/pkg/api/v2alpha1/type_platform.gointernal/pkg/archive/image-blob-gatherer_test.gointernal/pkg/batch/concurrent_chan_worker.gointernal/pkg/helm/local_stored_collector.gointernal/pkg/mirror/mirror.gointernal/pkg/mirror/mirror_test.gointernal/pkg/mirror/options.gointernal/pkg/operator/catalog_handler.gointernal/pkg/operator/catalog_handler_test.gointernal/pkg/operator/filtered_collector.gointernal/pkg/operator/filtered_collector_test.gointernal/pkg/operator/interface.gointernal/pkg/release/local_stored_collector.go
🚧 Files skipped from review as they are similar to previous changes (13)
- internal/pkg/mirror/options.go
- internal/pkg/archive/image-blob-gatherer_test.go
- internal/pkg/additional/local_stored_collector.go
- internal/pkg/batch/concurrent_chan_worker.go
- internal/pkg/operator/catalog_handler_test.go
- internal/pkg/api/v2alpha1/type_platform.go
- internal/pkg/api/v2alpha1/type_internal.go
- internal/pkg/operator/interface.go
- internal/pkg/mirror/mirror_test.go
- internal/pkg/operator/catalog_handler.go
- internal/pkg/release/local_stored_collector.go
- internal/pkg/mirror/mirror.go
- internal/pkg/api/v2alpha1/type_config.go
| module github.com/openshift/oc-mirror/v2 | ||
|
|
||
| go 1.24.3 | ||
| go 1.25.6 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== go.mod go directive =="
rg -n '^go ' go.mod
echo
echo "== toolchain directives (if any) =="
rg -n '^toolchain ' go.mod || true
echo
echo "== Go version pins in common repo files =="
rg -n '1\.25|go-version|GOTOOLCHAIN|golang' Makefile .golangci.v2.yaml .golangci.yaml .github || true
echo
echo "== Dockerfiles / CI configs that may pin Go versions =="
fd -i 'Dockerfile|\.ya?ml$|\.json$' .github | xargs -r rg -n 'golang:|go1\.|1\.25|GOTOOLCHAIN|actions/setup-go' || trueRepository: openshift/oc-mirror
Length of output: 313
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Search for setup-go go-version pins =="
fd -i '*.yml' .github/workflows .github 2>/dev/null | xargs -r rg -n 'actions/setup-go|go-version:|go-version|GOTOOLCHAIN|toolchain:|GO_VERSION' || true
echo
echo "== Search for GOTOOLCHAIN / go1.25 across repo (limited to text/config files) =="
fd -i '*.*' . | rg -n --glob '!**/vendor/**' --glob '!**/node_modules/**' --glob '!**/dist/**' 'GOTOOLCHAIN|go1\.25|go-version|GO_VERSION' || true
echo
echo "== Check Makefile toolchain behavior (go env / go version) =="
rg -n 'GOTOOLCHAIN|GO_VERSION|setup-go|go1\.|golangci-lint|go env|toolchain|GOROOT' Makefile .github || true
echo
echo "== Any local toolchain files / scripts? =="
ls -la | rg -n 'go\.version|toolchain|GOTOOLCHAIN|\.go-version' || true
fd -i -t f 'go\.version|\.go-version|toolchain.*|*go*version*' .github Makefile . || trueRepository: openshift/oc-mirror
Length of output: 1223
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== actions/setup-go usage in workflows =="
rg -n --no-heading 'actions/setup-go' .github/workflows .github 2>/dev/null || true
echo
echo "== go-version / Go version pins in workflows (yaml/yml) =="
rg -n --no-heading 'go-version:|GOTOOLCHAIN|toolchain:|GO_VERSION' .github/workflows .github 2>/dev/null || true
echo
echo "== Look for GOTOOLCHAIN / GO_VERSION elsewhere (excluding vendor) =="
rg -n --no-heading 'GOTOOLCHAIN|GO_VERSION' . --glob '!**/vendor/**' --glob '!**/node_modules/**' 2>/dev/null || true
echo
echo "== Check for Go toolchain files by name =="
fd -i -t f 'go\.version|\.go-version|tool-versions|\.tool-versions|asdf\.tool-versions' . 2>/dev/null || true
echo
echo "== Check Makefile for any GOTOOLCHAIN/Go toolchain logic =="
rg -n --no-heading 'GOTOOLCHAIN|GO_VERSION|setup-go|go-version:|go env|GOROOT' Makefile 2>/dev/null || trueRepository: openshift/oc-mirror
Length of output: 1206
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Search for GO_VERSION / go1.23.5 / go1.25 in repo =="
rg -n --no-heading 'GO_VERSION=|go1\.23\.5|go1\.25|1\.25\.6|GOTOOLCHAIN' . --glob '!**/vendor/**' --glob '!**/node_modules/**' || true
echo
echo "== Inspect Dockerfile around GO_VERSION pin (lines ~1-80) =="
nl -ba Dockerfile | sed -n '1,120p'
echo
echo "== Inspect tests/e2e/Makefile =="
nl -ba tests/e2e/Makefile | sed -n '1,80p'
echo
echo "== Search workflows for Dockerfile usage (build/push) =="
rg -n --no-heading 'Dockerfile|docker build|build-args|GO_VERSION|go1\.23|go1\.25|GOTOOLCHAIN' .github/workflows .github 2>/dev/null || true
echo
echo "== Inspect Makefile for any go/toolchain pin logic =="
nl -ba Makefile | sed -n '1,120p'Repository: openshift/oc-mirror
Length of output: 1031
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Show relevant Dockerfile section (around GO_VERSION pin) =="
sed -n '1,120p' Dockerfile
echo
echo "== Show relevant Dockerfile.tests-extension section (if small) =="
sed -n '1,120p' Dockerfile.tests-extension || true
echo
echo "== Show relevant images/cli/Dockerfile.ci section (if small) =="
sed -n '1,140p' images/cli/Dockerfile.ci || true
echo
echo "== Show tests/e2e/Makefile (small) =="
sed -n '1,120p' tests/e2e/Makefile || true
echo
echo "== Show Makefile top section =="
sed -n '1,120p' MakefileRepository: openshift/oc-mirror
Length of output: 11260
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== List workflows =="
ls -ლა .github/workflows 2>/dev/null || true
echo
echo "== Search workflows for oc-mirror image build (Dockerfiles referenced) =="
rg -n --no-heading 'Dockerfile\.ci|images/cli/Dockerfile\.ci|Dockerfile\.tests-extension|Dockerfile\.tests|Dockerfile[^/]*\b|docker build|buildx|ko |go-toolset|local/go-toolset' .github/workflows 2>/dev/null || true
echo
echo "== Search workflows for build machinery / make targets =="
rg -n --no-heading 'make (build|sanity|verify|test|test-unit)|sanity|golangci-lint|GOTOOLCHAIN|GO_VERSION|setup-go' .github/workflows 2>/dev/null || trueRepository: openshift/oc-mirror
Length of output: 218
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== List .github directory (top-level) =="
find .github -maxdepth 2 -type f -print 2>/dev/null | sed -n '1,200p' || true
echo
echo "== Search for CI build config files (yaml/yml) =="
fd -i -t f '*.yml' -a -a .github 2>/dev/null || true
fd -i -t f '*.yaml' .github 2>/dev/null || true
echo
echo "== Search entire repo for setup-go / go-toolset / builder image tags =="
rg -n --no-heading 'actions/setup-go|go-toolset|Dockerfile\.ci|golang-1\.2|golang-1\.23|golang-1\.24|golang-1\.25|GOTOOLCHAIN=auto|GO_VERSION=go' . --glob '!**/vendor/**' --glob '!**/node_modules/**' 2>/dev/null || trueRepository: openshift/oc-mirror
Length of output: 2658
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== hack/build.sh =="
sed -n '1,160p' hack/build.sh
echo
echo "== hack/e2e.sh =="
sed -n '1,160p' hack/e2e.sh
echo
echo "== tests/integration/image-builders/release/containerfile-rhel9 =="
sed -n '1,120p' tests/integration/image-builders/release/containerfile-rhel9
echo
echo "== List any other integration image-builder Dockerfiles mentioning golang-1.2* =="
rg -n --no-heading 'golang-1\.23|golang-1\.24|golang-1\.25' tests/integration/image-builders --glob '!**/vendor/**' 2>/dev/null || trueRepository: openshift/oc-mirror
Length of output: 2585
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== go.mod excerpt around lines 1-200 =="
sed -n '1,220p' go.mod
echo
echo "== go.mod lines with the specific modules mentioned in the review (if present) =="
rg -n 'github.com/distribution/distribution/v3|github.com/containerd/containerd|github.com/moby/spdystream' go.mod || trueRepository: openshift/oc-mirror
Length of output: 11645
Align local Go toolchain with go.mod (Go 1.25.6 vs GO_VERSION=go1.23.5)
go.modrequires Go1.25.6, but the local builder used byhack/build.shandhack/e2e.sh(Dockerfile→local/go-toolset) downloadsGO_VERSION=go1.23.5and those hack flows don’t setGOTOOLCHAIN=auto, somake buildcan fail when enforcing thegodirective.- Update
Dockerfile/hack scripts to install or enable the Go 1.25.6 toolchain consistently (alternatively setGOTOOLCHAIN=autofor the hack builds).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@go.mod` at line 3, The go.mod specifies Go 1.25.6 but the build sandbox uses
GO_VERSION=go1.23.5 causing mismatched toolchains; update the hack/build.sh,
hack/e2e.sh and the Dockerfile (local/go-toolset) to either install/use Go
1.25.6 (set GO_VERSION=go1.25.6 and ensure the local/go-toolset image installs
that toolchain) or make the scripts export GOTOOLCHAIN=auto so the runtime
respects the go.mod directive; change occurrences of GO_VERSION and any image
build steps that pull the older toolset, and verify createToolchain/install
steps in local/go-toolset use the 1.25.6 installer to keep builds consistent
with go.mod.
adolfo-ab
left a comment
There was a problem hiding this comment.
Can you check if you need to also update internal/pkg/config/defaults.go and cincinnati.go?
Also, maybe you could add one or two integration tests, so that this feature is already covered.
|
|
||
| // Fall back to deprecated Architectures field (assume linux) | ||
| //nolint:staticcheck // SA1019: Architectures is deprecated but we maintain backward compatibility | ||
| if len(o.Config.Mirror.Platform.Architectures) > 0 { |
There was a problem hiding this comment.
Since Architectures is deprecated, maybe we can add a log line mentioning it here, and asking to consider using Platform instead
| // InstancePlatformFilter defines OS and Architecture for filtering | ||
| // multi-architecture manifest lists. This allows selecting specific | ||
| // platforms (e.g., linux/amd64, linux/arm64) when mirroring images. | ||
| type InstancePlatformFilter struct { |
There was a problem hiding this comment.
What happens if a user only sets the OS or the Architecture? Should we check that we always have both? Otherwise we might get linux/ or /amd64, no?
Implement InstancePlatformFilter feature with sparse manifest support to allow users to specify OS/Architecture pairs for filtering multi-architecture images across all image types (additional images, operators, helm charts, and releases). This feature brings the platform filtering capability from skopeo (containers/image PR #2874) to oc-mirror, enabling users to mirror only specific platforms instead of all architectures. The implementation uses sparse manifests where the manifest list references all platforms but only the specified platforms have their actual layer blobs downloaded, significantly reducing disk usage and bandwidth. Platform filtering is applied during Mirror-to-Disk and Mirror-to-Mirror workflows. Disk-to-Mirror workflow uses already-filtered images from disk without re-applying platform filters. The implementation includes backward compatibility with the deprecated Platform.Architectures field and follows the same strategy as skopeo for consistency. Fixes: CLID-290 Signed-off-by: Alex Guidi <aguidi@redhat.com>
|
/test v1-e2e |
|
@aguidirh: all tests passed! Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
Description
This PR implements sparse manifest platform filtering for multi-architecture images in oc-mirror. Users can now specify OS/Architecture pairs to filter which platforms are mirrored, significantly reducing disk usage and bandwidth requirements.
The implementation brings the platform filtering capability from containers/image (containers/container-libs PR #656) to oc-mirror. It uses sparse manifests where the manifest list references all platforms but only the specified platforms have their actual layer blobs downloaded.
Platform filtering works across all image types:
architecturesfield)Github / Jira issue: CLID-290
Type of change
How Has This Been Tested?
Still in Progress.
Expected Outcome
Platform filtering reduces disk usage by 60-75% when mirroring only specific platforms instead of all architectures. Sparse manifests are created where manifest lists reference all platforms but only selected platforms have layer blobs downloaded.
Summary by CodeRabbit