Teams: support separate graphTenantId for cross-tenant Graph API access#67174
Teams: support separate graphTenantId for cross-tenant Graph API access#67174hddevteam wants to merge 6 commits into
Conversation
Greptile SummaryAdds All three inline findings are P2 and do not block merge. Confidence Score: 5/5Safe to merge; all findings are P2 style/improvement suggestions with no current production breakage. The cross-tenant token-provider plumbing is logically correct and well-scoped. Single-tenant behavior is unchanged. The three flagged items (error-result caching after removing the silent catch, undocumented federated-auth limitation, missing tests for the new cross-tenant path) are all quality/documentation concerns rather than defects in the changed code path. extensions/msteams/src/thread-parent-context.ts (error-caching behavior after fetchChannelMessage change), extensions/msteams/src/graph.ts and token.ts (missing test coverage for graphTenantId paths)
|
There was a problem hiding this comment.
Pull request overview
Adds cross-tenant Microsoft Graph token acquisition support for the bundled Microsoft Teams integration, so Bot Framework reply tokens and Graph API tokens can be issued from different Azure tenants when needed.
Changes:
- Introduces
graphTenantId/MSTEAMS_GRAPH_TENANT_IDand wires a dedicated Graph token provider into Teams runtime. - Improves channel thread context behavior (thread root resolution, mention-only thread replies, Graph error propagation, and an in-memory fallback cache).
- Hardens Teams webhook JSON parsing by repairing invalid escape sequences; extends runtime logging to forward structured
meta.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/plugins/runtime/runtime-logging.ts | Passes meta through runtime logger methods. |
| src/plugins/runtime/runtime-logging.test.ts | Adds tests ensuring logger meta is forwarded and shouldLogVerbose is re-exported. |
| src/plugin-sdk/msteams.ts | Re-exports resolveThreadSessionKeys via the Teams plugin SDK surface. |
| src/config/zod-schema.providers-core.ts | Adds graphTenantId to the Teams config schema. |
| src/config/types.msteams.ts | Documents and types the new graphTenantId config field. |
| extensions/msteams/src/token.ts | Resolves graphTenantId from config/env and returns it in secret credentials. |
| extensions/msteams/src/thread-message-cache.ts | Adds a simple in-memory per-thread message cache with TTL. |
| extensions/msteams/src/sdk-types.ts | Extends activity typing to include team.aadGroupId. |
| extensions/msteams/src/monitor.ts | Creates a dedicated Graph token provider when graphTenantId differs; switches webhook parsing to raw + repair middleware. |
| extensions/msteams/src/monitor.lifecycle.test.ts | Updates Express mocking for raw() and middleware count/order assertions. |
| extensions/msteams/src/monitor-handler/message-handler.ts | Uses graph token provider, adds mention-only thread handling, thread root resolution, and cache-based context fallback. |
| extensions/msteams/src/monitor-handler/message-handler.thread-parent.test.ts | Adds coverage for mention-only thread invocation and cache fallback behaviors. |
| extensions/msteams/src/monitor-handler/message-handler.test-support.ts | Extends test logger stub with warn. |
| extensions/msteams/src/monitor-handler.types.ts | Adds optional graphTokenProvider dependency. |
| extensions/msteams/src/graph.ts | Uses graphTenantId when resolving app-only Graph tokens. |
| extensions/msteams/src/graph-thread.ts | Removes silent error swallowing in fetchChannelMessage. |
| extensions/msteams/src/graph-thread.test.ts | Updates test to assert errors propagate. |
| extensions/msteams/src/tests/monitor-json-repair.test.ts | Adds regression tests for the JSON repair behavior. |
| docs/channels/msteams.md | Documents mention-only thread behavior and Graph permission requirement. |
| CHANGELOG.md | Adds changelog entry for the new cross-tenant Graph token acquisition support. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b782db1718
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
b782db1 to
38defac
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 38defaca07
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
Thanks for the context here. I swept through the related work, and this is now duplicate or superseded. Keep this PR open because the split-tenant Teams Graph idea is still not implemented on current main and the newer overlapping PR is not a safe superseding target, but this branch is not merge-ready: it needs a current-main rebase that preserves Teams cloud/serviceUrl and China Graph guard behavior plus redacted real split-tenant proof. Canonical path: Close this stale PR. The latest review rated it F, the branch still lacks merge-ready proof, and there has been no human follow-up after the durable review. So I’m closing this here because the remaining work is already tracked in the canonical issue. Review detailsBest possible solution: Close this stale PR. The latest review rated it F, the branch still lacks merge-ready proof, and there has been no human follow-up after the durable review. Do we have a high-confidence way to reproduce the issue? Partially. The missing capability is source-visible because current main has no Is this the best way to solve the issue? No, not yet. The Teams plugin is the right owner, but this branch must be rebased to preserve current cloud/serviceUrl boundaries and then proven against a real split-tenant setup. Security review: Security review needs attention: The diff is security-sensitive because the new Graph tenant override must not bypass existing Teams cloud/serviceUrl boundaries.
AGENTS.md: found and applied where relevant. What I checked:
Likely related people:
Codex review notes: model internal, reasoning high; reviewed against f3f8ca3d922c. |
0eb41ae to
6c36b1f
Compare
Add `graphTenantId` config field (and `MSTEAMS_GRAPH_TENANT_ID` env var) so the bot can acquire Bot Framework reply tokens and Graph API tokens from different Azure tenants. This enables thread context fetching when the bot app is registered in one Azure tenant but Teams/M365 data lives in a separate Microsoft 365 tenant. Changes: - `MSTeamsConfig.graphTenantId`: new optional field in config type + zod schema - `MSTeamsSecretCredentials.graphTenantId`: carry through credential resolution - `token.ts`: resolve graphTenantId from config or MSTEAMS_GRAPH_TENANT_ID env - `graph.ts`: use graphTenantId tenant when acquiring Graph-only token - `monitor.ts`: create dedicated graphTokenProvider App when tenants differ - `monitor-handler.types.ts`: add optional graphTokenProvider to handler deps - `message-handler.ts`: use effectiveGraphTokenProvider for thread context calls - `graph-thread.ts`: remove silent error catch in fetchChannelMessage so 403s surface to the caller's Promise.allSettled handler instead of silently returning undefined Co-authored-by: Copilot <[email protected]>
6c36b1f to
a07328f
Compare
|
ClawSweeper PR egg 🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat. Where did the egg go?
|
|
This pull request has been automatically marked as stale due to inactivity. |
|
ClawSweeper applied the proposed close for this PR.
|
Summary
Adds
graphTenantIdconfig field (andMSTEAMS_GRAPH_TENANT_IDenv var) to the Microsoft Teams provider so deployments where the bot app is registered in one Azure tenant but Teams/M365 data lives in a separate Microsoft 365 tenant can acquire tokens from the correct tenant for each operation.Problem
In multi-tenant deployments (bot app registered in Azure AD tenant A, Teams data in M365 tenant B), the existing code used the same Bot Framework
Appinstance to acquire both:This caused 403 errors on all Graph API calls (
ChannelMessage.Read.All, etc.), silently returning no thread context when a bot was @mentioned in a channel thread.Solution
MSTeamsConfig.graphTenantId: new optional config fieldMSTEAMS_GRAPH_TENANT_ID: env var fallback (same precedence pattern as existingTEAMS_TENANT_ID)monitor.ts: creates a dedicatedgraphTokenProviderBot FrameworkAppinstance usinggraphTenantIdwhen it differs fromtenantIdmessage-handler.ts: useseffectiveGraphTokenProvider = graphTokenProvider ?? tokenProviderfor all Graph API token acquisitions — no behavior change for single-tenant setupsgraph-thread.ts: removed silenttry/catchinfetchChannelMessageso Graph 403s propagate to thePromise.allSettledhandler in the message handler instead of returningundefinedsilentlyConfiguration
Single-tenant deployments (most users): no change needed.
Cross-tenant deployments — add to
openclaw.json:{ "providers": { "msteams": { "tenantId": "<azure-tenant-id>", "graphTenantId": "<m365-tenant-id>" } } }Or via environment:
MSTEAMS_GRAPH_TENANT_ID=<m365-tenant-id>Testing
pnpm test)pnpm checkclean (lint, type-check, import cycles)pnpm config:docs:gen)Checklist
pnpm checkclean