fix(boundaries): harden DNS pinning, GraphQL cost limits, and CLI/provider validation (salvage #764, #774, #778) - #788
Merged
Merged
Conversation
…d CLI/provider validation Salvages the boundary work from draft PRs #764, #774 and #778 onto current main. From #764: - support/outboundUrl: resolvePublicHttpUrl returns the validated addresses, createPinnedPublicLookup answers the connect hook from that same set (no second DNS round-trip), and publicFetch installs a per-request pinned dispatcher instead of a shared unpinned agent. - issues/graphql/server: GRAPHQL_MAX_DEPTH/FIELD_COUNT/ALIAS_COUNT/COST plus createGraphQLCostRule, and exact-path '/graphql' matching. - mcp/mcpClient: MAX_INPUT_SCHEMA_BYTES/PROPERTIES with countSchemaProperties. - auth/oauthPkce: isLoopbackRemote guard on the callback server (+ re-export). - verify/runner: buildVerifyToolchainPath replaces the inherited sandbox PATH. - adapters/webTools: cancel the redirect body before the next hop. From #774: - issues/graphql/costAnalysis: registry CRUD costs (registerEntity 100, updateEntity/removeEntity 80, addEntityRelation/removeEntityRelation 60). - issues/graphql/server: applyCors returns early without an Origin header. - bulkRegisterEntities alias/fragment-multiplication tests. From #778: - adapters/rateLimitError: parseRetryAfterSeconds handles HTTP-date Retry-After; classifyLimitResponse falls back to the codex reset epoch. - cli/mcpCommand: preset/url/command validation before persisting the registry. - cli/prCreate: fail closed on a dirty tree or a branch with no upstream. - adapters/webTools: refuse non-http(s) redirect destinations. Kept main's newer clone-timeout/resource-budget code in verify/runner and its onValidate cost plugin; dropped the already-in-main #774 files and all scratch probe files.
This was referenced Sep 28, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Rebuilds the network-boundary work from three abandoned draft PRs as one reviewable change on current
main.Salvaged from: #764, #774, #778.
Kept
#764 — remote redirects, callbacks, schemas, GraphQL execution
support/outboundUrl.ts:resolvePublicHttpUrlnow returns the validated addresses alongside the URL, andcreatePinnedPublicLookupanswers theconnect.lookuphook from that same set — a second DNS answer can no longer steer the socket after the check.publicFetchinstalls a per-request pinned dispatcher instead of a shared, unpinned agent.assertPublicHttpUrlstays as a thin wrapper.issues/graphql/server.ts:GRAPHQL_MAX_DEPTH/FIELD_COUNT/ALIAS_COUNT/COST+createGraphQLCostRule(depth-weighted cost) installed via a typed Yoga plugin;isGraphQLRequestnow matches the exact/graphqlpath (with query/hash) instead ofstartsWith.mcp/mcpClient.ts:MAX_INPUT_SCHEMA_BYTES/MAX_INPUT_SCHEMA_PROPERTIES+countSchemaProperties(walks nested objects, composed schemas, arrays,additionalProperties).auth/oauthPkce.ts:isLoopbackRemoteguard on the callback server; re-exported fromauth/index.ts.verify/runner.ts:buildVerifyToolchainPathreplaces the inherited sandbox PATH with project bins + an explicit read-only allowlist.adapters/webTools.ts: cancel the redirect body before the next hop.#774 — GraphQL costing
issues/graphql/costAnalysis.ts: registry CRUD costs (registerEntity100,updateEntity/removeEntity80,addEntityRelation/removeEntityRelation60) so aliasing them multiplies past the limit.issues/graphql/server.ts:applyCorsreturns early when noOriginis present.#778 — provider/CLI boundary data
adapters/rateLimitError.ts:parseRetryAfterSeconds(RFC 7231 delta-seconds or HTTP-date);classifyLimitResponseuses it and falls back to the codex reset epoch.cli/mcpCommand.ts: preset/url/command validated before the registry is written.cli/prCreate.ts: fail closed on a dirty tree or a branch with no upstream.adapters/webTools.ts: refuse non-http(s) redirect destinations.Fixed the failing
Testscheck from #778'rate limit exceeded'signature and the local-server overload entry, somatchesRateLimitMessage('Rate limit exceeded')/detectRateLimitare truthy.{attempt, maxAttempts}whileThrottleStateis{attempts}; the tests now use the real shape.Dropped
_trigger_vitest.txt,run-agt3442-vitest-temp.sh,cli-permissions-override.json,cursor-*.json,hooks.json+hooks/,ls,run_diag.sh,scripts/agt3473-bootstrap.sh,scripts/run-cost-analysis-smoke.mjs,_cursor_dir_probe/,git-index-copy.txt,agt3473-probe.txt.main(verified by hash):deletedTestGuard.{ts,test.ts},publicationReviewHook.{ts,test.ts},publishOnPark.test.ts,recallStatus.test.ts, and thepublishOnPark/runnerExecutionparked-publication hook wiring.mainis at 0.24.3; fix(graphql-costing): account for aliased expensive mutations — enforce query-cost limits against resolver multiplication #774 would have reverted it to 0.24.0.Conflicts resolved
issues/graphql/server.ts+costAnalysis.ts(764 × 774): kept main'sonValidatecost plugin (onParse/replaceParseResultis measured to return 500) and main'sAUTO_LINK_MEMORIES_COST, merged 764's shape rule and exact-path match and 774's registry-cost table and CORS guard.adapters/webTools.ts(764 × 778): both hunks kept — redirect-body cancellation plus the non-http(s) refusal, ordered so the protocol check runs before the origin check.verify/runner.ts: kept main's clone-timeout (CLONE_TIMEOUT_MS/gitTimeoutMsFor) and test-resource-budget code; only the PATH construction changed.auth/oauthPkce.ts: rejected fix(boundaries): harden remote redirects, callbacks, schemas, and GraphQL execution — constrain untrusted network inputs #764'slisten('localhost')— measured on macOS it resolves once and binds::1only, so127.0.0.1clients getECONNREFUSED. Main's deterministic loopback bind is kept;isLoopbackRemotestill accepts the v4, v6 and v4-mapped forms.Two deliberate tightenings found while verifying:
'overloaded'is matched as'server is overloaded', not as a bare word: Anthropic/OpenRouter report a 529 capacity blip with that single word, and matching it would re-bucket every overload ahead ofisInfraErrorinto a scheduler pause.buildVerifyToolchainPathplaces the running interpreter's own bin directory directly after the project bins — on this host/usr/local/bin/nodeis a different major version, and the sandbox must run the interpreter the daemon runs.Verification
npx tsc --noEmit— clean.Smoke-tested against real surfaces, not just mocks:
(addresses)/(address, family)from the pinned set, refuses a set containing a private address, and a realpublicFetchto a public origin streams the full body.bulkRegisterEntities→ 400GRAPHQL_COST_LIMIT_EXCEEDED;registerEntitypriced below bulk;/graphqlfoo,/graphql/admin,/graphql/→ 404 while/graphql?query=→ 200;OPTIONSwith noOriginis not answered by the CORS layer, a bad origin gets 403, localhost gets 204; GraphiQL still renders and full introspection fits the caps (237/250).prCreate: refuses clean-no-upstream, clean-in-sync and dirty trees; publishes only when clean and ahead of@{u}.webTools: a real public redirector returningfile:/javascript:is refused and never followed; a legitimate hop lands with the body intact.mcpCommand: malformed URL / unknown preset / blank name refused with nothing written to the registry.buildVerifyToolchainPath: 45 host entries → 13, still resolvingnode/npm/git.Refs #764, #774, #778.