* fix(agents): scope provider SSRF trust by origin
* fix(provider): preserve explicit private-network deny
* docs(provider): document exact-origin SSRF trust
* test(provider): cover exact-origin SSRF edges
* docs(provider): align local model private-origin guidance
* refactor(ssrf): keep policy merging in infra
* test(ssrf): cover exact-origin trust through guard
* test(ssrf): block sibling private-origin redirects
* fix(provider): keep loopback trust origin-scoped
* fix(provider): block metadata origin trust
* fix(ssrf): keep metadata rebinding blocked
* fix(ssrf): block cloud metadata origins
* fix(ssrf): block ipv6 metadata origins
* fix(ssrf): block embedded metadata origins
* test(ssrf): cover embedded link-local metadata
* test(provider): cover custom anthropic proxy classification
* test(provider): widen transport policy mock
* test(plugin-sdk): assert metadata-IP allowedOrigins entries are rejected
Plugin authors can construct an SsrFPolicy that lists any well-formed
http(s) origin in allowedOrigins. The abuse-resistance lives one layer
deeper, in resolvePinnedHostnameWithPolicy's metadata/link-local block.
Add an SDK-level smoke test asserting that contract directly:
- AWS/Alibaba IMDS IPv4 literals, GCP metadata canonical hostname,
IPv6 ULA metadata literal, and non-metadata link-local IPv4 entries
build a policy via ssrfPolicyFromHttpBaseUrlAllowedOrigin and are
then rejected at resolvePinnedHostnameWithPolicy.
- DNS rebinding from a trusted private DNS origin to a metadata IP is
rejected even when the request hostname is origin-trusted.
This would fail if the SDK helper or resolveSsrFPolicyForUrl ever
short-circuited past the metadata block.
* chore(docs): regenerate baselines after upstream rebase
upstream/main moved between rebases; the merged source state for the
PR's `src/config/schema.help.ts` change and the upstream plugin-sdk
surface changes both produce different hashes than the committed
baselines, so `config:docs:check` and `plugin-sdk:api:check` would fail.
Regenerated via `pnpm config:docs:gen` + `pnpm plugin-sdk:api:gen` on
Crabbox; both baselines verified with their respective `--check`
generators.
* test(plugin-sdk): assert SSRF blocked error class
* fix(lint): satisfy exact-origin PR lint rules
* docs: clarify custom provider origin trust
* chore(docs): refresh plugin sdk api baseline
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* test: align extension runtime mocks with plugin-sdk
Update stale extension tests to mock the plugin-sdk runtime barrels that production code now imports, and harden the Signal tool-result harness around system-event assertions so the channels lane matches current extension boundaries.
Regeneration-Prompt: |
Verify the failing channels-lane tests against current origin/main in an isolated worktree before changing anything. If the failures reproduce on main, keep the fix test-only unless production behavior is clearly wrong. Recent extension refactors moved Telegram, WhatsApp, and Signal code onto plugin-sdk runtime barrels, so update stale tests that still mock old core module paths to intercept the seams production code now uses. For Signal reaction notifications, avoid brittle assertions that depend on shared queued system-event state when a direct harness spy on enqueue behavior is sufficient. Preserve scope: only touch the failing tests and their local harness, then rerun the reproduced targeted tests plus the full channels lane and repo check gate.
* test: fix extension test drift on main
* fix: lazy-load bundled web search plugin registry
* test: make matrix sweeper failure injection portable
* fix: split heavy matrix runtime-api seams
* fix: simplify bundled web search id lookup
* test: tolerate windows env key casing