fix(api): validate API responses at the boundary - #1071
Merged
Conversation
EhabY
force-pushed
the
fix/1050-validate-api-responses
branch
from
August 10, 2026 12:55
1160549 to
5b16292
Compare
…generated types The SDK casts 2xx response bodies to generated TypeScript types with no runtime check. A non-Coder service at the configured URL, a proxy HTML error page, or a partial body would flow in as if valid and crash far from the cause (e.g. user.roles.some -> 'Cannot read properties of undefined'). Add a zod-based parseApiResponse helper and InvalidApiResponseError that names the endpoint and deployment URL. Validate on CoderApi overrides for the login/connect paths (users/me, workspace, workspace build, template version resources, deployment SSH config) and at the OAuth entry points (metadata, client registration, token exchange/refresh). Schemas are permissive looseObjects requiring only the fields the extension reads, so newer deployments adding fields never break login. A roles-less /users/me now hard-fails login with a clear error instead of silently treating the user as non-owner. Fixes #1050
Add a private CoderApi.validate helper supplying the host so each override is a single call. Trim doc comments to the essential rationale and merge redundant passthrough tests into one identity assertion.
- Drop hostname_suffix, organization_ids, and architecture from the schemas; nothing reads them and older deployments do not send them - Replace the six validation overrides and captureBaseMethods with a typed wrap helper reassigned in the constructor - Reimplement waitForBuild, whose SDK version swallows errors inside a voided IIFE and would hang callers on a validation failure - Validate getTemplate, stopWorkspace, and startWorkspace responses too - Validate the *_supported arrays in OAuth metadata and blame the endpoint origin, not the deployment, in OAuth validation errors - Fold validateRequiredEndpoints into the OAuth metadata schema - Use safeParse and drop the misleading Output > Coder pointer - Pin the minimal old-deployment body each schema must keep accepting
EhabY
force-pushed
the
fix/1050-validate-api-responses
branch
from
August 11, 2026 10:40
5b16292 to
4f1103b
Compare
Replace the nine hand-written wrapper assignments with a single VALIDATED_RESPONSES map next to the schemas it references, so adding a validated method is a one-line change and the key serves as both the method to wrap and the endpoint name in the error. Mirror the layout on the OAuth side (helper first, schemas below) and collapse the repeated field expressions. Rework the tests around one table per concern, including a guard that fails when a method is added to the map without a case covering it.
jeremyruppel
approved these changes
Aug 11, 2026
jeremyruppel
left a comment
There was a problem hiding this comment.
zod ftw! one type nit but otherwise this looks fantastic. nice one!
The map-driven wrapper reached the SDK methods through an `as unknown as`, which asserted the shape rather than checking it. Store the schemas as `as const` pairs so iterating keeps each method name as a literal type, and assign the instance to a `ValidatedMethods` record that CoderApi satisfies structurally. `never` parameters accept any signature and the uniform value type permits assigning by a name held in a variable, so the whole wrap is compiler-checked with no assertions. Also tighten the new comments.
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
Fixes #1050
The SDK casts 2xx bodies to the generated TypeScript types with no runtime check, so a proxy error page, a non-Coder service, or a partial body flowed in as valid and crashed far from the cause — e.g.
user?.roles.some(...)indeploymentManager.tsthrowingCannot read properties of undefined.Responses are now validated at the HTTP call and fail with an error naming the URL and endpoint.
What changed
src/api/responseValidation.ts—parseApiResponse+InvalidApiResponseError(the Zod failure kept ascause), the schemas, andVALIDATED_RESPONSESmapping each SDK method to its schema. Schemas arelooseObjects listing only fields the extension reads; a field is required only if every supported deployment sends it, so unknown fields pass through untouched and newer ones must be.optional().src/api/coderApi.ts—wrapWithValidationiterates that map in the constructor. Also reimplementswaitForBuild: the SDK polls inside a voided IIFE that swallows errors, so a validation failure would hang callers forever.src/oauth/validation.tsplusmetadataClient.ts,authorizer.ts,sessionManager.ts— same treatment for the endpoints hit before a session exists (metadata, client registration, token exchange and refresh).validateRequiredEndpointsfolded into the schema via.min(1). Errors blame the endpoint's own origin, which may differ from the deployment.Behavior change
/api/v2/users/menow fails login with a clear error instead of silently treating the user as non-owner.waitForBuildinstead of hanging "Stopping workspace for update..." forever.Notes
Apimethods are arrow-function instance properties, sosuper.getAuthenticatedUser()does not compile (ts(2855)) andoverridefields would depend on declaration order.AxiosErrorrejections would confuseisApiErrorhandling.codersdkat v0.25.0, the floorfeatureSet.tsdeclares. The three collection fields we require (resources,roles,ssh_config_options) are built withmake(...)upstream, so they serialize as[]/{}rather than Go'snull.Testing
Table-driven: one case per schema pinning the minimal body an old deployment sends, one per validated method for pass and reject, and a guard that fails when a method joins
VALIDATED_RESPONSESwithout a test case.pnpm test(2416 tests),typecheck, andlintall green.Generated by Coder Agents on behalf of @EhabY