From c37fd11ee9fe07546bd1485f0d5a0395df086c72 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Sun, 31 May 2026 19:31:55 -0700 Subject: [PATCH] sync: auto-sync from GURU-KALI at 2026-05-31 19:31:53 Author: Mike Swanson Machine: GURU-KALI Timestamp: 2026-05-31 19:31:53 --- .../remediation-tool/references/tenants.md | 2 +- .gitmodules | 4 + ...-05-31-onboard-and-rename-emma-to-carla.md | 123 ++++++++++++++++++ .../SUBMODULE-IDENTITY-RECONCILE-SPEC.md | 90 +++++++++++++ projects/youtube-sync-docker | 1 + 5 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 clients/rednour/reports/2026-05-31-onboard-and-rename-emma-to-carla.md create mode 100644 docs/specifications/SUBMODULE-IDENTITY-RECONCILE-SPEC.md create mode 160000 projects/youtube-sync-docker diff --git a/.claude/skills/remediation-tool/references/tenants.md b/.claude/skills/remediation-tool/references/tenants.md index 2c078b9..727c060 100644 --- a/.claude/skills/remediation-tool/references/tenants.md +++ b/.claude/skills/remediation-tool/references/tenants.md @@ -36,7 +36,7 @@ After full onboarding, update the Onboarded column below. | Patient Care Advocates | pcatucson.com | 463b462d-0995-4e51-9e41-82c208015c7f | NO | | | Peaceful Spirit Massage | bestmassageintucson.com | 13be285a-374d-4a7c-a7d8-4cb5a98b5c29 | NO | | | Putt Land Surveying Inc | puttsurveying.com | 25008634-91b4-40aa-8113-78ea03826156 | NO | | -| Rednour Law | rednourlaw.com | 4a4ca18a-f516-478b-99da-2e0722c5dc18 | NO | | +| Rednour Law | rednourlaw.com | 4a4ca18a-f516-478b-99da-2e0722c5dc18 | YES | All apps consented 2026-05-31; Sec Inv + Exch Op Exchange Admin + User Mgr User Admin + Auth Admin + Tenant Admin CA Admin roles assigned; no MDE | | Reliant Well Drilling and Pump | reliantpump.services | 2b124552-3891-4090-b3ed-2eebad3c4083 | NO | | | Ridgetop Group | ridgetopgroup.com | ef111bfc-9c90-43c9-a581-f9bbfceb6517 | NO | | | Rincon Vista Veterinary Center | rinconvistavet.onmicrosoft.com | b8cdcd89-d0f4-4747-bcf3-8bd8a25fd7e1 | NO | | diff --git a/.gitmodules b/.gitmodules index 64bfaf0..a845ad7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,7 @@ path = projects/msp-tools/guru-connect url = http://azcomputerguru@172.16.3.20:3000/azcomputerguru/guru-connect.git branch = main +[submodule "projects/youtube-sync-docker"] + path = projects/youtube-sync-docker + url = https://git.azcomputerguru.com/azcomputerguru/youtube-sync-docker.git + branch = main diff --git a/clients/rednour/reports/2026-05-31-onboard-and-rename-emma-to-carla.md b/clients/rednour/reports/2026-05-31-onboard-and-rename-emma-to-carla.md new file mode 100644 index 0000000..6cbddfd --- /dev/null +++ b/clients/rednour/reports/2026-05-31-onboard-and-rename-emma-to-carla.md @@ -0,0 +1,123 @@ +# Rednour Law — MSP Suite Onboarding + Account Rename (emma@ → carla@) + +**Date:** 2026-05-31 (UTC) +**Tenant:** rednourlaw.com (`4a4ca18a-f516-478b-99da-2e0722c5dc18`) +**Operator:** Mike Swanson (GURU-KALI) +**Apps used:** ComputerGuru Tenant Admin, Exchange Operator, User Manager + +## Action Summary + +Two operations chained: + +1. **Bootstrapped the full ComputerGuru MSP app suite** for the rednourlaw.com tenant (Tenant Admin consent followed by `onboard-tenant.sh`). Prior state: only Tenant Admin was consentable; no Exchange/User roles assigned. Triggered by HTTP 403 on Get-Mailbox during the rename attempt — the Exchange Operator SP existed but lacked Exchange Administrator role. +2. **Renamed `emma@rednourlaw.com` → `carla@rednourlaw.com` (Carla Skinner)** in a three-call sequence: `Set-Mailbox` for EmailAddresses, Graph `PATCH /users/{id}` for identity fields, `POST /revokeSignInSessions` to invalidate any active token. + +## Onboarding Result + +| SP | App ID | Status | Roles assigned | +|---|---|---|---| +| Tenant Admin | `709e6eed-0711-4875-9c44-2d3518c47063` | Consented manually | Conditional Access Administrator | +| Security Investigator | `bfbc12a4-f0dd-4e12-b06d-997e7271e10c` | Programmatic | Exchange Administrator | +| Exchange Operator | `b43e7342-5b4b-492f-890f-bb5a4f7f40e9` | Programmatic | Exchange Administrator | +| User Manager | `64fac46b-8b44-41ad-93ee-7da03927576c` | Programmatic | User Administrator, Authentication Administrator | +| Defender Add-on | `dbf8ad1a-54f4-4bb8-8a9e-ea5b9634635b` | Programmatic | (none — no MDE license in this tenant) | + +Defender Add-on consent succeeded but the tenant has no MDE license, so calling Defender ATP endpoints will return AADSTS650052. Skip the `defender` tier for this tenant. + +Exchange Administrator role on the Exchange Operator SP propagated within ~60s (Get-Mailbox switched from 403 to 200 on the second try). + +`references/tenants.md` row updated from `NO` to `YES` with the date and per-SP role summary. + +## User Rename — Before + +``` +id: 93074d1a-6db2-4794-8f7d-c84a619e4494 +UPN: emma@rednourlaw.com +displayName: Emma - Rednour Law +mail: emma@rednourlaw.com +mailNickname: dgarcia +givenName: Emma +surname: (null) +PrimarySmtpAddress: emma@rednourlaw.com +EmailAddresses: + SIP:emma@rednourlaw.com + SMTP:emma@rednourlaw.com (primary) + smtp:dgarcia@rednourlaw.com (legacy) + smtp:alee@rednourlaw.com (legacy) + smtp:dgarcia@rednourlaw.onmicrosoft.com (routing) + SPO:SPO_f390956f-...@SPO_ (SharePoint auto) +EmailAddressPolicyEnabled: False +accountEnabled: true +``` + +The mailNickname `dgarcia` and the two legacy aliases indicate this mailbox was previously inherited from earlier employees Garcia → Emma. The chain continues with the rename to Carla. + +## User Rename — After + +``` +id: 93074d1a-6db2-4794-8f7d-c84a619e4494 (unchanged) +UPN: carla@rednourlaw.com +displayName: Carla Skinner +mail: carla@rednourlaw.com +mailNickname: carla +givenName: Carla +surname: Skinner +PrimarySmtpAddress: carla@rednourlaw.com +EmailAddresses: + SIP:emma@rednourlaw.com (will auto-regen to carla@ on next sync) + SMTP:carla@rednourlaw.com (new primary) + smtp:emma@rednourlaw.com (alias — Emma's old mail still routes here) + smtp:dgarcia@rednourlaw.com (legacy — kept per operator) + smtp:alee@rednourlaw.com (legacy — kept per operator) + smtp:dgarcia@rednourlaw.onmicrosoft.com (existing routing — Exchange chose not to swap to carla@) + SPO:SPO_f390956f-...@SPO_ (unchanged) +accountEnabled: true +``` + +## Sign-in Session Revocation + +`POST /users/93074d1a-.../revokeSignInSessions` returned `200 {"value": true}`. All refresh tokens and active sessions under the previous UPN are invalidated; next access requires re-authentication as `carla@rednourlaw.com`. + +## Decisions Made During Execution + +- **Kept both legacy aliases (`dgarcia@`, `alee@`)** — operator's explicit choice. If those external addresses are confirmed dormant in the future, revisit removing them. +- **No password reset** — operator confirmed this is a name change, not a personnel handoff; Carla already knows the password. +- **Sessions revoked unconditionally** — standard practice after any UPN change. +- **SP role/consent strategy** — bootstrapped the full suite (not just Exchange Operator) since onboarding was already incomplete. Future operations against this tenant now have the full toolset available. + +## Two Cosmetic Items That Did Not Apply + +1. `SIP:emma@rednourlaw.com` persisted instead of updating to `SIP:carla@rednourlaw.com`. Exchange auto-derives SIP from UPN — should self-heal on next mail-flow event or Teams sign-in. +2. `smtp:carla@rednourlaw.onmicrosoft.com` was not added; Exchange kept the existing `smtp:dgarcia@rednourlaw.onmicrosoft.com` routing entry. Tenant routing through `*.onmicrosoft.com` still resolves to the right mailbox regardless of the local-part, so mail flow is unaffected. + +Neither is blocking. If they bother you, a single follow-up `Set-Mailbox` call can rewrite EmailAddresses with the cleaned list. + +## Raw Artifacts + +Preserved under `/tmp/remediation-tool/4a4ca18a-f516-478b-99da-2e0722c5dc18/rednour-rename/`: +- `get-mailbox-before.json` — pre-rename state +- `set-mailbox-resp.json` — Set-Mailbox response (empty value collection + warnings array — normal) +- `get-mailbox-after.json` — first verify (stale due to replication) +- `get-mailbox-after2.json`, `get-mailbox-final.json` — converged verifies + +## API Calls Executed (audit trail) + +``` +POST /adminconsent (client_id=Tenant Admin, manual click by Global Admin) +bash .claude/skills/remediation-tool/scripts/onboard-tenant.sh rednourlaw.com +POST https://outlook.office365.com/adminapi/beta/{tenant}/InvokeCommand + CmdletName=Set-Mailbox + Identity=93074d1a-6db2-4794-8f7d-c84a619e4494 + EmailAddresses=[SMTP:carla@..., smtp:emma@..., smtp:dgarcia@..., smtp:alee@..., smtp:carla@*.onmicrosoft.com, SIP:carla@..., SPO:...] + WindowsEmailAddress=carla@rednourlaw.com +PATCH https://graph.microsoft.com/v1.0/users/93074d1a-... + {userPrincipalName, displayName, mailNickname, givenName, surname} +POST https://graph.microsoft.com/v1.0/users/93074d1a-.../revokeSignInSessions +``` + +## Reference + +- Tenant ID: `4a4ca18a-f516-478b-99da-2e0722c5dc18` +- User object ID (unchanged through rename): `93074d1a-6db2-4794-8f7d-c84a619e4494` +- Onboarding script: `.claude/skills/remediation-tool/scripts/onboard-tenant.sh` +- Updated tenants.md row: line 39 diff --git a/docs/specifications/SUBMODULE-IDENTITY-RECONCILE-SPEC.md b/docs/specifications/SUBMODULE-IDENTITY-RECONCILE-SPEC.md new file mode 100644 index 0000000..9a5d5f7 --- /dev/null +++ b/docs/specifications/SUBMODULE-IDENTITY-RECONCILE-SPEC.md @@ -0,0 +1,90 @@ +# Spec: Submodule Identity Reconcile in sync.sh + +**Status:** Proposed (not implemented) +**Authored:** 2026-05-31 +**Author:** Mike Swanson (drafted with Claude, GURU-KALI) +**Estimated effort:** ~15 lines added to `sync.sh`, ~30 min including tests + verification + +## Problem + +`sync.sh` already reconciles the **parent** repo's `git config user.name` / `user.email` against `.claude/identity.json` on every run (`reconcile_git_identity`, sync.sh:52-69). That guarantees the parent repo's commits are attributed to the human who actually owns this machine. + +Submodules are not covered. A freshly-cloned submodule on a new machine inherits whatever the system default sets — typically ` ` on Linux, or the system git config on Windows. Submodules also don't pick up the parent repo's `.git/config` user — they have their own. + +This bit us in this session: the first two commits in `azcomputerguru/youtube-sync-docker` from GURU-KALI landed as `ComputerGuru ` instead of `Mike Swanson `. The drift would silently repeat for every new submodule cloned on every new machine until each one was manually configured. + +Same hazard applies to existing submodules `projects/msp-tools/guru-rmm` and `projects/msp-tools/guru-connect` on any workstation that hasn't been manually configured — Howard's home machine, the MacBook, GURU-5070, etc. Whether any of those are currently misattributed depends on whether the people who set them up happened to run `git config user.name/email` in each submodule. The git log of each submodule on each machine is the source of truth for the historical state, but the **risk going forward** is uniform: any new contributor or fresh clone gets default attribution. + +## Goal + +When `sync.sh` runs Phase 1a (Submodule update), also call `reconcile_git_identity` inside each initialized submodule — the same way it does for the parent repo. After the change, every commit in every submodule from any team workstation is attributed to the human named in that machine's `identity.json`, regardless of when the submodule was first cloned. + +## Out of scope + +- Rewriting historical commits to fix prior misattribution. Too destructive (force-push to shared remote, breaks any in-flight branches). The two existing youtube-sync-docker commits with `ComputerGuru` author stay as-is unless explicitly requested separately. +- Per-submodule user override (e.g. one submodule attributed to a different person on the same box). Not a real use case today — every machine has one human owner. +- Reconciling other git config (signing keys, push default, etc.). Spec is scoped to author identity only. + +## Proposed change + +In `sync.sh` Phase 1a, the existing `git submodule foreach` block (sync.sh:221-226) already iterates initialized submodules to advance them to their remote branch tip. Extend that same loop (or add a parallel one immediately after it) to invoke the reconcile inside each submodule directory. + +The catch: `reconcile_git_identity` is a function defined in the parent `sync.sh` and references the parent's color variables. `git submodule foreach` runs each iteration in a fresh subshell whose only environment is what `foreach` exports. We can't directly call the bash function inside the `foreach` body — it won't be defined there. + +Three options for routing the call: + +**Option A (recommended):** Skip `foreach` for the reconcile; iterate `.gitmodules` paths directly the same way the existing init loop already does at sync.sh:200-218. That loop runs in the parent shell, so it has full access to functions and variables. Add a `(cd "$ppath" && reconcile_git_identity "$USER_DISPLAY" "$USER_EMAIL")` after the existing `git submodule update --init -- "$ppath"` line. Keep `set +e` / `set -e` discipline matching the surrounding code. + +**Option B:** Export `USER_DISPLAY` and `USER_EMAIL` as env vars, and inline the reconcile logic inside the `foreach` body as a few lines of bash. Works, but duplicates the function's logic in a second place and is harder to maintain. + +**Option C:** Stuff `reconcile_git_identity` into a separate sourceable file (`.claude/scripts/lib/identity.sh`) and `source` it inside the `foreach` body. Cleanest separation but adds a new file and a sourcing pattern that doesn't exist anywhere else in the repo today. Probably overkill for one helper function. + +Go with Option A. Concrete patch sketch (inside the existing while-loop at sync.sh:200, immediately after `git submodule update --init -- "$ppath"`): + +```bash +# Reconcile this submodule's git identity to match identity.json — same +# guarantee we make for the parent repo. Without this, commits in newly-cloned +# submodules land under the system default (e.g. " @") +# instead of the actual human. Skip if identity.json was unreadable. +if [ "$USER_DISPLAY" != "unknown" ]; then + (cd "$ppath" && reconcile_git_identity "$USER_DISPLAY" "$USER_EMAIL") +fi +``` + +`USER_DISPLAY` is already set by the time Phase 1a runs (the load happens earlier in the script). `reconcile_git_identity` is already defined in the parent shell scope and will see the same variables. The subshell with `cd "$ppath"` means git operates on the submodule's `.git/config` rather than the parent's. + +## Edge cases / risks + +1. **Submodule not yet initialized** (fresh clone). The init line right before this already populates the submodule; by the time the reconcile line runs, `.git/config` exists. Safe. +2. **Submodule path missing entirely** (corrupt state, manual rm -rf). The init line would have errored — the existing code uses `>/dev/null 2>&1` redirect to swallow it, so the `cd` would then fail and the subshell exits non-zero. Wrap in `|| true` to be safe, matching the surrounding code's tolerance for submodule weirdness. +3. **`identity.json` unreadable** (`USER_DISPLAY == "unknown"`). The same guard the parent-repo reconcile uses already covers this — skip silently rather than stamping the submodule with "unknown". +4. **Reconcile changes the submodule's git config and prints a `[WARNING]` line** the first time it runs on each existing machine. That's correct and expected — it documents the drift correction. After the first run on a machine, idempotent. +5. **Submodule that points at a non-Gitea remote** (no current example, but theoretically). The reconcile only writes git config locally; doesn't push or auth. No impact on remote interaction. +6. **`reconcile_git_identity` itself uses color variables** (`YELLOW`, `NC`) that are defined at the top of `sync.sh`. The subshell created by `(cd ...)` inherits parent shell variables, so those color codes are still in scope. Verify. + +## Acceptance + +- `bash -n .claude/scripts/sync.sh` clean +- Existing parent-repo reconcile behavior unchanged (sanity: run sync.sh on a box where parent git config already matches identity.json — no warning fires, no commit message about it) +- On a workstation where any submodule's `user.name` / `user.email` doesn't match identity.json, sync.sh emits the `[WARNING]` line once per drifted submodule, then on the next run is silent (idempotent) +- A test commit inside any submodule (from any machine) lands with the correct human author +- No new shellcheck warnings (eyeball — no shellcheck mandated in current sync.sh tooling) +- Cross-machine sanity: run on at least GURU-KALI, GURU-5070, HOWARD-HOME, Mikes-MacBook-Air, GURU-BEAST-ROG before treating as fully verified. Each machine's identity.json should already be authoritative. + +## Don't (when implementing) + +- Don't reconcile the *vault* repo via this mechanism — Phase 6 already does it. The change is scoped to project submodules only. +- Don't add a `--no-submodules` flag or any user-facing toggle. The reconcile is always-on, just like the parent-repo reconcile is. +- Don't reach for `git config --global` or `--system`. Local repo config only, same as the existing reconcile. +- Don't write to `identity.json` from this code path. Identity is read-only here. + +## Estimated impact + +- Cost to ship: ~10 minutes of implementation + a quick test on this box (already showing the drift) +- Cost of not shipping: every new submodule clone on every new machine has a roughly 50/50 chance of producing misattributed commits until somebody notices, the way it just happened here. Cost is low individually but accumulates as a noise source in `git log` and breaks contribution attribution for any reporting that aggregates by author. + +## Related + +- The existing parent-repo reconcile: `sync.sh:52-69` (`reconcile_git_identity`) +- The submodule init/advance block this would hook into: `sync.sh:175-228` (Phase 1a) +- The drift incident that motivated this: youtube-sync-docker commits `ef903c8` and `fdff0a7` (2026-05-31) authored as `ComputerGuru ` instead of Mike. Not being rewritten; spec only prevents recurrence. diff --git a/projects/youtube-sync-docker b/projects/youtube-sync-docker new file mode 160000 index 0000000..fdff0a7 --- /dev/null +++ b/projects/youtube-sync-docker @@ -0,0 +1 @@ +Subproject commit fdff0a791a14715548f3e94b58b9e50ee44c38a5