Skip to content

fix(docker): thread platform through Docker daemon inspect and save APIs#524

Merged
willmurphyscode merged 1 commit intomainfrom
fix-new-docker
Feb 19, 2026
Merged

fix(docker): thread platform through Docker daemon inspect and save APIs#524
willmurphyscode merged 1 commit intomainfrom
fix-new-docker

Conversation

@willmurphyscode
Copy link
Copy Markdown
Contributor

@willmurphyscode willmurphyscode commented Feb 19, 2026

Docker 29 changed image storage so tags point to manifest lists instead of platform-specific images. This broke platform selection via the Docker daemon: inspect returned empty OS/architecture for foreign platforms, and save failed entirely on manifest lists.

Pass the requested platform to ImageInspect (API v1.49+) and ImageSave (API v1.48+) so both calls resolve the manifest list correctly. Each call falls back to the plain API when talking to older daemons, keeping backward compatibility with Docker 27/28.

Before this change:

$ syft alpine:latest --from docker --platform linux/amd64
 ✔ Pulled image
[0001] ERROR could not determine source: an error occurred attempting to resolve 'alpine:latest': docker: image has unexpected OS "", which differs from the user specified PS "linux"

After this change:

$ go run ./cmd/syft alpine:latest --from docker --platform linux/amd64
 ✔ Loaded image                                                                                        alpine:latest
 ✔ Parsed image                              sha256:a40c03cbb81c59bfb0e0887ab0b1859727075da7b9cc576a1cec2c771f38c5fb
 ✔ Cataloged contents                               ceedcaa851833940d364da9a0a99b8c50699bef7776439e2fb3d923a60a6638b
   ├── ✔ Packages                        [16 packages]
   ├── ✔ Executables                     [17 executables]
   ├── ✔ File metadata                   [79 locations]
   └── ✔ File digests                    [79 files]
NAME                    VERSION      TYPE
alpine-baselayout       3.7.1-r8     apk
alpine-baselayout-data  3.7.1-r8     apk
alpine-keys             2.6-r0       apk
alpine-release          3.23.3-r0    apk

I think we're basically adding a compensation for moby/moby#51532 here.

Docker 29 changed image storage so tags point to manifest lists instead
of platform-specific images. This broke platform selection via the Docker
daemon: inspect returned empty OS/architecture for foreign platforms, and
save failed entirely on manifest lists.

Pass the requested platform to ImageInspect (API v1.49+) and ImageSave
(API v1.48+) so both calls resolve the manifest list correctly. Each
call falls back to the plain API when talking to older daemons, keeping
backward compatibility with Docker 27/28.

Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com>
@willmurphyscode willmurphyscode self-assigned this Feb 19, 2026
@github-actions
Copy link
Copy Markdown

Benchmark Test Results

