Add daily operations report with hardened log-noise filtering

Brings the previously untracked daily-status-report.sh and
send-operations-report-mail.sh into the repo, plus a refactor of the
log-noise pipeline:

- New helper services/posture-check/lib/normalize-noise-patterns.sh
  strips comments, empty lines and trailing whitespace from
  log-noise.patterns before grep -f sees it. A stray empty line in
  the pattern file would otherwise have made grep -Eaif match every
  hit and silently wipe the log highlights.
- log-noise.patterns is now documented per-pattern (Why / Re-check).
  The Vaultwarden pattern is split: token/session noise stays as
  noise; DNS/Connect/Resolve/reqwest/hyper errors are removed from
  the noise set so real network signals stay visible.
- collect_log_highlights now reports a per-container and per-pattern
  noise breakdown (Top N) and an escalation flag when any pattern
  exceeds NOISE_ESCALATION_THRESHOLD (default 500). The flag is fed
  into derive_report_status and the management summary.
- New shell tests under services/posture-check/tests/ verify the
  normalize helper handles comments, empty lines, whitespace-only
  lines, and that unknown error lines remain in the attention set.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-23 10:41:33 +02:00
parent b7cbbe51de
commit 9e7bebbd3c
5 changed files with 2026 additions and 0 deletions
@@ -0,0 +1,105 @@
#!/usr/bin/env bash
# test-log-noise-filter.sh
#
# Verifies that the log-noise filtering pipeline used by collect_log_highlights
# behaves correctly when the pattern file contains comments, empty lines and
# trailing whitespace, and that unknown error lines remain visible in attention.
#
# Run from anywhere:
# bash services/posture-check/tests/test-log-noise-filter.sh
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
NORMALIZE="$SCRIPT_DIR/../lib/normalize-noise-patterns.sh"
if [ ! -x "$NORMALIZE" ]; then
echo "FAIL: normalize helper not executable at $NORMALIZE" >&2
exit 1
fi
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
# Pattern file with: comment, empty line, whitespace-only line, real patterns
# with leading and trailing whitespace, and a duplicate-shaped pattern.
cat > "$tmp/patterns" <<'EOF'
# this is a comment that must be dropped
monitoring-loki.*context canceled
gitea.*user/login/openid.*403 Forbidden
# another comment line that must be dropped
authelia.*Request timeout occurred.*status_code=408
EOF
# Hits file: 3 known-noise lines (one per real pattern), 2 unknown-error
# lines that must remain in attention.
cat > "$tmp/hits" <<'EOF'
[monitoring-loki] caller=scheduler context canceled
[gitea] router: /user/login/openid 403 Forbidden
[authelia] Request timeout occurred status_code=408
[postgres] FATAL: connection refused for host backup-db
[traefik] error while serving request: tls handshake timeout
EOF
# Run the same pipeline collect_log_highlights uses.
"$NORMALIZE" "$tmp/patterns" > "$tmp/patterns.norm"
grep -Eaif "$tmp/patterns.norm" "$tmp/hits" > "$tmp/known" || true
sed -E 's/[[:space:]]+$//' "$tmp/known" > "$tmp/known.n"
sed -E 's/[[:space:]]+$//' "$tmp/hits" > "$tmp/hits.n"
grep -Fvxf "$tmp/known.n" "$tmp/hits.n" > "$tmp/attention" || true
fail() {
echo "FAIL: $*" >&2
echo "--- patterns.norm ---" >&2
cat "$tmp/patterns.norm" >&2
echo "--- known ---" >&2
cat "$tmp/known" >&2
echo "--- attention ---" >&2
cat "$tmp/attention" >&2
exit 1
}
# Test 1: normalize produced exactly 3 patterns (comments + empties dropped,
# whitespace trimmed).
norm_lines="$(wc -l < "$tmp/patterns.norm" | tr -d ' ')"
[ "$norm_lines" = "3" ] || fail "T1 expected 3 normalized patterns, got $norm_lines"
# Test 2: normalize output contains no comment lines.
if grep -q '^#' "$tmp/patterns.norm"; then
fail "T2 normalized output still contains a comment line"
fi
# Test 3: empty / whitespace-only pattern lines must NOT match all hits.
# With 3 real patterns there must be exactly 3 known-noise lines (out of 5).
known_count="$(wc -l < "$tmp/known" | tr -d ' ')"
[ "$known_count" = "3" ] || fail "T3 expected 3 known-noise hits, got $known_count"
# Test 4: unknown error lines remain in attention (postgres + traefik).
att_count="$(wc -l < "$tmp/attention" | tr -d ' ')"
[ "$att_count" = "2" ] || fail "T4 expected 2 attention hits, got $att_count"
grep -q 'postgres.*FATAL' "$tmp/attention" || fail "T4 postgres line missing in attention"
grep -q 'traefik.*tls handshake' "$tmp/attention" || fail "T4 traefik line missing in attention"
# Test 5: regression guard for the worst case - a pattern file containing
# ONLY empty / comment / whitespace lines must produce an empty normalized
# output AND must not knock out all hits when used as input to grep -f.
cat > "$tmp/patterns.only_empty" <<'EOF'
# only comments and whitespace below
# nothing real
EOF
"$NORMALIZE" "$tmp/patterns.only_empty" > "$tmp/patterns.only_empty.norm"
empty_norm_lines="$(wc -l < "$tmp/patterns.only_empty.norm" | tr -d ' ')"
[ "$empty_norm_lines" = "0" ] || fail "T5 expected 0 normalized patterns from empty-only input, got $empty_norm_lines"
# When the normalized file is empty, collect_log_highlights skips grep -f
# entirely. Simulate that branch and confirm attention preserves all hits.
if [ -s "$tmp/patterns.only_empty.norm" ]; then
fail "T5 expected normalized file to be empty"
fi
echo "OK - all log-noise filter tests passed (5 assertions)"