Skip to content

feat(m365): establish Breeze control plane foundation#2495

Merged
ToddHebebrand merged 7 commits into
mainfrom
agent/m365-control-plane-foundation
Jul 16, 2026
Merged

feat(m365): establish Breeze control plane foundation#2495
ToddHebebrand merged 7 commits into
mainfrom
agent/m365-control-plane-foundation

Conversation

@ToddHebebrand

Copy link
Copy Markdown
Collaborator

Summary

  • establish Breeze as the canonical M365 control-plane metadata authority for organization-owned customer administration and user-owned communications
  • add exact, versioned permission profiles for delegated communications, Graph read/actions, and Exchange PowerShell executors
  • add an executor-only Azure Key Vault credential provider with strict domain/material/reference validation and no API-layer secret access
  • keep legacy direct Graph routes compatible while selecting only the legacy-direct profile
  • add forced dual-axis RLS, owner/profile constraints, GUID tenant binding, and real-role isolation coverage
  • document the Breeze control-plane / narrow-executor architecture and Delegant consolidation path

Security and rollout boundaries

  • Personal communications connections are self-or-system only; partner-wide and same-organization tenancy grants do not expose another user's mailbox/Teams metadata.
  • The credential provider exposes version-pinned put/get only. Azure name-wide deletion is deferred until a DB-backed lifecycle workflow can load the authoritative row and serialize against rotation.
  • This is the expand release: legacy discriminator defaults and m365_connections_org_uniq are temporarily retained because production applies migrations before replacing the old API, whose upsert targets org_id.
  • A mandatory contract migration must remove that compatibility index/defaults before any writer creates a second organization-owned profile.

Verification

  • pnpm install --frozen-lockfile
  • focused M365 suite: 5 files, 48 tests passed
  • fresh-database M365 RLS integration: 5/5 passed as breeze_app with NOBYPASSRLS
  • fresh-database migration checksum/application check passed
  • focused ESLint passed
  • TypeScript --noEmit passed
  • API build passed (retains the existing CJS import.meta warning in src/db/seed.ts)
  • git diff --check passed
  • independent final code review: approved after rollout, RLS, lockfile, and credential-delete follow-ups

Known unrelated repository gate

The repository-wide RLS coverage run on the clean current-main-based branch remains 52/53 because the existing dynamic pax8_orders / pax8_order_lines org-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.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 14, 2026

Copy link
Copy Markdown

Deploying breeze with  Cloudflare Pages  Cloudflare Pages

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

View logs

@ToddHebebrand
ToddHebebrand marked this pull request as ready for review July 16, 2026 04:08
@ToddHebebrand
ToddHebebrand force-pushed the agent/m365-control-plane-foundation branch from ecf4597 to 11c9433 Compare July 16, 2026 04:12
@ToddHebebrand
ToddHebebrand force-pushed the agent/m365-control-plane-foundation branch from 11c9433 to 416d8d6 Compare July 16, 2026 04:21
@ToddHebebrand
ToddHebebrand merged commit d8a1fff into main Jul 16, 2026
42 checks passed
@ToddHebebrand
ToddHebebrand deleted the agent/m365-control-plane-foundation branch July 16, 2026 04:30
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant