From 17eeabb9a1f898cea812c4b2f8e6afdffc2b520f Mon Sep 17 00:00:00 2001 From: Cvicnaire Date: Wed, 14 Oct 2026 10:12:21 -0400 Subject: [PATCH] smoke_test.sh: --public-ports allows the ports published off loopback on purpose montilab publishes the Shiny port on SHINY_BIND=0.0.0.0 (#142), so the containment check failed on 0.0.0.0:8051 and every staging deploy ended red for an intended condition. --public-ports lists host ports allowed off 127.0.0.1; only the port is matched, so any other publish, and any other port, is still caught, and the pass line names what was allowed. Co-Authored-By: Claude Fable 5.1 --- NEWS.md | 1 + scripts/smoke_test.sh | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index a5169b3..e833eb3 100755 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,7 @@ # SigRepo_Server 1.0.0 * Documentation: https://montilab.github.io/SigRepo_Server/ * GitHub: https://github.com/montilab/SigRepo_Server/ +* `scripts/smoke_test.sh --containment` takes `--public-ports 8051,...`, the host ports published off 127.0.0.1 on purpose, and still fails on any other. montilab publishes the Shiny port on `SHINY_BIND=0.0.0.0` (#142), which made every staging deploy end red; the deploy script now passes the port from `SHINY_BIND`, and the pass line names what was allowed (#164). * The Shiny sign-in, sign-out, register, forgot-password and profile flows live in `legacy_app/modules/auth_module.R`, with their checks in `utils/auth_utils.R` and twenty-odd tests; `app_server.R` is down to the session plumbing, the two repository frames and the tab wiring. Registration and password reset now go through the API's own `register_new_user()` and `request_password_reset()`, so the Shiny form behaves like the `/users/register` and `/users/reset_password` routes: a reset never reveals whether an account exists, and an account whose admin notification fails says so instead of implying nothing happened. The sign-in handler no longer falls back to a hard-coded droplet address when `API_HOST` is unset; bootstrap logs a notice instead. One `field_value()` replaces the three identical helpers in the Signature, Collection and Browsing tabs (#161). * Five Shiny fixes. The Collections tab shows "No data available." instead of "Error: [object Object]" when the repository has no collections. The upload dialog's Private/Public choice now reaches `addSignature()` and `addCollection()`; it used to be ignored. Enter in the sign-in fields submits the form (the inline handlers referenced a variable that does not exist, so every keypress threw). Signing in no longer writes the user name and an MD5 of the password into the URL hash. The keepalive flush that stops an idle tab greying out behind a proxy runs every 20 seconds instead of every 2 and no longer prints a dot to the log each time (#159). * The Shiny app has one look, from one stylesheet. The Home tab's tokens (washed-blue page, white hairline cards, a blue accent, the system font) now style every tab, the navbar, the sign-in card, the modals, Bootstrap's controls, selectize and the DataTables chrome. The gradient hero banners on Signatures, Collections, Annotate, Compare and Browsing are replaced by the thin title bar Home uses, with each tab's primary action on it; uppercase tracked labels become sentence case; the Feedback tab is styled for the first time. `www/assets/css/sigrepo.css` replaces three stylesheets and about 600 lines of inline CSS inside the modules, and a test checks that every class the app emits has a rule there (#157). diff --git a/scripts/smoke_test.sh b/scripts/smoke_test.sh index 73c2c9a..de02cdc 100755 --- a/scripts/smoke_test.sh +++ b/scripts/smoke_test.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # API level verification of a SigRepo stack. # -# scripts/smoke_test.sh --host 127.0.0.1 --port 8020 --api-key KEY [--containment] +# scripts/smoke_test.sh --host 127.0.0.1 --port 8020 --api-key KEY [--containment] [--public-ports 8051,...] # # No R, no browser and (by default) no docker, so this runs on montilab.bu.edu, # which has no browser installed, as well as from a laptop through an SSH @@ -22,6 +22,10 @@ HOST=127.0.0.1 PORT=8020 API_KEY="" CONTAINMENT=0 +# Host ports allowed off 127.0.0.1 by --containment, comma separated. montilab +# publishes the Shiny port on SHINY_BIND=0.0.0.0 on purpose (#142), and a check +# that fails on an intended condition is one people learn to ignore. +PUBLIC_PORTS="" TIMEOUT=30 # Enrichment and compare are genuinely slow on montilab: 2 CPUs, ~3.4 GB free # against other people's workloads, and a single R worker that serialises every @@ -36,6 +40,7 @@ while [ $# -gt 0 ]; do --timeout) TIMEOUT=$2; shift 2 ;; --long-timeout) LONG_TIMEOUT=$2; shift 2 ;; --containment) CONTAINMENT=1; shift ;; + --public-ports) PUBLIC_PORTS=$2; shift 2 ;; -h|--help) sed -n '2,20p' "$0"; exit 0 ;; *) echo "unknown argument: $1" >&2; exit 2 ;; esac @@ -231,9 +236,21 @@ if [ "$CONTAINMENT" -eq 1 ]; then nonloopback=$(printf '%s\n' "$published" \ | grep -oE '[][0-9a-fA-F.:*]+:[0-9]+->' \ | grep -vE '^127\.0\.0\.1:' || true) + # --public-ports names the HOST ports that are published off loopback on + # purpose. Only the port is matched, so 0.0.0.0, a routable address and the + # IPv6 wildcard are all allowed for a listed port and still caught for any + # other. A listed port that is on loopback after all is not an error. + allowed="" + if [ -n "$PUBLIC_PORTS" ]; then + port_re=$(printf '%s' "$PUBLIC_PORTS" | tr -d ' ' | tr ',' '|') + allowed=$(printf '%s\n' "$nonloopback" | grep -E ":(${port_re})->$" || true) + nonloopback=$(printf '%s\n' "$nonloopback" | grep -vE ":(${port_re})->$" || true) + fi if [ -n "$nonloopback" ]; then fail "containment" "published off 127.0.0.1: $(printf '%s' "$nonloopback" | tr '\n' ' ')" printf '%s\n' "$published" + elif [ -n "$allowed" ]; then + pass "containment (every published port on 127.0.0.1, except by --public-ports: $(printf '%s' "$allowed" | tr '\n' ' '))" else pass "containment (every published port on 127.0.0.1)" fi