diff --git a/packages/main/src/plugin/api/image-info.ts b/packages/main/src/plugin/api/image-info.ts index 33a2cf4f862..771fac9ee64 100644 --- a/packages/main/src/plugin/api/image-info.ts +++ b/packages/main/src/plugin/api/image-info.ts @@ -25,6 +25,7 @@ export interface ImageInfo extends Dockerode.ImageInfo { engineId: string; engineName: string; History?: string[]; + isManifest?: boolean; } export interface BuildImageOptions { diff --git a/packages/main/src/plugin/container-registry.spec.ts b/packages/main/src/plugin/container-registry.spec.ts index 20b6eabb59a..3e0de774406 100644 --- a/packages/main/src/plugin/container-registry.spec.ts +++ b/packages/main/src/plugin/container-registry.spec.ts @@ -4391,3 +4391,73 @@ describe('loadImages', () => { ); }); }); + +test('manifest is listed as true with podmanListImages correctly', async () => { + const manifestImage: ImageInfo = { + Id: 'manifestImage', + Labels: {}, + engineId: 'engine1', + engineName: 'podman', + ParentId: '', + RepoTags: ['manifestTag'], + RepoDigests: ['manifestDigest'], + Created: 0, + Size: 0, + VirtualSize: 40 * 1024, // 40KB (less than 50KB threshold) + SharedSize: 0, + Containers: 0, + }; + + const regularImage: ImageInfo = { + Id: 'ee301c921b8aadc002973b2e0c3da17d701dcd994b606769a7e6eaa100b81d44', + Labels: {}, + engineId: 'engine5', // Assuming 'engineId' and 'engineName' are part of your ImageInfo but not relevant here + engineName: 'podman', + ParentId: '', + RepoTags: ['testdomain.io/library/hello:latest'], + RepoDigests: [ + 'testdomain.io/library/hello@sha256:2d4e459f4ecb5329407ae3e47cbc107a2fbace221354ca75960af4c047b3cb13', + 'testdomain.io/library/hello@sha256:53641cd209a4fecfc68e21a99871ce8c6920b2e7502df0a20671c6fccc73a7c6', + ], + Created: 1683046167, + Size: 23301, + VirtualSize: 23301, // Directly matches Size in this case + SharedSize: 0, + Containers: 0, + History: ['testdomain.io/library/hello:latest'], + }; + + const imagesList = [manifestImage, regularImage]; + nock('http://localhost').get('/v4.2.0/libpod/images/json').reply(200, imagesList); + const api = new Dockerode({ protocol: 'http', host: 'localhost' }); + + // set provider + containerRegistry.addInternalProvider('podman', { + name: 'podman', + id: 'podman1', + api, + libpodApi: api, + connection: { + type: 'podman', + }, + } as unknown as InternalContainerProvider); + + const images = await containerRegistry.podmanListImages(); + // ensure the field are correct + expect(images).toBeDefined(); + expect(images).toHaveLength(2); + + // Check the first image + const image = images[0]; + expect(image.engineId).toBe('podman1'); + expect(image.engineName).toBe('podman'); + expect(image.Id).toBe('manifestImage'); + expect(image.isManifest).toBe(true); + + // Check the second image + const image2 = images[1]; + expect(image2.engineId).toBe('podman1'); + expect(image2.engineName).toBe('podman'); + expect(image2.Id).toBe('ee301c921b8aadc002973b2e0c3da17d701dcd994b606769a7e6eaa100b81d44'); + expect(image2.isManifest).toBe(false); +}); diff --git a/packages/main/src/plugin/container-registry.ts b/packages/main/src/plugin/container-registry.ts index 599a8a93fe7..a19f4d661a6 100644 --- a/packages/main/src/plugin/container-registry.ts +++ b/packages/main/src/plugin/container-registry.ts @@ -75,6 +75,7 @@ import { Emitter } from './events/emitter.js'; import type { ImageRegistry } from './image-registry.js'; import type { Telemetry } from './telemetry/telemetry.js'; import { Disposable } from './types/disposable.js'; +import { guessIsManifest } from './util/manifest.js'; const tar: { pack: (dir: string) => NodeJS.ReadableStream } = require('tar-fs'); @@ -626,6 +627,10 @@ export class ContainerProviderRegistry { ...image, engineName: provider.name, engineId: provider.id, + // Using guessIsManifest, determine if the image is a manifest and set isManifest accordingly + // NOTE: This is a workaround until we have a better way to determine if an image is a manifest + // and may result in false positives until issue: https://github.com/containers/podman/issues/22184 is resolved + isManifest: guessIsManifest(image), })); }), );