Benchmark results from the latest changes vs base branch
make .tool/task
make[1]: Entering directory '/home/runner/work/stereoscope/stereoscope'
make[1]: Leaving directory '/home/runner/work/stereoscope/stereoscope'
.tool/task show-benchstat
?   	github.com/anchore/stereoscope	[no test files]
?   	github.com/anchore/stereoscope/examples	[no test files]
PASS
ok  	github.com/anchore/stereoscope/internal	0.004s
?   	github.com/anchore/stereoscope/internal/bus	[no test files]
PASS
ok  	github.com/anchore/stereoscope/internal/containerd	0.008s
PASS
ok  	github.com/anchore/stereoscope/internal/docker	0.005s
?   	github.com/anchore/stereoscope/internal/log	[no test files]
PASS
ok  	github.com/anchore/stereoscope/internal/podman	0.005s
?   	github.com/anchore/stereoscope/pkg/event	[no test files]
?   	github.com/anchore/stereoscope/pkg/event/parsers	[no test files]
goos: linux
goarch: amd64
pkg: github.com/anchore/stereoscope/pkg/file
cpu: AMD EPYC 7763 64-Core Processor                
BenchmarkTarIndex-4   	   26479	     44565 ns/op	    5701 B/op	      93 allocs/op
BenchmarkTarIndex-4   	   26703	     44662 ns/op	    5700 B/op	      93 allocs/op
BenchmarkTarIndex-4   	   27087	     44944 ns/op	    5700 B/op	      93 allocs/op
BenchmarkTarIndex-4   	   26997	     44644 ns/op	    5701 B/op	      93 allocs/op
BenchmarkTarIndex-4   	   26722	     45618 ns/op	    5700 B/op	      93 allocs/op
BenchmarkTarIndex-4   	   26752	     44275 ns/op	    5699 B/op	      93 allocs/op
BenchmarkTarIndex-4   	   27222	     44344 ns/op	    5699 B/op	      93 allocs/op
PASS
ok  	github.com/anchore/stereoscope/pkg/file	11.585s
PASS
ok  	github.com/anchore/stereoscope/pkg/filetree	0.005s
?   	github.com/anchore/stereoscope/pkg/filetree/filenode	[no test files]
PASS
ok  	github.com/anchore/stereoscope/pkg/image	0.005s
PASS
ok  	github.com/anchore/stereoscope/pkg/image/containerd	0.007s
PASS
ok  	github.com/anchore/stereoscope/pkg/image/docker	0.005s
PASS
ok  	github.com/anchore/stereoscope/pkg/image/oci	0.005s
PASS
ok  	github.com/anchore/stereoscope/pkg/image/oci/credhelpers	0.005s
?   	github.com/anchore/stereoscope/pkg/image/podman	[no test files]
PASS
ok  	github.com/anchore/stereoscope/pkg/image/sif	0.004s
?   	github.com/anchore/stereoscope/pkg/imagetest	[no test files]
PASS
ok  	github.com/anchore/stereoscope/pkg/tree	0.003s
PASS
ok  	github.com/anchore/stereoscope/pkg/tree/node	0.004s
goos: linux
goarch: amd64
pkg: github.com/anchore/stereoscope/test/integration
cpu: AMD EPYC 7763 64-Core Processor                
BenchmarkSimpleImage_GetImage/docker-archive-4 	     728	   1699091 ns/op	  787966 B/op	    2792 allocs/op
BenchmarkSimpleImage_GetImage/docker-archive-4 	     699	   1789371 ns/op	  788719 B/op	    2792 allocs/op
BenchmarkSimpleImage_GetImage/docker-archive-4 	     560	   2054272 ns/op	  788123 B/op	    2791 allocs/op
BenchmarkSimpleImage_GetImage/docker-archive-4 	     656	   1814761 ns/op	  787412 B/op	    2790 allocs/op
BenchmarkSimpleImage_GetImage/docker-archive-4 	     603	   1912282 ns/op	  787019 B/op	    2789 allocs/op
BenchmarkSimpleImage_GetImage/docker-archive-4 	     697	   1741066 ns/op	  786977 B/op	    2789 allocs/op
BenchmarkSimpleImage_GetImage/docker-archive-4 	     636	   1699431 ns/op	  786603 B/op	    2788 allocs/op
--- FAIL: BenchmarkSimpleImage_GetImage/podman
    fixture_image_simple_test.go:175: could not get fixture image: unable to detect input for 'stereoscope-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7', errs: podman not available: no host address
#0 building with "default" instance using docker driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 345B done
#1 DONE 0.0s

#2 [internal] load .dockerignore
#2 transferring context: 2B done
#2 DONE 0.0s

#3 [internal] load build context
#3 transferring context: 209B done
#3 DONE 0.0s

#4 [1/3] ADD file-1.txt /somefile-1.txt
#4 CACHED

#5 [2/3] ADD file-2.txt /somefile-2.txt
#5 CACHED

#6 [3/3] ADD target /
#6 CACHED

