Repository navigation
Releases: ipjohnson/Hardened.Framework
Releases · ipjohnson/Hardened.Framework
Release list
v0.43.0-rc1000
What's Changed
- Document where the JWT attribute goes, contract-first JWT, and a token whose nbf is after its exp by @ipjohnson in #587
- Document referencing a library, the Lambda Program.cs, and stream refusal media types by @ipjohnson in #588
- Correct cors.md on Vary: Origin and the ASP.NET Core logging filter by @ipjohnson in #589
- Log the response mode variable once in the SSE buffered-mode warning by @ipjohnson in #590
- Log line and template .gitignore fixes by @ipjohnson in #591
- Cover Hardened.Web.Testing for PR #592 by @ipjohnson in #593
- Give Returns() results Headers and name field errors in its failures by @ipjohnson in #592
- Payload 1.0 and uniform problem details by @ipjohnson in #594
- Report every missing JWT setting in one startup failure by @ipjohnson in #595
- Document data access, Lambda cold start, SAM and idempotency keys by @ipjohnson in #596
- A generated doc comment has two lines by @ipjohnson in #597
- Warn on an inline [Pattern] in the hardened-web template by @ipjohnson in #598
- Expose WWW-Authenticate to cross-origin scripts by default by @ipjohnson in #599
- Resolve a configuration-model interface named as a handler parameter by @ipjohnson in #600
- Load HardenedCoreModule beside a test's entry point by @ipjohnson in #601
- Write aws-lambda-tools-defaults.json beside each Lambda project in the templates by @ipjohnson in #603
- Keep a relative servers URL and the whole info object in the generated document by @ipjohnson in #602
- Scaffold a [LambdaWebTesting] test class in the aws-lambda web template by @ipjohnson in #604
- Delete stale OpenAPI, Smithy and validator outputs after a contract rename by @ipjohnson in #605
- Publish no 403 for [Authorize] alone by @ipjohnson in #606
- Log the Hardened environment on the ASP.NET Core host by @ipjohnson in #607
- Send the /docs request panel to the served origin in development by @ipjohnson in #608
- Document named-argument construction for generated models by @ipjohnson in #609
- Send messages unescaped and leave failure media types out of the 406 by @ipjohnson in #610
- Generate ToWire beside TryParseWire on enum converters by @ipjohnson in #611
- Publish problem type and Location as uri-reference strings by @ipjohnson in #612
- Name the member's type when a record member has a value of the wrong type by @ipjohnson in #613
- Publish minLength 1 on a [Required] string that refuses an empty one by @ipjohnson in #614
- Publish a code-first parameter's default in its schema by @ipjohnson in #615
- Declare 415 on every operation that reads a body by @ipjohnson in #616
- Let a change façade send a transition with distinct before and after rows by @ipjohnson in #618
- Report the time until a permit returns in RateLimit-Reset by @ipjohnson in #617
- Report every parameter binding failure with the constraint errors beside it by @ipjohnson in #619
- Report every undeclared enum value in a JSON body beside the other errors by @ipjohnson in #621
- Let a test assembly reuse one container on the pipeline host by @ipjohnson in #623
- Release 0.43.0-rc1000 by @ipjohnson in #624
Full Changelog: v0.42.0-rc1000...v0.43.0-rc1000
v0.42.0-rc1000
New packages
Hardened.Requests.Jwtvalidates JWT bearer tokens. It depends onMicrosoft.IdentityModel.JsonWebTokens8.23.0, and it is the only package that does.Hardened.Requests.Jwt.Testingmints tokens for tests (#510).
Breaking changes
Source and binary
Hardened.Shared.Runtime.Json.IJsonSerializerConfigurationandJsonSerializerConfigurationare renamed toISharedJsonConfigurationandSharedJsonConfiguration. TheHardened.Requests.Runtime.Configurationpair is unchanged (#506).- The constructors of
ExecutionRequestHandlerInfoandResponseCacheFiltergained trailing optional parameters, and the constructors ofAotJsonSerializerandJsonSerializerImplchanged 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, withAllowMultiple = true. It no longer compiles on any other target (#482).Hardened.Refit.Testingdepends 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-webtemplate pins Refitter 2.2.1 and sets"optionalParameters": truein.refitter. A regenerated client makes optional parameters optional arguments, and a streamed operation returnsIAsyncEnumerable<T>(#480). - An OpenAPI scalar request body with a
formatbinds to the formatted type.int64binds tolong,date-timetoDateTimeOffsetandbinarytobyte[]. The handler's parameter type changes (#477).
Diagnostics
HSMT035is a new error. It fires on a Smithy@paginatedtrait 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).HRDR011is 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).HRDW009is a new warning. It fires when a[CacheResponse<VaryByQuery>]key names no query key the operation binds (#506).HRDR012now 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,ConflictandBadRequestimplementIProblemDetailsand go out asapplication/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
patternor a Smithy@patternlabel 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
@httpPayloadblob and an OpenAPIformat: binarybody are the raw request body. A client that sent base64 in a JSON string must send the bytes (#477). - A Smithy error member with
@httpHeaderis sent as a response header and left out of the body. A service'serrorsapply to every operation in it, so an operation's 400 can become the service's declared error in place ofRequestValidationError(#478). [Authorize<TScheme>],[AuthorizeGrants]or anotherIAuthorizeAttributeon 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
CorsConfigurationregistered in a library module takes effect on the host. A route with[Cors], and every response once an origin is configured, carriesVary: Origin. A preflight allows the headers the operation reads (#506). - A response that compression would compress carries
Vary: Accept-Encodingeven 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. UnderStrictnegotiation, a request whoseAcceptnames types but not the stream's media type gets 406 (#506). - On AWS Lambda and Azure Functions, a request with no
Acceptheader names nothing. These hosts used to read it asapplication/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-Typeno deserializer reads answers 415 with anAcceptheader. It used to be read as JSON. A body with noContent-Typeis still read as JSON, andtext/jsonand+jsontypes are now read as JSON (#506). - The test harness sends
application/jsonfor a body with noContent-Type(#506). - On Kestrel and ASP.NET Core, a body over
MaxRequestBodySizeanswers 413. It used to answer 500 (#506). - A
DateTimeOffsetin a JSON request body must state its offset.2030-01-01T00:00:00gets 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_ENVIRONMENTdefaults toproductionwhenAWS_LAMBDA_RUNTIME_APIis set, so it no longer serves/docs. A local run throughLambdaEmulator.StartIfLocalstaysdevelopment(#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_FORMATis notJSONlogs a warning at startup.LambdaEmulator.StartIfLocalsets it toJSON(#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 aWWW-Authenticateheader (#486). - A
[Required]member no longer publishesnullin its schema (#506). - Without
[OpenApiInfo], the title is the assembly's name, not the module's class name (#506). [ConditionalGet]publishesIf-Modified-Sinceonly where the operation declaresLast-Modifiedon its 200, with[AnswersHeader(200, KnownHeaders.LastModified)](#506).[RateLimit]publishesRateLimit-Limit,RateLimit-RemainingandRateLimit-Reseton 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 callscontext.CreateHttpClient, beside[Grants],[Subject]or[Anonymous], and by a sharedITestWebApp's clients. Tests that relied on a fresh container per request there now share one (#481).TestWebResponse.Deserialize<T>()andDeserializeAsyncEnumerable<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 https://githu...
v0.41.0-rc1000
Breaking changes
Hardened.Validation.SourceGeneratoris removed. Replace<PackageReference Include="Hardened.Validation.SourceGenerator" />with<PackageReference Include="ValidationModules.SourceGenerator" Version="1.2.0" />. A nested type's validator is renamed fromInnerValidatortoOuter_InnerValidator. HRDV002, HRDV003 and HRDV004 are gone. A project with two[HardenedModule]classes now reports VM6001 (#432).- ValidationModules 1.2.0 changes
[StringLength].[StringLength(min, max)]no longer compiles, and[StringLength(n)]is now a maximum ofnwhere it was a minimum. A value that times out a pattern answers 400 instead of 500 (#431). - Every entity tag
[ConditionalGet]computes changes, because tags are now SHA-1. A client holding an old tag gets a 200 with the new tag on its first conditional request after the upgrade, and 304s after that. A response cache store an application wrote that outlives the deploy replays each entry's old tag until the entry expires (#435). IOFilterProviderandAsyncEnumerableIoFiltereach gained an optionalIMemoryStreamPoolconstructor parameter. Source that calls them compiles unchanged. A binary compiled against 0.40.0 that calls either constructor must be rebuilt (#434).
What's Changed
- Move repeated project settings into props files, pack the solution, and prune redundant references by @ipjohnson in #430
- Take ValidationModules 1.2.0 by @ipjohnson in #431
- Replace Hardened.Validation.SourceGenerator with ValidationModules' generator by @ipjohnson in #432
- Write each streamed item to the transport as one write by @ipjohnson in #434
- Tag conditional responses with SHA-1 and hold the body in a pooled MemoryStream by @ipjohnson in #435
- Release 0.41.0-rc1000 by @ipjohnson in #436
Full Changelog: v0.40.0-rc1000...v0.41.0-rc1000
v0.40.0-rc1000
Security
- Azure Functions enforced no authorization. On every release up to and including
0.39.0-rc1000, the isolated worker never ran the application's startup services, so authorization, authentication and CORS were not installed. Under[RequireAuthorization]or[AuthorizeGrants], a guarded HTTP route answered a caller with no credential. The trigger is emitted atAuthorizationLevel.Anonymous, so function keys were not a backstop. Fixed by #395 (#386, #412). Upgrade any Azure Functions application that uses Hardened's authorization. - A MessagePack request body could stop the process. Bodies were read with
TrustedData, which sets no depth limit, so a small, deeply nested body ended in aStackOverflowException, which cannot be caught. Bodies are now read withUntrustedData(#404). An application that set its ownMessagePackSecuritykeeps it.
Breaking changes
Hardened.Shared.Testing.xUnitandHardened.Shared.Testing.NUnitare removed, and[HardenedTest]with them. A test project uses[ModuleTest]fromDependencyModules.xUnit,DependencyModules.xUnit4orDependencyModules.NUnit.CurrentTestandICurrentTestProviderare removed fromHardened.Shared.Testing(#424).- A form handler answers 415 for a body that is not a form, and 413 for a url-encoded body over
FormConfiguration.MaxBodyBytes. A form with more than 1,024 fields answers 400. AFormatExceptionthrown by a handler answers 500 instead of 400 (#420). HAUTH002is a new warning:[AllowAnonymous]cancels an authorization attribute on the same handler's method (#423). A build that treats warnings as errors fails on it.- A
<see cref>in a handler's doc comment now puts the name it points at into the OpenAPIsummaryordescription, in place (#428). An exported document changes for every handler that uses one.
What's Changed
- Rewrite the documentation site by @ipjohnson in #389
- Fix UseHttps and SIGTERM on the Kestrel host, and run startup services on Azure Functions by @ipjohnson in #395
- Install Azure Functions Core Tools from its GitHub release by @ipjohnson in #403
- Read MessagePack request bodies with UntrustedData by @ipjohnson in #404
- Keep Roslyn out of applications, and stamp the release version into the assemblies by @ipjohnson in #413
- Refuse oversized and non-form bodies on form handlers, and answer a handler's FormatException with 500 by @ipjohnson in #420
- Count keys and headers against the response cache's size limit, and document cache durations from configuration by @ipjohnson in #421
- Give contract patterns a match timeout, and add [ValidateNever] to skip validation by @ipjohnson in #422
- Warn when [AllowAnonymous] cancels a handler's requirement, and document cross-site requests and public trigger services by @ipjohnson in #423
- Serve a run-time static content directory under a route prefix by @ipjohnson in #425
- Replace [HardenedTest] with DependencyModules' [ModuleTest], and remove the runner packages by @ipjohnson in #424
- Accept a Lambda deadline more than 49.7 days away by @ipjohnson in #427
- Ship symbol packages and XML documentation from every Hardened library by @ipjohnson in #428
- Release 0.40.0-rc1000 by @ipjohnson in #429
Full Changelog: v0.39.0-rc1000...v0.40.0-rc1000
v0.39.0-rc1000
What's Changed
- Stop ending NDJSON streams with a blank line by @ipjohnson in #390
- Add [ValidationMode] to stop validation at the first failure by @ipjohnson in #391
- Add [Cors] to limit CORS to the routes that declare it by @ipjohnson in #392
- Release 0.39.0-rc1000 by @ipjohnson in #394
Full Changelog: v0.38.0-rc1000...v0.39.0-rc1000
v0.38.0-rc1000
Breaking changes
- A spec-first property that references a named map is now
Dictionary<string, T>?rather thanJsonElement?(#382). Handler code that read it as aJsonElementstops compiling. - HRDW007 fails the build for a
[FromForm]or[FromQueryString]model the binder cannot construct (#381). Before this release such a parameter compiled and answered 400 to every request.
What's Changed
- Bind a model from a form or a query string by @ipjohnson in #381
- Type a property that references a named map as the map by @ipjohnson in #382
- Bind multipart forms and files by @ipjohnson in #383
- Rewrite the README from scratch by @ipjohnson in #384
- Release 0.38.0-rc1000 by @ipjohnson in #388
Full Changelog: v0.37.0-rc1000...v0.38.0-rc1000
v0.37.0-rc1000
What's Changed
- Escape a backslash when the handler catalog writes a C# literal by @ipjohnson in #368
- Record an attributed parameter as unresolved rather than dereferencing null by @ipjohnson in #369
- Give a registered route its own operation by @ipjohnson in #370
- Hold a lambda registration to the constraint its tokens need by @ipjohnson in #371
- Read what a lambda registration declares about its response by @ipjohnson in #372
- Answer with the bytes a response set's success case carries by @ipjohnson in #373
- Drop the async from a binder that has nothing to await by @ipjohnson in #375
- Write the object under the portable name in the blob adapters by @ipjohnson in #376
- Verify the combinations the templates refuse by @ipjohnson in #377
- Take validators from ValidationModules' own generator by @ipjohnson in #378
- Carry Ok's single header without a dictionary by @ipjohnson in #379
- Release 0.37.0-rc1000 by @ipjohnson in #380
Full Changelog: v0.36.0-rc1000...v0.37.0-rc1000
v0.36.0-rc1000
What's Changed
- Write the documented version in one place by @ipjohnson in #354
- Use a semicolon body for type declarations with no members by @ipjohnson in #355
- Adopt CSharpier as the formatter by @ipjohnson in #356
- Render a view for every caller, and publish what it writes by @ipjohnson in #357
- Key a cached response on the representation it holds by @ipjohnson in #358
- Bind a byte[] or Stream body to the bytes by @ipjohnson in #359
- Register routes whose paths only exist at run time by @ipjohnson in #360
- Register a route with a lambda by @ipjohnson in #361
- Describe the registered routes in the document by @ipjohnson in #362
- Speed up route matching and fix a generator crash by @ipjohnson in #363
- Write path tokens into the request, not into RequestHandlerInfo by @ipjohnson in #364
- Read the registered-routes documentation as one page by @ipjohnson in #365
- Run a Hardened application as a Cloud Functions 2nd gen function by @ipjohnson in #366
- Release 0.36.0-rc1000 by @ipjohnson in #367
Full Changelog: v0.35.0-rc1000...v0.36.0-rc1000
v0.35.0-rc1000
What's Changed
- Rewrite validation, routing and response caching in Simple Technical English by @ipjohnson in #347
- Decode MessagePack in the reference page, and restore a nested case type's schema by @ipjohnson in #348
- Verify the constraints the templates declare, on the wire and in the document by @ipjohnson in #349
- Describe seven things the generated document was getting wrong by @ipjohnson in #350
- Support static handler methods by @ipjohnson in #351
- Describe rendering HTML from a .cshtml view in the README by @ipjohnson in #352
- Point the documentation at 0.35.0-rc1000, and open the 0.36.0 line by @ipjohnson in #353
Full Changelog: v0.34.0-rc1000...v0.35.0-rc1000
v0.34.0-rc1000
What's Changed
- Issue a 13-character correlation id when nothing is tracing by @ipjohnson in #333
- Decide the response content type at compile time by @ipjohnson in #334
- Remove three allocations from the path every request takes by @ipjohnson in #335
- Gate allocation on every pull request, and give the harnesses their 404 back by @ipjohnson in #336
- Serve MessagePack, and describe every media type an operation produces by @ipjohnson in #338
- Move the build inputs out of the repository root, and stop tracking .claude by @ipjohnson in #337
- Carry a MessagePack key from the contract to the generated client by @ipjohnson in #339
- Skip a verb attribute on an interface instead of crashing the generator by @ipjohnson in #340
- Give each template its own options table in the README by @ipjohnson in #341
- Give the generated client a MessagePack serializer, and say what Refit will not do by @ipjohnson in #342
- Point the documentation at 0.34.0-rc1000, and open the 0.35.0 line by @ipjohnson in #345
- Rename [ApiGatewayModule] to [LambdaHttpModule], package included by @ipjohnson in #346
Full Changelog: v0.33.0-rc1000...v0.34.0-rc1000