Skip to content

Commit 840274b

Browse files
bpamiriclaude
andauthored
ci: add Adobe 2023 smoke legs so the #3029 failure class is PR-gated (#3051)
smoke-env.yml gains a smoke-adobe job (production/testing matrix) that boots the compat-matrix adobe2023 Docker engine with config/environment.cfm sed'd to the matrix environment before container start and runs the engine-agnostic probes in tools/ci/smoke-env.sh against http://localhost:62023. Design notes: - compat-matrix.yml runs weekly/manual only, so bolting the probes there would not make a regressing PR red; the PR-gated smoke-env.yml is the honest home. Cost measured on compat-matrix run 27081098861: the adobe2023 docker compose build is ~90s and the engine serves in ~4 min, so each leg lands around 6-7 minutes of parallel runner time, behind the same paths filter as the Lucee legs (plus compose.yml and tools/docker/adobe2023/**). - No database containers: the probes never query the datasource, and the bind-mounted harness settings.cfm is sed'd from wheelstestdb_sqlserver to wheelstestdb_sqlite (driver jar ships in tools/docker/adobe2023/lib/, DB files created at the repo root behind the bind mount). - Both seds run before docker compose up so the app cold-boots straight into the matrix environment; readiness loop adapted from compat-matrix (crash-restart, 200/302/404 accepted, last-HTTP-code diagnostics). - The harness settings.cfm reloadPassword is empty, which blocks reload (ReloadPasswordSpec), so the reload-refusal probes hold. - tools/ci/smoke-env.sh is unchanged (already engine-agnostic via BASE_URL). Probe behavior on Adobe was hand-verified green for both environments in PR #3044 (transcripts in its body) against wheels-test-adobe2023:v1.0.1, including red-verification on the pre-fix tree reproducing the #3029 500s. Fixes #3047. Refs #3029. Signed-off-by: Peter Amiri <peter@alurium.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent f84bf8c commit 840274b

1 file changed

Lines changed: 181 additions & 8 deletions

File tree

.github/workflows/smoke-env.yml

Lines changed: 181 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
name: Smoke (non-dev environments)
22

3-
# Lucee-leg regression net for discussion #3023 / issues #3030, #3031, #3053
4-
# (and any future engine-agnostic non-dev request regression): boots the demo
5-
# app with config/environment.cfm forced to production and testing and asserts
3+
# Regression net for discussion #3023 / issues #3029, #3030, #3031, #3053 (and
4+
# any future non-dev request regression): boots the demo app with
5+
# config/environment.cfm forced to production and testing and asserts
66
# non-development request behavior (clean 404s, no stack traces, reload refused
77
# without the password, authorized reload answers 302) via
88
# tools/ci/smoke-env.sh.
99
#
10-
# Scope note: this job runs Lucee 7 only. The Adobe-only failure class from
11-
# issue #3029 (engine error-template leakage in non-dev environments) is NOT
12-
# gated here — the cfabort idiom itself is pinned structurally by
13-
# vendor/wheels/tests/specs/security/BareCfabortGuardSpec.cfc, and the Adobe
14-
# smoke leg is tracked in issue #3047.
10+
# Two engine families, same probes:
11+
# smoke — Lucee 7 via the setup-wheels-test-env composite (LuCLI).
12+
# smoke-adobe — Adobe 2023 via the compat-matrix Docker engine
13+
# (compose service adobe2023, tools/docker/adobe2023/).
14+
# This is the executed gate for the Adobe-only failure class
15+
# from issue #3029 (engine error-template leakage in non-dev
16+
# environments — issue #3047); the bare-cfabort idiom itself
17+
# is additionally pinned structurally by
18+
# vendor/wheels/tests/specs/security/BareCfabortGuardSpec.cfc.
1519

1620
on:
1721
pull_request:
@@ -26,6 +30,8 @@ on:
2630
- '.github/workflows/smoke-env.yml'
2731
- 'tools/ci/lucee.ci.json'
2832
- '.github/actions/setup-wheels-test-env/**'
33+
- 'compose.yml'
34+
- 'tools/docker/adobe2023/**'
2935

3036
permissions:
3137
contents: read
@@ -79,3 +85,170 @@ jobs:
7985
if [ -f /tmp/lucli-server.pid ]; then
8086
kill $(cat /tmp/lucli-server.pid) 2>/dev/null || true
8187
fi
88+
89+
# Adobe leg (issue #3047): the #3029 failure class (bare `cfabort;` → Adobe
90+
# error template + HTTP 500 on `/` and `/wheels/info` in non-dev
91+
# environments) only manifests on Adobe engines — the Lucee job above stays
92+
# green on the pre-fix tree. Boots the same adobe2023 Docker engine the
93+
# weekly compat-matrix builds (engine images are not registry-pullable, but
94+
# the `docker compose build` is ~90s in CI and the engine is serving in
95+
# ~4 min — measured on compat-matrix run 27081098861). No database
96+
# containers: the probes never touch the datasource, and the harness
97+
# datasource is pointed at SQLite (driver jar ships in
98+
# tools/docker/adobe2023/lib/) so nothing depends on an absent DB server.
99+
smoke-adobe:
100+
name: "Smoke: ${{ matrix.wheels_env }} (Adobe 2023)"
101+
runs-on: ubuntu-latest
102+
timeout-minutes: 25
103+
strategy:
104+
fail-fast: false
105+
matrix:
106+
wheels_env: [production, testing]
107+
env:
108+
WHEELS_CI: "true"
109+
steps:
110+
- uses: actions/checkout@v5
111+
112+
# Must run before `docker compose up`: config/environment.cfm reaches the
113+
# container through the ./:/wheels-test-suite bind mount and is read once
114+
# at application start, so the app cold-boots directly into the matrix
115+
# environment. (Same step as the Lucee job above.)
116+
- name: Force ${{ matrix.wheels_env }} environment
117+
run: |
118+
sed -i 's/set(environment = "[a-z]*")/set(environment = "${{ matrix.wheels_env }}")/' config/environment.cfm
119+
grep -qF 'set(environment = "${{ matrix.wheels_env }}")' config/environment.cfm || {
120+
echo "::error::environment.cfm substitution failed — pattern drift?"; exit 1; }
121+
grep -n 'set(environment' config/environment.cfm
122+
123+
# The adobe2023 CFConfig's wheelstestdb_sqlite datasource points at
124+
# /wheels-test-suite/wheelstestdb.db — i.e. these files at the repo root
125+
# via the bind mount. Same recipe as setup-wheels-test-env.
126+
- name: Create SQLite test databases
127+
run: |
128+
sudo apt-get update -y && sudo apt-get install -y --no-install-recommends sqlite3
129+
sqlite3 wheelstestdb.db "SELECT 1;"
130+
sqlite3 wheelstestdb_tenant_b.db "SELECT 1;"
131+
132+
# compose.yml bind-mounts tools/docker/adobe2023/settings.cfm over
133+
# config/settings.cfm, and that harness file defaults the app datasource
134+
# to wheelstestdb_sqlserver — a container this job does not start. The
135+
# probes never query the database, but the app's default datasource
136+
# should exist and be reachable so no lazily-triggered DB touch can 500
137+
# a probe. Must run before `docker compose up` (sed -i replaces the
138+
# inode that the bind mount captures at container start).
139+
- name: Point the Adobe harness datasource at SQLite
140+
run: |
141+
sed -i 's/wheelstestdb_sqlserver/wheelstestdb_sqlite/' tools/docker/adobe2023/settings.cfm
142+
# The harness settings ship an EMPTY reloadPassword, which leaves
143+
# ?reload=true open to anonymous restarts — probe 4 would see a 302.
144+
# Stage a real password so probes 4/5 (refusal) and 6 (authorized
145+
# reload answers 302 — the #3053 Adobe regression path) all engage.
146+
sed -i 's/set(reloadPassword="")/set(reloadPassword="wheels-dev")/' tools/docker/adobe2023/settings.cfm
147+
grep -qF 'set(reloadPassword="wheels-dev")' tools/docker/adobe2023/settings.cfm || {
148+
echo "::error::settings.cfm reloadPassword substitution failed — pattern drift?"; exit 1; }
149+
grep -qF 'set(dataSourceName="wheelstestdb_sqlite")' tools/docker/adobe2023/settings.cfm || {
150+
echo "::error::settings.cfm datasource substitution failed — pattern drift?"; exit 1; }
151+
grep -in 'datasourcename' tools/docker/adobe2023/settings.cfm
152+
153+
# Build + boot mirrors compat-matrix.yml's "Start CF engine" step
154+
# (retry absorbs transient external download failures; the build is
155+
# idempotent, only `up -d` runs after success). No --no-cache: hosted
156+
# runners start with an empty build cache anyway.
157+
- name: Build and start Adobe 2023
158+
run: |
159+
set -e
160+
MAX_ATTEMPTS=3
161+
ATTEMPT=1
162+
until docker compose build adobe2023; do
163+
if [ $ATTEMPT -ge $MAX_ATTEMPTS ]; then
164+
echo "::error::docker compose build failed after ${MAX_ATTEMPTS} attempts"
165+
exit 1
166+
fi
167+
echo "::warning::Build attempt ${ATTEMPT} failed — sleeping 30s before retry"
168+
ATTEMPT=$((ATTEMPT + 1))
169+
sleep 30
170+
done
171+
docker compose up -d adobe2023
172+
173+
# Adapted from compat-matrix.yml's readiness loop: restart on container
174+
# crash, accept 200/302/404 (in non-dev the root route is a clean 404 —
175+
# the public welcome page is development-only), keep the last HTTP code
176+
# so timeout diagnostics distinguish "never bound" from "5xx".
177+
- name: Wait for Adobe 2023 to be ready
178+
run: |
179+
CONTAINER="wheels-adobe2023-1"
180+
PORT=62023
181+
MAX_WAIT=60
182+
WAIT_COUNT=0
183+
RESTARTS=0
184+
MAX_RESTARTS=3
185+
LAST_HTTP_CODE="000"
186+
READY=0
187+
while [ "$WAIT_COUNT" -lt "$MAX_WAIT" ]; do
188+
WAIT_COUNT=$((WAIT_COUNT + 1))
189+
190+
CONTAINER_STATUS=$(docker inspect --format='{{.State.Status}}' "$CONTAINER" 2>/dev/null || echo "missing")
191+
if [ "$CONTAINER_STATUS" = "exited" ] || [ "$CONTAINER_STATUS" = "dead" ] || [ "$CONTAINER_STATUS" = "missing" ]; then
192+
RESTARTS=$((RESTARTS + 1))
193+
if [ "$RESTARTS" -le "$MAX_RESTARTS" ]; then
194+
echo "Container $CONTAINER has status '$CONTAINER_STATUS' — restarting (attempt $RESTARTS/$MAX_RESTARTS)..."
195+
docker compose up -d adobe2023
196+
sleep 10
197+
continue
198+
else
199+
echo "::error::Container $CONTAINER failed to start after $MAX_RESTARTS restart attempts"
200+
docker logs "$CONTAINER" 2>&1 | tail -100
201+
exit 1
202+
fi
203+
fi
204+
205+
# curl -w "%{http_code}" always prints a code (000 if no response);
206+
# no `|| echo` fallback or codes concatenate to "000000".
207+
LAST_HTTP_CODE=$(curl -s -o /dev/null --connect-timeout 2 --max-time 5 -w "%{http_code}" "http://localhost:${PORT}/" 2>/dev/null || true)
208+
LAST_HTTP_CODE=${LAST_HTTP_CODE:-000}
209+
if echo "$LAST_HTTP_CODE" | grep -qE "^(200|302|404)$"; then
210+
echo "Adobe 2023 is ready (HTTP $LAST_HTTP_CODE on attempt $WAIT_COUNT)"
211+
READY=1
212+
break
213+
fi
214+
215+
if [ $((WAIT_COUNT % 10)) -eq 0 ]; then
216+
echo " attempt $WAIT_COUNT/$MAX_WAIT: container=$CONTAINER_STATUS, http=$LAST_HTTP_CODE"
217+
fi
218+
sleep 5
219+
done
220+
221+
if [ "$READY" -ne 1 ]; then
222+
echo "::error::Adobe 2023 not ready after ${MAX_WAIT} attempts (last HTTP code: $LAST_HTTP_CODE)"
223+
if [ "$LAST_HTTP_CODE" = "000" ]; then
224+
echo "::notice::No HTTP response received — engine likely never bound to port $PORT."
225+
else
226+
echo "::notice::HTTP $LAST_HTTP_CODE received — engine bound but the app is returning errors."
227+
echo "=== Final response body (first 500 bytes) ==="
228+
curl -s --max-time 5 "http://localhost:${PORT}/" 2>/dev/null | head -c 500 || true
229+
echo
230+
echo "=== /end response body ==="
231+
fi
232+
echo "=== Container logs (last 200 lines) ==="
233+
docker logs "$CONTAINER" 2>&1 | tail -200
234+
echo "=== /end logs ==="
235+
exit 1
236+
fi
237+
238+
# Warm-up: make sure Wheels onApplicationStart has fully completed
239+
# before probing (compat-matrix does the same before its test runs).
240+
curl -s -o /dev/null --max-time 60 "http://localhost:${PORT}/" || true
241+
sleep 2
242+
243+
- name: Run smoke probes
244+
run: |
245+
BASE_URL="http://localhost:62023" SMOKE_ENV="${{ matrix.wheels_env }}" \
246+
SMOKE_RELOAD_PASSWORD="wheels-dev" bash tools/ci/smoke-env.sh
247+
248+
- name: Debug container logs
249+
if: failure()
250+
run: docker logs wheels-adobe2023-1 2>&1 | tail -200 || true
251+
252+
- name: Stop container
253+
if: always()
254+
run: docker compose stop adobe2023 2>/dev/null || true

0 commit comments

Comments
 (0)