Skip to content

fix(msteams): route file.download.info links via graph shares#85845

Closed
IWhatsskill wants to merge 1 commit into
openclaw:mainfrom
IWhatsskill:fix/msteams-download-info-graph-shares-67177
Closed

fix(msteams): route file.download.info links via graph shares#85845
IWhatsskill wants to merge 1 commit into
openclaw:mainfrom
IWhatsskill:fix/msteams-download-info-graph-shares-67177

Conversation

@IWhatsskill

@IWhatsskill IWhatsskill commented May 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Problem: MSTeams application/vnd.microsoft.teams.file.download.info attachments can expose SharePoint/OneDrive downloadUrl values that require Graph auth, but the download path used those URLs directly.
  • Solution: Route eligible downloadUrl values through the existing Graph shares URL helper before downloading.
  • What changed: resolveDownloadCandidate() now applies tryBuildGraphSharesUrlForSharedLink() to file.download.info downloadUrl values, and a regression test locks the Graph-only allowlist/auth path.
  • What did NOT change (scope boundary): This does not change non-SharePoint download URLs, inline image handling, logging behavior, or the broader MSTeams media-drop issue tracked separately.

Motivation

  • Closes a P1 MSTeams message-loss workflow where DM file attachments can resolve only to a placeholder because the raw SharePoint/OneDrive URL is skipped or cannot authenticate through the existing media downloader.
  • This is a narrow follow-up to the existing Graph shares behavior that already existed for the contentUrl path.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: MSTeams file.download.info SharePoint/OneDrive downloadUrl attachments now resolve through https://graph.microsoft.com/v1.0/shares/.../driveItem/content instead of trying to fetch the raw SharePoint URL directly.

  • Real environment tested: Disposable OpenClaw checkout on a Linux testserver under /root/openclaw-pr-tests/runs/2026-05-23-msteams-download-info-67177/repo, base f6204d081fc35574c86c0df36fed0cced43db8ef, Node v22.22.2, pnpm 11.2.2.

  • Exact steps or command run after this patch:

    • node scripts/run-vitest.mjs extensions/msteams/src/attachments.test.ts -t 'routes file.download.info SharePoint downloadUrl through Graph shares endpoint'
    • node scripts/run-vitest.mjs extensions/msteams/src/attachments.test.ts extensions/msteams/src/attachments/shared.test.ts
    • corepack pnpm exec oxfmt --check --threads=1 extensions/msteams/src/attachments/download.ts extensions/msteams/src/attachments.test.ts
    • pnpm check:changed --base origin/main
    • git diff --check
  • Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output): Copied terminal output from the disposable OpenClaw checkout after applying this patch:

    $ node scripts/run-vitest.mjs extensions/msteams/src/attachments.test.ts -t 'routes file.download.info SharePoint downloadUrl through Graph shares endpoint'
    1 passed, 20 skipped
    
    $ node scripts/run-vitest.mjs extensions/msteams/src/attachments.test.ts extensions/msteams/src/attachments/shared.test.ts
    2 files passed, 72 tests passed
    
    $ corepack pnpm exec oxfmt --check --threads=1 extensions/msteams/src/attachments/download.ts extensions/msteams/src/attachments.test.ts
    all matched files correctly formatted
    
    $ pnpm check:changed --base origin/main
    passed: extensions typecheck, extensions lint, media download helper guard, runtime sidecar loader guard, runtime import-cycle guard
    
    $ git diff --check
    passed
    
  • Observed result after fix: The regression run saved a PDF media item from the MSTeams attachment path. Every fetched URL started with https://graph.microsoft.com/v1.0/shares/, and the Graph token provider was called. The raw SharePoint host was not fetched in the Graph-only allowlist/auth setup.

  • What was not tested: A live Teams tenant and real SharePoint file download were not replayed. This PR does not claim to fix unrelated inline image or broader DM media-drop paths.

  • Before evidence (optional but encouraged): Copied terminal output from the same disposable checkout with only the new regression test applied to the old production code:

    $ node scripts/run-vitest.mjs extensions/msteams/src/attachments.test.ts -t 'routes file.download.info SharePoint downloadUrl through Graph shares endpoint'
    AssertionError: expected [] to have a length of 1 but got +0
    