#7 exporting to image
#7 exporting layers done
#7 exporting manifest sha256:3a9f1033b7e5137a90c1782e3fcdcf13259fe636d8a532fa76a1d2c0eb690947 done
#7 exporting config sha256:bbee5c3ebf7d6f9e3d75aee9f0be16520ce4ba088be6627e9f50017626f67d6a done
#7 exporting attestation manifest sha256:58f0881a9154df5f27052a83d1e3a4b570acdecff08ece015ddf0b26f45489dd done
#7 exporting manifest list sha256:5b0bedbd7c2f6514e07c7669fe1f995f16a6719a9219cded384c536a25d9bb33 done
#7 naming to docker.io/library/stereoscope-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7 done
#7 unpacking to docker.io/library/stereoscope-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7 done
#7 naming to docker.io/library/stereoscope-fixture-image-simple:latest done
#7 unpacking to docker.io/library/stereoscope-fixture-image-simple:latest done
#7 DONE 0.0s
time="2026-02-19T18:32:38Z" level=warning msg="Failed to check deprecations" error="connection error: desc = \"transport: Error while dialing: dial unix /run/containerd/containerd.sock: connect: permission denied\""
ctr: connection error: desc = "transport: Error while dialing: dial unix /run/containerd/containerd.sock: connect: permission denied"
--- FAIL: BenchmarkSimpleImage_GetImage
    image_fixtures.go:193: using existing image tar: 'test-fixtures/cache/stereoscope-fixture-image-simple-04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7.tar' (size: 17408, modified: 2026-02-19 18:31:48.768816572 +0000 UTC, mode: -rw-r--r--)
    image_fixtures.go:241: Build docker image: name="stereoscope-fixture-image-simple" tag="04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7"
    image_fixtures.go:291: saveImage running: docker image save stereoscope-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7
    image_fixtures.go:286: 
        	Error Trace:	/home/runner/work/stereoscope/stereoscope/pkg/imagetest/image_fixtures.go:286
        	            				/home/runner/work/stereoscope/stereoscope/pkg/imagetest/image_fixtures.go:162
        	            				/home/runner/work/stereoscope/stereoscope/pkg/imagetest/image_fixtures.go:152
        	            				/home/runner/work/stereoscope/stereoscope/pkg/imagetest/image_fixtures.go:33
        	            				/home/runner/work/stereoscope/stereoscope/test/integration/fixture_image_simple_test.go:163
        	            				/opt/hostedtoolcache/go/1.25.7/x64/src/testing/benchmark.go:245
        	            				/opt/hostedtoolcache/go/1.25.7/x64/src/runtime/asm_amd64.s:1693
        	Error:      	Received unexpected error:
        	            	exit status 1
        	Test:       	BenchmarkSimpleImage_GetImage
        	Messages:   	could not import docker image to containerd (shell out)
BenchmarkSimpleImage_FetchSquashedContents/docker-archive-4         	   45307	     26599 ns/op	    2616 B/op	      18 allocs/op
BenchmarkSimpleImage_FetchSquashedContents/docker-archive-4         	   45364	     25990 ns/op	    2616 B/op	      18 allocs/op
BenchmarkSimpleImage_FetchSquashedContents/docker-archive-4         	   45289	     26026 ns/op	    2616 B/op	      18 allocs/op
BenchmarkSimpleImage_FetchSquashedContents/docker-archive-4         	   46003	     26222 ns/op	    2616 B/op	      18 allocs/op
BenchmarkSimpleImage_FetchSquashedContents/docker-archive-4         	   45768	     26489 ns/op	    2616 B/op	      18 allocs/op
BenchmarkSimpleImage_FetchSquashedContents/docker-archive-4         	   45580	     26677 ns/op	    2616 B/op	      18 allocs/op
BenchmarkSimpleImage_FetchSquashedContents/docker-archive-4         	   44762	     26181 ns/op	    2616 B/op	      18 allocs/op
--- FAIL: BenchmarkSimpleImage_FetchSquashedContents
    image_fixtures.go:193: using existing image tar: 'test-fixtures/cache/stereoscope-fixture-image-simple-04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7.tar' (size: 17408, modified: 2026-02-19 18:31:48.768816572 +0000 UTC, mode: -rw-r--r--)
    image_fixtures.go:75: error getting fixture image: 'podman' 'image-simple' with request 'podman:stereoscope-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7': unable to detect input for 'stereoscope-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7', errs: podman not available: no host address
FAIL
exit status 1
FAIL	github.com/anchore/stereoscope/test/integration	20.431s
?   	github.com/anchore/stereoscope/test/integration/test-fixtures/registry	[no test files]
FAIL
goos: linux
goarch: amd64
pkg: github.com/anchore/stereoscope/pkg/file
cpu: AMD EPYC 7763 64-Core Processor                
ctr: 
           │ .tmp/benchmark-b2fd38f.txt │
           │           sec/op           │
