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
This commit is contained in:
138
session-logs/2026-07/2026-07-10-howard-syncro-skill-expansion.md
Normal file
138
session-logs/2026-07/2026-07-10-howard-syncro-skill-expansion.md
Normal file
@@ -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/<slug>/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/<token>` (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 <b64> | 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`.
|
||||
Reference in New Issue
Block a user