test(jumper): add tests for verifying enabled/disabled Netty header validation for upstream client #564
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
| # SPDX-FileCopyrightText: 2025 Deutsche Telekom IT GmbH | |
| # | |
| # SPDX-License-Identifier: Apache-2.0 | |
| name: Build | |
| # Validates every change and, on a push to a release branch, publishes a release for the | |
| # commit that has just passed validation. | |
| # | |
| # Release order of operations (image before tag): | |
| # 1. compute-version - semantic-release dry run decides whether a release is due | |
| # 2. build-image - assert the version tag is unpublished, build the image tagged | |
| # directly with that version, scan the digest, then sign it | |
| # 3. publish-release - semantic-release creates the Git tag and GitHub release, and | |
| # points the floating alias (`latest` or `next`) at the digest | |
| # | |
| # A Git tag therefore never exists without a verified image. An interrupted release is | |
| # finished by re-running this workflow: if the version tag already exists, was built from | |
| # this same commit, and its digest still verifies, the build and sign steps are skipped | |
| # and the run completes the tagging. | |
| # | |
| # Required environment setup: | |
| # Variables: | |
| # - JAVA_VERSION: Java version to use (defaults to '25' if not specified) | |
| # - JAVA_DISTRIBUTION: Java distribution to use (defaults to 'zulu' if not specified) | |
| # - REGISTRY_HOST: Container registry host (e.g. registry.example.com) | |
| # - REGISTRY_REPO: Repository path (e.g. /my-repo/gateway/jumper) | |
| # | |
| # Required secrets: | |
| # - ARTIFACTORY_O28M_PUSH_USER: Container registry username | |
| # - ARTIFACTORY_O28M_PUSH_TOKEN: Container registry token/password | |
| # - COSIGN_PRIVATE_KEY / COSIGN_PUBLIC_KEY / COSIGN_PASSWORD: Image signing key material | |
| on: | |
| pull_request: | |
| push: | |
| branches: | |
| - main | |
| - next | |
| permissions: | |
| contents: read | |
| # Serialise runs per ref. Releases for a given branch therefore never overlap, which is | |
| # what makes the "version tag is unpublished" check in build-image race-free. Superseded | |
| # pull request runs are cancelled; release runs never are. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| env: | |
| JAVA_VERSION: ${{ vars.JAVA_VERSION || '25' }} | |
| JAVA_DISTRIBUTION: ${{ vars.JAVA_DISTRIBUTION || 'zulu' }} | |
| IMAGE_REPOSITORY: ${{ vars.REGISTRY_HOST }}${{ vars.REGISTRY_REPO }} | |
| jobs: | |
| lint-java: | |
| name: Lint Java | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 #v7.0.0 | |
| - name: Set up JDK | |
| uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 #v5.6.0 | |
| with: | |
| distribution: ${{ env.JAVA_DISTRIBUTION }} | |
| java-version: ${{ env.JAVA_VERSION }} | |
| cache: "maven" | |
| - name: Check code formatting with Spotless | |
| run: mvn com.diffplug.spotless:spotless-maven-plugin:check | |
| build-test-java: | |
| name: Build and test Java | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 #v7.0.0 | |
| - name: Set up JDK | |
| uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 #v5.6.0 | |
| with: | |
| distribution: ${{ env.JAVA_DISTRIBUTION }} | |
| java-version: ${{ env.JAVA_VERSION }} | |
| cache: "maven" | |
| - name: Build and test with Maven | |
| run: mvn -B -U package | |
| - name: Upload test results | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1 | |
| if: always() | |
| with: | |
| name: test-results | |
| path: | | |
| **/target/surefire-reports/ | |
| publish-preview-image: | |
| # Preview image created on PR builds. It is tagged using a floating `pr-<number>-<branch-slug>` | |
| # tag, rather than a permanent SemVer tag. | |
| name: Build and push preview image | |
| runs-on: ubuntu-latest | |
| needs: [lint-java, build-test-java] | |
| # Pull requests from forks are skipped. GitHub withholds secrets and variables from | |
| # them, so there are no registry credentials to push or sign with. Review a fork's | |
| # change on a release candidate after merge instead. | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| github.event.pull_request.head.repo.full_name == github.repository | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 #v7.0.0 | |
| - name: Set up JDK | |
| uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 #v5.6.0 | |
| with: | |
| distribution: ${{ env.JAVA_DISTRIBUTION }} | |
| java-version: ${{ env.JAVA_VERSION }} | |
| cache: "maven" | |
| - name: Inject slug vars | |
| uses: rlespinasse/github-slug-action@ef93b2ea4b6405d06fd8684fc3ff795d262ecae8 #v5.7.0 | |
| - name: Log in to the container registry | |
| uses: ./.github/actions/registry-login | |
| with: | |
| registry: ${{ vars.REGISTRY_HOST }} | |
| username: ${{ secrets.ARTIFACTORY_O28M_PUSH_USER }} | |
| password: ${{ secrets.ARTIFACTORY_O28M_PUSH_TOKEN }} | |
| - name: Build and push preview image | |
| id: build | |
| env: | |
| IMAGE_TAG: pr-${{ github.event.pull_request.number }}-${{ env.GITHUB_HEAD_REF_SLUG }} | |
| run: | | |
| # No credentials are passed: Jib reads the Docker config written by the registry | |
| # login step above, which this job also needs for cosign. | |
| mvn -B -U package -DskipTests jib:build \ | |
| -Djib.to.image="${IMAGE_REPOSITORY}:${IMAGE_TAG}" | |
| echo "digest=$(cat target/jib-image.digest)" >> "${GITHUB_OUTPUT}" | |
| - name: Scan preview image | |
| uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 #v0.36.0 | |
| env: | |
| TRIVY_USERNAME: ${{ secrets.ARTIFACTORY_O28M_PUSH_USER }} | |
| TRIVY_PASSWORD: ${{ secrets.ARTIFACTORY_O28M_PUSH_TOKEN }} | |
| with: | |
| image-ref: "${{ env.IMAGE_REPOSITORY }}@${{ steps.build.outputs.digest }}" | |
| exit-code: "0" | |
| vuln-type: os # library findings are handled by ort and github auto submission | |
| format: table | |
| - name: Sign image | |
| env: | |
| DIGEST: ${{ steps.build.outputs.digest }} | |
| COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }} | |
| COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }} | |
| run: | | |
| cosign sign --key env://COSIGN_PRIVATE_KEY --tlog-upload=false --yes \ | |
| "${IMAGE_REPOSITORY}@${DIGEST}" | |
| - name: Verify signature | |
| env: | |
| DIGEST: ${{ steps.build.outputs.digest }} | |
| COSIGN_PUBLIC_KEY: ${{ secrets.COSIGN_PUBLIC_KEY }} | |
| run: | | |
| cosign verify --insecure-ignore-tlog=true --key env://COSIGN_PUBLIC_KEY \ | |
| "${IMAGE_REPOSITORY}@${DIGEST}" | |
| compute-version: | |
| name: Compute release version | |
| runs-on: ubuntu-latest | |
| needs: [lint-java, build-test-java] | |
| # Only a push to a protected release branch may publish, PR runs never reach this job. | |
| # The two jobs below depend on this one, so they are skipped along with it. | |
| if: github.event_name == 'push' | |
| permissions: | |
| # semantic-release verifies push access with `git push --dry-run` even in dry-run | |
| # mode, so this job needs write permission although it writes nothing. | |
| contents: write | |
| outputs: | |
| new-release-published: ${{ steps.compute.outputs.new-release-published }} | |
| new-release-version: ${{ steps.compute.outputs.new-release-version }} | |
| steps: | |
| - name: Check out the validated commit | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 #v7.0.0 | |
| with: | |
| ref: ${{ github.sha }} | |
| fetch-depth: 0 | |
| fetch-tags: "true" | |
| - name: Restore the branch reference | |
| # Checking out a SHA leaves a detached HEAD. semantic-release compares the local | |
| # branch against its remote, so put HEAD back on the branch name without moving | |
| # it off the validated commit. | |
| env: | |
| BRANCH: ${{ github.ref_name }} | |
| run: git checkout -B "${BRANCH}" | |
| - name: Compute version | |
| # Dry run only: this decides the version for the image tag before anything is | |
| # built. It has no side effects, so it is safe to repeat on a re-run. | |
| id: compute | |
| uses: cycjimmy/semantic-release-action@b12c8f6015dc215fe37bc154d4ad456dd3833c90 #v6.0.0 | |
| with: | |
| dry_run: true | |
| extra_plugins: | | |
| semantic-release-export-data | |
| conventional-changelog-conventionalcommits@9.3.1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| build-image: | |
| name: Build, scan, and sign image | |
| runs-on: ubuntu-latest | |
| needs: [compute-version] | |
| if: needs.compute-version.outputs.new-release-published == 'true' | |
| permissions: | |
| contents: write # Trivy submits its findings to the dependency graph | |
| outputs: | |
| image-digest: ${{ steps.image.outputs.digest }} | |
| steps: | |
| - name: Check out the validated commit | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 #v7.0.0 | |
| with: | |
| ref: ${{ github.sha }} | |
| - name: Set up JDK | |
| uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 #v5.6.0 | |
| with: | |
| distribution: ${{ env.JAVA_DISTRIBUTION }} | |
| java-version: ${{ env.JAVA_VERSION }} | |
| cache: "maven" | |
| - name: Log in to the container registry | |
| uses: ./.github/actions/registry-login | |
| with: | |
| registry: ${{ vars.REGISTRY_HOST }} | |
| username: ${{ secrets.ARTIFACTORY_O28M_PUSH_USER }} | |
| password: ${{ secrets.ARTIFACTORY_O28M_PUSH_TOKEN }} | |
| - name: Look up the version tag | |
| id: version-tag | |
| env: | |
| VERSION: ${{ needs.compute-version.outputs.new-release-version }} | |
| SOURCE_SHA: ${{ github.sha }} | |
| run: | | |
| # SemVer image tags are immutable. The registry does not enforce that, so CI does. | |
| # An existing tag is only acceptable when this run is completing an interrupted | |
| # release of the very same commit: the scan and signature-verification steps below | |
| # then run against the existing digest and the run finishes tagging instead of | |
| # rebuilding. | |
| if ! digest="$(crane digest "${IMAGE_REPOSITORY}:${VERSION}" 2>/dev/null)"; then | |
| echo "exists=false" >> "${GITHUB_OUTPUT}" | |
| exit 0 | |
| fi | |
| # The version alone does not prove the existing image belongs to this release. An | |
| # interrupted release can be followed by further commits, and the next run then | |
| # computes the same version from a different source. | |
| # This is why we assert revision here. | |
| revision="$(crane config "${IMAGE_REPOSITORY}@${digest}" | | |
| jq -r '.config.Labels["org.opencontainers.image.revision"] // ""')" | |
| if [ "${revision}" != "${SOURCE_SHA}" ]; then | |
| printf 'release: %s:%s already exists (%s) and was built from %s, not from %s\n' \ | |
| "${IMAGE_REPOSITORY}" "${VERSION}" "${digest}" "${revision:-an unknown commit}" \ | |
| "${SOURCE_SHA}" >&2 | |
| exit 1 | |
| fi | |
| printf 'release: %s:%s already exists (%s); completing the interrupted release\n' \ | |
| "${IMAGE_REPOSITORY}" "${VERSION}" "${digest}" | |
| { | |
| echo "exists=true" | |
| echo "digest=${digest}" | |
| } >> "${GITHUB_OUTPUT}" | |
| - name: Build and push image | |
| if: steps.version-tag.outputs.exists == 'false' | |
| env: | |
| VERSION: ${{ needs.compute-version.outputs.new-release-version }} | |
| SOURCE_SHA: ${{ github.sha }} | |
| run: | | |
| mvn -B -U package -DskipTests jib:build \ | |
| -Djib.to.image="${IMAGE_REPOSITORY}:${VERSION}" \ | |
| -Djib.container.labels=org.opencontainers.image.revision="${SOURCE_SHA}" | |
| - name: Determine image digest | |
| id: image | |
| env: | |
| EXISTING_DIGEST: ${{ steps.version-tag.outputs.digest }} | |
| run: | | |
| if [ -n "${EXISTING_DIGEST}" ]; then | |
| digest="${EXISTING_DIGEST}" | |
| else | |
| digest="$(cat target/jib-image.digest)" | |
| fi | |
| printf 'release: releasing digest %s\n' "${digest}" | |
| echo "digest=${digest}" >> "${GITHUB_OUTPUT}" | |
| - name: Scan image | |
| # Always runs against the digest | |
| uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 #v0.36.0 | |
| env: | |
| TRIVY_USERNAME: ${{ secrets.ARTIFACTORY_O28M_PUSH_USER }} | |
| TRIVY_PASSWORD: ${{ secrets.ARTIFACTORY_O28M_PUSH_TOKEN }} | |
| with: | |
| image-ref: "${{ env.IMAGE_REPOSITORY }}@${{ steps.image.outputs.digest }}" | |
| exit-code: "0" | |
| vuln-type: os # library findings are handled by ort and github auto submission | |
| format: github | |
| output: dependency-results.sbom.json | |
| github-pat: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Sign image | |
| if: steps.version-tag.outputs.exists == 'false' | |
| env: | |
| DIGEST: ${{ steps.image.outputs.digest }} | |
| COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }} | |
| COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }} | |
| run: | | |
| cosign sign --key env://COSIGN_PRIVATE_KEY --tlog-upload=false --yes \ | |
| "${IMAGE_REPOSITORY}@${DIGEST}" | |
| - name: Verify signature | |
| env: | |
| DIGEST: ${{ steps.image.outputs.digest }} | |
| COSIGN_PUBLIC_KEY: ${{ secrets.COSIGN_PUBLIC_KEY }} | |
| run: | | |
| cosign verify --insecure-ignore-tlog=true --key env://COSIGN_PUBLIC_KEY \ | |
| "${IMAGE_REPOSITORY}@${DIGEST}" | |
| publish-release: | |
| name: Tag and publish release | |
| runs-on: ubuntu-latest | |
| needs: [compute-version, build-image] | |
| permissions: | |
| contents: write | |
| issues: write | |
| pull-requests: write | |
| steps: | |
| - name: Check out the validated commit | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 #v7.0.0 | |
| with: | |
| ref: ${{ github.sha }} | |
| fetch-depth: 0 | |
| fetch-tags: "true" | |
| - name: Restore the branch reference | |
| env: | |
| BRANCH: ${{ github.ref_name }} | |
| run: git checkout -B "${BRANCH}" | |
| - name: Tag and publish release | |
| # The image already exists and has been verified, so this is the last step that | |
| # can fail: a Git tag never appears without a released image behind it. | |
| id: publish | |
| uses: cycjimmy/semantic-release-action@b12c8f6015dc215fe37bc154d4ad456dd3833c90 #v6.0.0 | |
| with: | |
| extra_plugins: | | |
| semantic-release-export-data | |
| conventional-changelog-conventionalcommits@9.3.1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Log in to the container registry | |
| if: steps.publish.outputs.new-release-published == 'true' | |
| uses: ./.github/actions/registry-login | |
| with: | |
| registry: ${{ vars.REGISTRY_HOST }} | |
| username: ${{ secrets.ARTIFACTORY_O28M_PUSH_USER }} | |
| password: ${{ secrets.ARTIFACTORY_O28M_PUSH_TOKEN }} | |
| - name: Update floating alias | |
| if: steps.publish.outputs.new-release-published == 'true' | |
| env: | |
| DIGEST: ${{ needs.build-image.outputs.image-digest }} | |
| BRANCH: ${{ github.ref_name }} | |
| run: | | |
| # `latest` tracks the newest stable release and `next` the newest release | |
| # candidate. | |
| if [ "${BRANCH}" = "next" ]; then | |
| alias="next" | |
| else | |
| alias="latest" | |
| fi | |
| crane tag "${IMAGE_REPOSITORY}@${DIGEST}" "${alias}" |