Skip to content

fix(service-rpc): body limit, masked 500s, validation on the serving side only#135

Closed
wmadden-electric wants to merge 1 commit into
mainfrom
claude/service-rpc-hardening
Closed

fix(service-rpc): body limit, masked 500s, validation on the serving side only#135
wmadden-electric wants to merge 1 commit into
mainfrom
claude/service-rpc-hardening

Conversation

@wmadden-electric

Copy link
Copy Markdown
Contributor

Delivers the three hardening fixes publicly promised in the PR #114 evaluation comment (#114 (comment)): a request body size limit, masked handler failures, and single-side per-call validation.

Changes

  • Body size limit (packages/0-framework/2-authoring/service-rpc/src/serve.ts): serve() rejects oversized requests with 413 — first on the declared content-length header (before reading), then on the measured UTF-8 byte length (before JSON.parse). Default 1 MiB, exported as RPC_MAX_BODY_BYTES, overridable via a new optional ServeOptions third parameter ({ maxBodyBytes }). Absent or malformed content-length falls through to the measured check, so no false rejections.
  • Masked failures: a handler throw or output-validation failure now returns a generic 500 (RPC method "<name>" failed) — the exception message never reaches the caller (it previously did, leaking internals like connection strings or hostnames). Input-validation 400s deliberately keep the schema message: that error is the client's to act on.
  • Validation on the serving side only (src/client.ts): makeClient returns the response body without re-validating it against the output schema. Per-call validation is the protocol implementation's job and serve() already validates both input and output — the client-side re-check was redundant work on every call. The domain doc (docs/design/10-domains/connection-contracts.md, "How compatibility is checked" item 3) is amended to record this.

Tests pin all three behaviors: 413 via declared header and via measured body, a 500 body that provably excludes the exception text, and the client returning a schema-violating body untouched.

Why

These are the gaps the oRPC comparison in #114 exposed in our hand-written protocol layer — each a few lines to fix without adopting a new dependency, which is exactly the trade recorded in that evaluation. Scope deliberately excludes the in-flight idempotency-key/retry work, which will build on top of this.

Verification

Full workspace gate green: build 28/28, typecheck 58/58, tests 48 suites, lint, lint:deps, lint:casts all pass. Reviewed internally: SATISFIED, zero findings.

🤖 Generated with Claude Code

…side only

serve() rejects request bodies over a limit (default 1 MiB, RPC_MAX_BODY_BYTES,
ServeOptions.maxBodyBytes) with 413, checking the declared content-length
before reading and the measured byte length before parsing. Handler and
output-validation failures return a generic 500 that never carries the
exception message. makeClient returns the response body without re-validating
it — per-call validation is the serving adapter's job, and the domain doc
now says so.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@pkg-pr-new

pkg-pr-new Bot commented Jul 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@prisma/composer@135
npm i https://pkg.pr.new/@prisma/composer-prisma-cloud@135

commit: 5817350

@wmadden-electric

Copy link
Copy Markdown
Contributor Author

Superseded by #140, which reimplements two of the three fixes in stronger form on its rewritten response path (masked 500s now also log the real error server-side; client re-validation removed with the same rationale). The third fix — the request body size limit — is NOT in #140 as written and moves there: it slots into the new request-reading path before parse, and a 413 composes fine with the replay-cache rule (4xx outcomes replay). Closing rather than rebasing to spare #140 a conflict on code it already restructured.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant