Repository navigation
v0.10.0
-
Added.
NegativeRequestCaseArbitrary::partContentTypeMismatchForOperation()
(#80): the valid multipart body with one required part sent under a media
type itsencoding.contentTypedoes not allow. It is the only category that
can see a validator reading that keyword and ignoring it — neglecting it is
fail-open, so every valid case passes either way, and the recorded corpus in
openapi-contractreplayed green against a validator that ignored it. A part
without a declaredcontentType, an optional part, and a part declaring a
wildcard are skipped for the next declared part, and an operation left with
no candidate fails closed — as does a body that can travel as more than one
media type, since which one a valid case carries is a generation choice — so
the case never claims a contradiction it does not carry. -
Changed. A header parameter is written as it will be read: verbatim, not
percent-encoded, on both the request and the response side
(openapi-contract#66). Encoding one put a string on the wire that no client
sends and that the validator now reads as a different value. Generated
header strings stay inside what an HTTP field value may carry — printable
characters, no whitespace at either end, and no comma when the style needs
it to separate members — because reading a header as sent leaves nothing to
escape a delimiter with. A hand-written case carrying a CR or an LF is
refused asUnsupportedGenerationnaming the header, rather than
percent-encoded into something harmless or handed to a PSR-7 implementation
to reject in its own words. -
Added.
headers.getin the zoo: a scalar, a list and an exploded object
header, so the round trip a validator and a server have to agree on is
proven rather than assumed. It could not be proven before — the whole zoo
had no header parameter, and both sides percent-encoded, so they agreed with
each other and with nobody else. The differential fixture gets its header
parameter back for the same reason: the disagreement it was excluded for is
settled, not pinned. -
Fixed. A generated multipart text part no longer carries leading or
trailing whitespace. RFC 2046 puts the part body between the blank line and
the next delimiter and says nothing about trimming it; the parsers in the
wild trim anyway, so a part whose value is only a carriage return came back
as the empty string and any other value quietly lost its padding — the
handler receiving a value the client did not send, which is the same failure
as the query+. Found by the league differential on a seed the local runs
had not drawn, four times in six thousand; the shape itself is pinned as its
own case rather than removed from sight. Which way league falls on it is a
property of its parser's minor version — riverline 2.0.3 reads the bytes,
later ones trim — so the pin asserts our reading and the agreement on the
shape the generator does emit, not a verdict that is true only of today's
lock file. -
Requires
rasuvaeff/openapi-contract^0.7. -
Added. Three zoo operations carrying the document forms last month's
findings lived in, and a document accessor beside each contract so those
forms can be recorded into a portable corpus: a 3.0 body with a boolean
additionalProperties, a JSON body whose property names are decimal integers,
and a multipart body withencoding.contentType. Verified against the
pre-fix validator — replaying the recorded corpus onopenapi-contract
0.5.1 rejects abounded.createdocument outright and fails a valid
numeric.createbody, which is the point of recording it. -
Added. A differential against
league/openapi-psr7-validatorfed by the
generator.openapi-contracthas compared verdicts with league from the
start, but from a hand-written corpus, so it could only disagree about
requests someone thought to write down; this package produces requests nobody
thought of. Both readers are handed the same document and the same bytes: a
generated valid case both must accept, and a case built to violate exactly
one thing that neither may let through. The document is deliberately narrower
than the zoo — a differential is informative only on the intersection of what
two implementations claim to support, and outside it degenerates into a list
of the other library's limitations. What is left out is recorded with its
reason, including the one live disagreement it found: a header parameter is
RFC 6570 simple expansion to us and opaque bytes to league, so%C4%8Bis one
character againstmaxLengthon one side and six on the other. That case is
pinned rather than generated. Verified by reverting the query decoder in the
installed contract: the property turns red and names the parameter. -
Added. A test that asks the one question neither package can answer
alone: does the application behind the validator receive the value the
generator recorded? A case is generated, materialized, validated, and then
sent throughPsr15Transport, which reads it the wayparse_str()and the
SAPI do — and all three readings have to agree. A validator whose reading of
the wire is not the server's reading passes requests the application will
mishandle, and that is precisely how a+in the query stood as a literal
plus to the validator and a space to every SAPI for the life of the package.
The half of the question a generator cannot ask — wire forms a client sends
and a generator never emits, always percent-encoded as it is — is covered by
a raw-wire data provider beside it. Verified by reverting the fix in the
installed contract: the corresponding case turns red. -
Fixed.
RedactionPolicy::cookiesdoes something (#73). TheCookie
header was redacted wholesale by the default header set, so a policy naming a
cookie and one that did not produced byte-identical output — the option was
inert. It was also defending the wrong thing: the reproducer never applies
credentials, by construction, so what it hid was the case's own generated
data.cookieis out of the default set; a named cookie is redacted and the
rest of the header stays readable.authorization,proxy-authorizationand
set-cookiestay wholesale, because a header arrives as one opaque string
and its name is all there is to judge it by. -
Changed.
minMsiis 92 rather than 93, against a measured 93.05% (#75).
A gate set at the current score has no headroom: adding source code adds
mutants, some equivalent by construction, and the score falls before any test
can be written to stop it. Two changes in one wave failed the gate on nothing
but equivalent mutants they had introduced. The alarm the gate exists for — a
real drop of ~36 killed mutants — still fires; the noise does not.