ci: smoke job — all-in-one TLS sim call through real edge->FOB WS path (deploy-B §9)

Adds the smoke job to .github/workflows/ci.yml, gated on image-build.
Runs deploy/smoke/allinone_smoke.py against the freshly-built
rutster-allinone:smoke image:

* Boots the all-in-one container with RUTSTER_LOCAL_CERTS=true (Caddy
  internal CA, no ACME in CI per spec §9).
* Extracts Caddy's internal-CA root cert from /data/caddy/pki/
  authorities/local/root.crt via docker cp.
* Opens wss:// WS to /twilio/media-stream using the extracted root
  (Python stdlib ssl + socket — no pip install required, CI runner-
  image ships Python 3 + ssl).
* Sends Twilio's connected+start handshake frames (the same JSON
  sequence crates/rutster-trunk/tests/ws_ping.rs uses).
* Streams 200 PCM-zeroed frames at 20ms cadence as Twilio Media events.
* Asserts the engine replies with at least one text frame — proving
  the real edge->FOB WS path works end-to-end through TLS.

The compose smoke + reload-during-call smoke (Task 9) gate on this job.

Signed-off-by: Aaron D. Lee <himself@adlee.work>
This commit is contained in:
2026-07-06 15:34:33 -04:00
parent 219df74466
commit 142933c067

View File

@@ -265,3 +265,53 @@ jobs:
-v "$PWD/deploy/Caddyfile:/etc/caddy/Caddyfile:ro" \ -v "$PWD/deploy/Caddyfile:/etc/caddy/Caddyfile:ro" \
rutster-edge:smoke \ rutster-edge:smoke \
caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
# deploy-B §9 all-in-one smoke — boots rutster-allinone with
# RUTSTER_LOCAL_CERTS=true (Caddy internal CA, no ACME in CI), extracts
# the CA root cert from /data, opens wss:// to /twilio/media-stream,
# sends Twilio's connected+start handshake frames, streams 200 PCM-zeroed
# frames at 20ms cadence, asserts the engine replies with at least one
# text frame through the real edge->FOB WS path. Spec §9 acceptance:
# * "boots"
# * "Caddy terminates TLS via its internal CA (no ACME in CI)"
# * "full sim call through the real edge->FOB WS path"
# The reload-during-call smoke (Task 9 below) and compose smoke (Task 9)
# are separate jobs that depend on this one.
smoke:
name: smoke (all-in-one TLS sim call)
runs-on: ubuntu-latest
needs: [image-build]
steps:
- uses: actions/checkout@v4
- name: Set up Python (stdlib-only; no pip)
uses: actions/setup-python@v5
with:
python-version: "3.x"
# Pull the freshly-built image from the image-build job. Since
# jobs run on separate runners + `push: false` in image-build means
# the image isn't in any registry, the smoke job rebuilds from the
# GHA cache (warm — image-build populated it). This adds ~30s vs
# an image-download artifact, but avoids the registry-auth + image-
# save/load plumbing.
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Rebuild rutster-allinone:smoke (warm cache from image-build)
uses: docker/build-push-action@v5
with:
context: .
file: deploy/Dockerfile
target: rutster-allinone
tags: rutster-allinone:smoke
push: false
load: true
cache-from: type=gha,scope=rutster-allinone
- name: Run all-in-one smoke (deploy/smoke/allinone_smoke.py)
run: |
python3 deploy/smoke/allinone_smoke.py
env:
RUTSTER_ALLINONE_IMAGE: rutster-allinone:smoke
RUTSTER_ALLINONE_PORT: "18443"