Repository navigation
feat(core): several named proxy base URLs per module (F8) - #690
seanspeaks wants to merge 7 commits into
Conversation
The entity proxy joined a caller's path onto a single module-declared base
URL, so one Google entity could not reach Docs, Sheets, GA Data or Ads, which
live on other hosts.
A module may now declare proxy.baseUrls (name -> https URL); proxy.baseUrl
still means { default: baseUrl } and declaring both is a load error. The
proxy request takes an optional `base`, a NAME that is shape-checked before
the module is consulted, so a URL or host is refused and the host still comes
only from the module. Unknown names are 400 PROXY_UNKNOWN_BASE. Allow rules
(module and app level) gain an optional `base` and match only their own base;
a rule naming an undeclared base stops the app at load, because a rule that
can never match reads as permission. Threaded through the use case, OpenAPI
v2, the JSON schema, types and docs (ADR-052 amendment, API reference).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HyrF4oqcTdK2AtvcrocxE6
- baseUrls values are strings only (a function could return nothing and fall back to the requester's host with the module's token); a declared base never falls back to the requester - the PROXY_NOT_ALLOWED message is unchanged for single-base modules and names the base only when the module declares several; details.base stays - module and app JSON schemas accept baseUrls / allow[].base, with tests - audit the requested base on PROXY_UNKNOWN_BASE denials; omit the base key when not supplied; map an unvalidated definition to 501 - ModuleProxyConfig is wired into the entity type entry's definition type - replace the copied ADR-052 with a standalone amendment document Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HyrF4oqcTdK2AtvcrocxE6
There was a problem hiding this comment.
If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.
Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.
|
I compared the two runs suite by suite:
There is no fix for those devtools failures anywhere in this stack yet, so there is nothing to port into this PR. They predate the internal-MCP stack, and I haven't re-run the job because it would fail the same way. Generated by Claude Code |
The api-reference section on proxy named bases described the rules without pointing at the amendment that records the decision. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HyrF4oqcTdK2AtvcrocxE6
The entity proxy comma-joined every array query value, so APIs that want a repeated key (Airtable, Fathom: fields[]=a&fields[]=b) were unreachable. A query key ending in [] whose value is an array of strings is now sent once per value (fields%5B%5D=a&fields%5B%5D=b; an empty array sends nothing). Every other array keeps the comma-joined form, in the proxy policy and in the requester alike. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HyrF4oqcTdK2AtvcrocxE6
|
ADR reconciliation needed after Stack A/B — drafted with Claude Code at Sean's request Severity: must-reconcile (text placement and status; the design keeps ADR-052's SSRF property).
Merge order: #668 (052 with named bases folded in) → #671 → … → #685 → this PR. |
…roxy changelog - Move the ADR-052 named-bases amendment to docs/architecture-decisions/pending/ and mark it Proposed. ADR-052 on #668 does not describe named bases yet, so the text stays until it is folded into ADR-052 §4/§5 there. A 052- file in the register would read as a second claim on 052 under the ADR number check (ADR-014 amendment) and fails its heading rule. - State the three "more than one of a module" axes so a later ADR does not reuse `base`: several hosts per entity (named bases), several registry entries for one module (ADR-059), several configured instances (future). - api-reference: an "Entity proxy changes" note for the beta proxy: the additive optional `base` field, and `[]`-suffixed query keys now sent once per array value instead of comma-joined. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HyrF4oqcTdK2AtvcrocxE6
There was a problem hiding this comment.
If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.
Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.
…hedule scope, coreExtensions) into named proxy bases Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HyrF4oqcTdK2AtvcrocxE6
|
Reply to the ADR-reconciliation review (comment 6276667428), in The amendment and ADR-052
Three meanings of "more than one of a module". Added to the amendment, and it should carry into ADR-052 when folded:
OpenAPI changelog. There's no OpenAPI changelog file, so I added "Entity proxy changes" under "Entity proxy (beta)" in
Tests
Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HyrF4oqcTdK2AtvcrocxE6
|



