Repository navigation
Conversation
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
left a comment
There was a problem hiding this comment.
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)beforecontinue), with the transport pinned toredirect: "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. errorcancels the body and throws before any target request;manualreturns the 3xx from the authorized origin;followcaps at 5 hops under one sharedAbortControllerdeadline 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.
背景
Closes #1475
按 维护者的邀请 提交本功能 PR,并附最小测试插件。
变更
pi.net.fetch增加redirect: 'follow' | 'error' | 'manual';省略时保留现有 follow 行为及每跳网络授权检查。error遇到任何 3xx 返回REDIRECT_DISALLOWED,不请求目标;manual返回原始状态、响应头及正文。pi.net.getCapabilities(),插件可在发请求前拒绝不支持该能力的旧宿主。examples/plugins/fetch-redirect:最小插件、操作面板、仅绑定 loopback 的模拟服务及运行说明;无需真实凭据或外部服务。验证
pnpm build:js:通过(含桌面及文档站点构建)。pnpm --filter @pi-desktop/desktop typecheck:通过。pnpm --filter @pi-desktop/plugin-sdk test:376/376 通过(当前配置同时收集 src/dist 测试)。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:
3b0078904919ce6edee722be936d3aacddf5508bBase main:
05e71882beb7962808568f761aaec09056d4ed11Environment: Windows / Node 24.15.0 / pnpm 12.8.1。主工作区未安装依赖,因此在隔离 worktree 按 lockfile 初始化依赖;未连接运行中的用户桌面或真实服务。
未执行:原生插件面板点击验证(已验证相同
probe.fetch操作经过真实子进程与宿主协议);未运行不涉及的 Rust/全仓测试。待维护者审核与远端 CI,未尝试合并。