From fe91b4ecfc4e6165823d4df4c3fae08b0cca5b45 Mon Sep 17 00:00:00 2001 From: Howard Enos Date: Fri, 10 Jul 2026 17:21:55 -0700 Subject: [PATCH] sync: auto-sync from HOWARD-HOME at 2026-07-10 17:21:24 Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-07-10 17:21:24 --- ...026-07-10-howard-syncro-skill-expansion.md | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 session-logs/2026-07/2026-07-10-howard-syncro-skill-expansion.md diff --git a/session-logs/2026-07/2026-07-10-howard-syncro-skill-expansion.md b/session-logs/2026-07/2026-07-10-howard-syncro-skill-expansion.md new file mode 100644 index 00000000..973eeeb8 --- /dev/null +++ b/session-logs/2026-07/2026-07-10-howard-syncro-skill-expansion.md @@ -0,0 +1,138 @@ +## User +- **User:** Howard Enos (howard) +- **Machine:** Howard-Home +- **Role:** tech + +## Session Summary + +Expanded and end-to-end tested the `/syncro` skill from PSA-only to full Syncro API coverage, +including asset/RMM management and a working Syncro-agent deployment path. Started by auditing +the live OpenAPI 3.0 spec (`api-docs.syncromsp.com/swagger.json`) against the existing skill and +discovered the skill deliberately avoided asset writes based on a memory +(`reference-syncro-rmm-api-gui-only`) that turned out to be a token-scope symptom, not an API +limit. Pulled the complete inventory (~180 operations across 38 resource types), built a new +verified reference doc, and probed the live tenant with Howard's per-user token to map exactly +what works vs. what needs scope. + +Corrected the record: the entire asset/RMM surface (create/update, patches, +installed_applications, rmm_alerts, contacts, contracts, leads, vendors, POs, products, +payments, wiki) is API-drivable; only policy-folder operations were 401-gated by a missing +"Assets - Policy Change" token scope. Mike upgraded Howard's token to full scope mid-session; +verified the policy-folder move works via flip-and-restore on a test asset. Also checked Mike's +and Winter's keys — Winter full, Mike's vaulted token (…ebbeb3) still 401 (needs re-vault). + +Ran a full live test campaign on a new sandbox customer ("Howard Test", 36118743). Phase 1 +exercised the complete PSA + breadth write surface (tickets, comments, line items, invoices, +estimates, appointments, schedules, contracts, contacts, leads, vendors, products, purchase +orders, worksheets) and captured every response shape and gotcha. Phase 2 proved the deploy +path end-to-end: pushed the per-policy-folder Syncro MSI installer to RMM-TEST-MACHINE via +GuruRMM (`/rmm`), the box auto-enrolled as a Syncro asset in the correct client + policy folder, +then tested patches, installed_applications, policy-folder create/move/delete, and rmm_alerts on +the real device. + +Decoded the installer URL structure and confirmed it is a per-client secret (not constructible), +so harvested links are vaulted per client (4 seeded). Confirmed Syncro's public API has NO +remote device-control/exec endpoint — execution stays on GuruRMM. Finished by cleaning up the +sandbox (API-deleted the deletable records, uninstalled the Syncro agent from RMM-TEST-MACHINE) +and recording all findings in a living `test-findings.md` plus the skill's hard rules. + +## Key Decisions + +- Kept the high-frequency PSA workflows in `syncro.md` and put the full breadth in a new + `api-reference.md` rather than bloating the incident-scarred core. +- Installer-push (`deploy-agent`) lives in `/syncro` (Howard's call) but uses GuruRMM as the + execution arm — Syncro has no installer-download or exec API. +- Chose lazy harvest of installer URLs (grab+vault+wiki-pointer at first deploy) over proactive + harvesting of all ~69 clients. +- Vaulted installer URLs (they embed an unguessable per-client secret token) rather than storing + plaintext in the wiki; wiki gets a pointer. +- Built `move-asset` with a capability preflight + mandatory post-write verify because an + under-scoped token returns HTTP 200 and silently no-ops the folder change. +- Did not probe undocumented endpoints (e.g. guessed exec routes) per the skill's hard rule. + +## Problems Encountered + +- **Emails not delivered despite 200 "Email sent".** Invoice/estimate email endpoints take no + recipient param and send to nobody when `customer.email` is null. `customer.email` is unique + tenant-wide (Howard's real email was "already taken"). Fixed with a plus-addressed unique + email (`howard+synctest@`), which delivered — resolved. +- **Null write responses looked like failures.** POST /contacts (flat `.id`), POST /contracts + (no echo) returned null on the wrapped parse though the writes succeeded. GET-verify caught it; + a blind retry would have duplicated. Documented the three response-shape families. +- **Policy-folder 401 then 404.** Old token 401'd on `/policy_folders`; upgraded token 404s on + the bare route but 200s with `?customer_id=N`. `POST /policy_folders` requires `parent_id`. +- **PO line item rejected** until the product had `maintain_stock:true`. +- **Customer would not hard-delete** — `DELETE /customers` disables instead when associated data + (asset/lead) exists. Expected; noted GUI-only leftovers. +- **jq `--arg` path lookup quirk** on the swagger file — switched to single non-parameterized + walks / hardcoded paths. +- **/tmp write blocked** by the block-tmp-path hook (working as intended) — used repo-relative + `.claude/tmp/`. + +## Configuration Changes + +Created: +- `.claude/standards/syncro/api-reference.md` — full verified Syncro endpoint catalog + worked templates. +- `.claude/standards/syncro/test-findings.md` — living log of verified behaviors/gotchas. +- `session-logs/2026-07/2026-07-10-howard-syncro-skill-expansion.md` — this log. + +Modified: +- `.claude/commands/syncro.md` — asset read/write/move, RMM alerts, deploy-agent, capability + preflight helper, email-delivery hard rule, expanded Verified Response Shapes table, reference pointer. +- `.claude/memory/reference_syncro_rmm_api_gui_only.md` + `.claude/memory/MEMORY.md` — corrected + the "RMM is GUI-only" belief to the verified token-scope reality. +- `errorlog.md` — two `--correction` entries (asset-API assumption; email 200 != delivered). + +Vault (separate repo, pushed): +- `clients/{cascades-tucson,grabb-durando,reliant,howard-test}/syncro-agent-installer.sops.yaml` + — Syncro RMM MSI installer URLs (encrypted). + +## Credentials & Secrets + +- Syncro per-user API keys (unchanged): `msp-tools/syncro` (Mike, uid 1735, …ebbeb3 — still + lacks Policy-Change scope), `msp-tools/syncro-winter` (Winter, uid 1737, …5edb3a — full), + `msp-tools/syncro-howard` (Howard, uid 1750, …680e18 — full, upgraded this session). +- Syncro installer URLs vaulted at `clients//syncro-agent-installer` (`credentials.installer_url`). + Structure: `base64(v1-{customer_id}-{A:secret}-48753-{policy_folder_id})`; `48753` = ACG Syncro + account id; `A` is an unguessable per-client secret (not API-derivable). +- GuruRMM API creds unchanged: `infrastructure/gururmm-server.sops.yaml`. + +## Infrastructure & Servers + +- Syncro PSA API: `https://computerguru.syncromsp.com/api/v1` (query-param auth, 180 req/min). +- Syncro RMM installer host: `https://rmm.syncromsp.com/dl/msi/` (Kabuto, separate from PSA API). +- GuruRMM: `http://172.16.3.30:3001` (JWT auth). +- RMM-TEST-MACHINE (GuruRMM agent id `99d6d692-99e0-4359-9f9c-f43be89f49e5`, online, v0.6.66, + client "AZ Computer Guru", site "Howard-VM"). A second stale enrollment exists + (`7d3456f5-…`, offline). Syncro agent MSI product code `{B7F56D3D-2AD3-4021-9D36-3B9E9C9FBE33}`. +- Sandbox: Syncro customer "Howard Test" 36118743 (now DISABLED), policy folder 5092561, + enrolled asset 12676769. + +## Commands & Outputs + +- Decode installer token: `echo | base64 -d` → `v1-{customer_id}-{A}-48753-{policy_folder_id}`. +- Capability preflight (policy scope): `GET /policy_folders?customer_id=N` → 200 has scope, 401 lacks. +- Deploy (GuruRMM): download MSI, `Start-Process msiexec.exe -ArgumentList @('/i',$msi,'/qn','/norestart') -Wait` + → service `Syncro` Running, asset enrolls in ~1 min. +- Uninstall (GuruRMM): find Uninstall reg entry `DisplayName -match 'Syncro'`, `msiexec /x {ProductCode} /qn /norestart` + → service/process/dir/reg all removed. +- `DELETE /customers/{id}` on customer with associated data → + `{"message":"Customer was disabled instead of deleted because they have associated data."}`. + +## Pending / Incomplete Tasks + +- **Mike's Syncro token (…ebbeb3) still lacks Assets-Policy-Change** — re-vault after he confirms/upgrades + the correct token, so `move-asset` works in Mike-attributed sessions. +- **GUI-only sandbox leftovers** (no API DELETE): Howard Test asset 12676769 (archive), lead 43492446, + vendor 809317, product 23639304, PO 2101221; customer 36118743 stays DISABLED until asset+lead cleared. +- Optional: add a `deploy-agent --uninstall` action (msiexec /x method verified). +- Optional: grant Policy-Change scope to all per-user tokens for consistent `move-asset`. +- Lazy-harvest installer URLs for other clients at first deploy. + +## Reference Information + +- Spec: `https://api-docs.syncromsp.com/swagger.json` (OpenAPI 3.0, 116 paths / ~180 ops / 38 tags). +- Skill: `.claude/commands/syncro.md`; reference `.claude/standards/syncro/api-reference.md`; + findings `.claude/standards/syncro/test-findings.md`. +- Commits this session: `1f56098`, `12bb9f1`, `555e1ff`, `1fa1a42`, `ae2ee34`, `269449d`, `8afd7ec` (+ this save). +- Vault installer entries: `clients/{cascades-tucson,grabb-durando,reliant,howard-test}/syncro-agent-installer`.