Files
claudetools/.claude/skills/datto-edr/scripts/selftest.py
Howard Enos bd1e84d32c skills: add datto-edr (Datto EDR / Infocyte HUNT) + syncro-rmm memory
New /datto-edr skill — standalone CLI for the Datto EDR REST API (azcomp4587,
rebranded Infocyte HUNT, raw-token LoopBack). Live-verified reads across the whole
MSP fleet: orgs/sites/agents/detections/sweep + deploy-cmd. Scan/isolate gated
behind --confirm (shape-verified, not run against prod). Token vaulted at
msp-tools/datto-edr.sops.yaml.

Also: reference_syncro_rmm_api_gui_only memory (Syncro RMM policy mgmt is
GUI-only) and the guru-rmm submodule pointer bump (Feature 6 EDR research).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 12:39:58 -07:00

52 lines
1.7 KiB
Python

#!/usr/bin/env python3
"""Self-test for the datto-edr skill. Read-only; never mutates the tenant.
Confirms: token loads from vault, transport works, and the core read endpoints
return live data. Exits non-zero on any failure. Set EDR_SUPPRESS_ERRORLOG=1 so
expected probe errors don't spam errorlog.md.
"""
from __future__ import annotations
import os
import sys
os.environ.setdefault("EDR_SUPPRESS_ERRORLOG", "1")
from edr_client import DattoEDRClient, DattoEDRError
def main() -> int:
checks: list[tuple[str, bool, str]] = []
try:
client = DattoEDRClient()
_ = client.api_token
checks.append(("vault token load", True, ""))
except DattoEDRError as exc:
print(f"[FAIL] token load: {exc}", file=sys.stderr)
return 1
def check(name, fn):
try:
val = fn()
checks.append((name, True, str(val)))
except Exception as exc: # noqa: BLE001 - selftest summarizes failures
checks.append((name, False, str(exc)))
check("status rollup", lambda: client.get_status()["agents"])
check("list organizations", lambda: f"{len(client.list_organizations())} orgs")
check("list locations", lambda: f"{len(client.list_locations())} sites")
check("list targets", lambda: f"{len(client.list_targets())} scan groups")
check("list agents (limit 5)", lambda: f"{len(client.list_agents(limit=5))} agents")
check("list alerts (limit 5)", lambda: f"{len(client.list_alerts(limit=5))} alerts")
ok = True
for name, passed, detail in checks:
marker = "[OK]" if passed else "[FAIL]"
print(f"{marker} {name}{(' -> ' + detail) if detail else ''}")
ok = ok and passed
return 0 if ok else 1
if __name__ == "__main__":
raise SystemExit(main())