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:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user