sync: auto-sync from HOWARD-HOME at 2026-06-25 13:43:47
Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-06-25 13:43:47
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
# Datto EDR Skill Build + Full Lifecycle Test on RMM-TEST-MACHINE
|
||||
|
||||
## User
|
||||
- **User:** Howard Enos (howard)
|
||||
- **Machine:** Howard-Home
|
||||
- **Role:** tech
|
||||
|
||||
## Session Summary
|
||||
|
||||
Built a new `datto-edr` skill from scratch and ran a full create-group -> install -> scan
|
||||
lifecycle test against the live ACG Datto EDR tenant (`azcomp4587.infocyte.com`). Started by
|
||||
answering skill-inventory questions (no EDR/Autotask/Kaseya skills existed) and verifying that
|
||||
**Syncro's own RMM** (policies, asset/group moves) is GUI-only via API — saved as memory
|
||||
`reference_syncro_rmm_api_gui_only`. Then scoped Datto EDR control: research established Datto
|
||||
EDR == rebranded **Infocyte HUNT**, a per-tenant LoopBack REST API, and that **no Datto RMM
|
||||
skill is needed** (EDR API is standalone).
|
||||
|
||||
Howard provided the EDR API token; it was vaulted at `msp-tools/datto-edr.sops.yaml`,
|
||||
live-verified (215 agents, 96 boxes, 13 client orgs), and the full skill was authored and
|
||||
committed (`.claude/skills/datto-edr/`, commit `bd1e84d` on main). The skill drives the whole
|
||||
MSP fleet from one token: orgs/sites/agents/detections/sweep (all live-verified) plus gated
|
||||
scan/isolate/deploy.
|
||||
|
||||
The lifecycle test on **RMM-TEST-MACHINE** (ACG internal Howard-VM) created an EDR target group,
|
||||
minted a registration key, pushed the agent install via `/rmm`, and confirmed the agent
|
||||
registered into the group (active, default EDR real-time policy applied). The scan step exposed
|
||||
that the documented Infocyte scan endpoints are **dead** on this tenant; a research agent reading
|
||||
the live console's own JS bundle found the **definitive** working scan call. Session paused here
|
||||
to save + clear context before applying the code fix and running a detection->reporting test.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- **No Datto RMM skill** — Datto EDR has its own standalone API (Infocyte HUNT); RMM is a separate
|
||||
product/API (already vaulted at `msp-tools/datto-rmm.sops.yaml`, unrelated).
|
||||
- **Skill modeled on `bitdefender`** — same structure (SKILL.md + `<cli>.py` + `<cli>_client.py` +
|
||||
selftest + references), reads free, mutations `--confirm`, vault-keyed, live-verified. This skill
|
||||
is the prototype for GuruRMM security-connector #2 (RMM_THOUGHTS Feature 6).
|
||||
- **Policy assignment is console-only** — verified exhaustively (relation endpoints 404, policies
|
||||
are tenant-global typed `av`/`edr` templates, no policyId on org/target/agent, module ships no
|
||||
policy cmdlets). Default `av`+`edr` policies auto-apply; chose "proceed with defaults" for the test.
|
||||
- **Scan one agent via `where` filter** — the scan param is a LoopBack `where`, NOT `ids`; absent
|
||||
`where` = tenant-wide. Will rewrite the skill's scan command to this.
|
||||
- **Cancelled the accidental tenant-wide scan** immediately (was at 0%, contained).
|
||||
|
||||
## Problems Encountered
|
||||
|
||||
- **Install passed empty `--url`** — `Install-EDR -InstanceName azcomp4587` failed because the
|
||||
install script's loose `.com` regex matches "zcom" inside "azcomp4587", so it thought the cname
|
||||
was already a full URL and built an empty `$hunturl`. Fix: pass the **full URL**
|
||||
`-URL "https://azcomp4587.infocyte.com"`. Re-dispatch succeeded (exit 0).
|
||||
- **`agentKeys` POST 500 on `{targetId}`** — the key `id` is **caller-supplied** (a 10-char
|
||||
string), not auto-generated. `POST /agentKeys {"id":"tstrmm7053","targetId":"<tg>"}` works.
|
||||
- **All Infocyte scan routes 404** (`targets/{id}/scan`, `targets/scan`, `scans`) — superseded.
|
||||
- **`POST /Agents/scan` with `{ids:[...]}` or empty body = tenant-wide scan** ("Scanning 156
|
||||
hosts"). Root cause: endpoint takes a `where` filter; `ids` is silently ignored, no `where` =
|
||||
scan all. Logged to errorlog as friction.
|
||||
- **`is_connected` is null fleet-wide in GuruRMM** — first install dispatch went to the stale
|
||||
(offline) RMM-TEST-MACHINE agent row and queued `pending`. Resolve by **most-recent `last_seen`**,
|
||||
not `is_connected`. Cancelled + redispatched to the live agent.
|
||||
- **`eval "$(rmm-auth.sh)" | tail` lost env vars** — piping puts eval in a subshell; `$TOKEN`/`$RMM`
|
||||
never set in the parent. Run `eval` without a pipe.
|
||||
|
||||
## Configuration Changes
|
||||
|
||||
- **Created skill** `.claude/skills/datto-edr/` — `SKILL.md`, `scripts/edr.py`, `scripts/edr_client.py`,
|
||||
`scripts/selftest.py`, `references/api-reference.md`, `.gitignore`. Committed `bd1e84d` (main).
|
||||
**NOTE: the committed scan code still uses the DEAD `targets/{id}/scan` endpoint — must be fixed
|
||||
next session (see Pending).**
|
||||
- **Memory** `.claude/memory/reference_syncro_rmm_api_gui_only.md` + MEMORY.md index line. Committed.
|
||||
- **RMM_THOUGHTS Feature 6** (`projects/msp-tools/guru-rmm/docs/RMM_THOUGHTS.md`) — appended Datto EDR
|
||||
connector API research. Committed in guru-rmm submodule `3b3f069`, pointer bumped in main `bd1e84d`.
|
||||
- **errorlog.md** — one `--friction` entry (scan endpoints dead + tenant-wide footgun).
|
||||
|
||||
## Credentials & Secrets
|
||||
|
||||
- **Datto EDR API token** — vaulted `msp-tools/datto-edr.sops.yaml` field `credentials.api_token`.
|
||||
Value: `FpRvE6IENdctE5Mrf8CS8FpyawbY6MTQXwc9Vw9GmdqQq02TfGlvpfv5skzKhjO7`. Pushed to vault repo.
|
||||
**Auth = raw token in `Authorization` header (NO `Bearer`).** Created 2026-06-25, **expires
|
||||
~2027-06-25** (1yr). Generated in console: username menu -> Admin -> Users & Tokens -> API Tokens.
|
||||
- **EDR group registration key** `tstrmm7053` (minted this session, tied to test group `c3ba0672`).
|
||||
Not vaulted (disposable test key).
|
||||
|
||||
## Infrastructure & Servers
|
||||
|
||||
- **Datto EDR tenant:** `https://azcomp4587.infocyte.com` (API base `/api`). LoopBack REST.
|
||||
Explorer/swagger (`/explorer/*`) hangs/times out — unusable; `/api/*` is instant.
|
||||
- **Data model:** Organization (client) -> Location (site, carries `organizationId`) -> Agent
|
||||
(carries `locationId`). `Targets` = scan groups (often alias a Location id). `deviceGroups` =
|
||||
global categories ("Servers"/"Workstations"). Policies = tenant-global typed `av`/`edr`, `isDefault`.
|
||||
- **Test artifacts LIVE on the tenant (pending cleanup decision):**
|
||||
- EDR target group `[TEST] RMM-TEST-MACHINE` — targetId `c3ba0672-e6bb-4784-9a37-2f434fc6f08c`, org
|
||||
ACG `ac78844a-2d44-4c10-acc8-c9bcb6106346`.
|
||||
- Reg key `tstrmm7053`.
|
||||
- EDR agent `rmm-test-machine` — id `b98b3ba0-5f82-466f-911a-5a6b24cdbae7`, active, locationId
|
||||
`c3ba0672`, dattoAvEnabled=false, version 3.17.1.5409, Win11 22H2. deviceId/deviceShortId null.
|
||||
- **RMM-TEST-MACHINE in GuruRMM** (`http://172.16.3.30:3001`): ACG / Howard-VM / Windows. **Live
|
||||
agent id `99d6d692-99e0-4359-9f9c-f43be89f49e5`** (use most-recent last_seen; stale row is
|
||||
`7d3456f5...`).
|
||||
|
||||
## Commands & Outputs
|
||||
|
||||
- **VERIFIED single-agent scan (apply to skill next session):**
|
||||
```
|
||||
POST https://azcomp4587.infocyte.com/api/Agents/scan
|
||||
Authorization: <raw token>
|
||||
{"where":{"id":{"inq":["<agentId>"]}}, "options":{}, "taskName":"Scan - EDR"}
|
||||
```
|
||||
Source: live console JS bundle `index.DhsZtGr7.js` (`post("agents/scan",{where,options,taskName})`).
|
||||
Absent `where` => scans ALL active agents (the footgun). Also `POST organizations/scan`,
|
||||
`locations/scan`, `locations/{id}/scan` take `{where, options}`. `scanType` is client-side only.
|
||||
**AV scans are policy-driven, not callable.**
|
||||
- **Cancel a scan task:** `POST /userTasks/{id}/cancel` -> 204 (or `PATCH /userTasks/{id}` `{status:"Cancelled"}`).
|
||||
- **Create group:** `POST /Targets {"name":"...","organizationId":"..."}` -> `{id,...}`.
|
||||
- **Mint key:** `POST /agentKeys {"id":"<10char>","targetId":"<tg>"}` (id is caller-supplied).
|
||||
- **Install one-liner (push via /rmm, FULL url):**
|
||||
```
|
||||
[System.Net.ServicePointManager]::SecurityProtocol=[Enum]::ToObject([System.Net.SecurityProtocolType],3072); (new-object Net.WebClient).DownloadString("https://raw.githubusercontent.com/Infocyte/PowershellTools/master/AgentDeployment/install_huntagent.ps1") | iex; Install-EDR -URL "https://azcomp4587.infocyte.com" -RegKey tstrmm7053
|
||||
```
|
||||
Result: `Installed RTS agent to C:\Program Files\infocyte\agent\agent.exe`, exit 0.
|
||||
- **Skill CLI (working):** `bash .claude/scripts/py.sh .claude/skills/datto-edr/scripts/edr.py status|orgs|sites --org|agents --org|detections --org --days N|sweep|deploy-cmd|extensions`.
|
||||
|
||||
## Pending / Incomplete Tasks
|
||||
|
||||
**RESUME PLAN (next session, after context clear):**
|
||||
|
||||
1. **Fix the skill scan code** (currently committed with the DEAD `targets/{id}/scan`):
|
||||
- `edr_client.py`: replace `scan_target_group`/`scan_single_target` with `scan_agents(agent_ids)`
|
||||
-> `POST Agents/scan {"where":{"id":{"inq":[ids]}}, "options":{}, "taskName":"Scan - EDR"}`.
|
||||
Add a hard guard: refuse to POST without a non-empty `where`/agent list (prevents tenant-wide).
|
||||
Add `cancel_task(id)` (`POST userTasks/{id}/cancel`). Optionally add `create_group`, `mint_key`.
|
||||
- `edr.py`: change `scan` to `--agent <id>` (and/or `--agents`), keep `--confirm`; add `cancel`,
|
||||
and first-class `create-group` + `mint-key` + `deploy` subcommands. Update `_t_*` as needed.
|
||||
- Update `references/api-reference.md` + `SKILL.md`: verified scan endpoint, tenant-wide footgun,
|
||||
install full-URL gotcha, agentKeys caller-supplied id, policy console-only. Commit + push.
|
||||
2. **Detection -> reporting test:** push a **known-detectable file** to RMM-TEST-MACHINE (RMM agent
|
||||
`99d6d692`), then scan ONLY that agent (`where id inq [b98b3ba0]`) and verify a detection appears
|
||||
in `detections`/Alerts -> proves reporting. **CAVEAT:** the agent is **EDR-only (no Datto AV)**, so
|
||||
an EICAR/AV test file may NOT trigger — Datto EDR is behavioral/forensic (reputation/artifact
|
||||
scoring). Pick an EDR-detectable artifact (known-bad-hash test binary, or a tool flagged by
|
||||
reputation), or assign/enable Datto AV first. Decide the artifact at the start of next session.
|
||||
3. **Cleanup decision** on the test artifacts (group `c3ba0672`, key `tstrmm7053`, installed agent
|
||||
`b98b3ba0` on RMM-TEST-MACHINE) — keep as a live test endpoint, or tear down (agent.exe
|
||||
--uninstall via /rmm + delete group/key). Howard leaned toward keeping a test endpoint.
|
||||
|
||||
## Reference Information
|
||||
|
||||
- Skill: `.claude/skills/datto-edr/` (commit `bd1e84d`, main). Vault: `msp-tools/datto-edr.sops.yaml`.
|
||||
- Tenant: `azcomp4587.infocyte.com`. Org map e.g. Cascades `2d5ea96e...`, Dataforth `4a2664bf...`,
|
||||
ACG `ac78844a-2d44-4c10-acc8-c9bcb6106346`.
|
||||
- KaseyaDEDR/Infocyte GitHub `PowershellTools` (Apache-2.0) — install script + old API patterns;
|
||||
scan routes there are DEAD. Datto EDR help: edr.datto.com/help. RMM_THOUGHTS Feature 6 for the
|
||||
GuruRMM "EDR add-on" (webhooks Admin->Webhooks; needs Mike's go to build).
|
||||
- Research subagents (resumable): scan-endpoint finder `af59ee58a2ba28282`; EDR API research `ab14b157f92f91d49`.
|
||||
Reference in New Issue
Block a user