From 555e1ffd5a714b9a15b790691926efe5c872981c Mon Sep 17 00:00:00 2001 From: Howard Enos Date: Fri, 10 Jul 2026 16:23:37 -0700 Subject: [PATCH] syncro: finalize deploy-agent (installer URL = per-client vaulted secret, MSI) Decoded the Syncro RMM installer URL from 4 client samples: base64(v1-{customer_id}-{A}-48753-{policy_folder_id}). 48753 = our account id (constant); customer_id + policy_folder_id are API-readable; A is an unguessable per-client security token NOT exposed anywhere in the API -> the URL is NOT constructible and must be harvested per client and vaulted. Installer is an MSI -> deploy uses msiexec /qn /norestart. deploy-agent now reads clients//syncro-agent-installer (credentials.installer_url) from the vault (cascades-tucson, grabb-durando, reliant, howard-test seeded) and pushes via GuruRMM. Findings recorded in test-findings.md. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/commands/syncro.md | 71 ++++++++++++----------- .claude/standards/syncro/test-findings.md | 24 ++++++++ 2 files changed, 62 insertions(+), 33 deletions(-) diff --git a/.claude/commands/syncro.md b/.claude/commands/syncro.md index 52270651..ee82a951 100644 --- a/.claude/commands/syncro.md +++ b/.claude/commands/syncro.md @@ -741,46 +741,51 @@ curl -s "${BASE}/rmm_alerts?per_page=50&api_key=${API_KEY}" | tr -d '\000-\037' #### Agent Deployment (`/syncro deploy-agent`) — hybrid via GuruRMM -Push the Syncro RMM agent to a machine. Syncro's API has **no** installer-download endpoint, -so this is a **hybrid**: the per-policy-folder installer (which embeds the customer enrollment -token) is obtained once from the Syncro GUI and vaulted; **GuruRMM (`/rmm`)** does the actual -push (it runs PowerShell as SYSTEM on the endpoint). `/rmm diagnose` already *detects* a -Syncro agent as a competitor-RMM check — this is the deploy half. +Push the Syncro RMM agent to a machine. Syncro's API has **no** installer-download endpoint +(verified: 0 of 116 paths), so this is a **hybrid**: the per-policy-folder installer URL is +harvested once from the Syncro GUI and **vaulted**; **GuruRMM (`/rmm`)** does the push (runs as +SYSTEM). `/rmm diagnose` already *detects* a Syncro agent — this is the deploy half. -**Prerequisites (one-time per customer):** -1. In Syncro: **Assets & RMM → Downloads** (or the target Policy Folder) → copy the - `SyncroSetup--.exe` **download URL**. It is per-policy-folder — the token - binds the installed agent to that customer + policy. Do NOT reuse one customer's URL for - another. -2. Vault it via the `vault` skill at `clients//syncro-agent-installer.sops.yaml` - (`credentials.installer_url`). Never hardcode the token URL. +**The installer URL is a per-client SECRET and is NOT constructible.** Decoded (2026-07-10): +`https://rmm.syncromsp.com/dl/msi/` where `` = base64 of +`v1-{customer_id}-{A}-48753-{policy_folder_id}`. `48753` is OUR account id (constant across all +clients); `customer_id` and `policy_folder_id` are API-readable — but **`A` is an unguessable +~1.8-billion per-client security token that appears nowhere in the API** (checked customer + +policy-folder objects). So you cannot build the URL; it must be harvested per client. Note the +link is an **MSI** (`/dl/msi/`) → silent install is `msiexec /qn`, not the `.exe --console` path. + +**Prerequisites (one-time per client):** +1. In Syncro GUI: the client's Policy Folder → **Downloads** → copy the `.../dl/msi/` URL. +2. Vault it (it embeds the secret `A`): `bash .claude/skills/vault/scripts/vault-helper.sh new + clients//syncro-agent-installer --kind generic --name "Syncro RMM Installer - " + --set installer_url= --set customer_id= --set policy_folder_id=`. Already vaulted: + `cascades-tucson`, `grabb-durando`, `reliant`, `howard-test`. **Deploy workflow:** -1. Resolve the target host in GuruRMM (`/rmm` — resolve hostname → UUID; confirm `os_type` - is `windows` and it is `is_connected`). Confirm the customer↔host mapping with the user. -2. Preview the exact install command + target, get explicit confirmation. -3. Dispatch via GuruRMM (`command_type: powershell`, SYSTEM context). The agent installs - **silently by default**; `--console` runs it non-interactively and `--allow-force-reboot` - permits the reboot Syncro triggers if it must update .NET first: +1. Read the URL: `bash .claude/scripts/vault.sh get-field clients//syncro-agent-installer + credentials.installer_url`. If the client has no entry, STOP and have the URL harvested first. +2. Resolve the target host in GuruRMM (`/rmm` — hostname → UUID; confirm `os_type` windows + + `is_connected`). Confirm the client↔host mapping with the user. +3. Preview the exact command + target; get explicit confirmation. **deploy-agent is + outward-facing (installs software, may reboot) — always confirm first.** +4. Dispatch via GuruRMM (`command_type: powershell`, SYSTEM). Download the MSI and install silent: ```powershell - $url = '' - $exe = "$env:TEMP\SyncroSetup.exe" - Invoke-WebRequest -Uri $url -OutFile $exe -UseBasicParsing - Start-Process -FilePath $exe -ArgumentList '--console','--allow-force-reboot' -Wait + $url = '' + $msi = "$env:TEMP\SyncroSetup.msi" + Invoke-WebRequest -Uri $url -OutFile $msi -UseBasicParsing + Start-Process msiexec.exe -ArgumentList '/i',"`"$msi`"",'/qn','/norestart' -Wait ``` - (Refs: Syncro deploy docs `docs.syncrosecure.com/agents-alerts-automations/deploy-an-endpoint`; - community "Command Line install".) `--allow-force-reboot` CAN reboot the endpoint — treat - deploy-agent as an outward-facing action: confirm reboot tolerance with the user first. -4. **Verify** the agent enrolled: after ~2-3 min, either re-query GuruRMM output, or confirm - the new asset appears under the customer via `GET /customer_assets?customer_id=N&query=` - and/or that "Syncro" shows in the endpoint's `installed_applications`. -5. Bot alert (RMM write → `[RMM]`/`[DEPLOY]` routes to #dev-alerts; Syncro-side note to - #bot-alerts if an asset record was created). + (`.exe` variant, if a client's link is `/dl/exe/`: `Start-Process $exe -ArgumentList + '--console','--allow-force-reboot' -Wait`.) +5. **Verify enrollment:** after ~2-3 min, confirm the new asset appears — + `GET /customer_assets?customer_id=N&query=` — and/or "Syncro" shows in the endpoint's + `installed_applications`. +6. Bot alert (RMM write → `[RMM]`/`[DEPLOY]` routes to #dev-alerts). -**[VERIFY before first production use]** Confirm `--console --allow-force-reboot` against the -current Syncro installer on one ACG-internal test machine before rolling to a customer — the -switches are stable historically but the installer is versioned. +**[VERIFY before first production use]** Confirm the `msiexec /qn /norestart` silent behavior on +RMM-TEST-MACHINE (Howard Test) before rolling to a customer. Full detail: +`.claude/standards/syncro/test-findings.md`. #### Customers diff --git a/.claude/standards/syncro/test-findings.md b/.claude/standards/syncro/test-findings.md index 2d6d8c30..4648da23 100644 --- a/.claude/standards/syncro/test-findings.md +++ b/.claude/standards/syncro/test-findings.md @@ -5,6 +5,30 @@ Verified behaviors/gotchas discovered while testing `/syncro` against the live t Each entry is a rule the skill must not re-learn. Critical ones are also folded into `syncro.md` (operating manual) and `api-reference.md` (breadth reference). +## 2026-07-10 — Phase 2 prep: RMM installer URL (structure decoded) + +**The Syncro RMM installer URL is a base64 token that partly encodes API-derivable IDs.** +A working install link is `https://rmm.syncromsp.com/dl/msi/` where `` base64-decodes +to `v1-{customer_id}-{A}-{B}-{policy_folder_id}`. For Howard Test: +`djEt...` → `v1-36118743-1819842526-48753-5092561` (customer_id 36118743, policy_folder_id +5092561 — both pulled from the API; `A=1819842526`, `B=48753` are NOT on the customer or +policy-folder objects). Host is `rmm.syncromsp.com` (Kabuto/RMM), separate from the PSA API. + +- **RESOLVED (4-client sample):** `B=48753` is CONSTANT (our Syncro account id). `A` VARIES per + client (1819842526 / 1610167344 / 1552910968 / 1520216784) and is **not** `kabuto_customer_id` + nor anywhere in the customer/policy-folder objects — an unguessable per-client security token + (prevents URL forgery from sequential customer_ids). **Therefore the URL is NOT constructible** + — it must be harvested per client and vaulted as a secret. `customer_id` + `policy_folder_id` + ARE API-readable, but `A` is the blocker. Vaulted so far: cascades-tucson, grabb-durando, + reliant, howard-test at `clients//syncro-agent-installer.sops.yaml` + (`credentials.installer_url`). `deploy-agent` reads from there. +- **Installer is an MSI** (`/dl/msi/`), so silent deploy uses `msiexec /i .msi /qn + /norestart` (NOT the `.exe --console` path). Syncro also offers a `.exe` (`--console + --allow-force-reboot`); the download link determines which. Verify the exact MSI silent + behavior on RMM-TEST-MACHINE before any customer push. +- The token embeds an enrollment secret → it is a **credential**: vault it (per client), never + commit plaintext. `policy_folder_id` comes from `GET /policy_folders?customer_id=N`. + ## 2026-07-10 — Phase 1 (PSA CRUD) **Emailing an invoice/estimate returns 200 "Email sent" even when it delivered to NOBODY.**