For an image index, remove the original component and replace it with an expanded component with all its image manifests Do not raise an error if the image is inaccessible, it will be handled as a violation when evaluated against the policy This is to retain the original behavior of the `ec validate
(client oci.Client, component app.SnapshotComponent, componentChan chan<- []app.SnapshotComponent, errorsChan chan<- error, exp *ExpansionInfo)
| 212 | // Do not raise an error if the image is inaccessible, it will be handled as a violation when evaluated against the policy |
| 213 | // This is to retain the original behavior of the `ec validate` command. |
| 214 | func imageIndexWorker(client oci.Client, component app.SnapshotComponent, componentChan chan<- []app.SnapshotComponent, errorsChan chan<- error, exp *ExpansionInfo) { |
| 215 | var components []app.SnapshotComponent |
| 216 | components = append(components, component) |
| 217 | // to avoid adding to componentsChan before each return |
| 218 | defer func() { |
| 219 | componentChan <- components |
| 220 | }() |
| 221 | |
| 222 | ref, err := name.ParseReference(component.ContainerImage) |
| 223 | if err != nil { |
| 224 | errorsChan <- fmt.Errorf("unable to parse container image %s: %w", component.ContainerImage, err) |
| 225 | return |
| 226 | } |
| 227 | |
| 228 | desc, err := client.Head(ref) |
| 229 | if err != nil { |
| 230 | errorsChan <- fmt.Errorf("unable to fetch descriptior for container image %s: %w", ref, err) |
| 231 | return |
| 232 | } |
| 233 | |
| 234 | if !desc.MediaType.IsIndex() { |
| 235 | return |
| 236 | } |
| 237 | |
| 238 | index, err := client.Index(ref) |
| 239 | if err != nil { |
| 240 | errorsChan <- fmt.Errorf("unable to fetch index for container image %s: %w", component.ContainerImage, err) |
| 241 | return |
| 242 | } |
| 243 | |
| 244 | indexManifest, err := index.IndexManifest() |
| 245 | if err != nil { |
| 246 | errorsChan <- fmt.Errorf("unable to fetch index manifest for container image %s: %w", component.ContainerImage, err) |
| 247 | return |
| 248 | } |
| 249 | |
| 250 | // Track expansion metadata |
| 251 | idxPinned := fmt.Sprintf("%s@%s", ref.Context().Name(), desc.Digest) |
| 252 | exp.SetIndexAlias(ref.Name(), idxPinned) |
| 253 | |
| 254 | // Add the platform-specific image references (Image Manifests) to the list of components so |
| 255 | // each is validated as well as the multi-platform image reference (Image Index). |
| 256 | for i, manifest := range indexManifest.Manifests { |
| 257 | var arch string |
| 258 | if manifest.Platform != nil && manifest.Platform.Architecture != "" { |
| 259 | arch = manifest.Platform.Architecture |
| 260 | } else { |
| 261 | arch = fmt.Sprintf("noarch-%d", i) |
| 262 | } |
| 263 | archComponent := component |
| 264 | archComponent.Name = fmt.Sprintf("%s-%s-%s", component.Name, manifest.Digest, arch) |
| 265 | archComponent.ContainerImage = fmt.Sprintf("%s@%s", ref.Context().Name(), manifest.Digest) |
| 266 | components = append(components, archComponent) |
| 267 | |
| 268 | // Track parent-child relationships |
| 269 | childPinned := archComponent.ContainerImage |
| 270 | exp.AddChildToIndex(idxPinned, childPinned) |
| 271 | exp.SetParentByChild(childPinned, idxPinned) |
no test coverage detected