55
66import * as assert from 'assert' ;
77import * as path from 'path' ;
8- import { mkdir , writeFile } from 'fs/promises' ;
8+ import { chmod , writeFile } from 'fs/promises' ;
99import { shellExec } from './testUtils' ;
1010
1111const 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