feat: Bulk Image Patching #3990
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "[Blocking] Build" | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - release-* | |
| tags: | |
| - v* | |
| paths-ignore: | |
| - "**.md" | |
| - "website/**" | |
| - "docs/**" | |
| - "demo/**" | |
| pull_request: | |
| branches: | |
| - main | |
| - release-* | |
| paths-ignore: | |
| - "**.md" | |
| - "website/**" | |
| - "docs/**" | |
| - "demo/**" | |
| workflow_dispatch: | |
| env: | |
| TRIVY_VERSION: 0.59.1 | |
| BUILDKIT_VERSION: 0.19.0 | |
| TRIVY_DISABLE_VEX_NOTICE: "true" | |
| permissions: | |
| contents: read | |
| jobs: | |
| unit-test: | |
| name: Unit Test | |
| runs-on: oracle-vm-16cpu-64gb-x86-64 | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.3.1 | |
| with: | |
| egress-policy: audit | |
| - name: Check out code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version: "1.25" | |
| check-latest: true | |
| - name: Add containerd-snapshotter to docker daemon | |
| run: | | |
| echo '{"features": { "containerd-snapshotter": true }}' | sudo tee /etc/docker/daemon.json | |
| sudo systemctl restart docker | |
| - name: Unit test | |
| shell: bash | |
| env: | |
| CODECOV_OPTS: "-coverprofile=coverage.txt -covermode=atomic" | |
| run: make test | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 | |
| env: | |
| CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
| build: | |
| name: Build | |
| runs-on: oracle-vm-16cpu-64gb-x86-64 | |
| timeout-minutes: 5 | |
| permissions: | |
| packages: write | |
| contents: read | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.3.1 | |
| with: | |
| egress-policy: audit | |
| - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version: "1.25" | |
| check-latest: true | |
| - name: Build copa | |
| shell: bash | |
| run: | | |
| make build | |
| make archive | |
| - name: Upload copa to build artifacts | |
| uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| path: dist/linux_amd64/release/copa_edge_linux_amd64.tar.gz | |
| - name: Load test cases for patch testing | |
| id: load-test-envs-matrix | |
| shell: bash | |
| run: echo "buildkitenvs=$(.github/workflows/scripts/buildkit-env-matrix.sh)" | tee -a "${GITHUB_OUTPUT}" | |
| - name: Load multiplatform test environments | |
| id: load-multiplatform-envs-matrix | |
| shell: bash | |
| run: echo "multiplatformenvs=[\"docker\",\"podman/container\"]" | tee -a "${GITHUB_OUTPUT}" | |
| outputs: | |
| buildkitenvs: ${{ steps.load-test-envs-matrix.outputs.buildkitenvs }} | |
| multiplatformenvs: ${{ steps.load-multiplatform-envs-matrix.outputs.multiplatformenvs }} | |
| test-patch-trivy: | |
| needs: build | |
| name: Test patch with trivy ${{ matrix.buildkit_mode }} | |
| runs-on: oracle-vm-16cpu-64gb-x86-64 | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| buildkit_mode: ${{fromJson(needs.build.outputs.buildkitenvs)}} | |
| steps: | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - run: docker system prune -a -f --volumes | |
| - name: Check out code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version: "1.25" | |
| check-latest: true | |
| - name: Install required tools | |
| shell: bash | |
| run: .github/workflows/scripts/download-tooling.sh | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - name: Extract copa | |
| shell: bash | |
| run: | | |
| tar xzf copa_edge_linux_amd64.tar.gz | |
| ./copa --version | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
| - name: Run functional test | |
| shell: bash | |
| run: | | |
| set -eu -o pipefail | |
| . .github/workflows/scripts/buildkitenvs/${{ matrix.buildkit_mode}} | |
| gotestsum --format testname --junitfile test-results.xml -- ./integration/singlearch --addr="${COPA_BUILDKIT_ADDR}" --copa="$(pwd)/copa" -timeout 0 --report-file | |
| - name: Test Summary | |
| uses: test-summary/action@v2 | |
| with: | |
| paths: "test-results.xml" | |
| test-patch-no-report: | |
| needs: build | |
| name: Test patch no report ${{ matrix.buildkit_mode }} | |
| runs-on: oracle-vm-16cpu-64gb-x86-64 | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| buildkit_mode: ${{fromJson(needs.build.outputs.buildkitenvs)}} | |
| steps: | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - run: docker system prune -a -f --volumes | |
| - name: Check out code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version: "1.25" | |
| check-latest: true | |
| - name: Install required tools | |
| shell: bash | |
| run: .github/workflows/scripts/download-tooling.sh | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - name: Extract copa | |
| shell: bash | |
| run: | | |
| tar xzf copa_edge_linux_amd64.tar.gz | |
| ./copa --version | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
| - name: Run functional test | |
| shell: bash | |
| run: | | |
| set -eu -o pipefail | |
| . .github/workflows/scripts/buildkitenvs/${{ matrix.buildkit_mode}} | |
| echo "COPA_BUILDKIT_ADDR=${COPA_BUILDKIT_ADDR}" >> "$GITHUB_ENV" | |
| gotestsum --format testname --junitfile test-results.xml -- ./integration/singlearch --addr="${COPA_BUILDKIT_ADDR}" --copa="$(pwd)/copa" -timeout 0 | |
| - name: Test Summary | |
| uses: test-summary/action@v2 | |
| with: | |
| paths: "test-results.xml" | |
| - name: Test RPM validation - noreplace files | |
| if: ${{ !startsWith(env.COPA_BUILDKIT_ADDR, 'podman-container://') }} | |
| shell: bash | |
| run: | | |
| set -eux -o pipefail | |
| if [[ -n "${COPA_BUILDKIT_ADDR}" && "${COPA_BUILDKIT_ADDR}" == docker://* ]]; then | |
| export DOCKER_HOST="${COPA_BUILDKIT_ADDR#docker://}" | |
| fi | |
| docker create --name test ghcr.io/project-copacetic/copacetic/test/openssl:test-rpm-patched /bin/sh | |
| tmp="$(mktemp)" | |
| docker cp test:/etc/pki/tls/openssl.cnf "${tmp}" | |
| if ! grep -q foo "${tmp}"; then | |
| echo "Error: openssl.cnf content replaced" >&2 | |
| rm "${tmp}" | |
| docker rm -f test | |
| exit 1 | |
| fi | |
| rm "${tmp}" | |
| docker rm -f test | |
| - name: Test RPM validation - symlink | |
| if: ${{ !startsWith(env.COPA_BUILDKIT_ADDR, 'podman-container://') }} | |
| shell: bash | |
| run: | | |
| set -eux -o pipefail | |
| if [[ -n "${COPA_BUILDKIT_ADDR}" && "${COPA_BUILDKIT_ADDR}" == docker://* ]]; then | |
| export DOCKER_HOST="${COPA_BUILDKIT_ADDR#docker://}" | |
| fi | |
| docker create --name test ghcr.io/project-copacetic/copacetic/test/openssl:test-rpm-patched /bin/sh | |
| tmp="$(mktemp)" | |
| symlink_path="/sbin" | |
| docker cp test:"$symlink_path" "${tmp}_symlink" | |
| if [ ! -L "${tmp}_symlink" ]; then | |
| echo "Error: The path $symlink_path is not a symlink." | |
| rm "${tmp}" "${tmp}_symlink" | |
| docker rm -f test | |
| exit 1 | |
| fi | |
| rm "${tmp}" "${tmp}_symlink" | |
| docker rm -f test | |
| - name: Test Debian validation - noreplace files | |
| if: ${{ !startsWith(env.COPA_BUILDKIT_ADDR, 'podman-container://') }} | |
| shell: bash | |
| run: | | |
| set -eux -o pipefail | |
| _cleanup() { | |
| docker rm -f "$DOCKER_CUSTOM_UNIX_ID" | |
| sudo rm -rf "$SOCK_DIR" | |
| } | |
| if [[ -n "${COPA_BUILDKIT_ADDR}" && "${COPA_BUILDKIT_ADDR}" == docker://* ]]; then | |
| export DOCKER_HOST="${COPA_BUILDKIT_ADDR#docker://}" | |
| trap '_cleanup' EXIT | |
| fi | |
| docker create --name test ghcr.io/project-copacetic/copacetic/test/openssl:test-debian-patched /bin/sh | |
| tmp="$(mktemp)" | |
| docker cp test:/etc/ssl/openssl.cnf "${tmp}" | |
| if ! grep -q foo "${tmp}"; then | |
| echo "Error: openssl.cnf content replaced" >&2 | |
| rm "${tmp}" | |
| docker rm -f test | |
| exit 1 | |
| fi | |
| rm "${tmp}" | |
| docker rm -f test | |
| test-plugin: | |
| needs: build | |
| name: Test plugin | |
| runs-on: oracle-vm-16cpu-64gb-x86-64 | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.3.1 | |
| with: | |
| egress-policy: audit | |
| - name: Check out code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version: "1.25" | |
| check-latest: true | |
| - name: Install scanner-plugin-template | |
| shell: bash | |
| run: | | |
| go install github.com/project-copacetic/scanner-plugin-template@latest | |
| mv $(go env GOPATH)/bin/scanner-plugin-template $(go env GOPATH)/bin/copa-fake | |
| mv $(go env GOPATH)/bin/copa-fake /usr/local/bin | |
| - name: Install required tools | |
| shell: bash | |
| run: .github/workflows/scripts/download-tooling.sh | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - name: Extract copa | |
| shell: bash | |
| run: | | |
| tar xzf copa_edge_linux_amd64.tar.gz | |
| ./copa --version | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
| - name: Run e2e tests | |
| shell: bash | |
| run: | | |
| set -eu -o pipefail | |
| . .github/workflows/scripts/buildkitenvs/direct/tcp | |
| gotestsum --format testname --junitfile test-results.xml -- ./test/e2e/plugin --addr="${COPA_BUILDKIT_ADDR}" --copa="$(pwd)/copa" --scanner fake -timeout 0 | |
| - name: Test Summary | |
| uses: test-summary/action@v2 | |
| with: | |
| paths: "test-results.xml" | |
| test-push: | |
| needs: build | |
| name: Test push | |
| runs-on: oracle-vm-16cpu-64gb-x86-64 | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Check out code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version: "1.25" | |
| check-latest: true | |
| - name: Add containerd-snapshotter to docker daemon | |
| run: | | |
| echo '{"features": { "containerd-snapshotter": true }}' | sudo tee /etc/docker/daemon.json | |
| sudo systemctl restart docker | |
| - name: Set up buildx | |
| uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 | |
| with: | |
| install: true | |
| - name: Install oras CLI | |
| uses: oras-project/setup-oras@22ce207df3b08e061f537244349aac6ae1d214f6 # v1.2.4 | |
| - name: Install required tools | |
| shell: bash | |
| run: .github/workflows/scripts/download-tooling.sh | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - name: Extract copa | |
| shell: bash | |
| run: | | |
| tar xzf copa_edge_linux_amd64.tar.gz | |
| ./copa --version | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
| - name: Run e2e tests | |
| shell: bash | |
| run: | | |
| set -eu -o pipefail | |
| gotestsum --format testname --junitfile test-results.xml -- ./test/e2e/push --addr="docker://" --copa="$(pwd)/copa" | |
| - name: Test Summary | |
| uses: test-summary/action@v2 | |
| with: | |
| paths: "test-results.xml" | |
| test-patch-multiplatform: | |
| needs: build | |
| name: Test patch with multiplatform ${{ matrix.buildkit_mode }} | |
| runs-on: oracle-vm-16cpu-64gb-x86-64 | |
| timeout-minutes: 40 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| buildkit_mode: ${{fromJson(needs.build.outputs.multiplatformenvs)}} | |
| steps: | |
| - name: Change docker daemon config | |
| run: | | |
| echo '{"features": { "containerd-snapshotter": true }, "insecure-registries": ["localhost:5000"]}' | sudo tee /etc/docker/daemon.json | |
| sudo systemctl restart docker | |
| - name: Set up buildx | |
| uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 | |
| with: | |
| install: true | |
| platforms: linux/amd64,linux/arm/v5,linux/arm64,linux/386,linux/mips64le | |
| - name: Install oras CLI | |
| uses: oras-project/setup-oras@22ce207df3b08e061f537244349aac6ae1d214f6 # v1.2.4 | |
| - name: Set up local registry | |
| run: | | |
| docker run -d -p 5000:5000 --restart=always --name registry registry:2 | |
| # wait for the registry to be healthy | |
| for i in $(seq 1 60); do | |
| if curl -f http://localhost:5000/v2/_catalog; then | |
| break | |
| fi | |
| sleep 1 | |
| done | |
| - name: Test registry | |
| run: | | |
| set -eu -o pipefail | |
| docker pull nginx:latest | |
| docker tag nginx:latest localhost:5000/nginx:latest | |
| docker push localhost:5000/nginx:latest | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - run: docker system prune -a -f --volumes | |
| - name: Check out code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version: "1.25" | |
| check-latest: true | |
| - name: Install required tools | |
| shell: bash | |
| run: .github/workflows/scripts/download-tooling.sh | |
| - name: Install multiplatform tooling | |
| shell: bash | |
| run: .github/workflows/scripts/download-multiplatform-tooling.sh | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - name: Extract copa | |
| shell: bash | |
| run: | | |
| tar xzf copa_edge_linux_amd64.tar.gz | |
| ./copa --version | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
| - name: Run functional test | |
| shell: bash | |
| run: | | |
| set -eu -o pipefail | |
| if [[ "${{ matrix.buildkit_mode }}" == "docker" ]]; then | |
| # For docker mode, use the default docker daemon | |
| export COPA_BUILDKIT_ADDR="docker://" | |
| else | |
| # For other modes, source the corresponding script in the same shell session | |
| . .github/workflows/scripts/buildkitenvs/${{ matrix.buildkit_mode }} | |
| fi | |
| gotestsum --format testname --junitfile test-results.xml -- ./integration/multiarch --addr="${COPA_BUILDKIT_ADDR}" --copa="$(pwd)/copa" -timeout 0 | |
| - name: Test Summary | |
| uses: test-summary/action@v2 | |
| with: | |
| paths: "test-results.xml" | |
| test-generate: | |
| needs: build | |
| name: Test generate command ${{ matrix.buildkit_mode }} | |
| runs-on: oracle-vm-16cpu-64gb-x86-64 | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| buildkit_mode: ${{fromJson(needs.build.outputs.buildkitenvs)}} | |
| steps: | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - run: docker system prune -a -f --volumes | |
| - name: Check out code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version: "1.25" | |
| check-latest: true | |
| - name: Install required tools | |
| shell: bash | |
| run: .github/workflows/scripts/download-tooling.sh | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - name: Extract copa | |
| shell: bash | |
| run: | | |
| tar xzf copa_edge_linux_amd64.tar.gz | |
| ./copa --version | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
| - name: Run e2e tests | |
| shell: bash | |
| run: | | |
| set -eu -o pipefail | |
| . .github/workflows/scripts/buildkitenvs/${{ matrix.buildkit_mode}} | |
| go test -v ./test/e2e/generate --addr="${COPA_BUILDKIT_ADDR}" --copa="$(pwd)/copa" -timeout 0 | |
| test-patch-multiplatform-plugin: | |
| needs: build | |
| name: Test multiplatform with plugin | |
| runs-on: oracle-vm-16cpu-64gb-x86-64 | |
| timeout-minutes: 50 | |
| steps: | |
| - name: Change docker daemon config | |
| run: | | |
| echo '{"features": { "containerd-snapshotter": true }, "insecure-registries": ["localhost:5000"], "dns": ["8.8.8.8", "8.8.4.4"]}' | sudo tee /etc/docker/daemon.json | |
| echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf > /dev/null | |
| sudo systemctl restart docker | |
| - name: Set up buildx | |
| uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 | |
| with: | |
| install: true | |
| platforms: linux/amd64,linux/arm64 | |
| - name: Install oras CLI | |
| uses: oras-project/setup-oras@22ce207df3b08e061f537244349aac6ae1d214f6 # v1.2.4 | |
| - name: Set up local registry | |
| run: | | |
| docker run -d -p 5000:5000 --restart=always --name registry registry:2 | |
| # wait for the registry to be healthy | |
| for i in $(seq 1 60); do | |
| if curl -f http://localhost:5000/v2/_catalog; then | |
| break | |
| fi | |
| sleep 1 | |
| done | |
| - name: Test registry | |
| run: | | |
| set -eu -o pipefail | |
| docker pull nginx:latest | |
| docker tag nginx:latest localhost:5000/nginx:latest | |
| docker push localhost:5000/nginx:latest | |
| - name: Check out code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version: "1.25" | |
| check-latest: true | |
| - name: Install scanner-plugin-template | |
| shell: bash | |
| run: | | |
| go install github.com/project-copacetic/scanner-plugin-template@latest | |
| mv $(go env GOPATH)/bin/scanner-plugin-template $(go env GOPATH)/bin/copa-fake | |
| mv $(go env GOPATH)/bin/copa-fake /usr/local/bin | |
| - name: Install required tools | |
| shell: bash | |
| run: .github/workflows/scripts/download-tooling.sh | |
| - name: Install multiplatform tooling | |
| shell: bash | |
| run: .github/workflows/scripts/download-multiplatform-tooling.sh | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - run: docker system prune -a -f --volumes | |
| - name: Extract copa | |
| shell: bash | |
| run: | | |
| tar xzf copa_edge_linux_amd64.tar.gz | |
| ./copa --version | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
| - name: Run e2e multiplatform plugin tests | |
| shell: bash | |
| run: | | |
| set -eu -o pipefail | |
| gotestsum --format testname --junitfile test-results.xml -- ./test/e2e/multiplatform-plugin --addr=docker:// --copa="$(pwd)/copa" -timeout 0 | |
| - name: Test Summary | |
| uses: test-summary/action@v2 | |
| with: | |
| paths: "test-results.xml" | |
| test-patch-local-multiplatform-oci-layout: | |
| needs: build | |
| name: Test multiplatform OCI layout creation | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Change docker daemon config | |
| run: | | |
| echo '{"features": { "containerd-snapshotter": true }, "insecure-registries": ["localhost:5000"]}' | sudo tee /etc/docker/daemon.json | |
| sudo systemctl restart docker | |
| - name: Set up buildx | |
| uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 | |
| with: | |
| install: true | |
| platforms: linux/amd64,linux/arm64 | |
| - name: Check out code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version: "1.25" | |
| check-latest: true | |
| - name: Install required tools | |
| shell: bash | |
| run: .github/workflows/scripts/download-tooling.sh | |
| - name: Install multiplatform tooling | |
| shell: bash | |
| run: .github/workflows/scripts/download-multiplatform-tooling.sh | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - run: docker system prune -a -f --volumes | |
| - name: Extract copa | |
| shell: bash | |
| run: | | |
| tar xzf copa_edge_linux_amd64.tar.gz | |
| ./copa --version | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
| - name: Set up local registry with insecure access | |
| run: | | |
| docker run -d -p 5000:5000 --restart=always --name registry registry:2 | |
| # wait for the registry to be healthy | |
| for i in $(seq 1 60); do | |
| if curl -f http://localhost:5000/v2/_catalog; then | |
| echo "Registry is healthy after ${i} attempts" | |
| break | |
| fi | |
| echo "Waiting for registry... attempt ${i}/60" | |
| sleep 1 | |
| done | |
| # Verify registry is accessible | |
| curl -f http://localhost:5000/v2/_catalog || { echo "ERROR: Registry not accessible"; exit 1; } | |
| - name: Test OCI layout creation with local multiplatform manifest | |
| shell: bash | |
| run: | | |
| set -eu -o pipefail | |
| BASE_IMAGE="mcr.microsoft.com/cbl-mariner/base/core:2.0.20240112" | |
| LOCAL_REGISTRY="localhost:5000" | |
| PLATFORM_AMD64_IMAGE="${LOCAL_REGISTRY}/mariner:2.0.20240112-amd64" | |
| PLATFORM_ARM64_IMAGE="${LOCAL_REGISTRY}/mariner:2.0.20240112-arm64" | |
| LOCAL_MANIFEST="${LOCAL_REGISTRY}/mariner:2.0.20240112-multiplatform" | |
| echo "Building and pushing platform-specific images to local registry..." | |
| # Get platform-specific digests from the multi-platform image | |
| AMD64_DIGEST=$(docker manifest inspect "${BASE_IMAGE}" | jq -r '.manifests[] | select(.platform.architecture=="amd64") | .digest') | |
| ARM64_DIGEST=$(docker manifest inspect "${BASE_IMAGE}" | jq -r '.manifests[] | select(.platform.architecture=="arm64") | .digest') | |
| echo "AMD64 digest: ${AMD64_DIGEST}" | |
| echo "ARM64 digest: ${ARM64_DIGEST}" | |
| # Pull and push amd64 image using specific digest | |
| echo "Pulling amd64 image by digest..." | |
| docker pull "${BASE_IMAGE}@${AMD64_DIGEST}" | |
| echo "Tagging and pushing amd64 image..." | |
| docker tag "${BASE_IMAGE}@${AMD64_DIGEST}" "${PLATFORM_AMD64_IMAGE}" | |
| docker push "${PLATFORM_AMD64_IMAGE}" | |
| # Pull and push arm64 image using specific digest | |
| echo "Pulling arm64 image by digest..." | |
| docker pull "${BASE_IMAGE}@${ARM64_DIGEST}" | |
| echo "Tagging and pushing arm64 image..." | |
| docker tag "${BASE_IMAGE}@${ARM64_DIGEST}" "${PLATFORM_ARM64_IMAGE}" | |
| docker push "${PLATFORM_ARM64_IMAGE}" | |
| echo "Verifying platform-specific images exist in local registry..." | |
| curl -s http://localhost:5000/v2/mariner/tags/list | jq . | |
| # Verify images using registry API with retries | |
| for i in $(seq 1 10); do | |
| if curl -s -f "http://localhost:5000/v2/mariner/manifests/2.0.20240112-amd64" > /dev/null; then | |
| echo "✓ AMD64 image verified in registry" | |
| break | |
| fi | |
| echo "Waiting for AMD64 image... attempt ${i}/10" | |
| sleep 2 | |
| done | |
| for i in $(seq 1 10); do | |
| if curl -s -f "http://localhost:5000/v2/mariner/manifests/2.0.20240112-arm64" > /dev/null; then | |
| echo "✓ ARM64 image verified in registry" | |
| break | |
| fi | |
| echo "Waiting for ARM64 image... attempt ${i}/10" | |
| sleep 2 | |
| done | |
| echo "Enabling Docker CLI experimental features for manifest commands..." | |
| export DOCKER_CLI_EXPERIMENTAL=enabled | |
| echo "Creating local Docker manifest that references local registry platform images..." | |
| # Pull the images locally first to ensure they're available for manifest creation | |
| docker pull "${PLATFORM_AMD64_IMAGE}" | |
| docker pull "${PLATFORM_ARM64_IMAGE}" | |
| # Create local manifest list using --insecure for local registry | |
| docker manifest create --insecure "${LOCAL_MANIFEST}" "${PLATFORM_AMD64_IMAGE}" "${PLATFORM_ARM64_IMAGE}" | |
| docker manifest push --insecure "${LOCAL_MANIFEST}" | |
| echo "Verifying local multiplatform manifest was created..." | |
| docker manifest inspect "${LOCAL_MANIFEST}" | |
| # Verify manifest exists in registry | |
| curl -s "http://localhost:5000/v2/mariner/manifests/2.0.20240112-multiplatform" | jq . | |
| # Create temp directory for OCI layout | |
| OCI_LAYOUT_DIR=$(mktemp -d) | |
| echo "Patching local multiplatform manifest and creating OCI layout (patching only amd64)..." | |
| # Set buildkit to use Docker daemon to ensure it can access the local registry | |
| export COPA_BUILDKIT_ADDR="docker://" | |
| # Patch only amd64 platform, preserve arm64 platform | |
| ./copa patch \ | |
| -i="${LOCAL_MANIFEST}" \ | |
| -t="patched" \ | |
| --platform="linux/amd64" \ | |
| --timeout=30m \ | |
| --ignore-errors=true \ | |
| --oci-dir="${OCI_LAYOUT_DIR}" \ | |
| --debug | |
| echo "Validating OCI layout structure..." | |
| # Check that OCI layout directory was created | |
| if [ ! -d "${OCI_LAYOUT_DIR}" ]; then | |
| echo "ERROR: OCI layout directory was not created" | |
| exit 1 | |
| fi | |
| # Check for required OCI layout files | |
| if [ ! -f "${OCI_LAYOUT_DIR}/oci-layout" ]; then | |
| echo "ERROR: oci-layout file missing" | |
| exit 1 | |
| fi | |
| if [ ! -f "${OCI_LAYOUT_DIR}/index.json" ]; then | |
| echo "ERROR: index.json file missing" | |
| exit 1 | |
| fi | |
| if [ ! -d "${OCI_LAYOUT_DIR}/blobs" ]; then | |
| echo "ERROR: blobs directory missing" | |
| exit 1 | |
| fi | |
| echo "Validating OCI layout content..." | |
| # Check that index.json contains multiplatform index | |
| MEDIA_TYPE=$(jq -r '.mediaType' "${OCI_LAYOUT_DIR}/index.json") | |
| echo "Index media type: ${MEDIA_TYPE}" | |
| if [ "${MEDIA_TYPE}" != "application/vnd.oci.image.index.v1+json" ]; then | |
| echo "ERROR: Expected OCI image index media type, got ${MEDIA_TYPE}" | |
| exit 1 | |
| fi | |
| # Check for multiple platforms in the index (mixed layout) | |
| PLATFORM_COUNT=$(jq '.manifests | length' "${OCI_LAYOUT_DIR}/index.json") | |
| echo "Found ${PLATFORM_COUNT} platform(s) in index" | |
| if [ "${PLATFORM_COUNT}" -ne 2 ]; then | |
| echo "ERROR: Expected exactly 2 platforms (1 patched, 1 preserved), found ${PLATFORM_COUNT}" | |
| exit 1 | |
| fi | |
| # Validate specific platforms exist | |
| AMD64_FOUND=$(jq -r '.manifests[] | select(.platform.architecture=="amd64") | .platform.architecture' "${OCI_LAYOUT_DIR}/index.json") | |
| ARM64_FOUND=$(jq -r '.manifests[] | select(.platform.architecture=="arm64") | .platform.architecture' "${OCI_LAYOUT_DIR}/index.json") | |
| if [ "${AMD64_FOUND}" != "amd64" ]; then | |
| echo "ERROR: amd64 platform not found in index" | |
| exit 1 | |
| fi | |
| if [ "${ARM64_FOUND}" != "arm64" ]; then | |
| echo "ERROR: arm64 platform not found in index" | |
| exit 1 | |
| fi | |
| # Cleanup | |
| echo "Cleaning up..." | |
| rm -rf "${OCI_LAYOUT_DIR}" | |
| docker stop registry || true | |
| docker rm registry || true | |
| echo "Local registry mixed OCI layout test completed successfully!" | |
| test-nodejs: | |
| needs: build | |
| name: Test Node.js patching | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: read-all | |
| steps: | |
| - name: Check out code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version: "1.25" | |
| check-latest: true | |
| - name: Add containerd-snapshotter to docker daemon | |
| run: | | |
| echo '{"features": { "containerd-snapshotter": true }}' | sudo tee /etc/docker/daemon.json | |
| sudo systemctl restart docker | |
| - name: Install required tools | |
| shell: bash | |
| run: .github/workflows/scripts/download-tooling.sh | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - name: Extract copa | |
| shell: bash | |
| run: | | |
| tar xzf copa_edge_linux_amd64.tar.gz | |
| ./copa --version | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
| - name: Run Node.js e2e tests | |
| shell: bash | |
| run: | | |
| set -eu -o pipefail | |
| gotestsum --format testname --junitfile test-results.xml -- ./test/e2e/nodejs --addr=docker:// --copa="$(pwd)/copa" -timeout 0 | |
| - name: Test Summary | |
| uses: test-summary/action@v2 | |
| with: | |
| paths: "test-results.xml" | |
| test-patch-bulk: | |
| needs: build | |
| name: Test Bulk Patching | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Check out code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Configure Docker Daemon | |
| run: | | |
| echo '{"features": {"containerd-snapshotter": true}, "insecure-registries": ["127.0.0.1:37219"]}' | sudo tee /etc/docker/daemon.json | |
| sudo systemctl restart docker | |
| - name: Set up Buildx | |
| uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 | |
| with: | |
| install: true | |
| - name: Set up Go | |
| uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 | |
| with: | |
| go-version: "1.24" | |
| check-latest: true | |
| - name: Install required tools | |
| shell: bash | |
| run: .github/workflows/scripts/download-tooling.sh | |
| - name: Download copa from build artifacts | |
| uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 | |
| with: | |
| name: copa_edge_linux_amd64.tar.gz | |
| - name: Extract copa | |
| shell: bash | |
| run: | | |
| tar xzf copa_edge_linux_amd64.tar.gz | |
| ./copa --version | |
| - name: Run bulk patch integration test | |
| shell: bash | |
| run: | | |
| set -eu -o pipefail | |
| # The test now runs in a more realistic and consistent environment | |
| gotestsum --format testname --junitfile test-results.xml -- ./integration/bulk --copa="$(pwd)/copa" |