fix(scripts/ops): #3140 ADDENDUM — PRUNE_ZONE_DOMAIN covers staging.moleculesai.app #3148
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# prune_cf_e2e_dns.sh — targeted, fail-closed cleanup of disposable E2E DNS
|
||||
# records that accumulate under the moleculesai.app zone and exhaust the
|
||||
# Cloudflare DNS record quota (code 81045).
|
||||
# records that accumulate under the moleculesai.app zone (typically the
|
||||
# staging.moleculesai.app subdomain) and exhaust the Cloudflare DNS record
|
||||
# quota (code 81045).
|
||||
#
|
||||
# Why this exists: staging E2E harnesses create DNS records for slugs like
|
||||
# e2e-smoke-<date>-<run>-<uuid> and e2e-tmpl-<rand> (see
|
||||
@@ -16,6 +17,8 @@
|
||||
# - Records whose full name matches
|
||||
# e2e-smoke-*.<zone-domain>
|
||||
# e2e-tmpl-*.<zone-domain>
|
||||
# - Multiple zone domains may be supplied as a comma-separated list
|
||||
# (e.g. "moleculesai.app,staging.moleculesai.app").
|
||||
# - Records older than --min-age-hours / PRUNE_MIN_AGE_HOURS (default 24)
|
||||
# so in-flight runs are not touched.
|
||||
# - Anything else is kept untouched.
|
||||
@@ -33,7 +36,8 @@
|
||||
# PRUNE_MIN_AGE_HOURS=<int> — default minimum age in hours (default: 24).
|
||||
# MAX_DELETE_PCT=<int> — refuse to delete more than this percentage of
|
||||
# matched ephemeral records (default: 50).
|
||||
# PRUNE_ZONE_DOMAIN=<domain> — zone domain to anchor matches (default: moleculesai.app).
|
||||
# PRUNE_ZONE_DOMAIN=<domain> — comma-separated zone domain(s) to anchor
|
||||
# matches (default: staging.moleculesai.app).
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 — dry-run completed or prune executed successfully
|
||||
@@ -45,7 +49,10 @@ set -euo pipefail
|
||||
DRY_RUN=1
|
||||
MIN_AGE_HOURS="${PRUNE_MIN_AGE_HOURS:-24}"
|
||||
MAX_DELETE_PCT="${MAX_DELETE_PCT:-50}"
|
||||
ZONE_DOMAIN="${PRUNE_ZONE_DOMAIN:-moleculesai.app}"
|
||||
ZONE_DOMAIN="${PRUNE_ZONE_DOMAIN:-}"
|
||||
if [ -z "$ZONE_DOMAIN" ]; then
|
||||
ZONE_DOMAIN="staging.moleculesai.app"
|
||||
fi
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
@@ -246,15 +253,19 @@ from datetime import datetime, timezone, timedelta
|
||||
|
||||
min_age = timedelta(hours=int(os.environ["MIN_AGE_HOURS"]))
|
||||
zone_domain = os.environ["ZONE_DOMAIN"]
|
||||
zone_domains = [d.strip() for d in zone_domain.split(",") if d.strip()]
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
# Conservative: only the two known disposable E2E prefixes, anchored to the
|
||||
# configured zone domain so similarly-named records in other zones never match.
|
||||
# Conservative: only the two known disposable E2E prefixes, anchored to one
|
||||
# of the configured zone domains so similarly-named records in other zones
|
||||
# never match. Multiple zone domains may be supplied as a comma-separated
|
||||
# list (e.g. "moleculesai.app,staging.moleculesai.app").
|
||||
# The prefix MUST be followed immediately by a hyphen and then at least one
|
||||
# suffix character, so names like e2e-smokeprod, e2e-smoketest-keep, or
|
||||
# prod-e2e-smoke-x are NEVER matched.
|
||||
zone_part = r"(?:" + r"|".join(re.escape(d) for d in zone_domains) + r")"
|
||||
EPHEMERAL_RE = re.compile(
|
||||
r"^(e2e-smoke-[a-zA-Z0-9_-]+|e2e-tmpl-[a-zA-Z0-9_-]+)\." + re.escape(zone_domain) + r"$"
|
||||
r"^(e2e-smoke-[a-zA-Z0-9_-]+|e2e-tmpl-[a-zA-Z0-9_-]+)\." + zone_part + r"$"
|
||||
)
|
||||
|
||||
def parse_iso(s):
|
||||
|
||||
@@ -17,7 +17,7 @@ PASS=0
|
||||
FAIL=0
|
||||
|
||||
run_case() {
|
||||
local name="$1" list_exit="$2" list_body="$3" expect_delete_sentinel="$4" zone_domain="${5:-moleculesai.app}"
|
||||
local name="$1" list_exit="$2" list_body="$3" expect_delete_sentinel="$4" zone_domain="${5:-}"
|
||||
local tmp
|
||||
tmp=$(mktemp -d -t cf-e2e-prune-fail-closed-XXXXXX)
|
||||
local delete_sentinel="$tmp/delete_reached"
|
||||
@@ -129,9 +129,10 @@ run_case "CF DNS list returns malformed JSON" 0 'this is not json'
|
||||
run_case "CF DNS list returns non-array result" 0 '{"success":true,"result":{"id":"rec1"}}' false-abort
|
||||
|
||||
# Helper to build a DNS list result with one record, given created_on ISO string
|
||||
# and optional zone domain (default: moleculesai.app).
|
||||
# and optional zone domain (default: staging.moleculesai.app, the observed
|
||||
# domain for leaked e2e-smoke/e2e-tmpl records).
|
||||
make_list() {
|
||||
local created_on="$1" zone_domain="${2:-moleculesai.app}"
|
||||
local created_on="$1" zone_domain="${2:-staging.moleculesai.app}"
|
||||
cat <<JSON
|
||||
{"success":true,"result":[{"id":"rec1","name":"e2e-smoke-20260622-1234-abcdef12.${zone_domain}","type":"A","created_on":"$created_on"}],"result_info":{"page":1,"total_pages":1,"per_page":100,"count":1}}
|
||||
JSON
|
||||
@@ -154,12 +155,24 @@ run_case "e2e-tmplate-keep (extra chars before hyphen) kept" 0 "$(make_list "$ol
|
||||
run_case "e2e-smoke (no hyphen suffix) kept" 0 "$(make_list "$old_ts" | sed 's/e2e-smoke-20260622-1234-abcdef12/e2e-smoke/')" false-keep
|
||||
run_case "prod-e2e-smoke-x (does not start with prefix) kept" 0 "$(make_list "$old_ts" | sed 's/e2e-smoke-20260622-1234-abcdef12/prod-e2e-smoke-x/')" false-keep
|
||||
|
||||
# Staging subdomain must match when PRUNE_ZONE_DOMAIN is set.
|
||||
run_case "old e2e-smoke staging subdomain deleted" 0 "$(make_list "$old_ts" staging.moleculesai.app)" true staging.moleculesai.app
|
||||
# Zone-domain coverage (Researcher RC 13130 correctness blocker).
|
||||
# Default PRUNE_ZONE_DOMAIN is staging.moleculesai.app, matching observed leaks.
|
||||
run_case "old e2e-smoke staging subdomain deleted (default)" 0 "$(make_list "$old_ts")" true
|
||||
|
||||
# Old e2e-smoke record must be deleted (happy path, apex domain).
|
||||
run_case "old e2e-smoke record deleted" 0 "$(make_list "$old_ts")" true
|
||||
# Apex domain is NOT matched when PRUNE_ZONE_DOMAIN is staging only.
|
||||
run_case "apex e2e-smoke kept when staging-only" 0 "$(make_list "$old_ts" moleculesai.app)" false-keep staging.moleculesai.app
|
||||
|
||||
echo
|
||||
# A record under a different subdomain is NOT matched.
|
||||
run_case "dev-subdomain e2e-smoke kept" 0 "$(make_list "$old_ts" dev.moleculesai.app)" false-keep staging.moleculesai.app
|
||||
|
||||
# Explicit apex zone domain still works when requested.
|
||||
run_case "old e2e-smoke apex domain deleted" 0 "$(make_list "$old_ts" moleculesai.app)" true moleculesai.app
|
||||
|
||||
# Comma-separated zone domains match both apex and staging.
|
||||
run_case "multi-zone matches staging record" 0 "$(make_list "$old_ts")" true "moleculesai.app,staging.moleculesai.app"
|
||||
run_case "multi-zone matches apex record" 0 "$(make_list "$old_ts" moleculesai.app)" true "moleculesai.app,staging.moleculesai.app"
|
||||
|
||||
# Near-miss under the staging zone is still kept (safety guard).
|
||||
run_case "e2e-smoketest-keep under staging kept" 0 "$(make_list "$old_ts" | sed 's/e2e-smoke-20260622-1234-abcdef12/e2e-smoketest-keep/')" false-keep
|
||||
echo "passed=$PASS failed=$FAIL"
|
||||
[ "$FAIL" -eq 0 ]
|
||||
|
||||
Reference in New Issue
Block a user