diff --git a/docs/security.md b/docs/security.md index bd44294b..d313d65e 100644 --- a/docs/security.md +++ b/docs/security.md @@ -890,7 +890,7 @@ The fifth, `MapZbLocalDbSync()`, returns `IEndpointRouteBuilder` rather than an `app.MapGroup(string.Empty).AllowAnonymous().MapZbLocalDbSync()`, which carries the convention without changing the wire route pattern. -**Two standing guards**, both in `tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/`, so a future map +**Three standing guards**, all in `tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/`, so a future map cannot silently reopen this: - `MeshGrpcAnonymousMetadataTests` — an endpoint-metadata census that calls the SAME @@ -899,7 +899,7 @@ cannot silently reopen this: and a scope check that the opt-out never leaks onto an unrelated endpoint. - `MeshGrpcMapConventionTests` — a `Program.cs` source scan asserting zero direct `MapGrpcService( + // Review (R3-01): asserting a bare Exception was vacuous — an anonymised endpoint ALSO throws + // here (handler deps are not wired in this fixture => RpcException Unknown). Only the + // cookie-challenge signature discriminates: the FallbackPolicy's 302 to /login is a + // non-gRPC response, surfaced by grpc-dotnet as Internal + PROTOCOL_ERROR. + var ex = await Should.ThrowAsync( () => call.ResponseStream.MoveNext(TestContext.Current.CancellationToken)); + ex.StatusCode.ShouldBe(StatusCode.Internal); + ex.Status.Detail.ShouldContain("PROTOCOL_ERROR"); } // ---------------------------------------------------------------------------------------