Skip to content

Commit 9f8d7d2

Browse files
committed
Add markdown output mode to domain-security-monitor
1 parent 5ca86df commit 9f8d7d2

1 file changed

Lines changed: 59 additions & 2 deletions

File tree

domain-security-monitor.py

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ def parse_args() -> argparse.Namespace:
280280
p.add_argument("--input-file", help="Batch file with one domain per line")
281281
p.add_argument("--expected-ns", default=str(DEFAULT_EXPECTED_NS_FILE), help="Expected nameserver policy JSON")
282282
p.add_argument("--dkim-selectors", default=str(DEFAULT_DKIM_SELECTORS_FILE), help="Per-domain DKIM selectors JSON")
283-
p.add_argument("--output", choices=["json"], default="json")
283+
p.add_argument("--output", choices=["json", "markdown"], default="json")
284284
p.add_argument("--version", action="version", version=f"domain-security-monitor {VERSION}")
285285
return p.parse_args()
286286

@@ -306,6 +306,59 @@ def load_domains(args: argparse.Namespace) -> list[str]:
306306
return dedup
307307

308308

309+
def render_markdown(results: list[dict[str, Any]]) -> str:
310+
lines = [
311+
"# Domain Security Monitor Report",
312+
"",
313+
f"Domains checked: **{len(results)}**",
314+
"",
315+
]
316+
317+
for item in results:
318+
domain = item.get("domain", "unknown")
319+
generated = item.get("generated_at_utc", "")
320+
signals = item.get("signals", {})
321+
322+
lines.append(f"## {domain}")
323+
lines.append("")
324+
if generated:
325+
lines.append(f"- Generated (UTC): `{generated}`")
326+
327+
# quick summary counts
328+
status_counts = {"pass": 0, "warn": 0, "fail": 0, "unknown": 0}
329+
for sig in signals.values():
330+
st = str((sig or {}).get("status", "unknown")).lower()
331+
status_counts[st] = status_counts.get(st, 0) + 1
332+
lines.append(
333+
"- Summary: "
334+
f"pass={status_counts.get('pass', 0)}, "
335+
f"warn={status_counts.get('warn', 0)}, "
336+
f"fail={status_counts.get('fail', 0)}, "
337+
f"unknown={status_counts.get('unknown', 0)}"
338+
)
339+
lines.append("")
340+
341+
lines.append("| Signal | Status | Confidence | Data source |")
342+
lines.append("|---|---|---|---|")
343+
for name, sig in signals.items():
344+
sig = sig or {}
345+
lines.append(
346+
f"| `{name}` | {sig.get('status', 'unknown')} | {sig.get('confidence', 'low')} | {sig.get('data_source', 'unknown')} |"
347+
)
348+
349+
lines.append("")
350+
lines.append("<details>")
351+
lines.append("<summary>Signal details</summary>")
352+
lines.append("")
353+
lines.append("```json")
354+
lines.append(json.dumps(signals, indent=2))
355+
lines.append("```")
356+
lines.append("</details>")
357+
lines.append("")
358+
359+
return "\n".join(lines).rstrip() + "\n"
360+
361+
309362
def main() -> int:
310363
args = parse_args()
311364
domains = load_domains(args)
@@ -317,7 +370,11 @@ def main() -> int:
317370
dkim_cfg = load_json(Path(args.dkim_selectors), {})
318371

319372
results = [analyse_domain(d, expected_cfg, dkim_cfg) for d in domains]
320-
print(json.dumps({"count": len(results), "results": results}, indent=2))
373+
374+
if args.output == "markdown":
375+
print(render_markdown(results), end="")
376+
else:
377+
print(json.dumps({"count": len(results), "results": results}, indent=2))
321378
return 0
322379

323380

0 commit comments

Comments
 (0)