diff --git a/.github/workflows/build-push-test.yml b/.github/workflows/build-push-test.yml new file mode 100644 index 00000000..155803a1 --- /dev/null +++ b/.github/workflows/build-push-test.yml @@ -0,0 +1,60 @@ +--- +name: Build, Push & Test + +on: + workflow_call: + secrets: + TEST_GITHUB_PASSWORD: + required: false + TEST_GITHUB_TOKEN: + required: false + TEST_GITHUB_TOTP_SECRET: + required: false + TEST_GITHUB_USER: + required: false + +permissions: {} + +jobs: + build-push-test-base: + name: ๐Ÿจ base + uses: ./.github/workflows/wc-build-push-test.yml + permissions: &build-push-test-permissions + actions: read # is needed by anchore/sbom-action to find workflow artifacts when attaching release assets + artifact-metadata: write # is needed by actions/attest-build-provenance to write artifact metadata + attestations: write # is needed by actions/attest-build-provenance to push attestations + contents: write # is needed by anchore/sbom-action for artifact uploads + id-token: write # is needed by actions/attest-build-provenance to obtain an OIDC token + packages: write # is needed to push image manifest when using GitHub Container Registry + pull-requests: write # is needed by marocchino/sticky-pull-request-comment to post comments + with: + dockerfile: .devcontainer/base/Dockerfile + enable-edge-tag: ${{ github.event_name == 'merge_group' }} + image-name: ${{ github.repository }}-base + integration-test-file: test/base/integration-tests.bats + integration-test-podman: true + + build-push-test-flavors: + name: ๐Ÿจ ${{ matrix.flavor }} + needs: build-push-test-base + strategy: + matrix: + flavor: [cpp, rust] + uses: ./.github/workflows/wc-build-push-test.yml + secrets: + TEST_GITHUB_TOKEN: ${{ secrets.TEST_GITHUB_TOKEN }} + TEST_GITHUB_USER: ${{ secrets.TEST_GITHUB_USER }} + TEST_GITHUB_PASSWORD: ${{ secrets.TEST_GITHUB_PASSWORD }} + TEST_GITHUB_TOTP_SECRET: ${{ secrets.TEST_GITHUB_TOTP_SECRET }} + permissions: *build-push-test-permissions + with: + acceptance-test-path: ${{ (github.actor != 'dependabot[bot]' && matrix.flavor == 'cpp') && 'test/cpp/features' || '' }} + acceptance-test-devcontainer-file: .devcontainer/${{ matrix.flavor }}-test/devcontainer.json + build-args: | + BASE_IMAGE=${{ needs.build-push-test-base.outputs.fully-qualified-image-name }}@${{ needs.build-push-test-base.outputs.digest }} + devcontainer-metadata-file: .devcontainer/${{ matrix.flavor }}/devcontainer-metadata.json + dockerfile: .devcontainer/${{ matrix.flavor }}/Dockerfile + enable-edge-tag: ${{ github.event_name == 'merge_group' }} + image-name: ${{ github.repository }}-${{ matrix.flavor }} + integration-test-file: test/${{ matrix.flavor }}/integration-tests.bats + integration-test-podman: true diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 184fab9e..e85eadbf 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -13,9 +13,9 @@ concurrency: permissions: {} jobs: - build-push-base: - name: Build โ†’ Push โ†’ Test (๐Ÿจ base) - uses: ./.github/workflows/wc-build-push-test.yml + build-push-test: + name: Build โ†’ Push โ†’ Test + uses: ./.github/workflows/build-push-test.yml permissions: actions: read # is needed by anchore/sbom-action to find workflow artifacts when attaching release assets artifact-metadata: write # is needed by actions/attest-build-provenance to write artifact metadata @@ -24,46 +24,15 @@ jobs: id-token: write # is needed by actions/attest-build-provenance to obtain an OIDC token packages: write # is needed to push image manifest when using GitHub Container Registry pull-requests: write # is needed by marocchino/sticky-pull-request-comment to post comments - with: - dockerfile: .devcontainer/base/Dockerfile - enable-edge-tag: ${{ github.event_name == 'merge_group' }} - image-name: ${{ github.repository }}-base - integration-test-file: test/base/integration-tests.bats - - build-push-flavors: - name: Build โ†’ Push โ†’ Test (๐Ÿจ ${{ matrix.flavor }}) - needs: build-push-base - strategy: - matrix: - flavor: [cpp, rust] - uses: ./.github/workflows/wc-build-push-test.yml secrets: TEST_GITHUB_TOKEN: ${{ secrets.TEST_GITHUB_TOKEN }} TEST_GITHUB_USER: ${{ secrets.TEST_GITHUB_USER }} TEST_GITHUB_PASSWORD: ${{ secrets.TEST_GITHUB_PASSWORD }} TEST_GITHUB_TOTP_SECRET: ${{ secrets.TEST_GITHUB_TOTP_SECRET }} - permissions: - actions: read # is needed by anchore/sbom-action to find workflow artifacts when attaching release assets - artifact-metadata: write # is needed by actions/attest-build-provenance to write artifact metadata - attestations: write # is needed by actions/attest-build-provenance to push attestations - contents: write # is needed by anchore/sbom-action for artifact uploads - id-token: write # is needed by actions/attest-build-provenance to obtain an OIDC token - packages: write # is needed to push image manifest when using GitHub Container Registry - pull-requests: write # is needed by marocchino/sticky-pull-request-comment to post comments - with: - build-args: | - BASE_IMAGE=${{ needs.build-push-base.outputs.fully-qualified-image-name }}@${{ needs.build-push-base.outputs.digest }} - devcontainer-metadata-file: .devcontainer/${{ matrix.flavor }}/devcontainer-metadata.json - dockerfile: .devcontainer/${{ matrix.flavor }}/Dockerfile - enable-edge-tag: ${{ github.event_name == 'merge_group' }} - image-name: ${{ github.repository }}-${{ matrix.flavor }} - integration-test-file: test/${{ matrix.flavor }}/integration-tests.bats - acceptance-test-path: ${{ (github.actor != 'dependabot[bot]' && matrix.flavor == 'cpp') && 'test/cpp/features' || '' }} - test-devcontainer-file: .devcontainer/${{ matrix.flavor }}-test/devcontainer.json dependency-review: name: ๐Ÿ” Dependency Review - needs: build-push-flavors + needs: build-push-test uses: ./.github/workflows/wc-dependency-review.yml permissions: contents: read @@ -75,7 +44,7 @@ jobs: permissions: checks: write # is needed by EnricoMi/publish-unit-test-result-action to add a check run with test results pull-requests: write # is needed by EnricoMi/publish-unit-test-result-action to annotate PRs - needs: build-push-flavors + needs: build-push-test if: ${{ !cancelled() }} steps: - uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2 diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 48600189..16078d50 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -13,9 +13,9 @@ concurrency: permissions: {} jobs: - build-push-base: - name: Build โ†’ Push โ†’ Test (๐Ÿจ base) - uses: ./.github/workflows/wc-build-push-test.yml + build-push-test: + name: Build โ†’ Push โ†’ Test + uses: ./.github/workflows/build-push-test.yml permissions: actions: read # is needed by anchore/sbom-action to find workflow artifacts when attaching release assets artifact-metadata: write # is needed by actions/attest-build-provenance to write artifact metadata @@ -24,40 +24,11 @@ jobs: id-token: write # is needed by actions/attest-build-provenance to obtain an OIDC token packages: write # is needed to push image manifest when using GitHub Container Registry pull-requests: write # is needed by marocchino/sticky-pull-request-comment to post comments - with: - dockerfile: .devcontainer/base/Dockerfile - image-name: ${{ github.repository }}-base - integration-test-file: test/base/integration-tests.bats - - build-push-flavors: - name: Build โ†’ Push โ†’ Test (๐Ÿจ ${{ matrix.flavor }}) - needs: build-push-base - strategy: - matrix: - flavor: [cpp, rust] - uses: ./.github/workflows/wc-build-push-test.yml secrets: TEST_GITHUB_TOKEN: ${{ secrets.TEST_GITHUB_TOKEN }} TEST_GITHUB_USER: ${{ secrets.TEST_GITHUB_USER }} TEST_GITHUB_PASSWORD: ${{ secrets.TEST_GITHUB_PASSWORD }} TEST_GITHUB_TOTP_SECRET: ${{ secrets.TEST_GITHUB_TOTP_SECRET }} - permissions: - actions: read # is needed by anchore/sbom-action to find workflow artifacts when attaching release assets - artifact-metadata: write # is needed by actions/attest-build-provenance to write artifact metadata - attestations: write # is needed by actions/attest-build-provenance to push attestations - contents: write # is needed by anchore/sbom-action for artifact uploads - id-token: write # is needed by actions/attest-build-provenance to obtain an OIDC token - packages: write # is needed to push image manifest when using GitHub Container Registry - pull-requests: write # is needed by marocchino/sticky-pull-request-comment to post comments - with: - build-args: | - BASE_IMAGE=${{ needs.build-push-base.outputs.fully-qualified-image-name }}@${{ needs.build-push-base.outputs.digest }} - devcontainer-metadata-file: .devcontainer/${{ matrix.flavor }}/devcontainer-metadata.json - dockerfile: .devcontainer/${{ matrix.flavor }}/Dockerfile - image-name: ${{ github.repository }}-${{ matrix.flavor }} - integration-test-file: test/${{ matrix.flavor }}/integration-tests.bats - acceptance-test-path: ${{ matrix.flavor == 'cpp' && 'test/cpp/features' || '' }} - test-devcontainer-file: ${{ matrix.flavor == 'cpp' && '.devcontainer/cpp-test/devcontainer.json' || '' }} apply-release-notes-template: name: ๐Ÿ“ Apply Release Template @@ -96,7 +67,7 @@ jobs: # Please note that this is an overly broad scope, but GitHub does not # currently provide a more fine-grained permission for release modification. contents: write # is needed to modify a release - needs: [build-push-base, build-push-flavors, apply-release-notes-template] + needs: [build-push-test, apply-release-notes-template] env: CONTAINER_FLAVOR: ${{ matrix.flavor }} REF_NAME: ${{ github.ref_name }} diff --git a/.github/workflows/wc-build-push-test.yml b/.github/workflows/wc-build-push-test.yml index 9e8777d1..7fa64260 100644 --- a/.github/workflows/wc-build-push-test.yml +++ b/.github/workflows/wc-build-push-test.yml @@ -4,12 +4,16 @@ name: Build, Push & Test on: workflow_call: inputs: + acceptance-test-devcontainer-file: + description: Path to the devcontainer.json file to use for acceptance tests. + required: false + type: string acceptance-test-path: - description: Path to the Playwright acceptance tests (directory that contains playwright.config.ts) + description: Path to the Playwright acceptance tests (directory that contains playwright.config.ts). required: false type: string build-args: - description: Optional docker build args (newline-separated KEY=VALUE) + description: Optional docker build args (newline-separated KEY=VALUE). required: false type: string build-test-runner-labels: @@ -38,7 +42,7 @@ on: required: true type: string enable-edge-tag: - description: Whether to also build and push an "edge" tag for the image + description: Whether to also build and push an "edge" tag for the image. required: false type: boolean default: false @@ -52,9 +56,14 @@ on: required: true type: string integration-test-file: - description: Path to the BATS test file to run for integration tests + description: Path to the BATS test file to run for integration tests. required: false type: string + integration-test-podman: + description: Enable running the tests using the Podman container runtime, next to the default Docker container runtime. + required: false + type: boolean + default: false registry: description: >- Docker registry to push built containers to. @@ -73,10 +82,6 @@ on: required: false type: string default: '["ubuntu-latest"]' - test-devcontainer-file: - description: Path to the devcontainer.json file to use for acceptance tests - required: false - type: string outputs: digest: value: ${{ jobs.build-push.outputs.digest }} @@ -88,10 +93,10 @@ on: value: ${{ jobs.build-push.outputs.version }} secrets: DOCKER_REGISTRY_PASSWORD: - description: Password or token for Docker login, if not provided the GitHub token will be used + description: Password or token for Docker login, if not provided the GitHub token will be used. required: false DOCKER_REGISTRY_USERNAME: - description: User name for Docker login, if not provided the GitHub actor will be used + description: User name for Docker login, if not provided the GitHub actor will be used. required: false TEST_GITHUB_PASSWORD: required: false @@ -116,7 +121,7 @@ jobs: id-token: write # is needed by actions/attest-build-provenance to obtain an OIDC token packages: write # is needed to push image manifest when using GitHub Container Registry pull-requests: write # is needed by marocchino/sticky-pull-request-comment to post comments - secrets: + secrets: &docker-secrets DOCKER_REGISTRY_USERNAME: ${{ secrets.DOCKER_REGISTRY_USERNAME }} DOCKER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} with: @@ -129,17 +134,15 @@ jobs: runner-labels: ${{ inputs.runner-labels }} build-test-runner-labels: ${{ inputs.build-test-runner-labels }} - integration-test: + integration-test-docker: name: ๐Ÿงช if: ${{ inputs.integration-test-file }} needs: build-push - uses: ./.github/workflows/wc-integration-test.yml + uses: ./.github/workflows/wc-integration-test-docker.yml permissions: contents: read - secrets: - DOCKER_REGISTRY_USERNAME: ${{ secrets.DOCKER_REGISTRY_USERNAME }} - DOCKER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} - with: + secrets: *docker-secrets + with: &integration-test-inputs build-test-runner-labels: ${{ inputs.build-test-runner-labels }} fully-qualified-image-name: ${{ needs.build-push.outputs.fully-qualified-image-name }} image-basename: ${{ needs.build-push.outputs.image-basename }} @@ -147,9 +150,19 @@ jobs: registry: ${{ inputs.registry }} test-file: ${{ inputs.integration-test-file }} + integration-test-podman: + name: ๐Ÿงช + if: ${{ inputs.integration-test-file && inputs.integration-test-podman }} + needs: build-push + uses: ./.github/workflows/wc-integration-test-podman.yml + permissions: + contents: read + secrets: *docker-secrets + with: *integration-test-inputs + acceptance-test: name: ๐Ÿ—๏ธ - if: ${{ inputs.test-devcontainer-file && inputs.acceptance-test-path }} + if: ${{ inputs.acceptance-test-devcontainer-file && inputs.acceptance-test-path }} needs: build-push uses: ./.github/workflows/wc-acceptance-test.yml permissions: @@ -161,5 +174,5 @@ jobs: TEST_GITHUB_TOTP_SECRET: ${{ secrets.TEST_GITHUB_TOTP_SECRET }} with: image-basename: ${{ needs.build-push.outputs.image-basename }} - devcontainer-file: ${{ inputs.test-devcontainer-file }} + devcontainer-file: ${{ inputs.acceptance-test-devcontainer-file }} acceptance-test-path: ${{ inputs.acceptance-test-path }} diff --git a/.github/workflows/wc-integration-test.yml b/.github/workflows/wc-integration-test-docker.yml similarity index 86% rename from .github/workflows/wc-integration-test.yml rename to .github/workflows/wc-integration-test-docker.yml index f3e8b7c9..01b1dd15 100644 --- a/.github/workflows/wc-integration-test.yml +++ b/.github/workflows/wc-integration-test-docker.yml @@ -1,9 +1,12 @@ --- -name: Integration Test +name: ๐Ÿณ Integration Test on: workflow_call: inputs: + build-test-runner-labels: + required: true + type: string fully-qualified-image-name: required: true type: string @@ -13,26 +16,23 @@ on: image-digest: required: true type: string - test-file: - required: true - type: string - build-test-runner-labels: + registry: required: true type: string - registry: + test-file: required: true type: string secrets: - DOCKER_REGISTRY_USERNAME: - required: true DOCKER_REGISTRY_PASSWORD: required: true + DOCKER_REGISTRY_USERNAME: + required: true permissions: {} jobs: run-test: - name: Integration Test (${{ (startsWith(matrix.runner, '[') && endsWith(matrix.runner, ']')) && join(matrix.runner, ', ') || matrix.runner }}) + name: ๐Ÿณ Integration Test (${{ (startsWith(matrix.runner, '[') && endsWith(matrix.runner, ']')) && join(matrix.runner, ', ') || matrix.runner }}) strategy: matrix: runner: ${{ fromJson(inputs.build-test-runner-labels) }} @@ -62,5 +62,5 @@ jobs: - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 if: ${{ !cancelled() }} with: - name: test-results-integration-${{ inputs.image-basename }}-${{ steps.runner-arch.outputs.arch }} + name: test-results-integration-docker-${{ inputs.image-basename }}-${{ steps.runner-arch.outputs.arch }} path: test-report-*.xml diff --git a/.github/workflows/wc-integration-test-podman.yml b/.github/workflows/wc-integration-test-podman.yml new file mode 100644 index 00000000..83a16d78 --- /dev/null +++ b/.github/workflows/wc-integration-test-podman.yml @@ -0,0 +1,98 @@ +--- +name: ๐Ÿฆญ Integration Test + +on: + workflow_call: + inputs: + build-test-runner-labels: + required: true + type: string + fully-qualified-image-name: + required: true + type: string + image-basename: + required: true + type: string + image-digest: + required: true + type: string + registry: + required: true + type: string + test-file: + required: true + type: string + secrets: + DOCKER_REGISTRY_PASSWORD: + required: true + DOCKER_REGISTRY_USERNAME: + required: true + +permissions: {} + +jobs: + run-test: + name: ๐Ÿฆญ Integration Test (${{ (startsWith(matrix.runner, '[') && endsWith(matrix.runner, ']')) && join(matrix.runner, ', ') || matrix.runner }}) + strategy: + matrix: + runner: ${{ fromJson(inputs.build-test-runner-labels) }} + runs-on: ${{ matrix.runner }} + permissions: + contents: read + steps: + - uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2 + with: + disable-sudo: false + egress-policy: audit + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Install Podman + run: | + sudo apt-get update + sudo apt-get install -y podman + podman --version + - name: Login to container registry + run: | + printf '%s' "${REGISTRY_PASSWORD}" | podman login "${REGISTRY}" --username "${REGISTRY_USERNAME}" --password-stdin + env: + REGISTRY: ${{ inputs.registry }} + REGISTRY_USERNAME: ${{ secrets.DOCKER_REGISTRY_USERNAME || github.actor }} + REGISTRY_PASSWORD: ${{ secrets.DOCKER_REGISTRY_PASSWORD || github.token }} + - name: Pull container image + run: | + podman pull "${IMAGE_WITH_DIGEST}" + env: + IMAGE_WITH_DIGEST: ${{ inputs.fully-qualified-image-name }}@${{ inputs.image-digest }} + - run: echo "arch=$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT" + id: runner-arch + - name: Run integration tests using Podman + run: | + set -Eeuo pipefail + + podman run --rm \ + --network=host \ + -v "${WORKSPACE}:${WORKSPACE}" \ + -w "${WORKSPACE}" \ + -e IMAGE_BASENAME="${IMAGE_BASENAME}" \ + -e TEST_FILE="${TEST_FILE}" \ + -e RUNNER_ARCH="${RUNNER_ARCH}" \ + "${IMAGE_WITH_DIGEST}" \ + bats --formatter junit "${TEST_FILE}" | tee "test-report-${IMAGE_BASENAME}-podman-${RUNNER_ARCH}.xml" + env: + IMAGE_BASENAME: ${{ inputs.image-basename }} + IMAGE_WITH_DIGEST: ${{ inputs.fully-qualified-image-name }}@${{ inputs.image-digest }} + RUNNER_ARCH: ${{ steps.runner-arch.outputs.arch }} + TEST_FILE: ${{ inputs.test-file }} + WORKSPACE: ${{ github.workspace }} + - name: Log out of container registry + if: ${{ always() }} + run: | + podman logout "${REGISTRY}" + env: + REGISTRY: ${{ inputs.registry }} + - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + if: ${{ !cancelled() }} + with: + name: test-results-integration-podman-${{ inputs.image-basename }}-${{ steps.runner-arch.outputs.arch }} + path: test-report-*.xml