Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>0.7.0-alpha.1</Version>
<Version>0.7.0</Version>
<Authors>easyssf contributors</Authors>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
</PropertyGroup>
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` |
Expand Down Expand Up @@ -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
<PackageReference Include="EasySsf.Receiver.Hosting" Version="0.6.0" />
<PackageReference Include="EasySsf.Receiver.AspNetCore" Version="0.6.0" />
<PackageReference Include="EasySsf.Receiver.Hosting" Version="0.7.0" />
<PackageReference Include="EasySsf.Receiver.AspNetCore" Version="0.7.0" />
```

Configure the transmitter, register the receiver and your handlers, and map the push endpoint:
Expand Down Expand Up @@ -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
<PackageReference Include="EasySsf.Receiver.Data" Version="0.6.0" />
<PackageReference Include="EasySsf.Receiver.Data" Version="0.7.0" />
```

| Table | Store | Content |
Expand Down Expand Up @@ -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
<PackageReference Include="EasySsf.Receiver" Version="0.6.0" />
<PackageReference Include="EasySsf.Receiver" Version="0.7.0" />
```

```csharp
Expand Down Expand Up @@ -580,7 +580,7 @@ Set and metadata to an `HttpClient` in-process, without a socket. The tests of e
it.

```xml
<PackageReference Include="EasySsf.Testing" Version="0.6.0" />
<PackageReference Include="EasySsf.Testing" Version="0.7.0" />
```

```csharp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public sealed class SsfStreamManagementTests : IClassFixture<TestTransmitter>, I
/// <summary>how long StopAsync() waits for a registration that does not end, shortened</summary>
private static readonly TimeSpan StopTimeout = TimeSpan.FromMilliseconds(200);

/// <summary>how early a timer may fire relative to the stopwatch, generously</summary>
private static readonly TimeSpan TimerResolution = TimeSpan.FromMilliseconds(50);

private readonly List<HttpClient> _clients = [];

private readonly TestTransmitter _transmitter;
Expand Down Expand Up @@ -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);
Expand Down
Loading