import smtplib import ssl import imaplib import importlib.util from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.application import MIMEApplication from pathlib import Path # Signature module (hyphenated filename, load via importlib) spec = importlib.util.spec_from_file_location( "sig", "/root/.hermes/references/shonuff-signature.py" ) sig = importlib.util.module_from_spec(spec) spec.loader.exec_module(sig) signature_html = sig.build_signature_block() # Credentials pw = Path("/root/.config/himalaya/shonuff.pass").read_text().strip() FROM = "Sho'Nuff Brown " FROM_ADDR = "shonuff@germainebrown.com" TO = ["g@germainebrown.com"] SUBJECT = "ITPP Phase One Infrastructure Audit - Final Package" # ---- Plain text part ---- plain = """ITPP Phase One Infrastructure Audit - Final Package Phase One read-only audit is complete across all six servers plus the Gitea estate, DNS, and backups. Zero live changes were made. What we found (five systemic themes): 1. No segmentation - Docker published-port rules bypass UFW, roughly 20 management consoles public, no VLAN or Tailscale ACLs. 2. Plaintext credentials in world-readable locations across the estate. 3. Backups are write-only - 30 of 34 targets backed up, only 2 ever restore-tested; LiteLLM Postgres never backed up. 4. SIEM monitors only itself - Wazuh has zero enrolled agents; Grafana default admin/admin public, no MFA. 5. Warm standby not data-ready - app1-bu state.db roughly 28 days stale. Severity: 23 Critical, 34 High, 36 Medium, 17 Low (consolidated). Independent review (Indep, claude-sonnet-5): re-scored every Critical/High. Confirmed D1 (watchdog IP) false positive. Refined D2 (Gitea dropped from the finding, has a passing restore test). Caught two silent downgrades now restored (single SSH key restored to Critical as C10) and one missed finding (WISP tower router zero backup). Attached: report.md, policy-and-procedure.md, skill-spec.md, indep-review.md. Next step: Phase Two remediation is ordered in Section 4 of the report. The highest-leverage first moves are bind Docker publishes to loopback, rotate plaintext credentials, and enroll Wazuh agents. No action taken in Phase One. """ # ---- HTML part ---- html = """

ITPP Phase One Infrastructure Audit - Final Package


Phase One read-only audit is complete across all six servers plus the Gitea estate, DNS, and backups. Zero live changes were made. The full report, policy and procedure document, and the skill specification are attached.

What we found (five systemic themes)

  1. No segmentation - Docker published-port rules bypass UFW, leaving roughly 20 management consoles public, with no VLAN or Tailscale ACLs.
  2. Plaintext credentials in world-readable locations across the estate.
  3. Backups are write-only - 30 of 34 targets backed up, only 2 ever restore-tested; LiteLLM Postgres is never backed up.
  4. SIEM monitors only itself - Wazuh has zero enrolled agents; Grafana runs default admin/admin public with no MFA.
  5. Warm standby not data-ready - app1-bu state.db roughly 28 days stale.

Severity

23 Critical 34 High 36 Medium 17 Low

Independent review (Indep, claude-sonnet-5)

A second pass re-scored every Critical and High finding against the raw evidence. It confirmed D1 (watchdog IP) as a false positive, refined D2 (Gitea dropped from the finding, it has a passing restore test), and caught two silent severity downgrades now corrected, plus one missed finding (WISP tower router with zero backup). Full detail is in the report, Section 8.

Attached

Next step

Phase Two remediation is ordered in Section 4 of the report. The highest-leverage first moves are to bind Docker publishes to loopback, rotate plaintext credentials, and enroll Wazuh agents. No action was taken in Phase One per the read-only mandate.

""" # ---- Assemble MIME ---- msg = MIMEMultipart("mixed") msg["From"] = FROM msg["To"] = ", ".join(TO) msg["Subject"] = SUBJECT alt = MIMEMultipart("alternative") alt.attach(MIMEText(plain, "plain", "utf-8")) alt.attach(MIMEText(html + signature_html, "html", "utf-8")) msg.attach(alt) base = Path("/root/projects/itpp-infrastructure/audit/phase-one") attachments = [ (base / "report.md", "report.md"), (base / "policy-and-procedure.md", "policy-and-procedure.md"), (base / "skill-spec.md", "skill-spec.md"), (base / "findings" / "indep-review.md", "indep-review.md"), ] for path, filename in attachments: part = MIMEApplication(path.read_bytes(), _subtype="markdown") part.add_header("Content-Disposition", "attachment", filename=filename) msg.attach(part) # ---- Send ---- ctx = ssl.create_default_context() with smtplib.SMTP("mail.germainebrown.com", 2525, timeout=30) as s: s.starttls(context=ctx) s.login(FROM_ADDR, pw) s.send_message(msg, from_addr=FROM_ADDR, to_addrs=TO) print("SMTP send OK") # ---- IMAP APPEND to Sent ---- imap = imaplib.IMAP4_SSL("mail.germainebrown.com", 993, ssl_context=ctx) imap.login(FROM_ADDR, pw) typ, data = imap.append("Sent", None, None, msg.as_bytes()) imap.logout() print(f"IMAP append: {typ} {data}")