@@ -493,7 +493,7 @@ def _validate_image_architecture(self, expected_version: str) -> bool:
493493 """
494494 full_uri = f"{ self .registry } /{ self .image_name } :{ expected_version } "
495495
496- # Use docker buildx imagetools to get architecture from image
496+ # First, try to get the raw manifest
497497 result = subprocess .run (
498498 ["docker" , "buildx" , "imagetools" , "inspect" , "--raw" , full_uri ],
499499 capture_output = True ,
@@ -507,28 +507,88 @@ def _validate_image_architecture(self, expected_version: str) -> bool:
507507
508508 try :
509509 manifest_data = json .loads (result .stdout )
510- arch = manifest_data .get ("architecture" , "" )
511- os_name = manifest_data .get ("os" , "" )
512510
513- if not arch or not os_name :
514- print (f"❌ Architecture metadata not found in image" , file = sys .stderr )
511+ # Check if this is a manifest list (multi-platform) or single manifest
512+ media_type = manifest_data .get ("mediaType" , "" )
513+ schema_version = manifest_data .get ("schemaVersion" , 0 )
514+
515+ # Handle manifest list (multi-platform images)
516+ if media_type in [
517+ "application/vnd.docker.distribution.manifest.list.v2+json" ,
518+ "application/vnd.oci.image.index.v1+json" ,
519+ ]:
520+ manifests = manifest_data .get ("manifests" , [])
521+ if not manifests :
522+ print (f"❌ No manifests found in manifest list" , file = sys .stderr )
523+ return False
524+
525+ # Look for linux/amd64 platform
526+ for manifest in manifests :
527+ platform = manifest .get ("platform" , {})
528+ arch = platform .get ("architecture" , "" )
529+ os_name = platform .get ("os" , "" )
530+
531+ if arch == "amd64" and os_name == "linux" :
532+ print (f" Architecture: { os_name } /{ arch } (from manifest list)" , file = sys .stderr )
533+ print (f"✅ Valid production architecture: { os_name } /{ arch } " , file = sys .stderr )
534+ return True
535+
536+ print (f"❌ linux/amd64 platform not found in manifest list" , file = sys .stderr )
537+ return False
538+
539+ # Handle single manifest (single-platform images)
540+ # For single manifests, architecture is in the config blob, not the manifest
541+ # We need to inspect without --raw to get platform info
542+ result_formatted = subprocess .run (
543+ ["docker" , "buildx" , "imagetools" , "inspect" , full_uri ],
544+ capture_output = True ,
545+ text = True ,
546+ check = False ,
547+ )
548+
549+ if result_formatted .returncode != 0 :
550+ print (f"❌ Failed to inspect image (formatted): { result_formatted .stderr } " , file = sys .stderr )
515551 return False
516552
517- arch_info = f"{ os_name } /{ arch } "
518- print (f" Architecture: { arch_info } " , file = sys .stderr )
553+ # Parse the human-readable output for platform info
554+ # Output format: "Name: <image>\nMediaType: ...\nDigest: ...\nPlatform: linux/amd64"
555+ output = result_formatted .stdout
556+ platform_line = None
557+ for line in output .split ("\n " ):
558+ if line .strip ().startswith ("Platform:" ):
559+ platform_line = line .strip ()
560+ break
561+
562+ if not platform_line :
563+ # Fallback: try to get architecture from manifest's config
564+ arch = manifest_data .get ("architecture" , "" )
565+ os_name = manifest_data .get ("os" , "" )
566+
567+ if arch and os_name :
568+ arch_info = f"{ os_name } /{ arch } "
569+ print (f" Architecture: { arch_info } (from manifest)" , file = sys .stderr )
570+
571+ if arch == "amd64" and os_name == "linux" :
572+ print (f"✅ Valid production architecture: { arch_info } " , file = sys .stderr )
573+ return True
574+
575+ print (f"❌ Invalid architecture: { arch_info } " , file = sys .stderr )
576+ print (f" Production images MUST be linux/amd64" , file = sys .stderr )
577+ return False
578+
579+ print (f"❌ Architecture metadata not found in image" , file = sys .stderr )
580+ print (f" Debug: manifest mediaType={ media_type } , schemaVersion={ schema_version } " , file = sys .stderr )
581+ return False
519582
520- # Calculate image size
521- layers = manifest_data .get ("layers" , [])
522- if layers :
523- size_bytes = sum (layer .get ("size" , 0 ) for layer in layers )
524- print (f" Size: { self ._format_size (size_bytes )} " , file = sys .stderr )
583+ # Parse platform from the formatted output (e.g., "Platform: linux/amd64")
584+ platform_str = platform_line .split (":" , 1 )[1 ].strip ()
585+ print (f" Architecture: { platform_str } " , file = sys .stderr )
525586
526- # Validate it's linux/amd64
527- if arch == "amd64" and os_name == "linux" :
528- print (f"✅ Valid production architecture: { arch_info } " , file = sys .stderr )
587+ if platform_str == "linux/amd64" :
588+ print (f"✅ Valid production architecture: { platform_str } " , file = sys .stderr )
529589 return True
530590
531- print (f"❌ Invalid architecture: { arch_info } " , file = sys .stderr )
591+ print (f"❌ Invalid architecture: { platform_str } " , file = sys .stderr )
532592 print (f" Production images MUST be linux/amd64" , file = sys .stderr )
533593 return False
534594
0 commit comments