Commit 2676f0b
authored
* build(teams): add microsoft-teams-apps SDK to the teams extra (#93 PR 1 foundation)
Adds microsoft-teams-apps/-api/-cards >=2.0.13 to the [teams] extra for the Teams adapter migration to the official MS SDK (mirrors upstream adapter-teams@4.30.0). Graph stays hand-rolled (no [graph] extra / msgraph-sdk). Verified the SDK's TokenValidator (apps/auth/token_validator.py) validates RS256 + audience(app_id + api:// variants) + issuer(api.botframework.com) via the Bot Framework JWKS — equivalent-or-stronger than the hand-rolled _verify_bot_framework_token block it will replace.
* feat(teams): migrate inbound + auth to microsoft-teams-apps SDK (#93 PR 1/4)
Rewire the Teams adapter's inbound webhook path and JWT authentication to
delegate to the official microsoft-teams-apps Python SDK, mirroring upstream
adapter-teams@chat@4.30.0. Outbound (post/edit/delete/typing), native
streaming, and the Graph reader stay hand-rolled (PRs 2/3 + a separate
decision).
New: src/chat_sdk/adapters/teams/bridge.py
- BridgeHttpAdapter implements the SDK HttpServerAdapter protocol. It captures
the route handler the App registers during app.initialize(), exposes an async
dispatch(request, options) for handle_webhook to call, and owns a per-activity
WebhookOptions map (keyed by activity id, cleared in finally). Framework
agnostic — body/header extraction duck-types across web frameworks; response
shaping returns the {body, status, headers} dict consumers expect. Port of
upstream bridge-adapter.ts.
adapter.py:
- Construct the SDK App from TeamsAdapterConfig via _to_app_options (port of
config.ts toAppOptions): app_id/app_password/app_tenant_id/federated/app_type
-> client_id/client_secret/tenant_id/managed_identity_client_id, with the same
TEAMS_* env fallbacks. Inject the bridge; stamp client User-Agent
"Vercel.ChatSDK".
- initialize() registers SDK handlers (on_message/on_message_reaction/
on_card_action/on_dialog_open/on_dialog_submit/on_conversation_update/
on_install_add/remove), awaits app.initialize(), and overrides
server.on_request with _dispatch_activity.
- handle_webhook now delegates to bridge.dispatch. Inbound JWT validation is
performed by the SDK's TokenValidator (RS256 + audience app_id/api:// variants
+ Bot Framework issuer/JWKS), enforced by default (skip_auth=False). Deleted
the hand-rolled _verify_bot_framework_token / _jwks_client / openid-config
fetch / BOT_FRAMEWORK_OPENID_CONFIG_URL and the now-unused request/response
helpers (body/header extraction + response shaping live in the bridge).
- _handle_teams_error (port of errors.ts handleTeamsError) now maps both the
plain dicts the hand-rolled Graph/outbound path raises and the SDK's typed
exceptions (status on inner_http_error.status_code / status_code / retry_after)
onto AuthenticationError / AdapterPermissionError / AdapterRateLimitError /
NetworkError.
Divergence (SDK-forced, documented in docs/UPSTREAM_SYNC.md): the SDK's default
on_request runs strict per-activity validation + a live token fetch before any
handler. We keep the SDK as the auth + transport layer but route the
already-authenticated lenient CoreActivity ourselves so minimal serverless
payloads and the existing dict-based handler logic keep working unchanged.
Tests: add tests/test_teams_bridge.py (protocol conformance, dispatch happy/
error paths, WebhookOptions lifecycle, body/header extraction). Rework the
JWT-bypass fixtures to force the SDK's own skip_auth instead of patching the
deleted method; add TestSdkInboundAuth asserting the SDK rejects unauthenticated
/ bad-token / unconfigured requests. Add _to_app_options and SDK-exception
error-mapping tests. Point the shared body-extraction test at
BridgeHttpAdapter._read_body.
Public Adapter contract and create_teams_adapter(TeamsAdapterConfig(...))
unchanged. Gauntlet green: ruff/format/audit clean, pyrefly 0 errors,
4793 passed / 3 skipped.
* build(teams): install Teams SDK in dev group + all extra; pyrefly any-list (#143 CI fix)
PR-1's Teams SDK deps were only in the [teams] extra, but CI runs 'uv sync --group dev' — so the SDK was absent at test time and test_teams_bridge.py's module-level import aborted collection of the whole 4793-test suite. Adds microsoft-teams-apps/-api/-cards to the dev group and the all extra, plus pyrefly replace-imports-with-any. Verified: full collection 4796 tests (no abort), teams suites 187 passed.
1 parent 576ecbf commit 2676f0b
10 files changed
Lines changed: 1192 additions & 303 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
610 | 610 | | |
611 | 611 | | |
612 | 612 | | |
| 613 | + | |
| 614 | + | |
613 | 615 | | |
614 | 616 | | |
615 | 617 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
55 | | - | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
56 | 63 | | |
57 | 64 | | |
58 | 65 | | |
| |||
68 | 75 | | |
69 | 76 | | |
70 | 77 | | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
71 | 81 | | |
72 | 82 | | |
73 | 83 | | |
| |||
123 | 133 | | |
124 | 134 | | |
125 | 135 | | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
126 | 141 | | |
127 | 142 | | |
128 | 143 | | |
| |||
166 | 181 | | |
167 | 182 | | |
168 | 183 | | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
169 | 187 | | |
170 | 188 | | |
171 | 189 | | |
| |||
0 commit comments