sync: auto-sync from HOWARD-HOME at 2026-07-09 20:23:39
Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-07-09 20:23:39
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
# Cascades of Tucson — Chris Knight accounting mailbox delegation
|
||||
|
||||
## User
|
||||
- **User:** Howard Enos (howard)
|
||||
- **Machine:** Howard-Home
|
||||
- **Role:** tech
|
||||
|
||||
---
|
||||
|
||||
## Session Summary
|
||||
|
||||
Chris Knight needed access to the Cascades accounting email as an attached account in Outlook — able to read and to send. Routed the request through the `remediation-tool` skill against the Cascades M365 tenant (`cascadestucson.com`, `207fa277-e9d8-4eb7-ada1-1064d2221498`).
|
||||
|
||||
The opening consent audit graded the tenant RED, reporting "app NOT consented (token mint failed)" for all four app tiers. That was a false negative. The wiki recorded that the Exchange Operator app had worked against this tenant as recently as 2026-06-12 (the `grievances@`/`Surveys@` shared-mailbox delegations), which contradicted the audit. Testing the token mint directly surfaced the real fault: `get-token.sh` resolves the vault from `~/.claude/identity.json`, but this machine's identity and `vault_path` (`D:/vault`) live in the repo at `.claude/identity.json`. With `VAULT_ROOT_ENV=D:/vault` the `exchange-op` token minted immediately. The tenant was fully consented the whole time.
|
||||
|
||||
Read-only recon via the EXO REST `InvokeCommand` endpoint identified `accounting@cascadestucson.com` as a SharedMailbox ("Accounting Dept.", account disabled — normal for shared) and confirmed `accountingassistant@` is a distinct UserMailbox, not a delegate. The existing delegates — Lauren Hasselman, Ashley Jensen, Zachary Nelson — each held FullAccess + SendAs. The wiki independently records Chris Knight as "same access tier as Lauren Hasselman," so the grant pattern was unambiguous.
|
||||
|
||||
After explicit user confirmation, applied `Add-MailboxPermission` (FullAccess, `InheritanceType All`, `AutoMapping $true`) and `Add-RecipientPermission` (SendAs) via the `exchange-op` tier. Both returned OK. The first verification read-back showed FullAccess but **not** SendAs — Exchange replication lag, not a failed write. A re-read confirmed Chris on the SendAs list, and the trustee GUID returned by the write (`a1f1bb9e-0cee-4a49-8397-189e6137d680`) matched his `ExternalDirectoryObjectId`.
|
||||
|
||||
Closed out by updating `wiki/clients/cascades-tucson.md` with a new `accounting@` delegation record (delegates, grant pattern, replication gotcha) and a note on Chris's staff line. Logged two errorlog entries for the path-drift defects found along the way.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- **Did not trust the RED consent audit.** The wiki's 2026-06-12 record of a successful Exchange Operator write against this tenant contradicted it. Verifying the token mint directly was cheaper than acting on the audit — and acting on it would have meant emailing the client an admin-consent link they did not need.
|
||||
- **Granted SendAs, not SendOnBehalf.** All three existing delegates hold SendAs; SendOnBehalf would render as "Chris Knight on behalf of Accounting Dept." to recipients and break parity with the rest of the accounting staff.
|
||||
- **`AutoMapping $true`** was the specific mechanism the request required — "attached email account" means the mailbox self-attaches to the Outlook profile via AutoDiscover, rather than the user hand-adding it.
|
||||
- **Re-read before declaring the SendAs write failed.** The write returned a trustee GUID; resolving that GUID against `Get-Mailbox` proved the grant landed and the read was stale.
|
||||
- **Skipped a full `/wiki-lint` pass.** Two bullet edits to one existing article introduced no `[[wikilinks]]`. Ran the applicable checks (link integrity, article structure) instead of a whole-wiki scan.
|
||||
|
||||
## Problems Encountered
|
||||
|
||||
- **`consent-audit.sh` reported a false RED "app NOT consented" for all four tiers.** Root cause was a *local* vault-path lookup failure, not tenant consent. The script conflates "could not read the vault" with "tenant has not consented." Resolved with `VAULT_ROOT_ENV=D:/vault`. Logged to `errorlog.md`; the script should fail loud on a vault-path error rather than downgrading it to a consent finding. **This is the dangerous one** — the false negative points directly at sending a client an unnecessary consent link.
|
||||
- **`get-token.sh` and peers read `~/.claude/identity.json`,** but the authoritative identity (with `vault_path`) is the repo's `.claude/identity.json`. Same path-drift family.
|
||||
- **`.claude/commands/wiki-lint.md` hardcodes `cd D:/claudetools`,** but `claudetools_root` on this machine is `C:/claudetools`. Logged as `--friction`.
|
||||
- **Post-write `Get-RecipientPermission` did not show the new SendAs trustee.** Exchange replication lag across replicas. Re-read confirmed. Recorded in the wiki so the next delegate-add does not misread this as a failure.
|
||||
|
||||
## Configuration Changes
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `wiki/clients/cascades-tucson.md` | Added `accounting@` delegation record + grant pattern + replication gotcha (line ~291); appended accounting-mailbox note to Chris Knight's staff line (line ~214) |
|
||||
| `errorlog.md` | 2 entries: `remediation-tool/consent-audit.sh` (false RED), `wiki-lint` (hardcoded path, `--friction`) |
|
||||
|
||||
**M365 tenant changes (Cascades):** two permission grants on `accounting@cascadestucson.com` — see Commands below. No code changes.
|
||||
|
||||
## Credentials & Secrets
|
||||
|
||||
None discovered, created, or rotated this session.
|
||||
|
||||
- Vault accessed read-only for app credentials: `msp-tools/computerguru-exchange-operator.sops.yaml`, `msp-tools/computerguru-security-investigator.sops.yaml`.
|
||||
- Auth path was certificate-based (`[INFO] auth=cert`), client_credentials flow.
|
||||
- Vault root on this machine: `D:/vault` (from repo `.claude/identity.json` → `vault_path`).
|
||||
|
||||
## Infrastructure & Servers
|
||||
|
||||
- **M365 tenant:** `cascadestucson.com` | Tenant ID `207fa277-e9d8-4eb7-ada1-1064d2221498`
|
||||
- **EXO REST endpoint:** `https://outlook.office365.com/adminapi/beta/207fa277-e9d8-4eb7-ada1-1064d2221498/InvokeCommand`
|
||||
- **Token scope:** `https://outlook.office365.com/.default`
|
||||
- **Apps used:** ComputerGuru Exchange Operator `b43e7342-5b4b-492f-890f-bb5a4f7f40e9` (write); ComputerGuru Security Investigator `bfbc12a4-f0dd-4e12-b06d-997e7271e10c` (read)
|
||||
- **Target mailbox:** `accounting@cascadestucson.com` — SharedMailbox, "Accounting Dept.", cloud-only, `AccountDisabled: true`, `GrantSendOnBehalfTo: []`
|
||||
- **Grantee:** `Chris.Knight@cascadestucson.com` — UserMailbox | `ExternalDirectoryObjectId: a1f1bb9e-0cee-4a49-8397-189e6137d680` | `Guid: 04610882-68ab-4f15-a1e6-11966bbdc44c` | AD SID `S-1-5-21-3975168698-2031163149-733277609-62630518`
|
||||
- **Adjacent:** `accountingassistant@cascadestucson.com` is a **UserMailbox**, not a delegate of `accounting@`
|
||||
|
||||
### `accounting@` delegates (verified post-change 2026-07-09)
|
||||
|
||||
| Delegate | FullAccess | SendAs |
|
||||
|---|---|---|
|
||||
| lauren.hasselman@ | yes | yes |
|
||||
| ashley.jensen@ | yes | yes |
|
||||
| zachary.nelson@ | yes | yes |
|
||||
| Chris.Knight@ | yes (added) | yes (added) |
|
||||
|
||||
## Commands & Outputs
|
||||
|
||||
Token mint — the fix for the false RED:
|
||||
|
||||
```bash
|
||||
# FAILS: scripts look at ~/.claude/identity.json
|
||||
bash scripts/get-token.sh cascadestucson.com exchange-op
|
||||
# ERROR: vault_path not set in /c/Users/Howard/.claude/identity.json and VAULT_ROOT_ENV env var not set
|
||||
|
||||
# WORKS:
|
||||
VAULT_ROOT_ENV=D:/vault bash scripts/get-token.sh cascadestucson.com exchange-op
|
||||
# [INFO] auth=cert
|
||||
# eyJ0eXAiOiJKV1QiLCJub25jZSI6...
|
||||
```
|
||||
|
||||
The two grants (`exchange-op` token, POST to `InvokeCommand`):
|
||||
|
||||
```json
|
||||
{"CmdletInput":{"CmdletName":"Add-MailboxPermission","Parameters":{
|
||||
"Identity":"accounting@cascadestucson.com",
|
||||
"User":"Chris.Knight@cascadestucson.com",
|
||||
"AccessRights":"FullAccess","InheritanceType":"All","AutoMapping":true}}}
|
||||
```
|
||||
```json
|
||||
{"CmdletInput":{"CmdletName":"Add-RecipientPermission","Parameters":{
|
||||
"Identity":"accounting@cascadestucson.com",
|
||||
"Trustee":"Chris.Knight@cascadestucson.com",
|
||||
"AccessRights":"SendAs","Confirm":false}}}
|
||||
```
|
||||
|
||||
Outputs:
|
||||
```
|
||||
[OK] S-1-5-21-3975168698-2031163149-733277609-62630518 -> FullAccess (Deny=False)
|
||||
[OK] a1f1bb9e-0cee-4a49-8397-189e6137d680 -> SendAs (Allow)
|
||||
```
|
||||
|
||||
Verification (note the lag — first SendAs read omitted Chris, second included him):
|
||||
```json
|
||||
{"CmdletInput":{"CmdletName":"Get-MailboxPermission","Parameters":{"Identity":"accounting@cascadestucson.com"}}}
|
||||
{"CmdletInput":{"CmdletName":"Get-RecipientPermission","Parameters":{"Identity":"accounting@cascadestucson.com"}}}
|
||||
```
|
||||
|
||||
Errorlog:
|
||||
```bash
|
||||
bash .claude/scripts/log-skill-error.sh "remediation-tool/consent-audit.sh" "<false RED>" \
|
||||
--context "tenant=cascadestucson.com machine=HOWARD-HOME"
|
||||
bash .claude/scripts/log-skill-error.sh "wiki-lint" "<hardcoded D:/claudetools>" \
|
||||
--friction --context "ref=identity.json/claudetools_root machine=HOWARD-HOME"
|
||||
```
|
||||
|
||||
## Pending / Incomplete Tasks
|
||||
|
||||
- **Chris's Outlook:** AutoMapping attaches via AutoDiscover refresh — typically a few hours, reliably after an Outlook restart. SendAs can take ~60 min to replicate before sending from `accounting@` stops bouncing. Not yet confirmed on his endpoint (DESKTOP-N5G1ROO, GuruRMM agent `205025ee-2676-4498-8a27-e88562a6f69a`). Worth a spot-check if he reports the mailbox missing.
|
||||
- **`consent-audit.sh` fix (real bug, unfixed):** must distinguish "vault unreadable" from "tenant not consented." Currently a local config fault renders as a client-facing consent gap. Highest-value of the three.
|
||||
- **`get-token.sh` + sibling scripts:** resolve identity from repo `.claude/identity.json` (honoring `claudetools_root`), not `~/.claude/identity.json`. Until fixed, every remediation-tool invocation on this machine needs `VAULT_ROOT_ENV=D:/vault`.
|
||||
- **`.claude/commands/wiki-lint.md`:** replace hardcoded `cd D:/claudetools`.
|
||||
- **No Syncro ticket** was opened or referenced for this change. If it should be billed or tracked, it needs one.
|
||||
- **No `/wiki-compile`** run — wiki was hand-edited directly.
|
||||
|
||||
## Reference Information
|
||||
|
||||
- Wiki article: `wiki/clients/cascades-tucson.md`
|
||||
- Skill: `C:\Users\Howard\.claude\skills\remediation-tool` — `scripts/get-token.sh`, `scripts/consent-audit.sh`, `references/graph-endpoints.md`
|
||||
- Prior art (same grant pattern, 2026-06-12): `grievances@` + `Surveys@` shared-mailbox delegations, Syncro ticket **#32417**
|
||||
- Chris Knight workstation setup (2026-06-08): DESKTOP-N5G1ROO, Win 11 Pro for Workstations, AD account `chris.knight` (OU=Administrative)
|
||||
- EXO app-auth note: when the MSP app cert is absent from the Windows cert store, use client_credentials → EXO-scoped token → `Connect-ExchangeOnline -AccessToken`
|
||||
- Tenant consent link (only if genuinely needed — it was **not** this session):
|
||||
`https://login.microsoftonline.com/207fa277-e9d8-4eb7-ada1-1064d2221498/adminconsent?client_id=b43e7342-5b4b-492f-890f-bb5a4f7f40e9`
|
||||
Reference in New Issue
Block a user