From 8fcf653cb02d43b4dd2a217f6ef859e93eb05536 Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 11 May 2026 14:05:02 +0200 Subject: [PATCH] ci(smoke): pin HSTS to preload-list-eligible value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the presence-only `grep -qi strict-transport-security` smoke assertion in both nightly.yml and release.yml with a value-pinning regex that requires `max-age=31536000`, `includeSubDomains`, and `preload`. A future Caddyfile edit that drops any of those three parts now fails the deploy smoke step instead of passing silently. Verified locally that the new pattern matches the preload-eligible value and rejects three degraded forms (short max-age, missing includeSubDomains, missing preload). Addresses @sara's round-2 note on PR #499 — "presence check, not value check". Co-Authored-By: Claude Opus 4.7 --- .gitea/workflows/nightly.yml | 6 +++++- .gitea/workflows/release.yml | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/nightly.yml b/.gitea/workflows/nightly.yml index fa343eb4..3353e6f7 100644 --- a/.gitea/workflows/nightly.yml +++ b/.gitea/workflows/nightly.yml @@ -107,7 +107,11 @@ jobs: RESOLVE="--resolve $HOST:443:127.0.0.1" echo "Smoke test: $URL (pinned to 127.0.0.1)" curl -fsS $RESOLVE --max-time 10 "$URL/login" -o /dev/null - curl -fsS $RESOLVE --max-time 10 -I "$URL/" | grep -qi 'strict-transport-security' + # Pin the preload-list-eligible HSTS value, not just header presence: + # a degraded `max-age=1` or a dropped `includeSubDomains; preload` must + # fail this check rather than pass it silently. + curl -fsS $RESOLVE --max-time 10 -I "$URL/" \ + | grep -Eqi 'strict-transport-security:[[:space:]]*max-age=31536000.*includeSubDomains.*preload' status=$(curl -s $RESOLVE -o /dev/null -w "%{http_code}" --max-time 10 "$URL/actuator/health") [ "$status" = "404" ] || { echo "expected 404 from /actuator/health, got $status"; exit 1; } echo "All smoke checks passed" diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index e1eeca2c..69e59dd6 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -101,7 +101,11 @@ jobs: RESOLVE="--resolve $HOST:443:127.0.0.1" echo "Smoke test: $URL (pinned to 127.0.0.1)" curl -fsS $RESOLVE --max-time 10 "$URL/login" -o /dev/null - curl -fsS $RESOLVE --max-time 10 -I "$URL/" | grep -qi 'strict-transport-security' + # Pin the preload-list-eligible HSTS value, not just header presence: + # a degraded `max-age=1` or a dropped `includeSubDomains; preload` must + # fail this check rather than pass it silently. + curl -fsS $RESOLVE --max-time 10 -I "$URL/" \ + | grep -Eqi 'strict-transport-security:[[:space:]]*max-age=31536000.*includeSubDomains.*preload' status=$(curl -s $RESOLVE -o /dev/null -w "%{http_code}" --max-time 10 "$URL/actuator/health") [ "$status" = "404" ] || { echo "expected 404 from /actuator/health, got $status"; exit 1; } echo "All smoke checks passed"