fix(provider-microsoft): cast contentId on polymorphic attachment $select (fixes #59)#60
Merged
stevenobiajulu merged 2 commits intomainfrom Apr 28, 2026
Merged
Conversation
…lect (#59) Microsoft Graph rejects `contentId` in `$select` against the polymorphic `microsoft.graph.attachment` base type — the property is declared on `microsoft.graph.fileAttachment`. PR #56 shipped the bare field, so every Outlook `getMessage()` call (read_email, list_attachments, get_thread, reply flows) throws HTTP 400. Source: cast the field — `microsoft.graph.fileAttachment/contentId`. Verified live against real Graph (HTTP 200, contentId populated). Tests: add a tiny inlined schema-validating mock with explicit allow-lists for base attachment props and approved type casts. Convert the three `getMessage`/`getThread` tests that hard-coded the broken URL to use it. PR #56's broken string would now fail unit tests instead of passing. Doc-link comments added to the source constant and the test allow-lists so future readers can verify the schema against the canonical Graph docs. Fixes #59.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Codex peer review on #60 surfaced two optional improvements; both applied: - Drop `microsoft.graph.fileAttachment/contentLocation` from ALLOWED_ATTACHMENT_CASTS. The provider never selects it and Graph documents it as unsupported on fileAttachment, so pre-whitelisting weakened the "future casts must be deliberate" guard. - Pin Graph Learn URLs with ?view=graph-rest-1.0 so the doc-link comments stop redirecting (and so the version lined up against the schema is explicit).
This was referenced Apr 28, 2026
Merged
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
Fix the regression introduced by #56 —
getMessage()throws HTTP 400 on every Outlook message becausecontentIdis rejected by$selectagainst the polymorphicmicrosoft.graph.attachmentbase. Cast the field tomicrosoft.graph.fileAttachment/contentIdand rebuild the broken tests on a tiny schema-validating mock.Fixes #59.
What changed
Source (
packages/provider-microsoft/src/email-graph-provider.ts)ATTACHMENT_SELECTnow usesmicrosoft.graph.fileAttachment/contentId. No other source edits — the existing 400 fallback stays as defensive infra for unrelated 400s and now uses a valid select string.attachmentandfileAttachmentresource docs.Tests (
packages/provider-microsoft/src/email-graph-provider.test.ts)createSchemaValidatingClienthelper that validates$selectfragments against an explicit allow-list (baseattachmentprops + approved type casts) and throws a Graph-realisticGraphApiError(400)for invalid fields. Narrow allow-list (not a regex) so typos likefileAttachment/notARealPropfail fast.getMessage/getThreadtests that hard-coded the broken URL (lines 99, 159/164, and 793 onmain) to use the validating client. PR fix(provider-microsoft): populate attachments on getMessage (fixes #55) #56's bare-contentIdstring would now fail at unit-test time.grep -n 'isInline,contentId' email-graph-provider.test.tsreturns zero hits.Why this would have caught #56
PR #56's tests asserted the literal broken URL with
vi.fn().mockResolvedValue(...). The mock returned whatever object the test handed it — no OData validation — so the wrong-string-as-spec passed. The new validating client checks every URL passed to.get()against the allow-list before delegating to the response queue, so the same regression now throws an unhandledGraphApiError 400in unit tests.Test plan
npm run buildnpm run lint --workspaces --if-presentnpm run check:spec-coverage(186/186 scenarios)npm run test:run(538 tests pass across 4 workspaces)GET /me/messages/{id}?$expand=attachments($select=…microsoft.graph.fileAttachment/contentId)returns HTTP 200 withcontentIdpopulated.dist/email-graph-provider.js, rangetMessage()against a real Outlook message with attachments, confirmedattachments[0].contentIdis a non-empty string.Out of scope (follow-up)
$selectconstructed byGraphEmailProviderthrough an extended schema validator.Refs