feat(m365): establish Breeze control plane foundation#2495
Merged
Conversation
Deploying breeze with
|
| Latest commit: |
416d8d6
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://abccf6c1.breeze-9te.pages.dev |
| Branch Preview URL: | https://agent-m365-control-plane-fou.breeze-9te.pages.dev |
ToddHebebrand
marked this pull request as ready for review
July 16, 2026 04:08
ToddHebebrand
force-pushed
the
agent/m365-control-plane-foundation
branch
from
July 16, 2026 04:12
ecf4597 to
11c9433
Compare
added 7 commits
July 15, 2026 22:20
ToddHebebrand
force-pushed
the
agent/m365-control-plane-foundation
branch
from
July 16, 2026 04:21
11c9433 to
416d8d6
Compare
ToddHebebrand
added a commit
that referenced
this pull request
Jul 16, 2026
## Summary Adds Breeze-owned, customer-tenant Microsoft 365 Graph Read consent and lifecycle management on top of the M365 control-plane foundation. - defines the canonical least-privilege permission manifest and shared executor contracts - stores organization-scoped consent sessions and connection lifecycle state with RLS and compare-and-set protections - adds the public admin-consent/identity callback flow with one-time browser binding, tenant/admin verification, and audit attribution - isolates credentials and Microsoft Graph access in a private, narrowly scoped executor - adds connect, re-consent, status, drift, retest, suspend/revoked, and local-disconnect UI states - ships Compose, release, supply-chain, deployment, and disposable-tenant validation guidance ## Why This keeps Breeze as the approval and orchestration control plane while isolating customer-tenant Graph credentials and execution. It avoids making Delegant a second general authentication control plane and provides a safe foundation for future approval-tiered M365 tools. ## Security and correctness The final two-pass security review and independent whole-branch review are clean. Follow-up tests and fixes cover: - local disconnect preserving the database-valid manifest while clearing binding state - query-free request logging for OAuth callback artifacts - callback audit attribution to the initiating user only after trusted session validation - serialized retest generations so stale completions cannot overwrite newer results - fixed own-service-principal proof so permission removal reaches last-known/unavailable reconciliation - correct unknown versus last-known grant health across executor, API, and UI - nullable unknown grant names and revoked client identity across API/UI contracts - retest controls only for executable lifecycle states ## Validation - latest-HEAD focused suites: shared 10/10, executor 185/185, API 299/299, web 90/90 - real-role PostgreSQL RLS/lifecycle suites: 16/16; disconnect lifecycle regression: 3/3 - full shared suite: 1,212/1,212 - full web suite with Node 26 experimental web storage disabled: 3,750/3,750 - API, web, and executor lint/typecheck/build gates passed - migration replay: 339 migrations; drift ledger: 404 files - docs build: 146 pages - supply-chain hardening, executor Docker build, and production Compose configuration passed The local full API regression run completed with 13,436 passes, 31 failures, and 71 skips; the failures were unrelated timeout/load failures in existing OAuth/MCP/metrics/encryption/partner-route suites. The complete M365-focused API suite and API lint/typecheck/build gates are green. Live Microsoft consent and disposable-tenant permission mutation were not run because dedicated tenant/executor/Azure credentials were not present. The runbook scopes those checks to a disposable tenant. ## Dependency This is a stacked draft PR based on #2495 (`agent/m365-control-plane-foundation`). Review and merge #2495 first; GitHub will then reduce this PR to the Graph Read phase. Delegant removal is intentionally out of scope until Breeze-owned consumers are migrated. --------- Co-authored-by: Todd Hebebrand <todd@lanternops.io>
ToddHebebrand
added a commit
that referenced
this pull request
Jul 16, 2026
Technical-docs sweep for the **v0.96.0** release (range `v0.95.1..main`). Companion to the tagged release; no code changes, docs + docs-review mapping only. ## Pages updated - **TD SYNNEX AI tool** — `features/mcp-server.mdx`, `features/ai.mdx`, `features/distributor-integrations.mdx`: new `lookup_distributor_product` (Tier 2 / `ai:write`; live EC Express price+availability; reseller cost redacted for org-scoped callers, error+no outbound call when no partner in context) (#2559) - **M365 customer Graph-read host config** — `deploy/environment.mdx` new "Customer Microsoft 365 Graph-read consent (optional)" section: 9 env vars, **all required only when `M365_CUSTOMER_GRAPH_READ_ONBOARDING_ENABLED=true`** (dark by default); `deploy/production.mdx` optional `m365-graph-read-executor` sidecar note; `features/identity-integrations.mdx` pointer (#2495, #2511) - **Quotes** — `features/quotes.mdx`: cloning, change-customer-on-draft, per-table subtotals, customer bill-to "Prepared for" block, optional send message, click-to-zoom, Pax8-order-on-acceptance cross-link (#2535, #2584, #2549) - **Backups** — `backup/overview.mdx` (per-device "Run backup now", timezone-correct next-run, `breeze-backup` helper now bundled by shell-script installs), `backup/restoring.mdx` (System image badge, mode+mtime + system-image restore), `backup/verification.mdx` (integrity = size+SHA-256 vs manifest, real corruption detection) (#2558, #2564, #2581) - **Enrollment keys** — `agents/enrollment-keys.mdx`: required Site selector on create form (#2557) ## Mapping / tracker - `scripts/docs-review/mapping.json`: repoint pax8 → `distributor-integrations.mdx`; add `pax8Orders`, `pax8Order*`, `quoteToPax8Order`, `aiToolsCatalog`, `m365ControlPlane/**`, `runtimeConfig.ts`→environment, `m365CustomerGraphRead`/`m365ConsentCallback`, `apps/m365-graph-read-executor/**`, quote pdf/email services, `agent/scripts/install/**` - `scripts/docs-review/last-reviewed.json`: bumped to `20276393e` (2026-07-16) ## Verification notes - The M365 consent **callback URL derives from `PUBLIC_URL`** in the API; the `..._CALLBACK_URL` env var is consumed by the **executor app**, not the API — documented accordingly (not as dead config). - The `m365-graph-read-executor` sidecar is **published (GHCR) but not wired into the tracked compose files** — documented as such, not as a turnkey service. - `apps/docs` `astro build` passes. Intentionally **skipped** (no admin/integrator doc surface): versioned extension contract #2548 (developer-only SDK), Windows helper RDS lifecycle #2520 (internal agent fix), backup execution/result-recording internals #2554/#2556. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Todd Hebebrand <todd@lanternops.io> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ToddHebebrand
added a commit
that referenced
this pull request
Jul 18, 2026
…ion (#2615) ## Summary First consumer value from the M365 control plane (#2495/#2511): a closed, typed catalog of 12 Microsoft Graph **read** actions on the `customer-graph-read` connection, exposed as six `m365_query_*` AI tools (in-app chat + Breeze MCP). Risk-tier T1 only — no mutations, no approval layer, no manifest bump (all actions fit the already-consented manifest v2), and **zero DB migrations**. - **Shared contracts** (`packages/shared/src/m365/readActions.ts`): 12-action Zod discriminated union with bounded params, per-action field-projection allowlists, and typed failure codes. - **Executor** (`m365-graph-read-executor`): one new bounded op `POST /v1/read-action` (same Ed25519 body-hash-bound internal auth), fixed Graph URL templates, status-aware error mapping (license-403 vs permission-403, 404, 429 w/ bounded Retry-After), truncate-don't-throw pagination, projection so no non-allowlisted field ever leaves the executor. Credentials still never cross the boundary. - **API** (`m365ControlPlane/readActionService.ts`): authz ladder — site-restriction gate (`allowedSiteIds`), org resolution, `M365_GRAPH_READ_TOOLS_ENABLED` + org allowlist (boot-validated), connection state (`active`/`degraded` only), fail-closed Redis budget (30/min, 2,000/day per connection), executor call, audit (fixed 4-key metadata, never Graph payloads) + `breeze_m365_graph_read_actions_total{action,outcome}`. - **AI tools**: six tools registered across all gate surfaces (aiTools hub, guardrails, input schemas, system prompt, chat-SDK `TOOL_TIERS`/MCP server) with cap-accurate descriptions. - **Docs**: deploy env vars + read-action acceptance section (R1–R5) in the real-tenant runbook. Ships **dark**: `M365_GRAPH_READ_TOOLS_ENABLED=false` by default; deploy-order safe in both directions (old executor 404 → `executor_unavailable`). Spec: `docs/superpowers/specs/2026-07-18-m365-typed-graph-read-tools-design.md` · Plan: `docs/superpowers/plans/2026-07-18-m365-typed-graph-read-tools.md` ## Review Subagent-driven build: per-task spec+quality reviews on every task, plus a final whole-branch review (verdict: ready to merge). Notable catches fixed along the way: Zod v4 `z.record` arity, site-gate signal corrected to `allowedSiteIds` (`canAccessSite` is always defined for org scope), chat-SDK tool registration drift, boot validation of the tools allowlist. ## Verification - Shared 1,259/1,259 · executor 240/240 · API 14,927 passed (0 failed) — full suites - `tsc --noEmit` clean (API + executor + shared), eslint clean, `git diff --check` clean - Real-tenant read-action acceptance checklist added to the runbook (to run at rollout, tenant-side) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Todd Hebebrand <todd@lanternops.io> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
legacy-directprofileSecurity and rollout boundaries
put/getonly. Azure name-wide deletion is deferred until a DB-backed lifecycle workflow can load the authoritative row and serialize against rotation.m365_connections_org_uniqare temporarily retained because production applies migrations before replacing the old API, whose upsert targetsorg_id.Verification
pnpm install --frozen-lockfilebreeze_appwithNOBYPASSRLS--noEmitpassedimport.metawarning insrc/db/seed.ts)git diff --checkpassedKnown unrelated repository gate
The repository-wide RLS coverage run on the clean current-
main-based branch remains 52/53 because the existing dynamicpax8_orders/pax8_order_linesorg-vs-partner classification check fails against the shared test database state. This branch does not modify Pax8 or RLS coverage classification files; focused M365 RLS verification is green.