Skip to content

KNOX-3424: Dynamic audience handling in the KNOXTOKEN service #480

KNOX-3424: Dynamic audience handling in the KNOXTOKEN service

KNOX-3424: Dynamic audience handling in the KNOXTOKEN service #480

Workflow file for this run

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
name: Apache Knox Docker Compose Tests
on:
pull_request:
branches:
- '**' # triggers for all PRs
workflow_dispatch:
jobs:
build-and-test:
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'skip-tests')
runs-on: ubuntu-latest
permissions:
contents: read
checks: write
pull-requests: write
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: 'maven'
- name: Build with Maven
run: |
mvn clean -Ppackage,release install -T 1C \
-Dmaven.test.skip=true -Dpmd.skip=true -Dcpd.skip=true -Dcheckstyle.skip=true \
-Dspotbugs.skip=true -Drat.skip=true -Dforbiddenapis.skip=true -Denforcer.skip=true \
-Djacoco.skip=true -Dmaven.javadoc.skip=true -Dmaven.source.skip=true \
-Dshellcheck.skip=true -Dxml.skip=true \
-s .github/workflows/build/settings.xml
- name: Set up Docker Compose
run: docker compose version
- name: Build Docker Images
run: |
# Build only knox-dev which is the runtime image using artifacts
docker compose -f ./.github/workflows/compose/docker-compose.yml build knox-dev
- name: Start Knox and LDAP Services
run: docker compose -f ./.github/workflows/compose/docker-compose.yml up -d
- name: Wait for services to stabilize
run: sleep 30 # Adjust as needed for services startup time
- name: Run Knox Integration Tests
run: |
# Run the tests service defined in docker-compose.yml
docker compose -f ./.github/workflows/compose/docker-compose.yml up --exit-code-from tests tests
# KnoxIDF federation E2E runs only when the PR carries the 'test-federation'
# label. It stands up a real Keycloak (external OpenID Provider) via the
# override compose file and pulls a multi-hundred-MB image plus minutes of
# realm import, so it is opt-in rather than on every PR. It runs here, before
# the single-EKU steps, so 'knox' is still in its base (non-mTLS) config; the
# override only adds a keycloak dependency to knox, it does not reconfigure it.
- name: Start Keycloak + Knox for federation
if: contains(github.event.pull_request.labels.*.name, 'test-federation')
run: |
# 'up -d knox' blocks until keycloak is service_healthy (override depends_on).
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.knoxidf-federation.yml \
up -d knox keycloak
- name: Wait for federation stack to stabilize
if: contains(github.event.pull_request.labels.*.name, 'test-federation')
run: sleep 30 # Adjust as needed for services startup time
- name: Run KnoxIDF Federation Tests
id: knoxidf_federation_tests
if: contains(github.event.pull_request.labels.*.name, 'test-federation')
run: |
# Emit a distinct JUnit file so it reports as its own test suite.
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.knoxidf-federation.yml \
run --rm tests bash -c "pip install -r requirements.txt \
&& pytest test_knoxidf_federation.py --junitxml=test-results-federation.xml"
# Evidence gathering mirrors the single-EKU dumps: on a federation failure,
# capture container status and the knox + keycloak logs so a broker-flow
# failure (bad callback/issuer/JWKS) can be told apart from a Keycloak that
# never came up.
- name: Dump federation diagnostics on failure
if: failure() && steps.knoxidf_federation_tests.outcome == 'failure'
run: |
echo '===== docker compose ps -a ====='
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.knoxidf-federation.yml \
ps -a || true
echo '===== knox container logs ====='
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.knoxidf-federation.yml \
logs --no-color knox || true
echo '===== keycloak container logs ====='
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.knoxidf-federation.yml \
logs --no-color keycloak || true
echo '===== gateway.log ====='
cat ./.github/workflows/compose/logs/gateway.log || true
# Single-EKU mTLS runs as its own pass. Its override turns on
# gateway.client.auth.needed=true, which would break the default
# (no-client-cert) tests above, so the gateway is recreated with the
# single-EKU config and the mTLS suite runs against that instance. The
# already-built apache/knox-dev image is reused -- no second Maven build.
- name: Restart Knox in single-EKU mode
run: |
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.single-eku.yml \
up -d knox
- name: Wait for single-EKU gateway to stabilize
run: sleep 30 # Adjust as needed for services startup time
- name: Run Single-EKU mTLS Tests
id: single_eku_tests
run: |
# KNOX_SINGLE_EKU=true (set by the override) un-skips the suite.
# Emit a distinct JUnit file so it reports as its own test suite.
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.single-eku.yml \
run --rm tests bash -c "pip install -r requirements.txt \
&& pytest test_single_eku_mtls.py --junitxml=test-results-single-eku.xml"
# Evidence gathering: a "Connection refused" from the suite means the
# single-EKU gateway never listened. Dump container status, the knox
# container's stdout/stderr (includes the entrypoint's create-alias output
# and any Java startup stacktrace), and the gateway log so we can tell a
# failed entrypoint apart from single-EKU fail-fast validation.
- name: Dump single-EKU diagnostics on failure
if: failure() && steps.single_eku_tests.outcome == 'failure'
run: |
echo '===== docker compose ps -a ====='
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.single-eku.yml \
ps -a || true
echo '===== knox container logs ====='
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.single-eku.yml \
logs --no-color knox || true
echo '===== gateway.log ====='
cat ./.github/workflows/compose/logs/gateway.log || true
# Second single-EKU scenario: mTLS OFF. Proves single-EKU does not force
# inbound client authentication -- a no-client-cert request must succeed.
- name: Restart Knox in single-EKU (no mTLS) mode
run: |
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.single-eku-no-mtls.yml \
up -d knox
- name: Wait for single-EKU (no mTLS) gateway to stabilize
run: sleep 30 # Adjust as needed for services startup time
- name: Run Single-EKU (no mTLS) Tests
id: single_eku_no_mtls_tests
run: |
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.single-eku-no-mtls.yml \
run --rm tests bash -c "pip install -r requirements.txt \
&& pytest test_single_eku_no_mtls.py --junitxml=test-results-single-eku-no-mtls.xml"
- name: Dump single-EKU (no mTLS) diagnostics on failure
if: failure() && steps.single_eku_no_mtls_tests.outcome == 'failure'
run: |
echo '===== docker compose ps -a ====='
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.single-eku-no-mtls.yml \
ps -a || true
echo '===== knox container logs ====='
docker compose \
-f ./.github/workflows/compose/docker-compose.yml \
-f ./.github/workflows/compose/docker-compose.single-eku-no-mtls.yml \
logs --no-color knox || true
echo '===== gateway.log ====='
cat ./.github/workflows/compose/logs/gateway.log || true
- name: Collect Knox Logs and Conf
if: always()
run: |
mkdir -p .github/workflows/artifacts/knox-logs
mkdir -p .github/workflows/artifacts/knox-conf
docker compose -f ./.github/workflows/compose/docker-compose.yml cp knox:/knox-runtime/logs .github/workflows/artifacts/knox-logs
docker compose -f ./.github/workflows/compose/docker-compose.yml cp knox:/knox-runtime/conf .github/workflows/artifacts/knox-conf
- name: Upload Test Results
if: (!cancelled())
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
.github/workflows/tests/test-results.xml
.github/workflows/tests/test-results-single-eku.xml
.github/workflows/tests/test-results-single-eku-no-mtls.xml
.github/workflows/tests/test-results-federation.xml
- name: Archive Knox Logs
if: always()
run: tar -cvzf knox-logs.tar.gz -C .github/workflows/artifacts/knox-logs .
- name: Upload Knox Logs
if: always()
uses: actions/upload-artifact@v4
with:
name: knox-logs
path: knox-logs.tar.gz
- name: Archive Knox Conf
if: always()
run: tar -cvzf knox-conf.tar.gz -C .github/workflows/artifacts/knox-conf .
- name: Upload Knox Conf
if: always()
uses: actions/upload-artifact@v4
with:
name: knox-conf
path: knox-conf.tar.gz
- name: Upload Event File
uses: actions/upload-artifact@v4
with:
name: Event File
path: ${{ github.event_path }}
- name: Tear Down Docker Compose
if: always()
run: |
docker compose -f ./.github/workflows/compose/docker-compose.yml down --volumes
TAG=${IMAGE_TAG:-master}
if docker image inspect "apache/knox-dev:$TAG" >/dev/null 2>&1; then
docker rmi "apache/knox-dev:$TAG"
fi