fix(validation): surface a skip for non-JSON content types that declare a schema (#254)#255
Merged
Merged
Conversation
…re a schema (#254) When a non-JSON Content-Type matched a spec media-type key and that entry carried a `schema`, the body could not be validated by the JSON Schema engine, yet the run was still recorded as a clean success. Surface this as `Skipped` with a skip reason on both the request and response sides so the gap is visible. Non-JSON entries without a `schema` continue to succeed silently as before.
…nts (#254) Add constructor guards to RequestBodyValidationResult and ResponseBodyValidationResult that reject contradictory states via InvalidArgumentException: a skipReason set together with errors, and on the response side a skipReason set together with a null matchedContentType. This follows the precedent of the OpenApiValidationResult::failure([]) guard. Close the test gaps raised in review: - a non-JSON body skip must not mask a missing required response header error - a request-side skip reason must be recorded in coverage - skip on a wildcard (application/*) range match - the DTO guards fire on contradictory input Strengthen two existing tests that weakly pinned the old buggy behavior with assertions for the new skip behavior. Add a comment on non-array schema handling and fix a stale comment in OpenApiResponseValidator after the DTO grew to three fields.
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
When a non-JSON request/response Content-Type matched a spec media-type key
and that entry declared a
schema, the body went unchecked (this engine onlyevaluates JSON Schema) yet the run was still recorded as a clean success.
This surfaces such cases as
Skippedwith a skip reason on both the requestand response sides; non-JSON entries without a
schemakeep succeedingsilently as before.
Why
OpenAPI permits a
schemaon any media type, but the validation engine isJSON-Schema-only and cannot evaluate a non-JSON one. The response side already
surfaced a
Skippedoutcome for the "spec declares only non-JSON contenttypes" case — but only when
matchedContentTypewas null, so a non-JSON typethat matched a declared spec key bypassed that path and was reported as a
validated success. The request side had no skip surfacing at all. As a result
users could not tell that a non-JSON body's schema was never checked, and the
coverage report counted the endpoint as a clean pass — contrary to the tool's
"never show unvalidated as validated" principle.
Fixes #254.
Verification
Failing tests were added first (non-JSON media type with a
schema), then thefix. Tests that pinned the previous behaviour — most notably
ResponseValidationTest::non_json_endpoint_with_explicit_content_type_marks_validated,which encoded the exact bug — were rewritten to assert the corrected
Skippedoutcome and coverage row.
composer testpasses (1796 tests)composer stanpassescomposer cs-checkpassesNotes for reviewers
OpenApiValidationResult::skipped()gains an optionalmatchedContentTypeargument (BC-safe) so the response-side skip records coverage against the
exact media-type row rather than the wildcard bucket.
RequestBodyValidator::validate()return type changes fromstring[]to anew
@internal RequestBodyValidationResultDTO (errors+skipReason),mirroring the response-side
ResponseBodyValidationResult. The bodyvalidator is now run behind an inlined
RuntimeExceptionboundary inOpenApiRequestValidator::validateBody()— same pattern asOpenApiResponseValidator::validateBody(), since the DTO return cannot flowthrough
ValidatorErrorBoundary::safely().OpenApiRequestValidator::validate()/OpenApiResponseValidator::validate()) are unchanged.docs/setup.mdhad a stale claim thatisSkipped()is true "only forstatus-code skips" — corrected here alongside the behaviour change.