diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index a0e306ce5..53f066a66 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -23,8 +23,38 @@ permissions: packages: read jobs: + e2e-binaries: + name: E2E binaries + runs-on: ${{ inputs.runner }} + timeout-minutes: 20 + container: + image: ghcr.io/nvidia/openshell/ci:latest + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + env: + MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + with: + ref: ${{ inputs['checkout-ref'] || github.sha }} + + - name: Build gateway and CLI + run: | + cargo build -p openshell-server --bin openshell-gateway --features openshell-core/dev-settings + cargo build -p openshell-cli --bin openshell --features openshell-core/dev-settings + + - name: Upload e2e binaries + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: openshell-e2e-binaries + path: | + target/debug/openshell + target/debug/openshell-gateway + e2e: name: "E2E (${{ matrix.suite }})" + needs: e2e-binaries runs-on: ${{ inputs.runner }} timeout-minutes: 30 strategy: @@ -66,11 +96,22 @@ jobs: with: ref: ${{ inputs['checkout-ref'] || github.sha }} + - name: Download OpenShell e2e binaries + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: openshell-e2e-binaries + path: target/debug + + - name: Mark OpenShell e2e binaries executable + run: chmod +x target/debug/openshell target/debug/openshell-gateway + - name: Install OS test dependencies if: matrix.apt_packages != '' env: APT_PACKAGES: ${{ matrix.apt_packages }} - run: apt-get update && apt-get install -y ${APT_PACKAGES} && rm -rf /var/lib/apt/lists/* + run: | + # shellcheck disable=SC2086 + apt-get update && apt-get install -y ${APT_PACKAGES} && rm -rf /var/lib/apt/lists/* - name: Log in to GHCR with Docker run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin @@ -104,6 +145,8 @@ jobs: - name: Run tests env: OPENSHELL_SUPERVISOR_IMAGE: ${{ format('ghcr.io/nvidia/openshell/supervisor:{0}', inputs.image-tag) }} + OPENSHELL_E2E_PREBUILT_GATEWAY_BIN: ${{ github.workspace }}/target/debug/openshell-gateway + OPENSHELL_E2E_PREBUILT_CLI_BIN: ${{ github.workspace }}/target/debug/openshell E2E_CMD: ${{ matrix.cmd }} run: | if [ "${{ matrix.rootless }}" = "true" ]; then @@ -122,6 +165,8 @@ jobs: OPENSHELL_REGISTRY_HOST="${OPENSHELL_REGISTRY_HOST}" \ OPENSHELL_REGISTRY_USERNAME="${OPENSHELL_REGISTRY_USERNAME}" \ OPENSHELL_REGISTRY_PASSWORD="${OPENSHELL_REGISTRY_PASSWORD}" \ + OPENSHELL_E2E_PREBUILT_GATEWAY_BIN="${OPENSHELL_E2E_PREBUILT_GATEWAY_BIN}" \ + OPENSHELL_E2E_PREBUILT_CLI_BIN="${OPENSHELL_E2E_PREBUILT_CLI_BIN}" \ IMAGE_TAG="${IMAGE_TAG}" \ MISE_GITHUB_TOKEN="${MISE_GITHUB_TOKEN}" \ bash -c "${E2E_CMD}" diff --git a/e2e/rust/e2e-docker.sh b/e2e/rust/e2e-docker.sh index a020f87c8..30b0c7d91 100755 --- a/e2e/rust/e2e-docker.sh +++ b/e2e/rust/e2e-docker.sh @@ -12,7 +12,9 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" E2E_TEST="${OPENSHELL_E2E_DOCKER_TEST:-smoke}" E2E_FEATURES="${OPENSHELL_E2E_DOCKER_FEATURES:-e2e,e2e-docker}" -cargo build -p openshell-cli --features openshell-core/dev-settings +if [ -z "${OPENSHELL_E2E_PREBUILT_GATEWAY_BIN:-}" ] || [ -z "${OPENSHELL_E2E_PREBUILT_CLI_BIN:-}" ]; then + cargo build -p openshell-cli --features openshell-core/dev-settings +fi exec "${ROOT}/e2e/with-docker-gateway.sh" \ cargo test --manifest-path "${ROOT}/e2e/rust/Cargo.toml" \ diff --git a/e2e/rust/e2e-kubernetes.sh b/e2e/rust/e2e-kubernetes.sh index 0644a0618..78e2a8c11 100755 --- a/e2e/rust/e2e-kubernetes.sh +++ b/e2e/rust/e2e-kubernetes.sh @@ -21,7 +21,9 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" E2E_FEATURES="${OPENSHELL_E2E_KUBERNETES_FEATURES:-e2e,e2e-host-gateway,e2e-kubernetes}" -cargo build -p openshell-cli --features openshell-core/dev-settings +if [ -z "${OPENSHELL_E2E_PREBUILT_GATEWAY_BIN:-}" ] || [ -z "${OPENSHELL_E2E_PREBUILT_CLI_BIN:-}" ]; then + cargo build -p openshell-cli --features openshell-core/dev-settings +fi test_filter=() if [ -n "${OPENSHELL_E2E_KUBE_TEST:-}" ]; then diff --git a/e2e/rust/e2e-podman.sh b/e2e/rust/e2e-podman.sh index 5f325d0d2..10a81d9b1 100755 --- a/e2e/rust/e2e-podman.sh +++ b/e2e/rust/e2e-podman.sh @@ -12,7 +12,9 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" E2E_TEST="${OPENSHELL_E2E_PODMAN_TEST:-}" E2E_FEATURES="${OPENSHELL_E2E_PODMAN_FEATURES:-e2e-podman}" -cargo build -p openshell-cli --features openshell-core/dev-settings +if [ -z "${OPENSHELL_E2E_PREBUILT_GATEWAY_BIN:-}" ] || [ -z "${OPENSHELL_E2E_PREBUILT_CLI_BIN:-}" ]; then + cargo build -p openshell-cli --features openshell-core/dev-settings +fi TEST_ARGS=( cargo test --manifest-path "${ROOT}/e2e/rust/Cargo.toml" diff --git a/e2e/support/gateway-common.sh b/e2e/support/gateway-common.sh index 8da3d0706..aaef6c2d2 100644 --- a/e2e/support/gateway-common.sh +++ b/e2e/support/gateway-common.sh @@ -172,17 +172,47 @@ e2e_build_gateway_binaries() { local target_var=$2 local gateway_var=$3 local cli_var=$4 - local target_dir + local resolved_target_dir + local prebuilt_gateway="${OPENSHELL_E2E_PREBUILT_GATEWAY_BIN:-}" + local prebuilt_cli="${OPENSHELL_E2E_PREBUILT_CLI_BIN:-}" local jobs=() + # CI workflows can build these once and share them across e2e jobs. When + # unset, keep the local developer path unchanged and build from source here. + if [ -n "${prebuilt_gateway}" ] || [ -n "${prebuilt_cli}" ]; then + local prebuilt_cli_dir + + if [ -z "${prebuilt_gateway}" ] || [ -z "${prebuilt_cli}" ]; then + echo "ERROR: set both OPENSHELL_E2E_PREBUILT_GATEWAY_BIN and OPENSHELL_E2E_PREBUILT_CLI_BIN, or neither." >&2 + exit 2 + fi + if [ ! -x "${prebuilt_gateway}" ]; then + echo "ERROR: OPENSHELL_E2E_PREBUILT_GATEWAY_BIN is not executable: ${prebuilt_gateway}" >&2 + exit 2 + fi + if [ ! -x "${prebuilt_cli}" ]; then + echo "ERROR: OPENSHELL_E2E_PREBUILT_CLI_BIN is not executable: ${prebuilt_cli}" >&2 + exit 2 + fi + + prebuilt_cli_dir="$(cd "$(dirname "${prebuilt_cli}")" && pwd)" + resolved_target_dir="${OPENSHELL_E2E_PREBUILT_TARGET_DIR:-$(cd "${prebuilt_cli_dir}/.." && pwd)}" + printf -v "${target_var}" '%s' "${resolved_target_dir}" + printf -v "${gateway_var}" '%s' "${prebuilt_gateway}" + printf -v "${cli_var}" '%s' "${prebuilt_cli}" + echo "Using prebuilt e2e gateway binary: ${prebuilt_gateway}" + echo "Using prebuilt e2e CLI binary: ${prebuilt_cli}" + return 0 + fi + if [ -n "${CARGO_BUILD_JOBS:-}" ]; then jobs=(-j "${CARGO_BUILD_JOBS}") fi - target_dir="$(e2e_cargo_target_dir "${root}")" - printf -v "${target_var}" '%s' "${target_dir}" - printf -v "${gateway_var}" '%s' "${target_dir}/debug/openshell-gateway" - printf -v "${cli_var}" '%s' "${target_dir}/debug/openshell" + resolved_target_dir="$(e2e_cargo_target_dir "${root}")" + printf -v "${target_var}" '%s' "${resolved_target_dir}" + printf -v "${gateway_var}" '%s' "${resolved_target_dir}/debug/openshell-gateway" + printf -v "${cli_var}" '%s' "${resolved_target_dir}/debug/openshell" echo "Building openshell-gateway..." cargo build "${jobs[@]}" \ @@ -194,12 +224,12 @@ e2e_build_gateway_binaries() { -p openshell-cli --bin openshell \ --features openshell-core/dev-settings - if [ ! -x "${target_dir}/debug/openshell-gateway" ]; then - echo "ERROR: expected openshell-gateway binary at ${target_dir}/debug/openshell-gateway" >&2 + if [ ! -x "${resolved_target_dir}/debug/openshell-gateway" ]; then + echo "ERROR: expected openshell-gateway binary at ${resolved_target_dir}/debug/openshell-gateway" >&2 exit 1 fi - if [ ! -x "${target_dir}/debug/openshell" ]; then - echo "ERROR: expected openshell CLI binary at ${target_dir}/debug/openshell" >&2 + if [ ! -x "${resolved_target_dir}/debug/openshell" ]; then + echo "ERROR: expected openshell CLI binary at ${resolved_target_dir}/debug/openshell" >&2 exit 1 fi } diff --git a/tasks/test.toml b/tasks/test.toml index cf031bd6f..c9acd2253 100644 --- a/tasks/test.toml +++ b/tasks/test.toml @@ -60,14 +60,14 @@ hide = true ["e2e:rust"] description = "Run Rust CLI e2e tests against a Docker-backed gateway" run = [ - "cargo build -p openshell-cli --features openshell-core/dev-settings", + "if [ -z \"${OPENSHELL_E2E_PREBUILT_GATEWAY_BIN:-}\" ] || [ -z \"${OPENSHELL_E2E_PREBUILT_CLI_BIN:-}\" ]; then cargo build -p openshell-cli --features openshell-core/dev-settings; fi", "e2e/with-docker-gateway.sh cargo test --manifest-path e2e/rust/Cargo.toml --features e2e-docker", ] ["e2e:websocket-conformance"] description = "Run focused WebSocket conformance e2e tests against a Docker-backed gateway" run = [ - "cargo build -p openshell-cli --features openshell-core/dev-settings", + "if [ -z \"${OPENSHELL_E2E_PREBUILT_GATEWAY_BIN:-}\" ] || [ -z \"${OPENSHELL_E2E_PREBUILT_CLI_BIN:-}\" ]; then cargo build -p openshell-cli --features openshell-core/dev-settings; fi", "e2e/with-docker-gateway.sh cargo test --manifest-path e2e/rust/Cargo.toml --features e2e-docker --test websocket_conformance", ] @@ -116,7 +116,7 @@ run = "e2e/rust/e2e-docker.sh" ["e2e:mechanistic-smoke"] description = "Run mechanistic L4 smoke against a Docker-backed gateway" run = [ - "cargo build -p openshell-cli --features openshell-core/dev-settings", + "if [ -z \"${OPENSHELL_E2E_PREBUILT_GATEWAY_BIN:-}\" ] || [ -z \"${OPENSHELL_E2E_PREBUILT_CLI_BIN:-}\" ]; then cargo build -p openshell-cli --features openshell-core/dev-settings; fi", "e2e/with-docker-gateway.sh bash -lc 'target/debug/openshell settings set --global --key agent_policy_proposals_enabled --value true --yes && OPENSHELL_BIN=$PWD/target/debug/openshell bash e2e/policy-advisor/mechanistic-smoke.sh'", ]