From 8dcfecfc706c0ad12fdce61a0026a05e7c56deda Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Fri, 30 Oct 2026 17:26:52 +0100 Subject: [PATCH 1/2] Allow for the timer resolution when checking the stop timeout RegistrationThatOutlivesItsStopLeavesTheStreamToTheRegistrationThatFollowed asserted that StopAsync() took at least StopTimeout. The timer behind Task.WaitAsync may fire a little before the stopwatch measures the full timeout, and on a CI runner the stop returned just under 200 ms. The test now allows 50 ms for that, and checks directly that the stop gave up on the registration: the registrar no longer runs and nothing was published. Signed-off-by: Thomas Darimont --- .../Stream/SsfStreamManagementTests.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/EasySsf.Receiver.Tests/Stream/SsfStreamManagementTests.cs b/tests/EasySsf.Receiver.Tests/Stream/SsfStreamManagementTests.cs index 05d9061..9ab6775 100644 --- a/tests/EasySsf.Receiver.Tests/Stream/SsfStreamManagementTests.cs +++ b/tests/EasySsf.Receiver.Tests/Stream/SsfStreamManagementTests.cs @@ -16,6 +16,9 @@ public sealed class SsfStreamManagementTests : IClassFixture, I /// how long StopAsync() waits for a registration that does not end, shortened private static readonly TimeSpan StopTimeout = TimeSpan.FromMilliseconds(200); + /// how early a timer may fire relative to the stopwatch, generously + private static readonly TimeSpan TimerResolution = TimeSpan.FromMilliseconds(50); + private readonly List _clients = []; private readonly TestTransmitter _transmitter; @@ -389,7 +392,11 @@ public async Task RegistrationThatOutlivesItsStopLeavesTheStreamToTheRegistratio // one, which finds the stream the first created and adopts it long stopping = TimeProvider.System.GetTimestamp(); await registrar.StopAsync(); - Assert.True(TimeProvider.System.GetElapsedTime(stopping) >= StopTimeout); + // StopAsync() waited for the registration, give or take the resolution of the timer, which + // may fire a little before the stopwatch measures the full timeout (seen on a CI runner) + Assert.True(TimeProvider.System.GetElapsedTime(stopping) >= StopTimeout - TimerResolution); + Assert.False(registrar.IsRunning); + Assert.Empty(registered); registrar.Start(); await Eventually.UntilAsync(() => _receiverStream.StreamId is not null); Assert.Equal(streamId, _receiverStream.StreamId); From 71827d660251f925d0e8071058d4e9b0b9fbaf09 Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Fri, 30 Oct 2026 17:21:04 +0100 Subject: [PATCH 2/2] Release 0.7.0 Signed-off-by: Thomas Darimont --- CHANGELOG.md | 13 ++++++++++++- Directory.Build.props | 2 +- README.md | 12 ++++++------ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74be60d..649bef3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,16 @@ prereleases follow the Java development line (`0.7.0-alpha.N` alongside `0.7.0-S ## [Unreleased] +## [0.7.0] - 2026-10-30 + +A release of hardening, matching easyssf for Java 0.7.0. The poll endpoint is held to the URI +policy of the transmitter's metadata endpoints before the access token goes to it, responses from +the transmitter are bounded, 4 MiB by default, and every stream configuration the transmitter +returns has its issuer checked, not only a created one. Stopping and starting the stream registrar +again no longer leaves a stream behind or deletes the wrong one. Java's fixes for a host name like +`127.attacker.example` passing for loopback and for the pending-acks gauge turning `NaN` needed no +counterpart: neither bug occurs in .NET. + ### Security - The poll endpoint is held to the URI policy of the transmitter's metadata endpoints before the @@ -114,6 +124,7 @@ an in-process test transmitter. Six packages under the reserved prefix `EasySsf` conformance suite with push and poll delivery. Both are built with the solution and not published. -[Unreleased]: https://github.com/easyssf/easyssf-dotnet/compare/v0.6.0...HEAD +[Unreleased]: https://github.com/easyssf/easyssf-dotnet/compare/v0.7.0...HEAD +[0.7.0]: https://github.com/easyssf/easyssf-dotnet/compare/v0.6.0...v0.7.0 [0.6.0]: https://github.com/easyssf/easyssf-dotnet/compare/v0.6.0-alpha.1...v0.6.0 [0.6.0-alpha.1]: https://github.com/easyssf/easyssf-dotnet/releases/tag/v0.6.0-alpha.1 diff --git a/Directory.Build.props b/Directory.Build.props index be1b42f..544e430 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ latest enable enable - 0.7.0-alpha.1 + 0.7.0 easyssf contributors Apache-2.0 diff --git a/README.md b/README.md index b92cbe5..7cb27ce 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ behaviour; the two share their test suites, their database tables and their Keyc | | | |---|---| -| **Status** | Experimental, feature complete relative to the Java library; on [NuGet.org](https://www.nuget.org/profiles/easyssf) since `0.6.0`, and below 1.0 a minor version may break the API | +| **Status** | Experimental, feature complete relative to the Java library; on [NuGet.org](https://www.nuget.org/profiles/easyssf) since `0.7.0`, and below 1.0 a minor version may break the API | | **.NET** | 10, the current LTS; older runtimes leave support in November 2026 and are not targeted | | **Scope** | Receiver only; a transmitter is not planned, `EasySsf.Core` is written so that one could share it | | **Package prefix** | `EasySsf` | @@ -102,8 +102,8 @@ behaviour; the two share their test suites, their database tables and their Keyc Reference `EasySsf.Receiver.Hosting` and, for push delivery, `EasySsf.Receiver.AspNetCore`: ```xml - - + + ``` Configure the transmitter, register the receiver and your handlers, and map the push endpoint: @@ -227,7 +227,7 @@ unknown to the others. `EasySsf.Receiver.Data` keeps that state in the database application instead, in three tables that are the same as those of the Java library: ```xml - + ``` | Table | Store | Content | @@ -373,7 +373,7 @@ The meter `EasySsf.Receiver` records, under the names of the Java library: Without a framework, `EasySsf.Receiver` is the package to reference (it brings `EasySsf.Core`): ```xml - + ``` ```csharp @@ -580,7 +580,7 @@ Set and metadata to an `HttpClient` in-process, without a socket. The tests of e it. ```xml - + ``` ```csharp