eleven / messenger Public

deploy: hardening collector enumerates mesh peers from the -stats prefix its credential can actually list (#1176)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell d877c801e69a4d62cbefb3e1890a563bef11943b parent 9e6afb3
1 file changed, +12 −2
  • deploy/hardening-posture.sh +12 −2
diff --git a/deploy/hardening-posture.sh b/deploy/hardening-posture.sh
index 5cbd2c8..6be88ea 100755
--- a/deploy/hardening-posture.sh
+++ b/deploy/hardening-posture.sh
@@ -279,7 +279,7 @@ enumerate_members() {
prefix=$(env_str "$ROUTER_ENV" LCHAT_HIBERNATE_PREFIX)
[ -n "$bucket" ] && [ -n "$prefix" ] || return # mesh off -> no peers, just self
region=$(env_str "$ROUTER_ENV" LCHAT_HIBERNATE_REGION); region=${region:-eu-west-1}
- # Must match hc.meshPrefix() (activator.go): membership at
+ # Layout per hc.meshPrefix() (activator.go): membership at
# "<prefix>/mesh/members/<peer>", stats at "<prefix>/mesh/members-stats/<peer>".
mesh_prefix="${prefix}/mesh/members"
@@ -287,8 +287,18 @@ enumerate_members() {
# crashes on this fleet's aws-cli/Python combination (a botocore/argparse
# regression), same reason status-publish.sh gives. `s3 ls` prints
# "YYYY-MM-DD HH:MM:SS SIZE KEY"; the key is the b64url leaf.
+ #
+ # Members are enumerated from the "-stats/" SIBLING prefix, not members/
+ # itself: the status-publisher credential is deliberately scoped to
+ # "*-stats/*" in the hibernation bucket (infra/prod/status.tf) so it can
+ # never touch instance replicas, and a members/ listing comes back
+ # AccessDenied — silently empty here, which published a peer-less page on
+ # the collector's first real run (2026-07-19). Both prefixes carry the same
+ # b64url(peerURL) leaf at the same heartbeat cadence, so the stats listing
+ # is the same membership signal — read exactly as status-publish.sh's
+ # mesh_peer_boxes reads it.
local listing cutoff line date_part time_part key peer statsfile label reg
- listing=$(aws s3 ls "s3://$bucket/${mesh_prefix}/" --region "$region" 2>/dev/null) || true
+ listing=$(aws s3 ls "s3://$bucket/${mesh_prefix}-stats/" --region "$region" 2>/dev/null) || true
[ -n "$listing" ] || return
cutoff=$(date -u -d "-${STALE_SECONDS} seconds" '+%Y-%m-%d %H:%M:%S')