Skip to content

feat(extensions): serve local media in Flex viewer canvas + bundled MCP server - #8

Merged
pierre3 merged 1 commit into
mainfrom
feat-flex-preview-extension-local-media
Sep 4, 2026
Merged

feat(extensions): serve local media in Flex viewer canvas + bundled MCP server#8
pierre3 merged 1 commit into
mainfrom
feat-flex-preview-extension-local-media

Conversation

@pierre3

@pierre3 pierre3 commented Sep 4, 2026

Copy link
Copy Markdown
Owner

概要

Flex プレビューのローカルメディア配信LINE_FLEX_MCP_ASSET_DIR 配下の画像/動画を相対 url で参照)を、これまで対応していなかった Copilot キャンバス拡張(extension.mjs)と同梱 Node MCP サーバ(mcp/server.mjs に移植し、.NET Tools(FlexPreviewService)との機能 parity を取りました。

これまで両 Node サーバは静的ファイル whitelist + /api/* のみ配信し、相対 url のメディアは 404 でした(.NET MCP 経由のみ配信可=非対称)。本 PR でこの非対称を解消します。

利用シーン: 用意したメディアをフォルダに配置 → Flex JSON からは相対 url(例 "assets/hero.png")で参照 → 本番移行時は origin だけ HTTPS の CDN に差し替え(相対パスは不変)。プレビュー専用の利便機能。

変更点

  • lib/assets.mjs(新規) — 封じ込めロジックを共有モジュールに集約。resolveAssetPath / assetContentType / isLoopbackHost / resolveMediaRequest は .NET の同名ロジックの移植。セキュリティ上重要な封じ込めを 1 箇所に置き、2 サーバが同一の resolveMediaRequest を通す(二重持ち回避)。
  • extension.mjs / mcp/server.mjsLINE_FLEX_MCP_ASSET_DIR 配下メディア配信を配線(opt-in・ループバック Host ガード・拡張子 allowlist .png/.jpg/.jpeg/.mp4・パストラバーサル/symlink 越え拒否)。renderer.js ほか web/ は無改修。
  • lib/assets.test.mjs(新規・42 tests) — 依存ゼロの node:test。.NET FlexPreviewAssetServingTests の上位集合+ DNS リバインド/resolveMediaRequest 直接テスト。
  • ci.yml — 依存ゼロの extension-test ジョブ追加(node --test・Linux で symlink 越えテストも実走)。mcp/package.jsonnpm test
  • README 英日 — ローカルメディア配信の節を追加。

テスト

  • node --test extensions/line-flex-viewer/lib/assets.test.mjs = 42/42 全緑
  • mcp/server.mjs を stdio 起動した手動 e2e スモークで実配信確認(画像 200/バイト一致・.gif→404・トラバーサル→404・外部 Host→404)。

レビュー

3 役ゲート = security PASS / code PASS / test-arch PASS(非ブロッキング CONCERNS)、BLOCKING なし。封じ込め(トラバーサル・エンコード回避・rooted/UNC・制御文字・DNS リバインド・symlink 越え)は .NET 版と等価と実証。

記録: docs/reviews/2026-09-04-flex-preview-extension-parity-review.md

残(非ブロッキング follow-up・次サイクル)

  • /api/*・静的配信へのホストガード横展開(既存 follow-up と同一課題)
  • 実サーバ配線の e2e 化(handleRequest を SDK 非依存モジュールへ切り出し)
  • C1 制御文字・X-Content-Type-Options: nosniff の些細な parity(.NET も未対応)

未確認

  • Copilot キャンバス(extension.mjs)の実起動は SDK/ホストが必要で未検証。mcp/server.mjs と同一配線・共有関数のため単体テスト+実 MCP スモークで実質担保。

🤖 Generated with Claude Code

…CP server

Ports the .NET FlexPreviewService local-media serving (LINE_FLEX_MCP_ASSET_DIR)
to the two Node servers so a Flex message can reference local artwork/video by a
relative url in every preview path, not just the .NET MCP tool.

- Add shared lib/assets.mjs (resolveAssetPath / assetContentType / isLoopbackHost
  / resolveMediaRequest), a port of the .NET confinement logic kept in one place so
  the canvas (extension.mjs) and bundled MCP server (mcp/server.mjs) cannot diverge.
- Wire both servers to serve assets under LINE_FLEX_MCP_ASSET_DIR (opt-in, loopback
  host-guarded, extension allowlist .png/.jpg/.jpeg/.mp4, path traversal/symlink
  escape refused). renderer.js and web assets unchanged.
- Add zero-dependency node:test suite (42 tests): a superset of the .NET
  FlexPreviewAssetServingTests plus DNS-rebinding and resolveMediaRequest cases.
  Cleanup uses a single async fs.rm to avoid an rmSync recursive crash on Windows
  with non-ASCII temp paths.
- Add npm test script and a CI job (node --test) so JS-specific regressions are
  caught; runs on Linux where the symlink-escape test is exercised.
- Document local media serving in the extension README (en/ja).

3-role gate: security PASS / code PASS / test-arch PASS (non-blocking CONCERNS),
no blocking findings. Record: docs/reviews/2026-09-04-flex-preview-extension-parity-review.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pierre3
pierre3 merged commit a84ff5e into main Sep 4, 2026
3 checks passed
@pierre3
pierre3 deleted the feat-flex-preview-extension-local-media branch September 4, 2026 08:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant