Skip to content

feat(plugins): add host-enforced fetch redirect policies - #1483

Open
adoin wants to merge 1 commit into
vastsa:mainfrom
adoin:feat/plugin-fetch-redirect
Open

adoin wants to merge 1 commit into
vastsa:mainfrom
adoin:feat/plugin-fetch-redirect

Conversation

@adoin

@adoin adoin commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

背景

Closes #1475

按 维护者的邀请 提交本功能 PR,并附最小测试插件。

变更

  • pi.net.fetch 增加 redirect: 'follow' | 'error' | 'manual';省略时保留现有 follow 行为及每跳网络授权检查。
  • error 遇到任何 3xx 返回 REDIRECT_DISALLOWED,不请求目标;manual 返回原始状态、响应头及正文。
  • 新增 pi.net.getCapabilities(),插件可在发请求前拒绝不支持该能力的旧宿主。
  • 将跳转循环提取到专用模块,默认及注入传输共用宿主策略、跳转上限和截止时间。内部注入服务现在是遵守 manual/abort 的单次 Fetch 传输;原接口没有生产调用方。
  • 附 examples/plugins/fetch-redirect:最小插件、操作面板、仅绑定 loopback 的模拟服务及运行说明;无需真实凭据或外部服务。
  • 同步 SDK、API/安全规格、开发指南、ADR、未发布说明及验收场景。不新增仅同源模式,不扩大网络权限,不变更持久化。

验证

  • pnpm build:js:通过(含桌面及文档站点构建)。
  • pnpm --filter @pi-desktop/desktop typecheck:通过。
  • pnpm --filter @pi-desktop/plugin-sdk test:376/376 通过(当前配置同时收集 src/dist 测试)。
  • 目标插件回归测试:46/46 通过(egress、redirect、services、provider-oauth、timeout-budgets)。
  • pnpm lint、pnpm docs:check、git diff --check:通过。
  • node packages/plugin-devkit/dist/cli.js check examples/plugins/fetch-redirect:通过,仅预期的显式网络授权/loopback 提示。
  • pnpm test:e2e:plugin-fetch-redirect:11/11 通过;使用真实插件子进程、宿主 RPC 和本机 HTTP 服务,覆盖两种传输、301/302/303/307/308、零目标请求、非法参数、旧宿主拒绝、权限、相对/缺失 Location、循环及超时。

Task candidate: 3b0078904919ce6edee722be936d3aacddf5508b

Base main: 05e71882beb7962808568f761aaec09056d4ed11

Environment: Windows / Node 24.15.0 / pnpm 12.8.1。主工作区未安装依赖,因此在隔离 worktree 按 lockfile 初始化依赖;未连接运行中的用户桌面或真实服务。

未执行:原生插件面板点击验证(已验证相同 probe.fetch 操作经过真实子进程与宿主协议);未运行不涉及的 Rust/全仓测试。待维护者审核与远端 CI,未尝试合并。

Let plugins refuse or inspect redirects before the host contacts a target,
while preserving the default follow policy and existing egress grants.
Use capability detection so older hosts cannot silently ignore the option.

Cover both transports and the real plugin child protocol with loopback
fixtures, and provide a minimal probe plugin for maintainer validation.

closes vastsa#1475

@muzimu217 muzimu217 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified locally on macOS (worktree off current main): desktop plugin-fetch-redirect.test.mjs 11/11 (the real-subprocess + host-RPC + local-HTTP harness), and @pi-desktop/plugin-sdk 376/376 — the verification claims in the description reproduce on a second machine.

I audited the enforcement module for the security-critical properties, and they all hold:

  • Egress is asserted on the input URL before the first request and re-asserted on every resolved hop (new URL(location, url) before continue), with the transport pinned to redirect: "manual" so the host — not undici/fetch — owns every hop. That closes the classic "authorize host A, 302 to an internal host B" bypass for both the default and the injected transport, which now share the one policy owner, loop cap, and deadline.
  • error cancels the body and throws before any target request; manual returns the 3xx from the authorized origin; follow caps at 5 hops under one shared AbortController deadline that survives across hops.
  • Redirect-path bodies are cancelled rather than buffered, and the injected internal service was converted to a single-shot manual/abort-compliant transport (no production callers of the old shape).

pi.net.getCapabilities() is the right versioning story — old hosts fail closed at the plugin instead of silently following.

feat/policy note is moot: the maintainer invited this via #1475, and the docs breadth (ADR + spec en/zh + guide + examples + unreleased notes) matches repo discipline.

One non-blocking question: cross-method redirect semantics (301/302 turning POST into GET per common client behavior vs RFC 9110's strict reissuance rules) — the tests cover all five status codes for the policy paths; worth one sentence in the ADR stating which method/body behavior follow implements, since plugin authors will rely on it.

Nothing blocking.

This branch has not been deployed

No deployments
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.

[Feature] 为 pi.net.fetch 增加显式重定向策略,支持自部署插件端点控制

2 participants