diff --git a/.github/actions/setup-compose/action.yml b/.github/actions/setup-compose/action.yml new file mode 100644 index 000000000..04439bc11 --- /dev/null +++ b/.github/actions/setup-compose/action.yml @@ -0,0 +1,110 @@ +name: Set up Compose with build input permissions +description: Build Compose from source only when a probe reproduces the external-Dockerfile permission error. + +runs: + using: composite + steps: + - name: Probe installed Compose + id: check + shell: bash + env: + # https://github.com/docker/compose/pull/14325 fixes https://github.com/devcontainers/cli/issues/1320. + FIX_COMMIT: 1e1c577eab08ceb5ff0fcf4d8e3cbbc08a34ef35 + FIX_VERSION: 5.6.0-dev.1e1c577 + run: | + echo "ref=$FIX_COMMIT" >> "$GITHUB_OUTPUT" + echo "version=$FIX_VERSION" >> "$GITHUB_OUTPUT" + docker compose version + probe_dir=$(mktemp -d "$RUNNER_TEMP/compose-probe.XXXXXX") + echo "probe=$probe_dir" >> "$GITHUB_OUTPUT" + image="devcontainers-compose-probe:${probe_dir##*/}" + echo "image=$image" >> "$GITHUB_OUTPUT" + mkdir "$probe_dir/context" + printf 'FROM scratch\nLABEL devcontainers.compose-probe=true\n' > "$probe_dir/Dockerfile" + cat > "$probe_dir/compose.yaml" < "$probe_dir/build.log" 2>&1; then + cat "$probe_dir/build.log" + echo "image-created=true" >> "$GITHUB_OUTPUT" + echo "Compose can build with an external Dockerfile; keeping it." + echo "install=false" >> "$GITHUB_OUTPUT" + else + status=$? + cat "$probe_dir/build.log" + if grep -Fq "additional privileges requested: pass \"--allow=fs.read=$probe_dir/Dockerfile\"" "$probe_dir/build.log"; then + echo "Compose lacks the external-Dockerfile permission fix; building it from source." + echo "install=true" >> "$GITHUB_OUTPUT" + else + echo "::error::Compose probe failed for a reason other than the external-Dockerfile permission error." + exit "$status" + fi + fi + + - name: Fetch fixed Compose source + if: steps.check.outputs.install == 'true' + id: source + shell: bash + env: + FIX_COMMIT: ${{ steps.check.outputs.ref }} + run: | + source_dir=$(mktemp -d "$RUNNER_TEMP/compose-source.XXXXXX") + git -C "$source_dir" init + git -C "$source_dir" fetch --depth=1 https://github.com/docker/compose.git "$FIX_COMMIT" + git -C "$source_dir" checkout --detach FETCH_HEAD + test "$(git -C "$source_dir" rev-parse HEAD)" = "$FIX_COMMIT" + echo "path=$source_dir" >> "$GITHUB_OUTPUT" + + - uses: actions/setup-go@v6 + if: steps.check.outputs.install == 'true' + with: + go-version-file: ${{ steps.source.outputs.path }}/go.mod + cache: false + + - name: Build and install fixed Compose + if: steps.check.outputs.install == 'true' + id: install + shell: bash + env: + CGO_ENABLED: '0' + SOURCE_DIR: ${{ steps.source.outputs.path }} + FIX_VERSION: ${{ steps.check.outputs.version }} + PROBE_DIR: ${{ steps.check.outputs.probe }} + run: | + cd "$SOURCE_DIR" + # Preserve the CLI's Compose version gates for this unreleased source build. + go build -trimpath \ + -ldflags "-s -w -X github.com/docker/compose/v5/internal.Version=v$FIX_VERSION" \ + -o docker-compose ./cmd + install -D -m 755 docker-compose "${DOCKER_CONFIG:-$HOME/.docker}/cli-plugins/docker-compose" + version=$(docker compose version --short) + if [[ "${version#v}" != "$FIX_VERSION" ]]; then + echo "::error::Expected Compose $FIX_VERSION after installation, got $version" + exit 1 + fi + docker compose version + docker compose --project-name compose-probe -f "$PROBE_DIR/compose.yaml" build + echo "image-created=true" >> "$GITHUB_OUTPUT" + + - name: Clean up Compose probe + if: always() && steps.check.outputs.probe != '' + shell: bash + env: + PROBE_DIR: ${{ steps.check.outputs.probe }} + PROBE_IMAGE: ${{ steps.check.outputs.image }} + IMAGE_CREATED: ${{ steps.check.outputs.image-created == 'true' || steps.install.outputs.image-created == 'true' }} + run: | + rm -f -- "$PROBE_DIR/Dockerfile" "$PROBE_DIR/compose.yaml" "$PROBE_DIR/build.log" + if [[ -d "$PROBE_DIR/context" ]]; then + rmdir -- "$PROBE_DIR/context" + fi + rmdir -- "$PROBE_DIR" + if [[ "$IMAGE_CREATED" == 'true' ]]; then + docker image rm "$PROBE_IMAGE" + fi diff --git a/.github/workflows/dev-containers.yml b/.github/workflows/dev-containers.yml index 81ffb8226..a292819b8 100644 --- a/.github/workflows/dev-containers.yml +++ b/.github/workflows/dev-containers.yml @@ -90,6 +90,7 @@ jobs: fi cat "$DAEMON_JSON" sudo systemctl restart docker + - uses: ./.github/actions/setup-compose - name: Tools Info run: | docker info diff --git a/.github/workflows/test-docker-v29.yml b/.github/workflows/test-docker-v29.yml index de475f246..2b4ea9623 100644 --- a/.github/workflows/test-docker-v29.yml +++ b/.github/workflows/test-docker-v29.yml @@ -29,6 +29,8 @@ jobs: sudo VERSION=29.0.0 sh get-docker.sh sudo systemctl restart docker + - uses: ./.github/actions/setup-compose + - name: Verify Docker version, Install and Test run: | # Verify