Files
claudetools/.claude/commands/remediation-tool.md
Mike Swanson 100a491ac6 Session log: multi-user setup, audit + gap fixes, Howard onboarding package
Two session logs:
- session-logs/2026-04-16-session.md: cross-cutting (multi-user, audit, infrastructure)
- guru-rmm session log appended: MSI installer, Len's Auto Brokerage, Uranus, migration drift

Gap fixes: GrepAI initialized + MCP server added, Ollama models pulling,
settings.json created (bypassPermissions), MCP_SERVERS.md written.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 18:56:26 -07:00

6.6 KiB

description
description
M365 tenant investigation + remediation via the Claude-MSP-Access Graph API app. Breach checks, tenant sweeps, consent URLs, and gated remediation actions.

/remediation-tool

M365 investigation and remediation using the Claude-MSP-Access Graph API multi-tenant app (App ID fabb3421-8b34-484b-bc17-e46de9703418, display name in customer tenants: "ComputerGuru - AI Remediation").

Default posture: READ-ONLY. Remediation actions require explicit YES confirmation in chat.


Subcommands

Form What it does
/remediation-tool check <upn> 10-point breach check on a single user
/remediation-tool sweep <domain> Tenant-wide signals (sign-ins, audits, risky users, guests)
/remediation-tool signins <domain> [--user upn] [--failed-only] [--days N] Ad-hoc sign-in query
/remediation-tool consent-url <domain> Emit admin consent URL for a tenant
/remediation-tool remediate <upn> <action> GATED: password-reset, revoke-sessions, disable-forwarding, remove-inbox-rules, disable-account

<domain> accepts a tenant domain (cascadestucson.com), a UPN (user@domain.com), or a tenant GUID.


Workflow Claude should follow

0. Parse invocation

  • Extract subcommand, target, and any flags from $ARGUMENTS.
  • Normalize: UPN -> domain (split on @), domain -> look up tenant-id.
  • If the target is ambiguous or missing, ask the user once and proceed.

1. Resolve tenant ID

Run bash .claude/skills/remediation-tool/scripts/resolve-tenant.sh <domain> — returns tenant GUID via OpenID discovery. If it fails, the domain is not in Entra ID; surface the error and stop.

2. Acquire tokens (cached)

Run bash .claude/skills/remediation-tool/scripts/get-token.sh <tenant-id> graph and ... exchange as needed. Tokens cache at /tmp/remediation-tool/{tenant}/{scope}.jwt with 55-minute TTL. The script pulls the app secret from the SOPS vault (msp-tools/claude-msp-access-graph-api.sops.yaml, field credentials.credential).

If either token returns 403/401 on first use, check .claude/skills/remediation-tool/references/gotchas.md for the per-tenant prerequisites (directory roles, admin consent) and emit the remediation link to the user.

3. Run the requested checks

  • check <upn> -> bash scripts/user-breach-check.sh <tenant> <upn>. Script runs all 10 checks in parallel where possible and dumps raw JSON to /tmp/remediation-tool/{tenant}/user-breach/<slug>/. Claude then interprets findings against the rubric in references/checklist.md and writes a report.

  • sweep <domain> -> bash scripts/tenant-sweep.sh <tenant>. Script pulls tenant-wide failed sign-ins (30d), successful non-US sign-ins, directory audits filtered for consent/auth-method/service-principal changes, risky users (if permission granted), B2B guest invites, user location profile. Claude summarizes priority findings.

  • signins — build ad-hoc curl against Graph /auditLogs/signIns with the requested filter.

  • consent-url <domain> — emit https://login.microsoftonline.com/{tenant-id}/adminconsent?client_id=fabb3421-8b34-484b-bc17-e46de9703418&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient plus the note that the nativeclient landing page "looks like an error, that's normal."

  • remediate — see Remediation section below.

4. Write the report

Location: clients/{client-slug}/reports/YYYY-MM-DD-{action}.md (UTC date). Derive the client slug from the domain:

  • cascadestucson.com -> cascades-tucson
  • foobarwidgets.com -> foobar-widgets
  • Use existing clients/<slug>/ directory if present; if no matching client dir exists, ask the user for the slug before creating one.

Use templates/breach-report.md as the skeleton. For single-user checks, fill in per-check findings using raw JSON in /tmp/remediation-tool/{tenant}/user-breach/<slug>/.

5. Summarize to the user

Short chat summary: top findings, blocked checks (with remediation links), next actions. Save raw JSON artifacts paths in the report for later re-analysis.

6. Auto-commit

After writing the report, delegate to the Gitea Agent to commit with a message like Remediation report: <action> for <target>. Do not push unless the user asks.


Remediation (gated)

When the user runs /remediation-tool remediate <upn> <action>:

  1. Confirm read-only context first: the skill must have recently run a check <upn> in this session (check /tmp/remediation-tool/{tenant}/user-breach/<slug>/ exists). If not, tell the user to run the check first.
  2. Display the exact action that will run (curl command, cmdlet name, parameters).
  3. Require explicit YES in chat — not approval via permission prompt. If the user types anything else, abort.
  4. Execute via Graph/Exchange REST. Capture response to a remediation log at /tmp/remediation-tool/{tenant}/remediation/<slug>-YYYY-MM-DDTHHMMSS.json.
  5. Update the user's report with a ## Remediation Actions section appending what was done and the result.

Allowed <action> values:

Action API Result
password-reset Graph PATCH /users/{upn} with new passwordProfile Forces sign-in; revokes refresh tokens
revoke-sessions Graph POST /users/{upn}/revokeSignInSessions Kills all active sessions
disable-forwarding Exchange REST Set-Mailbox -ForwardingAddress $null -ForwardingSmtpAddress $null -DeliverToMailboxAndForward $false Clears all forwarding
remove-inbox-rules Exchange REST Remove-InboxRule for each non-default rule Asks which to keep first
disable-account Graph PATCH /users/{upn} with accountEnabled: false Hard disable

Arguments

$ARGUMENTS — the full invocation text. Parse freely; common forms:

  • check john.trozzi@cascadestucson.com
  • sweep cascadestucson.com
  • signins cascadestucson.com --user megan.hiatt@cascadestucson.com --failed-only --days 30
  • consent-url cascadestucson.com
  • remediate megan.hiatt@cascadestucson.com password-reset

If the user's phrasing is loose ("check john's box at cascades", "who's being attacked"), infer intent from CONTEXT.md and session logs. Prefer asking one clarifying question to guessing.


Scope and references

  • Detailed check rubric: .claude/skills/remediation-tool/references/checklist.md
  • Permission/role gotchas + consent URLs: .claude/skills/remediation-tool/references/gotchas.md
  • Endpoint cheatsheet: .claude/skills/remediation-tool/references/graph-endpoints.md
  • Report template: .claude/skills/remediation-tool/templates/breach-report.md
  • Memory note on what the tool IS: .claude/memory/feedback_365_remediation_tool.md