Commit 19acaef
authored
feat(teams): api primitive subpath + SSRF allowlist divergence (chat@4.31 8c71411) (#158)
* feat(teams): api primitive subpath + SSRF allowlist divergence (chat@4.31 8c71411)
Port the Teams Bot Connector API primitives (NEW in chat@4.31.0) as a
runtime-free subpath `chat_sdk.adapters.teams.api`, mirroring the
`slack/api/` layout: an injectable async `fetch` (lazy `httpx` default),
plain-dict activities, and no `microsoft_teams.*` / adapter imports.
Ports `resolve_teams_access_token` (client_credentials grant),
`call_teams_connector_api`, post/update/delete message, typing indicator,
`create_teams_conversation`, `build_teams_message_activity`, and
`TeamsApiError`.
SSRF / token-leak divergence: `call_teams_connector_api` gates `service_url`
through `is_trusted_teams_service_url` BEFORE attaching the Bearer token,
raising `ValueError` for any host outside the Bot Framework allowlist (the
same `ALLOWED_SERVICE_URL_PATTERNS` the high-level adapter uses). Upstream
attaches the token to any caller-supplied `serviceUrl` with no host check.
Documented as an append-only Known Non-Parity row in docs/UPSTREAM_SYNC.md.
Tests: 13 faithful ports of `api/index.test.ts` + a source-scan boundary
test (port of `api/boundary.test.ts`) + SSRF divergence/adversarial cases,
all with an injected AsyncMock fetch. The lazy `teams/__init__.py` subpath
registration is deferred to the packaging PR.
* feat(teams): export assert_teams_ok + TeamsContinuationContext from api primitive
Restore two public exports the api primitive omitted from upstream
chat@4.31.0's api/client.ts / api/messages.ts:
- Port assertTeamsOk -> assert_teams_ok (no-op for 2xx; raises TeamsApiError
carrying the parsed body + status otherwise), add to __all__.
- Define + export TeamsContinuationContext (conversation_id + service_url
required, optional addressing hints) to match upstream's exported surface.
Tests:
- assert_teams_ok: passes silently for 2xx/204, raises with body+status on 403.
- TeamsContinuationContext: required/optional field surface.
- SSRF: subdomain-suffix lookalike host
(smba.uk.botframework.com.attacker.example) is rejected by the anchored
allowlist before any token fetch (proves the .com/ boundary anchor, not a
loose suffix match).
- SSRF: empty-string access_token falls through to client-credentials and
raises the credentials-required error (upstream truthiness parity); no
token request issued.
Allowlist unchanged. UPSTREAM_SYNC SSRF row already documents the lookalike
rejection; the new exports are upstream-parity (not divergences).1 parent b0246e9 commit 19acaef
3 files changed
Lines changed: 1206 additions & 0 deletions
File tree
- docs
- src/chat_sdk/adapters/teams/api
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
652 | 652 | | |
653 | 653 | | |
654 | 654 | | |
| 655 | + | |
655 | 656 | | |
656 | 657 | | |
657 | 658 | | |
| |||
0 commit comments