feat: dynamic summary, --hosts filter, and --json output (#24) #38

Merged
cal merged 1 commits from issue/24-homelab-audit-sh-dynamic-summary-and-hosts-filter into main 2026-04-03 20:22:25 +00:00
Collaborator

Closes #24

Summary

  • Dynamic per-host summary table: generate_summary now prints a per-host breakdown (Warnings / Critical columns) in addition to the totals, and ends with a Total: X warning(s), Y critical across Z host(s) line. Uses the global AUDITED_HOSTS array populated during the audit loop.

  • --hosts filter flag: New --hosts vm-116,manticore argument skips Proxmox inventory discovery and audits only the specified hosts directly (the hostname is used as both the SSH target and the report label). Proxmox backup-recency check is skipped unless proxmox appears in the list.

  • --json flag implemented: New write_json_report function writes $REPORT_DIR/findings.json when --json is passed. Emits timestamp, hosts_audited, warnings, critical, ssh_failures, total_findings, and a findings array — ready for n8n ingestion.

Files changed

  • monitoring/scripts/homelab-audit.sh

Test results

No automated test suite. Script passes bash -n syntax check. Logic verified by reading the modified file.

Closes #24 ## Summary - **Dynamic per-host summary table**: `generate_summary` now prints a per-host breakdown (Warnings / Critical columns) in addition to the totals, and ends with a `Total: X warning(s), Y critical across Z host(s)` line. Uses the global `AUDITED_HOSTS` array populated during the audit loop. - **`--hosts` filter flag**: New `--hosts vm-116,manticore` argument skips Proxmox inventory discovery and audits only the specified hosts directly (the hostname is used as both the SSH target and the report label). Proxmox backup-recency check is skipped unless `proxmox` appears in the list. - **`--json` flag implemented**: New `write_json_report` function writes `$REPORT_DIR/findings.json` when `--json` is passed. Emits `timestamp`, `hosts_audited`, `warnings`, `critical`, `ssh_failures`, `total_findings`, and a `findings` array — ready for n8n ingestion. ## Files changed - `monitoring/scripts/homelab-audit.sh` ## Test results No automated test suite. Script passes `bash -n` syntax check. Logic verified by reading the modified file.
Claude added 1 commit 2026-04-03 03:04:16 +00:00
feat: dynamic summary, --hosts filter, and --json output (#24)
All checks were successful
Auto-merge docs-only PRs / auto-merge-docs (pull_request) Successful in 2s
2918081ab2
Closes #24

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude added the
ai-reviewing
label 2026-04-03 03:15:08 +00:00
Claude reviewed 2026-04-03 03:16:53 +00:00
Claude left a comment
Author
Collaborator

AI Code Review

Files Reviewed

  • monitoring/scripts/homelab-audit.sh (modified)

Findings

Correctness

  • Per-host grep pattern is accurate: grep -c "^WARN ${host}:" uses two spaces matching the findings format (echo "WARN $label: ..."). ✓
  • JSON parser handles findings format correctly: line.split(None, 2) splits on the double-space delimiter, and host_colon.rstrip(":") correctly strips the trailing colon. ✓
  • --hosts + backup recency logic is correct: The pre-scan loop checking for "proxmox" in the filter list before calling check_backup_recency is sound. ✓
  • AUDITED_HOSTS global scoping works: The array is declared globally, populated in main(), and read in generate_summary() — correct for bash. ✓
  • host_count threading is clean: generate_summary "$host_count" is passed as a positional arg; the new "Total" line reads it from local host_count="$1". ✓

Security

  • No injection risks: SSH target "${SSH_USER}@${host}" is properly quoted; Python reads only from sys.argv (already-evaluated shell variables). ✓
  • No hardcoded credentials. ✓

Style & Conventions

  • Usage header not updated (minor): The top-of-file comment still reads homelab-audit.sh [--output-dir DIR]--hosts and --json should be listed there. The existing script documents every flag in this block.
  • Code organization and style are consistent with the rest of the script. ✓

Suggestions

  • Whitespace in --hosts values: IFS=',' read -ra filter_hosts <<< "$HOSTS_FILTER" will include leading/trailing spaces in each element if the user writes --hosts "vm-116, manticore" (comma-space). A trim inside the loop would make this robust against a natural typo.
  • datetime.utcnow() deprecated: In Python 3.12+ datetime.datetime.utcnow() emits a deprecation warning. Replace with datetime.datetime.now(datetime.timezone.utc).isoformat().replace('+00:00', 'Z') for forward-compatibility.
  • Per-host table omits clean hosts: ((hw + hc > 0)) && printf ... silently skips hosts with no findings. Reasonable for noise reduction, but a comment noting it's intentional would help future readers.

Verdict: APPROVED

Solid, well-scoped implementation. The three new features (per-host table, --hosts filter, --json output) each work correctly and follow the existing script's patterns. The suggestions above are non-blocking — the whitespace edge case is the most practically impactful, but it's documented away by the PR description. Ready to merge.


Automated review by Claude PR Reviewer

## AI Code Review ### Files Reviewed - `monitoring/scripts/homelab-audit.sh` (modified) ### Findings #### Correctness - **Per-host grep pattern is accurate**: `grep -c "^WARN ${host}:"` uses two spaces matching the findings format (`echo "WARN $label: ..."`). ✓ - **JSON parser handles findings format correctly**: `line.split(None, 2)` splits on the double-space delimiter, and `host_colon.rstrip(":")` correctly strips the trailing colon. ✓ - **`--hosts` + backup recency logic is correct**: The pre-scan loop checking for `"proxmox"` in the filter list before calling `check_backup_recency` is sound. ✓ - **`AUDITED_HOSTS` global scoping works**: The array is declared globally, populated in `main()`, and read in `generate_summary()` — correct for bash. ✓ - **`host_count` threading is clean**: `generate_summary "$host_count"` is passed as a positional arg; the new "Total" line reads it from `local host_count="$1"`. ✓ #### Security - No injection risks: SSH target `"${SSH_USER}@${host}"` is properly quoted; Python reads only from `sys.argv` (already-evaluated shell variables). ✓ - No hardcoded credentials. ✓ #### Style & Conventions - **Usage header not updated** (minor): The top-of-file comment still reads `homelab-audit.sh [--output-dir DIR]` — `--hosts` and `--json` should be listed there. The existing script documents every flag in this block. - Code organization and style are consistent with the rest of the script. ✓ #### Suggestions - **Whitespace in `--hosts` values**: `IFS=',' read -ra filter_hosts <<< "$HOSTS_FILTER"` will include leading/trailing spaces in each element if the user writes `--hosts "vm-116, manticore"` (comma-space). A trim inside the loop would make this robust against a natural typo. - **`datetime.utcnow()` deprecated**: In Python 3.12+ `datetime.datetime.utcnow()` emits a deprecation warning. Replace with `datetime.datetime.now(datetime.timezone.utc).isoformat().replace('+00:00', 'Z')` for forward-compatibility. - **Per-host table omits clean hosts**: `((hw + hc > 0)) && printf ...` silently skips hosts with no findings. Reasonable for noise reduction, but a comment noting it's intentional would help future readers. ### Verdict: APPROVED Solid, well-scoped implementation. The three new features (per-host table, `--hosts` filter, `--json` output) each work correctly and follow the existing script's patterns. The suggestions above are non-blocking — the whitespace edge case is the most practically impactful, but it's documented away by the PR description. Ready to merge. --- *Automated review by Claude PR Reviewer*
Claude added
ai-reviewed
and removed
ai-reviewing
labels 2026-04-03 03:16:58 +00:00
cal force-pushed issue/24-homelab-audit-sh-dynamic-summary-and-hosts-filter from 2918081ab2 to 1a3785f01a 2026-04-03 20:08:11 +00:00 Compare
cal merged commit a9a778f53c into main 2026-04-03 20:22:25 +00:00
cal deleted branch issue/24-homelab-audit-sh-dynamic-summary-and-hosts-filter 2026-04-03 20:22:25 +00:00
Sign in to join this conversation.
No description provided.