diff --git a/packages/backend/src/build-disk-image.ts b/packages/backend/src/build-disk-image.ts index ab0f9f74..33648bef 100644 --- a/packages/backend/src/build-disk-image.ts +++ b/packages/backend/src/build-disk-image.ts @@ -31,17 +31,12 @@ const telemetryLogger = extensionApi.env.createTelemetryLogger(); export async function buildDiskImage(imageData: unknown, history: History) { // Before we do ANYTHING, we should be checking to see if the podman machine is rootful or not // as that's a requirement for bootc-image-builder to work correctly. - - // Only do this check on Windows or Mac - - if (!machineUtils.isLinux()) { - const isRootful = await machineUtils.isPodmanMachineRootful(); - if (!isRootful) { - await extensionApi.window.showErrorMessage( - 'The podman machine is not set as rootful. Please recreate the podman machine with rootful privileges set and try again.', - ); - return; - } + const isRootful = await machineUtils.isPodmanMachineRootful(); + if (!isRootful) { + await extensionApi.window.showErrorMessage( + 'The podman machine is not set as rootful. Please recreate the podman machine with rootful privileges set and try again.', + ); + return; } const image = imageData as { name: string; engineId: string; tag: string }; diff --git a/packages/backend/src/machine-utils.spec.ts b/packages/backend/src/machine-utils.spec.ts index e79a5396..5c997bea 100644 --- a/packages/backend/src/machine-utils.spec.ts +++ b/packages/backend/src/machine-utils.spec.ts @@ -84,3 +84,77 @@ test('Check isPodmanMachineRootful functionality', async () => { spyReadFile.mockResolvedValue(JSON.stringify({ Rootful: true })); await expect(machineUtils.isPodmanMachineRootful()).resolves.toBe(true); }); + +test('Fail isPodmanMachineRootful functionality be false if Rootful does not exist in the root of the object, or in HostUser', async () => { + const fakeMachineInfoJSON = { + Host: { + Arch: 'amd64', + CurrentMachine: '', + DefaultMachine: '', + EventsDir: 'dir1', + MachineConfigDir: 'dir2', + MachineImageDir: 'dir3', + MachineState: '', + NumberOfMachines: 5, + OS: 'windows', + VMType: 'wsl', + }, + }; + + vi.spyOn(extensionApi.process, 'exec').mockImplementation( + () => + new Promise(resolve => { + resolve({ stdout: JSON.stringify(fakeMachineInfoJSON) } as extensionApi.RunResult); + }), + ); + + // Mock existsSync to return true (the "fake" file is there) + vi.mock('node:fs'); + vi.spyOn(fs, 'existsSync').mockImplementation(() => { + return true; + }); + + // Mock the readFile function to return the "fake" file with Rootful not existing + const spyReadFile = vi.spyOn(fs.promises, 'readFile'); + + // Mock reading the file to have Rootful as true + spyReadFile.mockResolvedValue(JSON.stringify({})); + await expect(machineUtils.isPodmanMachineRootful()).resolves.toBe(false); +}); + +test('Pass true if Rootful is in HostUser', async () => { + const fakeMachineInfoJSON = { + Host: { + Arch: 'amd64', + CurrentMachine: '', + DefaultMachine: '', + EventsDir: 'dir1', + MachineConfigDir: 'dir2', + MachineImageDir: 'dir3', + MachineState: '', + NumberOfMachines: 5, + OS: 'windows', + VMType: 'wsl', + }, + }; + + vi.spyOn(extensionApi.process, 'exec').mockImplementation( + () => + new Promise(resolve => { + resolve({ stdout: JSON.stringify(fakeMachineInfoJSON) } as extensionApi.RunResult); + }), + ); + + // Mock existsSync to return true (the "fake" file is there) + vi.mock('node:fs'); + vi.spyOn(fs, 'existsSync').mockImplementation(() => { + return true; + }); + + // Mock the readFile function to return the "fake" file with Rootful not existing + const spyReadFile = vi.spyOn(fs.promises, 'readFile'); + + // Mock reading the file to have Rootful as true + spyReadFile.mockResolvedValue(JSON.stringify({ HostUser: { Rootful: true } })); + await expect(machineUtils.isPodmanMachineRootful()).resolves.toBe(true); +}); diff --git a/packages/backend/src/machine-utils.ts b/packages/backend/src/machine-utils.ts index 34e22f91..95b78d5d 100644 --- a/packages/backend/src/machine-utils.ts +++ b/packages/backend/src/machine-utils.ts @@ -51,8 +51,17 @@ export async function isPodmanMachineRootful() { const machineInfo = await getMachineInfo(); const machineConfig = await readMachineConfig(machineInfo.Host.MachineConfigDir, machineInfo.Host.CurrentMachine); - if (machineConfig.Rootful !== undefined) { - // Make sure we convert to boolean in case the value is "true", not true. + // If you are on Podman Machine 4.9.0 with applehv activated, the rootful key will be located + // in the root of the JSON object. + // If on 5.0.0, the rootful key will be located in the "HostUser" object. + if (machineConfig?.HostUser?.Rootful) { + // 5.0.0 check first + return Boolean(machineConfig.HostUser.Rootful); + } else if (machineConfig?.Rootful) { + // 4.9.0 check + console.log( + 'Rootful key found in root object of the machine config file, you could be on Podman Machine 4.9.0, it is recommended to upgrade to 5.0.0.', + ); return Boolean(machineConfig.Rootful); } else { console.error('No Rootful key found in machine config file, there should be one.');