Root Cause (if applicable)

  • Root cause: resolveDownloadCandidate() had already learned to normalize SharePoint/OneDrive shared contentUrl values through Graph shares, but the application/vnd.microsoft.teams.file.download.info branch returned content.downloadUrl directly.
  • Missing detection / guardrail: No regression test covered a file.download.info attachment where only graph.microsoft.com was allowed/authenticated and the source downloadUrl was a SharePoint shared link.
  • Contributing context (if known): PR fix(msteams): fetch OneDrive/SharePoint shared media via Graph shares endpoint (#55383) #63942 fixed the related contentUrl path, but the Teams-specific downloadUrl branch remained outside that guardrail.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: extensions/msteams/src/attachments.test.ts
  • Scenario the test should lock in: A Teams file.download.info attachment with a SharePoint downloadUrl should be rewritten to the Graph shares endpoint, use Graph auth, and save the downloaded document media.
  • Why this is the smallest reliable guardrail: It exercises the MSTeams attachment resolver and downloader behavior around host allowlists, auth allowlists, token selection, and persistence without needing live tenant credentials.
  • Existing test that already covers this (if any): Existing shared-link tests covered contentUrl, not the file.download.info downloadUrl branch.
  • If no new test is added, why not: N/A. A new regression test is added.

User-visible / Behavior Changes

MSTeams DM file attachments that arrive as file.download.info with SharePoint/OneDrive download URLs can now download through the existing Graph shares flow when Graph auth is configured, producing actual inbound media instead of only a placeholder.

Diagram (if applicable)

Before:
Teams file.download.info -> raw SharePoint downloadUrl -> media fetch/auth fallback -> empty media result

After:
Teams file.download.info -> Graph shares URL -> Graph auth fetch -> stored inbound document media

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) Yes
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: Eligible Teams file download links are normalized to the existing Graph shares content endpoint instead of the raw SharePoint/OneDrive URL. This reuses the existing Graph auth fallback and existing media host allowlist/auth-allowlist checks; it does not introduce a new token source or broaden file access beyond the configured Graph permissions.

Repro + Verification

Environment

  • OS: Linux disposable testserver checkout
  • Runtime/container: Node v22.22.2, pnpm 11.2.2
  • Model/provider: N/A
  • Integration/channel (if any): MSTeams attachment download path
  • Relevant config (redacted): Regression test configured media allow/auth hosts to permit graph.microsoft.com for the download path.

Steps

  1. Add the regression test for a file.download.info attachment carrying a SharePoint downloadUrl.
  2. Run the focused test before the production change to confirm the old path returns no media.
  3. Apply the production change to rewrite eligible downloadUrl values through Graph shares.
  4. Run focused, adjacent, formatting, and changed-workspace checks.

Expected

  • The Teams file.download.info SharePoint/OneDrive downloadUrl is fetched through the Graph shares endpoint with Graph auth and produces a stored document media item.

Actual

  • Before the fix, the focused regression test returned an empty media list.
  • After the fix, the focused regression test produced the expected PDF media item and all validation commands passed.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

The required copied terminal output is included directly in the Real behavior proof section above so the PR-body gate can evaluate it.

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: I verified the exact old failure and new success in a disposable checkout by running the focused regression test red against the old production code and green after this patch. I also verified adjacent MSTeams attachment/shared-link tests, formatting, changed-workspace checks, and whitespace checks.
  • Edge cases checked: The new test constrains the media host/auth path to Graph and asserts that fetched URLs use the Graph shares endpoint instead of the raw SharePoint URL.
  • What you did not verify: I did not replay a live Teams tenant upload with real SharePoint credentials, and I did not verify unrelated inline image attachment paths.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

No review conversations exist yet for this new draft PR.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: A live tenant could expose a Teams downloadUrl shape not represented by the regression fixture.
    • Mitigation: The production change uses the existing shared-link parser and falls back to the original downloadUrl when the URL cannot be converted.
  • Risk: This fix may be mistaken for a complete fix for all MSTeams media drops.
    • Mitigation: The PR scope is explicitly limited to the file.download.info downloadUrl branch and does not claim broader inline image coverage.

@openclaw-barnacle openclaw-barnacle Bot added channel: msteams Channel integration: msteams size: XS triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels May 23, 2026
@clawsweeper

clawsweeper Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 24, 2026, 12:17 PM ET / 16:17 UTC.

Summary
The PR rewrites MSTeams file.download.info SharePoint/OneDrive downloadUrl candidates through the existing Graph shares helper and adds a focused regression test.

PR surface: Source +1, Tests +33. Total +34 across 2 files.

Reproducibility: yes. at source level. Current main treats file.download.info attachments as downloadable but returns the raw SharePoint/OneDrive downloadUrl, while the sibling shared-link branch already rewrites through Graph shares; I did not run a live Teams tenant replay.

Review metrics: 1 noteworthy metric.

  • Network Target Rewrite: 1 attachment branch changed. Eligible file.download.info SharePoint/OneDrive URLs now fetch through graph.microsoft.com, which maintainers should evaluate against restrictive custom media/auth host allowlists.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #67177
Summary: This PR is the open fix candidate for the canonical MSTeams file.download.info downloadUrl Graph shares gap; the older merged Graph shares PR fixed only the adjacent shared-link/contentUrl path.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🦞 diamond lobster
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add redacted live Teams/SharePoint logs, terminal output, recording, or a linked artifact showing a real file.download.info attachment fetching through Graph shares and saving inbound document media.
  • [P1] Clarify whether restrictive custom mediaAllowHosts or mediaAuthAllowHosts configurations must include graph.microsoft.com for this path.
  • After adding proof, update the PR body so ClawSweeper re-reviews automatically; if it does not, ask a maintainer to comment @clawsweeper re-review.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body supplies copied mocked regression/check output and explicitly says no live Teams tenant or real SharePoint file download was replayed, so contributor-side real behavior proof is still needed before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Mantis proof suggestion
