Files
rustfs/scripts/check_security_smoke_count.sh
Zhengchao An 0e7b8ea16b test(security): wire negative-auth suites into e2e-smoke with a count-floor guard (#4815)
The header-SigV4 (sec-1), presigned-URL (sec-2), and admin-gate (sec-4) negative
auth-rejection e2e suites merged earlier but only presigned_negative was actually
selected by any CI profile; negative_sigv4_test and admin_auth_test compiled and
sat unrun. Add both to the e2e-smoke default-filter so all three attacker-facing
S3 auth-rejection suites execute on every PR. They already meet the smoke
admission criteria (RustFSTestEnvironment, random ports, parallel-safe, no
#[ignore], no feature gates), so this is a pure filterset change — the single
e2e-in-CI wiring mechanism (backlog#1149 ci-4), not a new job.

Because the filter selects by module name, a rename or deletion could silently
drop a suite out of the security gate with no CI signal. Add
scripts/check_security_smoke_count.sh (infra-12 count-floor mechanism): it lists
what the e2e-smoke profile selects and fails if the count of security
auth-rejection tests drops below the committed floor in
.config/security-smoke-floor.txt (16). Invoked from the e2e-tests job, before the
smoke run, so the nextest list compiles the binaries the run reuses.

The GHSA-3p3x FTPS/WebDAV constant-time e2e (protocols::test_protocol_core_suite)
stays out by topology: it binds fixed ports, needs the ftps,webdav features, and
is #[serial], so it cannot join the random-port default-feature smoke profile as
a filterset change (global ruling G5). Its GHSA-r5qv sibling is a unit test that
already runs in the default CI pass. docs/testing/security-regressions.md now
carries the full CI-execution map and flags the GHSA-3p3x e2e CI-lane gap as a
ci-domain follow-up.

Refs: backlog#1151 (sec-5)
2026-07-15 09:33:30 +08:00

86 lines
4.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Count-floor guard for the security negative-auth smoke subset (backlog#1151
# sec-5), built on the infra-12 mechanism (scripts/check_migration_gate_count.sh,
# backlog#1153).
#
# The e2e-smoke profile in .config/nextest.toml selects tests BY MODULE NAME.
# The three attacker-facing S3 auth-rejection suites — negative_sigv4_test
# (header SigV4, sec-1), presigned_negative_test (presigned URL, sec-2), and
# admin_auth_test (admin gate + root-credential lifecycle, sec-4) — are wired
# into that filter so they run on every PR. A rename that drops a suite out of
# the filter (or a deletion) silently thins the security gate to nothing with no
# CI signal, exactly the failure mode the migration-gate guard was built for.
#
# This script lists what the e2e-smoke profile ACTUALLY selects and counts the
# security suites among them, then fails when that number drops below the
# committed floor in .config/security-smoke-floor.txt. Because it lists via the
# profile (not a standalone name filter), it verifies real smoke MEMBERSHIP: a
# suite renamed without updating the nextest.toml filter stops being selected,
# its tests vanish from the listing, and the count falls below the floor. To
# shrink the subset intentionally, update the floor file in the same PR so the
# reduction is explicit and reviewable (adding tests never requires a bump —
# the floor is a lower bound — but bumping keeps the guard tight).
#
# NAMING CONVENTION DEPENDENCY: the security suites are matched by these
# reserved module-name prefixes:
#
# negative_sigv4_test, presigned_negative_test, admin_auth_test
#
# Renaming a suite away from all of these prefixes removes it from the count.
# Keep this regex in sync with the module names in the e2e-smoke filter.
#
# Usage:
# scripts/check_security_smoke_count.sh # count check (alias of check)
# scripts/check_security_smoke_count.sh check # count check only
set -euo pipefail
cd "$(dirname "$0")/.."
# Anchored module-name prefixes of the security negative-auth smoke subset.
# Kept deliberately in lockstep with the e2e-smoke filter in .config/nextest.toml.
SECURITY_SMOKE_REGEX='^(negative_sigv4|presigned_negative|admin_auth)_test::'
FLOOR_FILE=".config/security-smoke-floor.txt"
mode="${1:-check}"
case "$mode" in
all | check) ;;
*)
echo "usage: $0 [check]" >&2
exit 2
;;
esac
floor="$(grep -Ev '^[[:space:]]*(#|$)' "$FLOOR_FILE" | head -n1 | tr -d '[:space:]')"
if ! [[ "$floor" =~ ^[0-9]+$ ]]; then
echo "error: $FLOOR_FILE does not contain a numeric floor (got: '$floor')" >&2
exit 1
fi
# List via the e2e-smoke PROFILE so the default-filter is applied: only the
# tests the PR smoke suite would actually run appear in the output. Count the
# ones whose test name starts with a security module prefix. The structured JSON
# listing is used (not the human format) for the same reason infra-12 does: the
# human format's indentation varies across nextest versions; a JSON schema change
# makes jq fail loudly rather than silently collapsing the count to zero.
count="$(cargo nextest list --profile e2e-smoke -p e2e_test --message-format json \
| jq --arg re "$SECURITY_SMOKE_REGEX" \
'[."rust-suites"[].testcases | to_entries[] | select(.key | test($re))] | length')"
if ! [[ "$count" =~ ^[0-9]+$ ]]; then
echo "error: could not parse nextest JSON listing (got count: '$count')" >&2
exit 1
fi
if ((count < floor)); then
echo "error: e2e-smoke selects $count security auth-rejection tests, below the committed floor of $floor." >&2
echo "" >&2
echo "The security smoke subset is matched by module name (negative_sigv4_test /" >&2
echo "presigned_negative_test / admin_auth_test) in the e2e-smoke default-filter" >&2
echo "(.config/nextest.toml). A rename or removal has dropped one out of the smoke" >&2
echo "suite. Either restore the module names (and this script's regex), or — if the" >&2
echo "reduction is intentional — update $FLOOR_FILE in this PR so the" >&2
echo "security-gate change is explicit and reviewable." >&2
exit 1
fi
echo "security smoke count OK: $count selected auth-rejection tests (floor: $floor)"