From a05140e14235287a533bcc66c60b56ffd531bc39 Mon Sep 17 00:00:00 2001 From: beamologist Date: Thu, 29 Oct 2026 02:01:30 +0100 Subject: [PATCH 1/2] release 0.9.0: the A0 re-seal, and what this release does not change libmacula is pinned to macula-go v0.29.0, the release that carries the A0 contract: a call a keyed provider refuses sealed_required is resealed to the key in the refusal's signed tbs and answered, instead of the caller failing on a stale keyless candidate. The 0.9.0 intro said v0.27.0 while the pin is v0.29.0, and the heading was dated the flag day on a release first tagged now. Both fixed, with v0.27.0 kept as history. The note states what does not change as well: KemAdvertise is off by default (src/Macula/Pool.cs:42), so two pools on default options talk in the clear, and a procedure served with no policy is advertised open, unary and streaming alike (macula-dotnet#24, macula-dotnet#25). Refs macula-dotnet#21, macula-dotnet#24, macula-dotnet#25. --- CHANGELOG.md | 26 ++++++++++++++++++++++---- README.md | 5 +++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3576d28..1ea8d0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.9.0] - 2026-10-19 +## [0.9.0] - 2026-10-29 The wire 1.0 release, for the fleet's flag day (19 Oct 2026, 18:03 UTC): from then on every live station speaks wire 1.0 (macula 15) and nothing older, and -0.8.0 can no longer connect. libmacula is macula-go v0.27.0, whose code is -v0.27.0-rc.8's; this package's code is 0.9.0-rc.5's. The entries for rc.1 to -rc.5 below are what changed since 0.8.0. +0.8.0 can no longer connect. libmacula is macula-go v0.29.0, the release that +carries the A0 contract (v0.27.0 at the flag day); this package's code is +0.9.0-rc.5's. The entries for rc.1 to rc.5 below are what changed since 0.8.0. + +### Changed since this entry was written + +- **A call a keyed provider refuses `sealed_required` is resealed and answered**, instead of the + caller failing on a stale keyless candidate: the caller seals again to the key in the refusal's + signed tbs, which is the key the provider holds now (macula-go v0.29.0, macula-dotnet#21). + +### What this release does not change + +- Sealing is the default where the provider names a key, and only there. A provider names a KEM key + only when it opts in with `KemAdvertise`, which is off by default (`src/Macula/Pool.cs:42`), so two + pools on default options talk in the clear. A served procedure is `ServedConfidential.Preferred` + by default, which names the key when the pool advertises one, and a caller still reaches a + provider that names no key in the clear. Refusing a clear call unless the caller opts out is not + in this release. +- A procedure served with no policy is advertised open, unary and streaming alike: `Serve` and + `ServeStream` take the policy as an optional parameter, and omitting it serves any caller + (macula-dotnet#24 for streams, macula-dotnet#25 for unary). ## [0.9.0-rc.5] - 2026-10-17 diff --git a/README.md b/README.md index c9a4cb7..fde1600 100644 --- a/README.md +++ b/README.md @@ -239,6 +239,11 @@ var (result, report) = await caller.CallReportAsync(realm, procedure, payload, - `KemAdvertise` is off by default. Enable it only once every station runs macula 12.11 or later and every caller can seal (macula 13, macula-go 0.18, Macula .NET 0.7 or later). +- A keyed provider that refuses a call `sealed_required`, because its key rotated + between the advertisement the caller read and the call, has the call resealed + to the key in the refusal's signed tbs and answered, the key that provider + holds now, rather than the caller failing on a stale keyless candidate + (macula-go v0.29.0). - A served procedure is `ServedConfidential.Preferred` by default: it names the key when the pool advertises one, and still takes a clear call while its last keyless advertisement could be served. `Required` refuses every clear From d5d53c17e507db6e45a10eb05f2c6fe20c72b16a Mon Sep 17 00:00:00 2001 From: beamologist Date: Thu, 29 Oct 2026 02:01:54 +0100 Subject: [PATCH 2/2] release 0.9.0: sealed_required is a keyless advertisement, not a rotated key The paragraph as first written gave the wrong cause: sealed_required comes from a caller holding a KEYLESS advertisement and calling clear, while a caller holding an old key gets sealed_refused with the current key id in detail. Caught in the macula-py review of the same sentence before this branch was reviewed. Refs macula-dotnet#21. --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fde1600..bfce791 100644 --- a/README.md +++ b/README.md @@ -239,11 +239,10 @@ var (result, report) = await caller.CallReportAsync(realm, procedure, payload, - `KemAdvertise` is off by default. Enable it only once every station runs macula 12.11 or later and every caller can seal (macula 13, macula-go 0.18, Macula .NET 0.7 or later). -- A keyed provider that refuses a call `sealed_required`, because its key rotated - between the advertisement the caller read and the call, has the call resealed - to the key in the refusal's signed tbs and answered, the key that provider - holds now, rather than the caller failing on a stale keyless candidate - (macula-go v0.29.0). +- A keyed provider that refuses a call `sealed_required`, because the + advertisement the caller read named no key, has the call resealed to the key in + the refusal's signed tbs and answered, the key that provider holds now, rather + than the caller failing on a stale keyless candidate (macula-go v0.29.0). - A served procedure is `ServedConfidential.Preferred` by default: it names the key when the pool advertises one, and still takes a clear call while its last keyless advertisement could be served. `Required` refuses every clear