diff --git a/packages/main/src/plugin/image-registry.spec.ts b/packages/main/src/plugin/image-registry.spec.ts index 77a0bd256117f..67ce8921e18ba 100644 --- a/packages/main/src/plugin/image-registry.spec.ts +++ b/packages/main/src/plugin/image-registry.spec.ts @@ -585,3 +585,78 @@ test('getBestManifest returns the expected manifest', () => { imageRegistry.getBestManifest([manifests['windows-amd64'], manifests['darwin-amd64']], 'amd64', 'linux'), ).toBeUndefined(); }); + +test('getManifestFromUrl returns the expected manifest with mediaType', async () => { + const fakeManifest = { + schemaVersion: 2, + mediaType: 'application/vnd.oci.image.index.v1+json', + manifests: [], + }; + + // image index + nock('https://my-podman-desktop-fake-registry.io').get('/v2/foo/bar/manifests/latest').reply(200, fakeManifest); + + // digest + nock('https://my-podman-desktop-fake-registry.io') + .get('/v2/foo/bar/manifests/1234') + .reply(200, JSON.stringify({ endManifest: true })); + + // mock getBestManifest + const spyGetBestManifest = vi.spyOn(imageRegistry, 'getBestManifest'); + spyGetBestManifest.mockReturnValue({ + digest: 1234, + }); + + const manifest = await imageRegistry.getManifest( + { + name: 'foo/bar', + tag: 'latest', + registry: 'my-podman-desktop-fake-registry.io', + registryURL: 'https://my-podman-desktop-fake-registry.io/v2', + }, + 'dummyToken', + ); + + expect(manifest).toBeDefined(); + expect(manifest).toHaveProperty('endManifest', true); + expect(spyGetBestManifest).toHaveBeenCalled(); +}); + +test('getManifestFromUrl returns the expected manifest without mediaType but with manifests', async () => { + const fakeManifest = { + schemaVersion: 2, + manifests: [ + { + dummyManifest: true, + }, + ], + }; + + // image index + nock('https://my-podman-desktop-fake-registry.io').get('/v2/foo/bar/manifests/latest').reply(200, fakeManifest); + + // digest + nock('https://my-podman-desktop-fake-registry.io') + .get('/v2/foo/bar/manifests/1234') + .reply(200, JSON.stringify({ endManifest: true })); + + // mock getBestManifest + const spyGetBestManifest = vi.spyOn(imageRegistry, 'getBestManifest'); + spyGetBestManifest.mockReturnValue({ + digest: 1234, + }); + + const manifest = await imageRegistry.getManifest( + { + name: 'foo/bar', + tag: 'latest', + registry: 'my-podman-desktop-fake-registry.io', + registryURL: 'https://my-podman-desktop-fake-registry.io/v2', + }, + 'dummyToken', + ); + + expect(manifest).toBeDefined(); + expect(manifest).toHaveProperty('endManifest', true); + expect(spyGetBestManifest).toHaveBeenCalled(); +}); diff --git a/packages/main/src/plugin/image-registry.ts b/packages/main/src/plugin/image-registry.ts index a7d2a17912aa0..2f46041a65263 100644 --- a/packages/main/src/plugin/image-registry.ts +++ b/packages/main/src/plugin/image-registry.ts @@ -614,9 +614,13 @@ export class ImageRegistry { } } - // check mediaType of the manifest - // if it is application/vnd.oci.image.index.v1+json it is an index - if (parsedManifest.mediaType === 'application/vnd.oci.image.index.v1+json') { + // https://github.com/opencontainers/image-spec/blob/main/image-index.md + // check schemaVersion and (mediaType of the manifest or if it contains manifests field being an array) + if ( + parsedManifest.schemaVersion === 2 && + (parsedManifest.mediaType === 'application/vnd.oci.image.index.v1+json' || + Array.isArray(parsedManifest.manifests)) + ) { // need to grab correct manifest from the index corresponding to our platform let platformArch: 'amd64' | 'arm64' = 'amd64'; const arch = os.arch();