Summary
Stacked on #686. Today the v2 entity proxy (ADR-052) joins a request path onto one base URL per module. Google's APIs live on several hosts (
www.googleapis.com,docs.,sheets.,analyticsdata.,googleads.). One Google entity therefore can't reach Docs, Sheets, GA Data or Ads, even when its token carries the scopes.This PR lets a module declare several named bases, and lets a proxy request pick one by name.
proxy.baseUrls: { default, docs, sheets, … }.^[a-z][a-z0-9-]*$.proxy.baseUrlstill works and means{ default: baseUrl }. Declaring both is a load error.base, which is a name and never a URL or host. When omitted it meansdefault.https://evil.example,evil.example,../xordocs:8080, gets 400INVALID_PROXY_REQUEST.PROXY_UNKNOWN_BASE.base(defaultdefault) and match only that base. Redirects are re-checked against the same base.baseon a module that has nodefault.baseUrlfunction that returns nothing now gets 501PROXY_NOT_CONFIGURED.PROXY_NOT_ALLOWEDmessage is byte-identical to before. The base is named only when a module declares more than one.details.baseis always present, and the audit record carries the base.api-proxy.schema.json,api-module-definition.schema.json,app-definition.schema.jsonandtypes/modules/index.d.ts.docs/architecture-decisions/052-amendment-1-named-proxy-bases.mdis a dated amendment. ADR-052 itself lives onadr/052-053-management-apiand is not copied here. The base usage is also documented indocs/reference/api-reference.md.Test plan
Requester, with onlyfetchfaked, and asserts the outbound URL.base: 'docs'reaches the docs host, and an omittedbasereachesdefault.baseUrlbehaves as before.proxy-bases.test.jsand through the real app-definition loader.packages/schemas, 235/235).Part of the Left Hook internal-MCP work (ADR 0016). frigg-internal will move to this PR's canary so its Google module can reach Sheets, Docs, GA and Ads.
Generated by Claude Code
Note
Medium Risk
Touches the security-sensitive entity proxy (host selection, allow-lists, redirects) and changes query serialization for
[]keys, which may break callers that relied on comma-joined values.Overview
Adds named proxy base URLs so one entity credential can reach multiple upstream hosts (e.g. Google Drive vs Docs) while keeping hosts module-controlled for SSRF safety.
Modules may declare
proxy.baseUrls(or keepproxy.baseUrlas{ default: … }). Proxy requests accept an optionalbasename (never a URL); unknown names return400 PROXY_UNKNOWN_BASE. Module and app allow rules gain optionalbaseand only match that host; redirects are re-checked on the same base. InvalidbaseUrlsor rules referencing undeclared bases fail at app load viaassertProxyConfig(ProxyConfigError).Query encoding change: array values under keys ending in
[]are sent as repeated query pairs instead of comma-separated (documented as a beta proxy contract change). OpenAPI, JSON schemas, types, and API reference are updated accordingly.Reviewed by Cursor Bugbot for commit 08cd07e. Bugbot is set up for automated code reviews on this repo. Configure here.
📦 Published PR as canary version:
2.0.0--canary.690.08cd07e.0✨ Test out this PR locally via:
npm install @friggframework/admin-scripts@2.0.0--canary.690.08cd07e.0 npm install @friggframework/core@2.0.0--canary.690.08cd07e.0 npm install @friggframework/devtools@2.0.0--canary.690.08cd07e.0 npm install @friggframework/eslint-config@2.0.0--canary.690.08cd07e.0 npm install @friggframework/extension-db-credentials@2.0.0--canary.690.08cd07e.0 npm install @friggframework/prettier-config@2.0.0--canary.690.08cd07e.0 npm install @friggframework/provider-aws@2.0.0--canary.690.08cd07e.0 npm install @friggframework/provider-netlify@2.0.0--canary.690.08cd07e.0 npm install @friggframework/schemas@2.0.0--canary.690.08cd07e.0 npm install @friggframework/serverless-plugin@2.0.0--canary.690.08cd07e.0 npm install @friggframework/test@2.0.0--canary.690.08cd07e.0 npm install @friggframework/ui@2.0.0--canary.690.08cd07e.0 # or yarn add @friggframework/admin-scripts@2.0.0--canary.690.08cd07e.0 yarn add @friggframework/core@2.0.0--canary.690.08cd07e.0 yarn add @friggframework/devtools@2.0.0--canary.690.08cd07e.0 yarn add @friggframework/eslint-config@2.0.0--canary.690.08cd07e.0 yarn add @friggframework/extension-db-credentials@2.0.0--canary.690.08cd07e.0 yarn add @friggframework/prettier-config@2.0.0--canary.690.08cd07e.0 yarn add @friggframework/provider-aws@2.0.0--canary.690.08cd07e.0 yarn add @friggframework/provider-netlify@2.0.0--canary.690.08cd07e.0 yarn add @friggframework/schemas@2.0.0--canary.690.08cd07e.0 yarn add @friggframework/serverless-plugin@2.0.0--canary.690.08cd07e.0 yarn add @friggframework/test@2.0.0--canary.690.08cd07e.0 yarn add @friggframework/ui@2.0.0--canary.690.08cd07e.0