Skip to content

v0.42.0-rc1000

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 29 Sep 10:39
· 40 commits to main since this release
416d938

New packages

  • Hardened.Requests.Jwt validates JWT bearer tokens. It depends on Microsoft.IdentityModel.JsonWebTokens 8.23.0, and it is the only package that does. Hardened.Requests.Jwt.Testing mints tokens for tests (#510).

Breaking changes

Source and binary

  • Hardened.Shared.Runtime.Json.IJsonSerializerConfiguration and JsonSerializerConfiguration are renamed to ISharedJsonConfiguration and SharedJsonConfiguration. The Hardened.Requests.Runtime.Configuration pair is unchanged (#506).
  • The constructors of ExecutionRequestHandlerInfo and ResponseCacheFilter gained trailing optional parameters, and the constructors of AotJsonSerializer and JsonSerializerImpl changed a parameter type. A library compiled against 0.41.0-rc1000 must be rebuilt, because its generated handler info calls the old constructor (#476, #491, #506).
  • [EnvironmentValue] is now valid on a method, a class and an assembly, with AllowMultiple = true. It no longer compiles on any other target (#482).
  • Hardened.Refit.Testing depends on Refit 16.3.0, up from 8.0.0. A test project that pins Refit 8 must move to 16.3.0 (#480).
  • The hardened-web template pins Refitter 2.2.1 and sets "optionalParameters": true in .refitter. A regenerated client makes optional parameters optional arguments, and a streamed operation returns IAsyncEnumerable<T> (#480).
  • An OpenAPI scalar request body with a format binds to the formatted type. int64 binds to long, date-time to DateTimeOffset and binary to byte[]. The handler's parameter type changes (#477).

Diagnostics

  • HSMT035 is a new error. It fires on a Smithy @paginated trait that names a missing member or a member of the wrong type. The Smithy CLI already refuses these models, so only a committed AST reaches it (#511).
  • HRDR011 is reported at the handler's method name in the project that compiles the handler. A handler project with no entry point can now fail with it (#506).
  • HRDW009 is a new warning. It fires when a [CacheResponse<VaryByQuery>] key names no query key the operation binds (#506).
  • HRDR012 now covers contract-first operations. It warns on a declared media type that nothing writes (#472).
  • A build that skips the extract task reports that task's last warnings again, such as HSMT006. With warnings as errors, every incremental build fails, not only the first (#479).

Wire behaviour

  • Problem records such as NotFound, Conflict and BadRequest implement IProblemDetails and go out as application/problem+json. A failure negotiates within the media types its operation declares for failures (#472).
  • A framework refusal at a status where the operation declares its own body sends that body. This covers validation, a malformed body, a deadline, a binding BadRequestException, an unhandled 500 and the 406. A validation failure at a declared status carries no field errors (#473).
  • A path value that fails an OpenAPI pattern or a Smithy @pattern label answers 400 naming the parameter. It used to answer 404 with no body (#475).
  • In throws mode, a thrown framework record under a contract that declares its own body at that status sends the declared body (#476).
  • A Smithy @httpPayload blob and an OpenAPI format: binary body are the raw request body. A client that sent base64 in a JSON string must send the bytes (#477).
  • A Smithy error member with @httpHeader is sent as a response header and left out of the body. A service's errors apply to every operation in it, so an operation's 400 can become the service's declared error in place of RequestValidationError (#478).
  • [Authorize<TScheme>], [AuthorizeGrants] or another IAuthorizeAttribute on a [HardenedModule] class guards every handler compiled with that module. It used to guard nothing, so anonymous requests those handlers served now get 401. [AllowAnonymous] on a handler still exempts it (#470).
  • The health probes send {"status":"Healthy"} over Kestrel and ASP.NET Core. They used to send an empty 200 (#487).
  • A handler that cleared ShouldSerialize, set a status and then threw before writing answers with the failure's status and body. It used to answer the status it had set, with no body (#487).
  • A CorsConfiguration registered in a library module takes effect on the host. A route with [Cors], and every response once an origin is configured, carries Vary: Origin. A preflight allows the headers the operation reads (#506).
  • A response that compression would compress carries Vary: Accept-Encoding even when it goes out uncompressed, and so does /openapi.json (#506).
  • A [CacheResponse<VaryByQuery>] with no keys varies on every query key the operation binds. It used to throw while the chain was built (#506).
  • In a contract-first implementation, the method's filters come before the class's, and the method's [Timeout] wins. With a class and a method [CacheResponse], the method's key parts come first, so existing cache keys change (#506).
  • A stream that times out before its first item answers its timeout status, 504 by default, with its body. It used to answer 500 with no body (#506).
  • A stream reads Accept. Under Strict negotiation, a request whose Accept names types but not the stream's media type gets 406 (#506).
  • On AWS Lambda and Azure Functions, a request with no Accept header names nothing. These hosts used to read it as application/json (#506).
  • A request cancelled on its own token is logged as one Information line with event id 78006. It used to be logged at Error with a stack trace (#506).
  • A body whose Content-Type no deserializer reads answers 415 with an Accept header. It used to be read as JSON. A body with no Content-Type is still read as JSON, and text/json and +json types are now read as JSON (#506).
  • The test harness sends application/json for a body with no Content-Type (#506).
  • On Kestrel and ASP.NET Core, a body over MaxRequestBodySize answers 413. It used to answer 500 (#506).
  • A DateTimeOffset in a JSON request body must state its offset. 2030-01-01T00:00:00 gets 400. Query, route and header values are unchanged (#506).
  • The 400 message for a value of the wrong type changed. "The JSON value could not be converted to System.Int32." is now "The value is not an integer this field can hold." (#506).
  • A Lambda function with no HARDENED_ENVIRONMENT defaults to production when AWS_LAMBDA_RUNTIME_API is set, so it no longer serves /docs. A local run through LambdaEmulator.StartIfLocal stays development (#506).
  • Environment values are parsed with the invariant culture, and a Nullable<T> converts as its underlying type (#506).
  • A spec-first body whose constraints exist only in the models it holds is validated. Requests that used to reach the handler can now get 400 (#509).
  • On Lambda, startup services run as the bootstrap's initializer, and one that throws is reported as an init error. A function whose AWS_LAMBDA_LOG_FORMAT is not JSON logs a warning at startup. LambdaEmulator.StartIfLocal sets it to JSON (#508).

Published OpenAPI document

  • A failure status whose bodies are all problem records is published under application/problem+json (#472).
  • An operation guarded by a module-level requirement publishes security, a 401 and a 403. An [AllowAnonymous] method under a guarded class no longer publishes its class's requirement (#470).
  • Every guarded operation publishes a 401 with WWW-Authenticate. When the document declares exactly one scheme, a guarded operation that names none is published under it. The 403 lists a WWW-Authenticate header (#486).
  • A [Required] member no longer publishes null in its schema (#506).
  • Without [OpenApiInfo], the title is the assembly's name, not the module's class name (#506).
  • [ConditionalGet] publishes If-Modified-Since only where the operation declares Last-Modified on its 200, with [AnswersHeader(200, KnownHeaders.LastModified)] (#506).
  • [RateLimit] publishes RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset on every response the operation lists (#506).
  • A header-bound Smithy member is no longer listed under the body schema's properties (#478).
  • A path parameter with a pattern publishes the validation 400 (#475).

Testing

  • [Shared] is honoured by Kiota clients, by a factory that calls context.CreateHttpClient, beside [Grants], [Subject] or [Anonymous], and by a shared ITestWebApp's clients. Tests that relied on a fresh container per request there now share one (#481).
  • TestWebResponse.Deserialize<T>() and DeserializeAsyncEnumerable<T>() read with the application's JSON options and resolvers (#482).

What's Changed

  • Store the handler's 200 when a revalidation fills the response cache by @ipjohnson in #468
  • Apply [Authorize] on a module class to every handler compiled with it by @ipjohnson in #470
  • Send problem documents as application/problem+json by @ipjohnson in #472
  • Send the declared body for the framework's own refusals by @ipjohnson in #473
  • Answer a path value that fails its pattern with 400, not a bodyless 404 by @ipjohnson in #475
  • Send a thrown framework record as the body the contract declares by @ipjohnson in #476
  • Bind a described binary request body to the raw bytes by @ipjohnson in #477
  • Bind a Smithy error's header members and apply a service's errors by @ipjohnson in #478
  • Replay a build task's warnings, prune stale generated files, and fix two Smithy notes by @ipjohnson in #479
  • Pin Refitter 2.2.1 and Refit 16.3.0, make optional client parameters optional, and name the restore race by @ipjohnson in #480
  • Send a [Shared] client's requests to one container on every construction path by @ipjohnson in #481
  • Read test responses with the application's JSON settings, carry claims, stream socket bodies, and add Accepted by @ipjohnson in #482
  • Carry content headers through the Lambda test host's client handler, and let a test set the remaining time by @ipjohnson in #485
  • Publish the 401 for every guarded operation, the one scheme for a requirement naming none, and the 403's challenge by @ipjohnson in #486
  • Send the health probes' body on a socket, answer a handler that threw after taking over its body, and let default-deny keep the probes and document public by @ipjohnson in #487
  • Land the 0.41 trial fixes for #452 to #461, #465 to #467 and #419 by @ipjohnson in #506
  • Add a mixed Lambda response mode that streams only event streams and NDJSON by @ipjohnson in #507
  • Log Lambda functions in JSON, and run their startup services under the runtime's writer by @ipjohnson in #508
  • Validate constraints reachable only through a nested model by @ipjohnson in #509
  • Ship a JWT bearer principal source in its own package by @ipjohnson in #510
  • Add Page and page tokens, and read Smithy's @paginated by @ipjohnson in #511
  • Release 0.42.0-rc1000 by @ipjohnson in #512

Full Changelog: v0.41.0-rc1000...v0.42.0-rc1000