Files
itpp-infrastructure/audit/phase-one/send-final-package.py
T
root f5175f1ce0 Sync docs, audit artifacts, project notes, and VerdictTank proposal docs
- audit/phase-one + phase-two: security audit briefs, findings, credential-rotation plan, Docker-USER hardening scripts, rollback refs
- disaster-recovery/restore-test-log.md + backup-dr-audit-2026-08-10.md
- clients/ (modelortho SEO audit, ai-biz-dev competitive landscape), notes/ (tiktok strategy)
- projects/: front-desk-voice-agent, seo-visibility-checker product plan, hotnow-savannah HTML, resend-transactional-email, backup-dashboard-enhancements, code-review-graph, seo-ci-architecture
- proposals/verdicttank/: architecture v4.0, methodology, judge-pool review, consolidation reasoning, cross-check review
- docs/super-search/firecrawl-provider-strategy.md
- updates: CHANGELOG, model-chain, projects-master-readme, intelsight.io
- .gitignore: exclude nested standalone repos (seo-tool, venturebuilt)
2026-08-26 02:27:28 -04:00

148 lines
6.2 KiB
Python

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 <shonuff@germainebrown.com>"
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 = """
<h2 style="color:#1a1a2e;">ITPP Phase One Infrastructure Audit - Final Package</h2>
<hr style="border:none;border-top:2px solid #cc0000;margin:12px 0 20px 0;">
<p>Phase One read-only audit is complete across all six servers plus the Gitea
estate, DNS, and backups. <strong>Zero live changes were made.</strong> The full
report, policy and procedure document, and the skill specification are attached.</p>
<h3 style="color:#1a1a2e;">What we found (five systemic themes)</h3>
<ol>
<li><strong>No segmentation</strong> - Docker published-port rules bypass UFW,
leaving roughly 20 management consoles public, with no VLAN or Tailscale ACLs.</li>
<li><strong>Plaintext credentials</strong> in world-readable locations across the estate.</li>
<li><strong>Backups are write-only</strong> - 30 of 34 targets backed up, only 2 ever
restore-tested; LiteLLM Postgres is never backed up.</li>
<li><strong>SIEM monitors only itself</strong> - Wazuh has zero enrolled agents;
Grafana runs default admin/admin public with no MFA.</li>
<li><strong>Warm standby not data-ready</strong> - app1-bu state.db roughly 28 days stale.</li>
</ol>
<h3 style="color:#1a1a2e;">Severity</h3>
<table cellpadding="6" cellspacing="0" style="border-collapse:collapse;font-size:14px;">
<tr>
<td style="border:1px solid #ddd;background:#fdecea;color:#a30;"><strong>23 Critical</strong></td>
<td style="border:1px solid #ddd;background:#fff4e5;color:#a30;"><strong>34 High</strong></td>
<td style="border:1px solid #ddd;background:#fffbe6;"><strong>36 Medium</strong></td>
<td style="border:1px solid #ddd;"><strong>17 Low</strong></td>
</tr>
</table>
<h3 style="color:#1a1a2e;">Independent review (Indep, claude-sonnet-5)</h3>
<p>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.</p>
<h3 style="color:#1a1a2e;">Attached</h3>
<ul>
<li><strong>report.md</strong> - Final Report (severity matrix, recommendations, disagreements log)</li>
<li><strong>policy-and-procedure.md</strong> - v1.0 policy and procedure document</li>
<li><strong>skill-spec.md</strong> - itpp-policy-adherence skill specification</li>
<li><strong>indep-review.md</strong> - independent severity review</li>
</ul>
<h3 style="color:#1a1a2e;">Next step</h3>
<p>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.</p>
"""
# ---- 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}")