TarIndex-4                  44.64µ ± 2%

           │ .tmp/benchmark-b2fd38f.txt │
           │            B/op            │
TarIndex-4                 5.566Ki ± 0%

           │ .tmp/benchmark-b2fd38f.txt │
           │         allocs/op          │
TarIndex-4                   93.00 ± 0%

pkg: github.com/anchore/stereoscope/test/integration
                                      │ .tmp/benchmark-b2fd38f.txt │
                                      │           sec/op           │
SimpleImage_GetImage/docker-archive-4                 1.789m ± 15%

                                      │ .tmp/benchmark-b2fd38f.txt │
                                      │            B/op            │
SimpleImage_GetImage/docker-archive-4                 769.0Ki ± 0%

                                      │ .tmp/benchmark-b2fd38f.txt │
                                      │         allocs/op          │
SimpleImage_GetImage/docker-archive-4                  2.790k ± 0%

ctr: connection error: desc = "transport: Error while dialing: dial unix /run/containerd/containerd.sock: connect: permission denied"
                                                   │ .tmp/benchmark-b2fd38f.txt │
                                                   │           sec/op           │
SimpleImage_FetchSquashedContents/docker-archive-4                  26.22µ ± 2%

                                                   │ .tmp/benchmark-b2fd38f.txt │
                                                   │            B/op            │
SimpleImage_FetchSquashedContents/docker-archive-4                 2.555Ki ± 0%

                                                   │ .tmp/benchmark-b2fd38f.txt │
                                                   │         allocs/op          │
SimpleImage_FetchSquashedContents/docker-archive-4                   18.00 ± 0%
goos: linux
goarch: amd64
pkg: github.com/anchore/stereoscope/pkg/file
cpu: AMD EPYC 7763 64-Core Processor                
ctr: 
           │ .tmp/benchmark-b2fd38f.txt │
           │           sec/op           │
TarIndex-4                  44.64µ ± 2%

           │ .tmp/benchmark-b2fd38f.txt │
           │            B/op            │
TarIndex-4                 5.566Ki ± 0%

           │ .tmp/benchmark-b2fd38f.txt │
           │         allocs/op          │
TarIndex-4                   93.00 ± 0%

pkg: github.com/anchore/stereoscope/test/integration
                                      │ .tmp/benchmark-b2fd38f.txt │
                                      │           sec/op           │
SimpleImage_GetImage/docker-archive-4                 1.789m ± 15%

                                      │ .tmp/benchmark-b2fd38f.txt │
                                      │            B/op            │
SimpleImage_GetImage/docker-archive-4                 769.0Ki ± 0%

                                      │ .tmp/benchmark-b2fd38f.txt │
                                      │         allocs/op          │
SimpleImage_GetImage/docker-archive-4                  2.790k ± 0%

ctr: connection error: desc = "transport: Error while dialing: dial unix /run/containerd/containerd.sock: connect: permission denied"
                                                   │ .tmp/benchmark-b2fd38f.txt │
                                                   │           sec/op           │
SimpleImage_FetchSquashedContents/docker-archive-4                  26.22µ ± 2%

                                                   │ .tmp/benchmark-b2fd38f.txt │
                                                   │            B/op            │
SimpleImage_FetchSquashedContents/docker-archive-4                 2.555Ki ± 0%

                                                   │ .tmp/benchmark-b2fd38f.txt │
                                                   │         allocs/op          │
SimpleImage_FetchSquashedContents/docker-archive-4                   18.00 ± 0%

Copy link
Copy Markdown
Contributor

@kzantow kzantow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM -- honoring explicit platform requests seems like the right thing to do here 👍

@willmurphyscode willmurphyscode marked this pull request as ready for review February 19, 2026 21:11
@willmurphyscode willmurphyscode merged commit 1754fdc into main Feb 19, 2026
7 checks passed
@willmurphyscode willmurphyscode deleted the fix-new-docker branch February 19, 2026 21:11
@willmurphyscode willmurphyscode added the bug Something isn't working label Feb 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants