Skip to content

Commit 24be598

Browse files
chrmartiCopilot
andcommitted
Run hosted Podman Feature tests rootfully
Retain the Docker-in-Docker Feature workload while avoiding the hosted runner's rootless Podman 5.8 APT sandbox regression. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2932b23 commit 24be598

1 file changed

Lines changed: 12 additions & 52 deletions

File tree

‎src/test/cli.podman.test.ts‎

Lines changed: 12 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import * as assert from 'assert';
77
import * as path from 'path';
8-
import { mkdir, writeFile } from 'fs/promises';
8+
import { chmod, writeFile } from 'fs/promises';
99
import { shellExec } from './testUtils';
1010

1111
const pkg = require('../../package.json');
@@ -15,79 +15,39 @@ describe('Dev Containers CLI using Podman', function () {
1515

1616
const tmp = path.relative(process.cwd(), path.join(__dirname, 'tmp'));
1717
const cli = `npx --prefix ${tmp} devcontainer`;
18-
const podmanBuildOptions = {
19-
env: {
20-
...process.env,
21-
BUILDAH_ISOLATION: 'chroot',
22-
},
23-
};
18+
const podman = process.env.GITHUB_ACTIONS === 'true' ? path.join(process.cwd(), tmp, 'podman-rootful') : 'podman';
2419

2520
before('Install', async () => {
2621
await shellExec(`rm -rf ${tmp}/node_modules`);
2722
await shellExec(`mkdir -p ${tmp}`);
2823
if (process.env.GITHUB_ACTIONS === 'true') {
29-
await shellExec('podman system reset --force');
30-
const storageConfig = path.join(process.env.HOME!, '.config', 'containers', 'storage.conf');
31-
await mkdir(path.dirname(storageConfig), { recursive: true });
32-
await writeFile(storageConfig, [
33-
'[storage]',
34-
'driver = "overlay"',
35-
'[storage.options.overlay]',
36-
'ignore_chown_errors = "false"',
37-
'',
38-
].join('\n'));
39-
const containersConfig = path.join(process.env.HOME!, '.config', 'containers', 'containers.conf');
40-
await writeFile(containersConfig, [
41-
'[engine]',
42-
'runtime = "/usr/local/bin/runc"',
43-
'',
44-
].join('\n'));
45-
const { stdout } = await shellExec('podman info --format \'{{json .Store}}\'');
46-
console.log(`Podman store after override: ${stdout.trim()}`);
47-
const runtime = await shellExec('podman info --format \'{{.Host.OCIRuntime.Path}}\'');
48-
console.log(`Podman OCI runtime after override: ${runtime.stdout.trim()}`);
49-
50-
const image = 'mcr.microsoft.com/devcontainers/typescript-node:1-18-bookworm';
51-
await shellExec(`podman pull ${image}`);
52-
const tmpInfo = await shellExec(`podman run --rm --user root --entrypoint /usr/bin/stat ${image} -c '%a %u %g' /tmp`);
53-
console.log(`Base image /tmp: ${tmpInfo.stdout.trim()}`);
54-
await shellExec(`podman run --rm --user _apt --entrypoint /bin/sh ${image} -c 'touch /tmp/devcontainers-apt-write-test && rm /tmp/devcontainers-apt-write-test'`);
55-
console.log('Base image _apt write check: succeeded');
56-
57-
const probeDockerfile = path.join(process.cwd(), tmp, 'PodmanProbe.Dockerfile');
58-
await writeFile(probeDockerfile, [
59-
`FROM ${image}`,
60-
'RUN --mount=type=bind,source=.,target=/tmp/build-context \\',
61-
' stat -c "Build RUN /tmp: %a %u %g" /tmp \\',
62-
' && su -s /bin/sh _apt -c "touch /tmp/devcontainers-apt-write-test && rm /tmp/devcontainers-apt-write-test" \\',
63-
' && echo "Build RUN _apt write check: succeeded"',
64-
'',
65-
].join('\n'));
66-
const buildProbe = await shellExec(`podman buildx build --no-cache -f ${probeDockerfile} ${path.dirname(probeDockerfile)}`, podmanBuildOptions);
67-
console.log(buildProbe.stdout);
68-
console.error(buildProbe.stderr);
24+
// The hosted runner's rootless Podman 5.8 build fails when APT drops
25+
// privileges to _apt, so retain the full Feature coverage rootfully.
26+
const podmanExecutable = (await shellExec('command -v podman')).stdout.trim();
27+
await writeFile(podman, `#!/bin/sh\nexec sudo -- ${podmanExecutable} "$@"\n`);
28+
await chmod(podman, 0o755);
6929
}
7030
await shellExec(`npm --prefix ${tmp} install devcontainers-cli-${pkg.version}.tgz`);
7131
});
7232

7333
describe('Command up using Podman', () => {
7434

7535
it('should execute successfully with valid config with features', async () => {
76-
const res = await shellExec(`${cli} up --docker-path podman --workspace-folder ${__dirname}/configs/image-with-features`, podmanBuildOptions);
36+
const res = await shellExec(`${cli} up --docker-path ${podman} --workspace-folder ${__dirname}/configs/image-with-features`);
7737
const response = JSON.parse(res.stdout);
7838
assert.equal(response.outcome, 'success');
7939
const containerId: string = response.containerId;
8040
assert.ok(containerId, 'Container id not found.');
81-
await shellExec(`podman rm -f ${containerId}`);
41+
await shellExec(`${podman} rm -f ${containerId}`);
8242
});
8343

8444
it('should execute successfully with valid config with features', async () => {
85-
const res = await shellExec(`${cli} up --docker-path podman --workspace-folder ${__dirname}/configs/dockerfile-with-features`, podmanBuildOptions);
45+
const res = await shellExec(`${cli} up --docker-path ${podman} --workspace-folder ${__dirname}/configs/dockerfile-with-features`);
8646
const response = JSON.parse(res.stdout);
8747
assert.equal(response.outcome, 'success');
8848
const containerId: string = response.containerId;
8949
assert.ok(containerId, 'Container id not found.');
90-
await shellExec(`podman rm -f ${containerId}`);
50+
await shellExec(`${podman} rm -f ${containerId}`);
9151
});
9252
});
93-
});
53+
});

0 commit comments

Comments
 (0)