A redacted real Teams DM attachment run or runtime-log proof would materially reduce the remaining live-tenant uncertainty. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis visual task: verify that a Teams DM file.download.info PDF attachment fetches via Graph shares and is saved as inbound document media with private details redacted.

Risk before merge

  • [P1] The PR proof is still mocked regression/check output; it does not show a real Teams tenant and SharePoint/OneDrive file.download.info attachment downloading after the patch.
  • [P1] Eligible SharePoint/OneDrive file.download.info downloads move from tenant hosts to graph.microsoft.com, so deployments with restrictive custom mediaAllowHosts or mediaAuthAllowHosts may need Graph explicitly allowed even though defaults include Graph.
  • [P1] The PR is still draft, so final merge review should refresh after the contributor marks it ready and adds proof.

Maintainer options:

  1. Require Live Graph And Allowlist Proof (recommended)
    Ask for redacted live Teams/SharePoint or runtime-log proof that a real file.download.info attachment downloads through Graph shares, plus explicit guidance for restrictive custom allowlists.
  2. Accept Existing Graph Precedent
    Maintainers may intentionally accept the compatibility risk because the adjacent contentUrl SharePoint path already uses Graph shares and default media/auth allowlists include Graph hosts.
  3. Pause The Draft
    If live proof or allowlist guidance is not available, keep the linked issue canonical and leave this draft PR paused rather than merging a proof-gated channel change.

Next step before merge

  • [P1] Needs contributor-side live proof plus maintainer compatibility judgment; there is no narrow code repair for automation to perform on the current patch.

Security
Cleared: No concrete security or supply-chain regression found; the patch reuses the existing Graph shares helper, guarded fetch path, token provider, and host allowlists.

Review details

Best possible solution:

Keep the narrow resolver/test change, require redacted live Teams/SharePoint proof, and clarify the graph.microsoft.com allowlist expectation before merge.

Do we have a high-confidence way to reproduce the issue?

Yes, at source level. Current main treats file.download.info attachments as downloadable but returns the raw SharePoint/OneDrive downloadUrl, while the sibling shared-link branch already rewrites through Graph shares; I did not run a live Teams tenant replay.

Is this the best way to solve the issue?

Yes for the code shape. Reusing tryBuildGraphSharesUrlForSharedLink() in the missing resolver branch is the narrow maintainable fix, but merge readiness still needs live proof and allowlist compatibility handling.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 3217165be770.

Label changes

Label justifications:

  • P1: The PR targets a user-facing MSTeams inbound file attachment workflow where usable media can be dropped before reaching the agent.
  • merge-risk: 🚨 compatibility: The diff changes eligible file-download targets to graph.microsoft.com, which can affect deployments with restrictive custom media/auth host allowlists.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🦞 diamond lobster.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body supplies copied mocked regression/check output and explicitly says no live Teams tenant or real SharePoint file download was replayed, so contributor-side real behavior proof is still needed before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +1, Tests +33. Total +34 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 2 1 +1
Tests 1 33 0 +33
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 35 1 +34

What I checked:

Likely related people:

  • sudie-codes: Authored the merged Graph shares helper and adjacent contentUrl rewrite that this PR reuses for the missing file.download.info branch. (role: prior Graph shares feature contributor; confidence: high; commits: 526cb5943b09, 4fc5016f8fd2; files: extensions/msteams/src/attachments/download.ts, extensions/msteams/src/attachments/shared.ts, extensions/msteams/src/attachments.test.ts)
  • BradGroux: Merged the prior Graph shares PR and authored follow-up commits in that PR around the allowlist and typed fetch assertions for the same attachment path. (role: merger and adjacent contributor; confidence: medium; commits: 0bbb8a1be4c8, 8c12de2eb55b, 4fc5016f8fd2; files: extensions/msteams/src/attachments/download.ts, extensions/msteams/src/attachments.test.ts)
  • vincentkoc: Live PR metadata shows this PR assigned to Vincent Koc; shallow local blame also points current MSTeams attachment files at recent Vincent-authored history, though the grafted checkout limits full provenance. (role: assigned follow-up owner; confidence: medium; commits: e9720c27fa; files: extensions/msteams/src/attachments/download.ts, extensions/msteams/src/attachments/shared.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels May 23, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels May 23, 2026
@clawsweeper

clawsweeper Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat.

Where did the egg go?
  • The egg game starts only after the PR passes the real-behavior proof check.
  • Before that, no creature or rarity is rolled. The treat waits for real proof.
  • This is still just collectible flavor: proof affects review readiness, not creature quality.

@openclaw-barnacle

Copy link
Copy Markdown

This assigned pull request has been automatically marked as stale after being open for 27 days.
Please add updates or it will be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: msteams Channel integration: msteams merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P1 High-priority user-facing bug, regression, or broken workflow. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XS stale Marked as stale due to inactivity status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[msteams] Inbound file attachments silently fail in DMs — file.download.info downloadUrl not rewritten to Graph shares endpoint

2 participants