This is an automated email from the ASF dual-hosted git repository. jungm pushed a commit to branch ee11 in repository https://gitbox.apache.org/repos/asf/tomee-tck.git
commit beed181f4892d01d105c39aec3d3968272838787 Author: Markus Jung <[email protected]> AuthorDate: Sun Jul 19 16:28:54 2026 +0200 Add a shared free-port selector and harden the TomEE port guard select-free-port.sh echoes the preferred port when free and otherwise scans upward for the first free port not in the avoid list, with the same TCP probe as require-tomee-ports-free.sh so selection and the final assertion agree on what free means. Both scripts fail closed when neither nc nor bash is available, run the /dev/tcp fallback through an explicit bash (an inline redirect under dash silently marks every port free), and the guard accepts additional positional ports beyond http/https/shutdown. --- environment/ports/select-free-port.sh | 75 +++++++++++++++++++++++++++ environment/tomee/require-tomee-ports-free.sh | 36 ++++++++++--- 2 files changed, 104 insertions(+), 7 deletions(-) diff --git a/environment/ports/select-free-port.sh b/environment/ports/select-free-port.sh new file mode 100755 index 0000000..bece560 --- /dev/null +++ b/environment/ports/select-free-port.sh @@ -0,0 +1,75 @@ +#!/bin/sh + +# 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. + +# Selects a free TCP port for a runner to bind. Echoes the preferred port when +# it is free, otherwise scans upward for the first free port not in the avoid +# list. The probe is kept identical to +# environment/tomee/require-tomee-ports-free.sh so that selection and the final +# refuse-if-busy assertion agree on what "free" means. Only the chosen port +# reaches stdout; all diagnostics go to stderr so callers can capture it with +# a simple command substitution. +# +# select-free-port.sh <preferred-port> [port-to-avoid ...] + +set -eu + +# Resolve a TCP probe once, up front, and fail closed if none is usable. This +# script runs under dash on the CI agents, where /dev/tcp is not wired, so the +# /dev/tcp fallback must run through an explicit bash rather than inline -- an +# inline redirect under dash silently succeeds and makes every port look free. +# With neither nc nor bash available the script cannot tell a bound port from a +# free one; picking or approving an unverifiable port would let the Arquillian +# adapter attach to a foreign server already on it, so refuse instead. +NC=$(command -v nc 2>/dev/null || true) +BASH=$(command -v bash 2>/dev/null || true) +if [ -z "$NC" ] && [ -z "$BASH" ]; then + echo "no working TCP probe available (need nc, or bash with /dev/tcp); refusing to select an unverifiable port" >&2 + exit 1 +fi + +# A connect that succeeds means something already listens on the port. +port_in_use() { + port=$1 + if [ -n "$NC" ]; then + "$NC" -z localhost "$port" >/dev/null 2>&1 + else + "$BASH" -c 'exec 3<>"/dev/tcp/localhost/$1" && exec 3>&- 3<&-' _ "$port" >/dev/null 2>&1 + fi +} + +preferred=${1:?usage: select-free-port.sh <preferred-port> [port-to-avoid ...]} +shift + +# Ports this selection must not reuse (e.g. this branch's other picks). Ports +# are space-safe tokens, so a single captured copy iterates cleanly. +avoid="$*" + +attempts=0 +port=$preferred +while [ "$attempts" -lt 500 ]; do + skip=0 + for a in $avoid; do + if [ "$a" = "$port" ]; then + skip=1 + break + fi + done + + if [ "$skip" -eq 0 ] && ! port_in_use "$port"; then + if [ "$port" != "$preferred" ]; then + echo "port $preferred is busy or reserved; selected $port instead" >&2 + fi + echo "$port" + exit 0 + fi + + port=$((port + 1)) + attempts=$((attempts + 1)) +done + +echo "no free TCP port found scanning upward from $preferred" >&2 +exit 1 diff --git a/environment/tomee/require-tomee-ports-free.sh b/environment/tomee/require-tomee-ports-free.sh index 929eb9c..792732c 100755 --- a/environment/tomee/require-tomee-ports-free.sh +++ b/environment/tomee/require-tomee-ports-free.sh @@ -11,20 +11,35 @@ # green without ever exercising the TomEE under test. Mirrors # environment/database/require-derby-port-free.sh for the container ports. # -# require-tomee-ports-free.sh <http-port> [https-port] [shutdown-port] +# require-tomee-ports-free.sh <http-port> [https-port] [shutdown-port] [additional-port ...] set -eu busy=0 -# A connect that succeeds means something already listens on the port. Prefer -# nc, fall back to bash's /dev/tcp; both are present on the CI agents. +# Resolve a TCP probe once, up front, and fail closed if none is usable. This +# script runs under dash on the CI agents, where /dev/tcp is not wired, so the +# /dev/tcp fallback must run through an explicit bash rather than inline -- an +# inline redirect under dash silently succeeds and makes every port look free. +# With neither nc nor bash available the guard cannot tell a bound port from a +# free one; approving an unverifiable port would let the Arquillian adapter +# attach to a foreign server already on it, so refuse instead. Kept identical +# to environment/ports/select-free-port.sh so selection and this final +# assertion agree on what "free" means. +NC=$(command -v nc 2>/dev/null || true) +BASH=$(command -v bash 2>/dev/null || true) +if [ -z "$NC" ] && [ -z "$BASH" ]; then + echo "Refusing to start: no working TCP probe available (need nc, or bash with /dev/tcp)" >&2 + exit 1 +fi + +# A connect that succeeds means something already listens on the port. port_in_use() { port=$1 - if command -v nc >/dev/null 2>&1; then - nc -z localhost "$port" >/dev/null 2>&1 + if [ -n "$NC" ]; then + "$NC" -z localhost "$port" >/dev/null 2>&1 else - (exec 3<>"/dev/tcp/localhost/$port") 2>/dev/null && exec 3>&- 3<&- + "$BASH" -c 'exec 3<>"/dev/tcp/localhost/$1" && exec 3>&- 3<&-' _ "$port" >/dev/null 2>&1 fi } @@ -40,10 +55,17 @@ check_port() { fi } -check_port "HTTP" "${1:?usage: require-tomee-ports-free.sh <http-port> [https-port] [shutdown-port]}" +check_port "HTTP" "${1:?usage: require-tomee-ports-free.sh <http-port> [https-port] [shutdown-port] [additional-port ...]}" check_port "HTTPS" "${2:-}" check_port "shutdown" "${3:-}" +if [ "$#" -ge 4 ]; then + shift 3 + for extra in "$@"; do + check_port "additional" "$extra" + done +fi + if [ "$busy" -ne 0 ]; then exit 1 fi
