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:
@@ -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)"
|
||||
Reference in New Issue
Block a user