From 33ec2d6f4948f44701780181a3b6fc7447a5b79d Mon Sep 17 00:00:00 2001 From: Tharsanan1 Date: Mon, 9 Mar 2026 11:53:21 +0530 Subject: [PATCH 1/4] Update router image and add smoke test workflow --- .github/workflows/router-smoke-test.yml | 48 ++++ .../directory-structure-maker/README.md | 1 + .../directory-structure-maker.sh | 3 + .../docker-image-builder.sh | 3 + .../{.bazelversion => .bazelversion} | 0 resources/license/LICENSE-ROUTER.txt | 1 + resources/license/NOTICE-ROUTER.txt | 4 + router/src/main/assembly/assembly.xml | 5 + router/src/main/resources/Dockerfile | 14 +- test.sh | 248 ++++++++++++++++++ 10 files changed, 323 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/router-smoke-test.yml rename envoy-filters/mgw-source/filters/http/mgw-wasm-websocket/{.bazelversion => .bazelversion} (100%) create mode 100644 resources/license/NOTICE-ROUTER.txt create mode 100755 test.sh diff --git a/.github/workflows/router-smoke-test.yml b/.github/workflows/router-smoke-test.yml new file mode 100644 index 0000000000..60c7ce884a --- /dev/null +++ b/.github/workflows/router-smoke-test.yml @@ -0,0 +1,48 @@ +name: Router Smoke Test + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + smoke-test: + runs-on: ubuntu-22.04 + timeout-minutes: 120 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Free disk space + run: | + df -h + sudo rm -rf /usr/local/lib/android /opt/ghc /usr/share/dotnet + docker system prune -af || true + df -h + + - name: Set up JDK 11 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '11' + cache: maven + + - name: Set up Go 1.18 + uses: actions/setup-go@v5 + with: + go-version: '1.18.10' + + - name: Show tool versions + run: | + java -version + mvn -version + go version + docker version + docker compose version + + - name: Run smoke test + env: + COMPOSE_PROJECT_NAME: ccsmokegha + run: ./test.sh diff --git a/dev-scripts/directory-structure-maker/README.md b/dev-scripts/directory-structure-maker/README.md index 489c966635..b54d18884e 100644 --- a/dev-scripts/directory-structure-maker/README.md +++ b/dev-scripts/directory-structure-maker/README.md @@ -76,6 +76,7 @@ choreo-connect-1.1.0 │ ├── Dockerfile │ ├── Dockerfile.ubuntu │ ├── LICENSE.txt +│ ├── NOTICE.txt │ └── etc │ ├── envoy │ │ └── envoy.yaml diff --git a/dev-scripts/directory-structure-maker/directory-structure-maker.sh b/dev-scripts/directory-structure-maker/directory-structure-maker.sh index 181b9c7744..ad9bca91bc 100755 --- a/dev-scripts/directory-structure-maker/directory-structure-maker.sh +++ b/dev-scripts/directory-structure-maker/directory-structure-maker.sh @@ -84,6 +84,9 @@ mv ./ENFORCER/bin/grpc_health_probe ./ENFORCER/bin/grpc_healt docker cp $ROUTER_IMAGE_ID:home/wso2/interceptor ./ROUTER/\$HOME/ docker cp $ROUTER_IMAGE_ID:home/wso2/wasm ./ROUTER/\$HOME/ cp ../temp/LICENSE.txt ./ROUTER/ +if docker cp $ROUTER_IMAGE_ID:/NOTICE.txt ./ROUTER/; then + echo "Router NOTICE.txt copied" +fi docker cp $ROUTER_IMAGE_ID:/etc/envoy/envoy.yaml ./ROUTER/etc/envoy/ docker cp $ROUTER_IMAGE_ID:/home/wso2/envoy.yaml.template ./ROUTER/\$HOME/ docker cp $ROUTER_IMAGE_ID:/home/wso2/docker-entrypoint.sh ./ROUTER/\$HOME/ diff --git a/dev-scripts/directory-structure-maker/docker-image-builder.sh b/dev-scripts/directory-structure-maker/docker-image-builder.sh index 7a0bfad6a2..cdd320d33f 100755 --- a/dev-scripts/directory-structure-maker/docker-image-builder.sh +++ b/dev-scripts/directory-structure-maker/docker-image-builder.sh @@ -91,6 +91,9 @@ echo "Building Router image" mkdir -p router/maven/security/truststore/ cp -r ROUTER/\$HOME/* router/maven cp ROUTER/LICENSE.txt router/maven +if [ -f ROUTER/NOTICE.txt ]; then + cp ROUTER/NOTICE.txt router/maven +fi cp ROUTER/etc/envoy/envoy.yaml router/maven/envoy.yaml docker build -f ROUTER/Dockerfile -t "${docker_repo}/choreo-connect-router:${docker_tag}" router diff --git a/envoy-filters/mgw-source/filters/http/mgw-wasm-websocket/.bazelversion b/envoy-filters/mgw-source/filters/http/mgw-wasm-websocket/.bazelversion similarity index 100% rename from envoy-filters/mgw-source/filters/http/mgw-wasm-websocket/.bazelversion rename to envoy-filters/mgw-source/filters/http/mgw-wasm-websocket/.bazelversion diff --git a/resources/license/LICENSE-ROUTER.txt b/resources/license/LICENSE-ROUTER.txt index cac794f3cb..89d0a89382 100644 --- a/resources/license/LICENSE-ROUTER.txt +++ b/resources/license/LICENSE-ROUTER.txt @@ -14,6 +14,7 @@ below is and where the actual text of the license can be found. Dependency Version License ------------------------------------------------------------------------------------------------------------- +https://github.com/envoyproxy/envoy v1.24.1 apache2 https://github.com/proxy-wasm/proxy-wasm-cpp-sdk c32d380ca6c9b1afac38a3841be99c37af2698bf apache2 The license types used by the above libraries and their information is given below: diff --git a/resources/license/NOTICE-ROUTER.txt b/resources/license/NOTICE-ROUTER.txt new file mode 100644 index 0000000000..a6fa949131 --- /dev/null +++ b/resources/license/NOTICE-ROUTER.txt @@ -0,0 +1,4 @@ +Envoy +Copyright The Envoy Project Authors + +Licensed under Apache License 2.0. See LICENSE for terms. diff --git a/router/src/main/assembly/assembly.xml b/router/src/main/assembly/assembly.xml index ae213d1e14..a98a87abcc 100644 --- a/router/src/main/assembly/assembly.xml +++ b/router/src/main/assembly/assembly.xml @@ -47,6 +47,11 @@ LICENSE.txt + + ../resources/license/NOTICE-ROUTER.txt + + NOTICE.txt + src/main/resources/envoy.yaml.template diff --git a/router/src/main/resources/Dockerfile b/router/src/main/resources/Dockerfile index ef7fcf3837..6d258fde26 100644 --- a/router/src/main/resources/Dockerfile +++ b/router/src/main/resources/Dockerfile @@ -13,11 +13,15 @@ # See the License for the specific language governing permissions and # limitations under the License. # ----------------------------------------------------------------------- -FROM envoyproxy/envoy:v1.24.1 +FROM envoyproxy/envoy:v1.24.1 AS envoy-binary + +FROM ubuntu:22.04 LABEL maintainer="WSO2 Docker Maintainers " RUN apt-get update && apt-get upgrade -y \ - && apt-get install --no-install-recommends --no-install-suggests -y gettext-base + && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates gettext-base \ + && apt-get autoremove -y && apt-get clean \ + && rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* ENV LANG=C.UTF-8 @@ -34,8 +38,8 @@ ARG MOTD="\n\ which is under the Apache License, Version 2.0. \n\ Read more about Apache License, Version 2.0 here @ http://www.apache.org/licenses/LICENSE-2.0.\n" -RUN \ - groupadd --system -g ${MG_USER_GROUP_ID} ${MG_USER_GROUP} \ +RUN mkdir -p /etc/envoy \ + && groupadd --system -g ${MG_USER_GROUP_ID} ${MG_USER_GROUP} \ && useradd --system --create-home --home-dir ${MG_USER_HOME} --no-log-init -g ${MG_USER_GROUP_ID} -u ${MG_USER_ID} ${MG_USER} \ && chown -R ${MG_USER}:${MG_USER_GROUP} ${MG_USER_HOME} \ && echo '[ ! -z "${TERM}" -a -r /etc/motd ] && cat /etc/motd' >> /etc/bash.bashrc; echo "${MOTD}" > /etc/motd @@ -66,7 +70,9 @@ USER ${MG_USER} ENV ENVOY_UID=0 ENV ENVOY_GID=0 +COPY --from=envoy-binary /usr/local/bin/envoy /usr/local/bin/envoy COPY maven/LICENSE.txt . +COPY maven/NOTICE.txt . COPY maven/wasm /home/wso2/wasm COPY maven/interceptor /home/wso2/interceptor COPY maven/envoy.yaml /etc/envoy/envoy.yaml diff --git a/test.sh b/test.sh new file mode 100755 index 0000000000..8220791639 --- /dev/null +++ b/test.sh @@ -0,0 +1,248 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$SCRIPT_DIR" +TMP_DIR="$(mktemp -d)" +COMPOSE_FILE="$TMP_DIR/docker-compose.smoke.yaml" +API_PROJECT_DIR="$TMP_DIR/petstore" +MOUNTED_APIS_DIR="$TMP_DIR/mounted-apis" +PROJECT_VERSION="$(grep -m1 '' "$REPO_ROOT/pom.xml" | sed -E 's/.*([^<]+)<\/version>.*/\1/')" +COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:-ccsmoke$$}" +MVN_BIN="${MVN_BIN:-mvn}" +SKIP_BUILD="${SKIP_BUILD:-0}" +KEEP_RUNNING="${KEEP_RUNNING:-0}" +FAILURE=1 + +if docker compose version >/dev/null 2>&1; then + DOCKER_COMPOSE=(docker compose) +elif command -v docker-compose >/dev/null 2>&1; then + DOCKER_COMPOSE=(docker-compose) +else + echo "error: docker compose is required" >&2 + exit 1 +fi + +require_command() { + if ! command -v "$1" >/dev/null 2>&1; then + echo "error: required command not found: $1" >&2 + exit 1 + fi +} + +run_compose() { + "${DOCKER_COMPOSE[@]}" -p "$COMPOSE_PROJECT_NAME" -f "$COMPOSE_FILE" "$@" +} + +wait_for_http_code() { + local url="$1" + local expected="$2" + local max_attempts="${3:-60}" + local extra_args=("${@:4}") + local attempt code + + for ((attempt = 1; attempt <= max_attempts; attempt++)); do + code="$(curl -ksS -o /dev/null -w '%{http_code}' "${extra_args[@]}" "$url" || true)" + if [[ "$code" == "$expected" ]]; then + return 0 + fi + sleep 2 + done + + echo "error: timed out waiting for $url to return HTTP $expected" >&2 + return 1 +} + +wait_for_nonzero_http_code() { + local url="$1" + local max_attempts="${2:-60}" + local attempt code + + for ((attempt = 1; attempt <= max_attempts; attempt++)); do + code="$(curl -ksS -o /dev/null -w '%{http_code}' "$url" || true)" + if [[ "$code" != "000" ]]; then + return 0 + fi + sleep 2 + done + + echo "error: timed out waiting for $url to accept HTTP connections" >&2 + return 1 +} + +cleanup() { + set +e + + if [[ "$FAILURE" -ne 0 ]]; then + echo + echo "Smoke test failed. Recent container status:" + run_compose ps || true + echo + echo "Recent logs:" + run_compose logs --tail=100 || true + fi + + if [[ "$KEEP_RUNNING" != "1" ]]; then + run_compose down -v --remove-orphans >/dev/null 2>&1 || true + fi + + rm -rf "$TMP_DIR" +} + +trap cleanup EXIT + +require_command docker +require_command curl +require_command grep +require_command sed +require_command "$MVN_BIN" + +docker info >/dev/null + +mkdir -p "$MOUNTED_APIS_DIR" +cp -R "$REPO_ROOT/integration/test-integration/src/test/resources/git-artifacts/directory/petstore" "$API_PROJECT_DIR" +cp -R "$API_PROJECT_DIR" "$MOUNTED_APIS_DIR/" + +cat > "$COMPOSE_FILE" < Building router, adapter, enforcer, and mock backend images" + "$MVN_BIN" -PRelease -pl router,adapter,enforcer-parent,integration/mock-backend-server -am clean package -DskipTests +fi + +echo +echo "==> Starting Choreo Connect and local mock backend" +run_compose up -d + +echo +echo "==> Waiting for local services" +wait_for_http_code "https://localhost:9095/health" "200" 90 +wait_for_http_code "https://localhost:9095/ready" "200" 90 +wait_for_nonzero_http_code "https://localhost:9843/" 90 +wait_for_http_code "http://localhost:2383/v2/pet/findByStatus?status=available" "200" 60 + +echo +echo "==> Requesting test key" +TOKEN="$(curl -fksS -X POST "https://localhost:9095/testkey" -d "scope=read:pets" -H "Authorization: Basic YWRtaW46YWRtaW4=")" +TOKEN="$(printf '%s' "$TOKEN" | tr -d '\r\n')" +if [[ -z "$TOKEN" ]]; then + echo "error: empty token received from /testkey" >&2 + exit 1 +fi + +echo +echo "==> Waiting for mounted API to be available" +wait_for_http_code "https://localhost:9095/v2/pet/findByStatus?status=available" "200" 90 -H "Authorization: Bearer $TOKEN" -H "accept: application/json" + +echo +echo "==> Verifying unauthorized invoke is rejected" +UNAUTHORIZED_CODE="$(curl -ksS -o /dev/null -w '%{http_code}' "https://localhost:9095/v2/pet/findByStatus?status=available")" +if [[ "$UNAUTHORIZED_CODE" == "200" ]]; then + echo "error: unauthorized invoke unexpectedly succeeded" >&2 + exit 1 +fi +echo "Unauthorized invoke returned HTTP $UNAUTHORIZED_CODE" + +echo +echo "==> Invoking mounted API" +API_RESPONSE="$(curl -fksS "https://localhost:9095/v2/pet/findByStatus?status=available" -H "Authorization: Bearer $TOKEN" -H "accept: application/json")" +echo "$API_RESPONSE" + +if ! grep -q 'doggieUpdated' <<<"$API_RESPONSE"; then + echo "error: API response did not contain expected mock backend payload" >&2 + exit 1 +fi + +echo +echo "==> Verifying router notice and license files exist in the built image" +docker run --rm --entrypoint sh "wso2/choreo-connect-router:${PROJECT_VERSION}" -lc 'test -f /LICENSE.txt && test -f /NOTICE.txt' + +FAILURE=0 + +echo +echo "Smoke test completed successfully." +if [[ "$KEEP_RUNNING" == "1" ]]; then + echo "Containers are still running under compose project: $COMPOSE_PROJECT_NAME" +else + echo "Containers will be cleaned up now." +fi From 3bae951884bf91739b0eb67945f5a5a1dddda664 Mon Sep 17 00:00:00 2001 From: Tharsanan1 Date: Mon, 9 Mar 2026 11:55:44 +0530 Subject: [PATCH 2/4] Run router smoke test on pull requests --- .github/workflows/router-smoke-test.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/router-smoke-test.yml b/.github/workflows/router-smoke-test.yml index 60c7ce884a..d2d878434f 100644 --- a/.github/workflows/router-smoke-test.yml +++ b/.github/workflows/router-smoke-test.yml @@ -2,6 +2,13 @@ name: Router Smoke Test on: workflow_dispatch: + pull_request: + paths: + - '.github/workflows/router-smoke-test.yml' + - 'dev-scripts/directory-structure-maker/**' + - 'resources/license/**' + - 'router/**' + - 'test.sh' permissions: contents: read From 0fa9d977bc10375305b8105b397fb1f0ea311675 Mon Sep 17 00:00:00 2001 From: Tharsanan1 Date: Mon, 9 Mar 2026 12:13:48 +0530 Subject: [PATCH 3/4] Fix adapter metrics golint comment --- adapter/pkg/metrics/metrics.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/adapter/pkg/metrics/metrics.go b/adapter/pkg/metrics/metrics.go index 182946a0da..0a1ada7230 100644 --- a/adapter/pkg/metrics/metrics.go +++ b/adapter/pkg/metrics/metrics.go @@ -172,13 +172,10 @@ func handleError(err error, message string) bool { return false } -/* StartPrometheusMetricsServer initializes and starts the metrics server to expose metrics to prometheus. - It employs goroutines for concurrent execution of serving metrics and recording them, while ensuring - sequential execution for each recordMetrics call using a synchronization channel (done). - Parameters: - - port: The port number to listen on. - - collectionInterval: The interval for recording metrics. -*/ +// StartPrometheusMetricsServer initializes and starts the metrics server to expose +// metrics to Prometheus. It uses goroutines for serving metrics and recording +// them concurrently while ensuring each recordMetrics call completes before the +// next one starts. func StartPrometheusMetricsServer(port int32, collectionInterval int32) { done := make(chan struct{}) // Channel to indicate recordMetrics routine exit From 23d0b0e0cfb9df516c40e8ce80cf1e981d645d86 Mon Sep 17 00:00:00 2001 From: Tharsanan1 Date: Mon, 9 Mar 2026 12:23:32 +0530 Subject: [PATCH 4/4] Tighten smoke test and router packaging checks --- .github/workflows/router-smoke-test.yml | 12 +++++++++++ .../docker-image-builder.sh | 3 +++ router/src/main/resources/Dockerfile | 3 ++- test.sh | 20 ++++++++++++------- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/.github/workflows/router-smoke-test.yml b/.github/workflows/router-smoke-test.yml index d2d878434f..d113c2e313 100644 --- a/.github/workflows/router-smoke-test.yml +++ b/.github/workflows/router-smoke-test.yml @@ -10,6 +10,10 @@ on: - 'router/**' - 'test.sh' +concurrency: + group: router-smoke-test-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + permissions: contents: read @@ -53,3 +57,11 @@ jobs: env: COMPOSE_PROJECT_NAME: ccsmokegha run: ./test.sh + + - name: Upload smoke test artifacts + if: failure() + uses: actions/upload-artifact@v4 + with: + name: smoke-test-logs + path: test-artifacts/** + if-no-files-found: ignore diff --git a/dev-scripts/directory-structure-maker/docker-image-builder.sh b/dev-scripts/directory-structure-maker/docker-image-builder.sh index cdd320d33f..a327127c0a 100755 --- a/dev-scripts/directory-structure-maker/docker-image-builder.sh +++ b/dev-scripts/directory-structure-maker/docker-image-builder.sh @@ -93,6 +93,9 @@ cp -r ROUTER/\$HOME/* router/maven cp ROUTER/LICENSE.txt router/maven if [ -f ROUTER/NOTICE.txt ]; then cp ROUTER/NOTICE.txt router/maven +else + echo "error: ROUTER/NOTICE.txt is missing; router docker build will fail without maven/NOTICE.txt" + exit 1 fi cp ROUTER/etc/envoy/envoy.yaml router/maven/envoy.yaml docker build -f ROUTER/Dockerfile -t "${docker_repo}/choreo-connect-router:${docker_tag}" router diff --git a/router/src/main/resources/Dockerfile b/router/src/main/resources/Dockerfile index 6d258fde26..9b5765640f 100644 --- a/router/src/main/resources/Dockerfile +++ b/router/src/main/resources/Dockerfile @@ -42,7 +42,8 @@ RUN mkdir -p /etc/envoy \ && groupadd --system -g ${MG_USER_GROUP_ID} ${MG_USER_GROUP} \ && useradd --system --create-home --home-dir ${MG_USER_HOME} --no-log-init -g ${MG_USER_GROUP_ID} -u ${MG_USER_ID} ${MG_USER} \ && chown -R ${MG_USER}:${MG_USER_GROUP} ${MG_USER_HOME} \ - && echo '[ ! -z "${TERM}" -a -r /etc/motd ] && cat /etc/motd' >> /etc/bash.bashrc; echo "${MOTD}" > /etc/motd + && echo '[ ! -z "${TERM}" -a -r /etc/motd ] && cat /etc/motd' >> /etc/bash.bashrc \ + && echo "${MOTD}" > /etc/motd ENV ROUTER_ADMIN_HOST=0.0.0.0 ENV ROUTER_ADMIN_PORT=9000 diff --git a/test.sh b/test.sh index 8220791639..5b4099d44f 100755 --- a/test.sh +++ b/test.sh @@ -8,6 +8,7 @@ TMP_DIR="$(mktemp -d)" COMPOSE_FILE="$TMP_DIR/docker-compose.smoke.yaml" API_PROJECT_DIR="$TMP_DIR/petstore" MOUNTED_APIS_DIR="$TMP_DIR/mounted-apis" +ARTIFACTS_DIR="${ARTIFACTS_DIR:-$REPO_ROOT/test-artifacts/${COMPOSE_PROJECT_NAME:-ccsmoke$$}}" PROJECT_VERSION="$(grep -m1 '' "$REPO_ROOT/pom.xml" | sed -E 's/.*([^<]+)<\/version>.*/\1/')" COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:-ccsmoke$$}" MVN_BIN="${MVN_BIN:-mvn}" @@ -75,19 +76,22 @@ cleanup() { set +e if [[ "$FAILURE" -ne 0 ]]; then + mkdir -p "$ARTIFACTS_DIR" echo echo "Smoke test failed. Recent container status:" - run_compose ps || true + run_compose ps | tee "$ARTIFACTS_DIR/compose-ps.log" || true echo echo "Recent logs:" - run_compose logs --tail=100 || true + run_compose logs --tail=100 | tee "$ARTIFACTS_DIR/compose-logs.log" || true + if [[ -f "$COMPOSE_FILE" ]]; then + cp "$COMPOSE_FILE" "$ARTIFACTS_DIR/docker-compose.smoke.yaml" + fi fi if [[ "$KEEP_RUNNING" != "1" ]]; then run_compose down -v --remove-orphans >/dev/null 2>&1 || true + rm -rf "$TMP_DIR" fi - - rm -rf "$TMP_DIR" } trap cleanup EXIT @@ -96,7 +100,9 @@ require_command docker require_command curl require_command grep require_command sed -require_command "$MVN_BIN" +if [[ "$SKIP_BUILD" != "1" ]]; then + require_command "$MVN_BIN" +fi docker info >/dev/null @@ -217,8 +223,8 @@ wait_for_http_code "https://localhost:9095/v2/pet/findByStatus?status=available" echo echo "==> Verifying unauthorized invoke is rejected" UNAUTHORIZED_CODE="$(curl -ksS -o /dev/null -w '%{http_code}' "https://localhost:9095/v2/pet/findByStatus?status=available")" -if [[ "$UNAUTHORIZED_CODE" == "200" ]]; then - echo "error: unauthorized invoke unexpectedly succeeded" >&2 +if [[ "$UNAUTHORIZED_CODE" != "401" ]]; then + echo "error: unauthorized invoke returned HTTP $UNAUTHORIZED_CODE, expected 401" >&2 exit 1 fi echo "Unauthorized invoke returned HTTP $UNAUTHORIZED_CODE"