fix(tool): port upstream webfetch redirect rule checks (anomalyco/opencode#59748)

DE
1d ago
+167-7

Issue for this PR

Closes #1658

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Ports the upstream webfetch permission fixes to the fork's packages/opencode/src/tool/webfetch.ts:

  • anomalyco/opencode#59748: webfetch used fetch's default redirect: "follow", so only the URL the model passed was checked against the webfetch rules. An allowed page that redirects to a denied URL (for example http://169.254.169.254/... under {"*": "allow", "http://169.254.169.254/*": "deny"}) was fetched and returned to the model. Redirects are now followed by hand (redirect: "manual", max 10 hops). Each target is evaluated against the effective ruleset (ctx.permissions) before it is requested. A denied target throws PermissionDeniedError; as upstream does, the user is not asked again for redirect targets. Redirects to non-HTTP schemes fail.
  • anomalyco/opencode#61701: URLs with credentials are rejected, both the requested URL and redirect targets. Without this, a rule for https://docs.example.com* also matched https://docs.example.com@evil.example/. Fragments are dropped before rules are matched.
  • anomalyco/opencode#60505: the permission prompt matches the normalized URL.href, not the raw string the model typed.

Upstream made these changes in the v2 packages/core/src/tool/plugin/webfetch.ts. This PR adapts them to the fork's legacy tool and wraps the changes in altimate_change ... upstream_fix: markers. The failure cache, UA fallback and error messages are unchanged.

How did you verify your code works?

  • Added four tests to packages/opencode/test/tool/webfetch.test.ts: an allowed redirect is followed, a denied redirect target stops before it is requested, non-HTTP and endless redirects fail, and credentials are rejected. On main, the denied-redirect, scheme and credential tests fail. With this change, all 37 tests in webfetch.test.ts and webfetch-cache.test.ts pass.
  • bun run typecheck (tsgo) in packages/opencode passes, and so does the pre-push bun typecheck.
  • bun run script/upstream/analyze.ts --markers --base origin/main --strict: ok.

Cost side effects

None. A redirect issues the same number of HTTP requests as before. Rule checks are local.

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR
  • I checked for cost side effects (model calls, queries or cloud resources that grow with user data) and described them, or wrote "none"

Tracked in #1478.

Written by Devin


Summary by cubic

Fixes the webfetch tool's permission checks so allowed pages can no longer redirect to denied URLs, and incoming URLs are normalized before being matched against rules.

  • Follows redirects manually (max 10 hops) and checks each target against the effective ruleset before requesting it; denied targets throw without prompting the user again.
  • Rejects URLs with embedded credentials and drops URL fragments before matching rules, so a rule like https://docs.example.com* no longer matches https://docs.example.com@evil.example/.
  • Permission prompts now use the normalized URL.href instead of the raw input string.
  • Adds four tests covering allowed redirects, denied redirect targets, non-HTTP and endless redirects, and credential rejection.