sync: auto-sync from HOWARD-HOME at 2026-04-22 11:48:29

Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-04-22 11:48:29
This commit is contained in:
2026-04-22 11:48:29 -07:00
parent d39fef2a23
commit dcc852b12d
2 changed files with 70 additions and 6 deletions

View File

@@ -19,7 +19,7 @@ Create, update, close, comment on, and bill tickets in Syncro PSA.
## API Configuration
**Base URL:** `https://computerguru.syncromsp.com/api/v1`
**API Key:** SOPS vault `msp-tools/syncro.sops.yaml``credentials.credential`
**API Key:** per-user tokens in SOPS vault — see "Get API key" below
**Rate limit:** 180 requests/minute per IP
**Docs:** https://api-docs.syncromsp.com/
@@ -27,21 +27,65 @@ Create, update, close, comment on, and bill tickets in Syncro PSA.
When invoked, use the Syncro REST API via `curl`. All requests include `?api_key=<key>` as query parameter (NOT in header — Syncro uses query param auth).
### Attribution rule (CRITICAL)
Every Syncro API call is attributed to the **owner of the API key**. Comments, line items, timer entries, and invoices created by the API are logged as the API user — regardless of who is running the command. So the skill MUST use a per-user API key that matches the actual tech running it, or comments will be misattributed.
| Vault entry | Syncro user | user_id |
|---|---|---|
| `msp-tools/syncro-howard.sops.yaml` | Howard Enos | 1750 |
| `msp-tools/syncro.sops.yaml` | Michael Swanson | 1735 (current shared fallback) |
When Mike generates his own per-user key, add `msp-tools/syncro-mike.sops.yaml` and demote the shared entry or remove it entirely.
### Get API key
```bash
# Vault path comes from .claude/identity.json (per-machine) via the ClaudeTools wrapper
VAULT="$CLAUDETOOLS_ROOT/.claude/scripts/vault.sh"
API_KEY=$(bash "$VAULT" get-field msp-tools/syncro.sops.yaml credentials.credential)
BASE="https://computerguru.syncromsp.com/api/v1"
# Select key by identity.json user; fall back to shared key if per-user missing
USER_ID=$(jq -r '.user // empty' "$CLAUDETOOLS_ROOT/.claude/identity.json")
KEY_PATH="msp-tools/syncro-${USER_ID}.sops.yaml"
if ! bash "$VAULT" list 2>/dev/null | grep -qx "${KEY_PATH}"; then
echo "[WARN] No per-user Syncro key at ${KEY_PATH} — falling back to shared key. Actions will be attributed to the shared key owner." >&2
KEY_PATH="msp-tools/syncro.sops.yaml"
fi
API_KEY=$(bash "$VAULT" get-field "$KEY_PATH" credentials.credential)
```
If `vault.sh get-field` fails (yq not installed), fall back to:
Verify attribution before destructive operations:
```bash
VAULT_ROOT=$(bash "$VAULT" get msp-tools/syncro.sops.yaml 2>/dev/null | head -1 || python3 -c "import json; print(json.load(open('$CLAUDETOOLS_ROOT/.claude/identity.json'))['vault_path'])")
API_KEY=$(sops -d "$VAULT_ROOT/msp-tools/syncro.sops.yaml" | py -c "import sys,yaml; print(yaml.safe_load(sys.stdin)['credentials']['credential'])")
ME=$(curl -s "${BASE}/me?api_key=${API_KEY}" | jq -r '.user_name + " (user_id=" + (.user_id|tostring) + ")"')
echo "Authenticated as: $ME"
```
### Adding a per-user key
1. User logs into Syncro → Admin → API Tokens → New (`/api_tokens/new`)
2. Type: Integration API Token (or Custom with all standard scopes: asset/customer/ticket/invoice/payment read+write+delete, worksheet add+manage+delete, chat + script.execute)
3. Copy the token once (Syncro only shows it on creation)
4. Encrypt to vault:
```bash
cat > $VAULT_ROOT/msp-tools/syncro-<user>.sops.yaml <<YAML
kind: api-key
name: Syncro (<Full Name>)
subdomain: computerguru
api-base-url: https://computerguru.syncromsp.com/api/v1
api-docs: https://api-docs.syncromsp.com/
status: active
owner: <user>
syncro_user_id: <id>
tags: [msp-tools, per-user]
credentials:
credential: <TOKEN>
notes: Per-user Syncro API token for <Full Name>. Created YYYY-MM-DD.
YAML
# MUST run from vault root so sops picks up .sops.yaml
(cd "$VAULT_ROOT" && sops --encrypt --in-place "msp-tools/syncro-<user>.sops.yaml")
```
5. Commit + push vault repo.
### Endpoints reference
#### Tickets

View File

@@ -4,6 +4,26 @@ Check this file at sync. Delete items after you've addressed them.
---
## From Howard, 2026-04-22 — Per-user Syncro keys (attribution fix)
I hit the issue that my Syncro comments/line items on ticket #32179 were getting logged as you (user_id 1735) because we share your API key. Fixed it with per-user tokens:
- Generated my own Syncro API token (Custom, admin, indefinite) → `user_id 1750`
- Added vault entry: `msp-tools/syncro-howard.sops.yaml`
- Patched `.claude/commands/syncro.md` to pick the key from `identity.json`'s `user` field, falls back to the shared `msp-tools/syncro.sops.yaml` if no per-user file exists
- Verified `/me` now returns Howard Enos on my machine
**When you get a chance** (after Valleywide settles), do the same for yourself so the shared key can be retired:
1. Syncro → Admin → API Tokens → New (integration or custom, full scopes)
2. `cat > $VAULT_ROOT/msp-tools/syncro-mike.sops.yaml <<YAML ... YAML` (template in the patched syncro.md)
3. `cd $VAULT_ROOT && sops --encrypt --in-place msp-tools/syncro-mike.sops.yaml`
4. Commit + push vault. The skill will pick it up automatically on your next sync.
After your key is in place we can delete `msp-tools/syncro.sops.yaml` (shared). Until then the skill warns on stderr when it falls back to the shared key.
---
## From Howard, 2026-04-22 — Ack: intune-manager + rates
Pulled vault (got `ebdd711` + `1c837ba`). intune-manager vault file loads fine now. Tried a token against grabblaw.com — returns `AADSTS700016` (app not consented in that tenant). Same category as the `defender` case, tenant-onboarding work, not a code bug. No action needed from you.