Skip to content

Commit 5bf5559

Browse files
dforsberclaude
andcommitted
chore(release): catch up to 0.10.24 / chart 0.3.31
CHANGELOG backfill for the three releases the public repo missed: - 0.10.22 — license-enforced cluster caps (NEW): community/starter/ growth/scale tiers, ed25519-signed license, `boilstream-admin license install/status/request/remove`, free-tier 8 vCPU / 2 pod cap. - 0.10.23 — license integrity hardening: hash-pinned PEMs, dual-key signature, replay watermark, runtime cap re-check at PGWire / Flight / Kafka / broker-register. - 0.10.24 — `cluster_secret.json` auto-bootstrap on first leader election; fix for license-binding prefix mismatch that caused valid licenses to be rejected on multi-pod clusters. Chart 0.3.28 → 0.3.31; appVersion 0.10.21 → 0.10.24. README and values-hetzner-example.yaml bumped to 0.10.24. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7833a98 commit 5bf5559

4 files changed

Lines changed: 70 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,71 @@ All notable changes to BoilStream will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.10.24] - 2026-04-27
9+
10+
### Fixes
11+
12+
- **License-binding prefix mismatch on multi-pod clusters.** The runtime `ClusterBinding` was built from the cluster_state directory prefix (e.g. `cluster/cluster_state/`) while licenses are signed against, and `boilstream-admin license request` reports, the parent prefix (`cluster/`). On 0.10.23 every valid license was rejected with `WrongBinding` and the cluster fell back to community caps. Fixed by trimming the trailing `cluster_state/` segment in `ClusterConfig::license_binding_prefix()` before binding comparison.
13+
14+
### Enhancements
15+
16+
- **Automatic `cluster_secret.json` bootstrap on first leader election.** Previously, `boilstream-admin license install` would fail its pre-flight binding check on a brand-new cluster because nothing wrote `cluster_state/cluster_secret.json` until an operator did so by hand. The elected leader (both at initial startup and during failover promotion) now creates it via an atomic `PutMode::Create` on first leadership acquisition. The persisted bytes become the source of truth for `cluster_secret_hash` going forward, and the file is available before the first license refresh runs.
17+
- **Race-safe across multi-pod startup** — when several pods race for leadership and call the bootstrap simultaneously, exactly one wins the conditional PUT; the loser falls through to GET and continues with the winner's secret.
18+
- **Pre-existing secrets are never overwritten** — operators migrating from a previous deployment can pre-seed `cluster_secret.json`; the bootstrap detects the existing object and adopts it.
19+
20+
### Notes
21+
22+
- Chart version **0.3.31** tracks appVersion `0.10.24`.
23+
24+
## [0.10.23] - 2026-04-26
25+
26+
### Enhancements — License integrity hardening
27+
28+
License enforcement gains four layers of defence against binary tampering and signed-license replay. No customer-visible API changes.
29+
30+
- **Embedded public-key hash-pin.** The license module's primary and secondary ed25519 PEMs are SHA-256 hashed at build time and re-checked at every load. A binary patcher who swaps the embedded PEM bytes must also find and patch the (separately-located) hex digest constants.
31+
- **Memory integrity checker.** The leader heartbeat re-hashes both PEMs in-memory each cycle and trips a sticky `tampered` flag on drift. Once set, all data-plane cap checks (PGWire, Flight, Kafka) deny new connections until the operator restarts the process.
32+
- **M-of-2 dual-key signature.** Operators can mint licenses dual-signed with two offline private keys. Both signatures must verify; either side's failure trips the same `LicenseError::Signature` as a wholly-invalid token.
33+
- **Replay watermark persistence.** The highest accepted `iat` is now persisted to `cluster_state/license_min_iat.json` alongside the license file. After a leader restart, an attacker who tries to reinstall an older signed license trips the watermark.
34+
- **Runtime cap re-check at four sites** — broker register, PGWire connection accept, Flight `do_get`/`do_put`, and Kafka producer connect all consult the cached license + cached cluster usage. A binary patcher who removes one site still trips on the others.
35+
- **Audit-grep startup line**`License enforcement: vCPU cap=N pod cap=M tier=T (in_grace=…, tampered=…)` emitted at process start.
36+
37+
### Notes
38+
39+
- Chart version **0.3.30** tracks appVersion `0.10.23`.
40+
41+
## [0.10.22] - 2026-04-26
42+
43+
### Features — License-enforced cluster caps (NEW)
44+
45+
BoilStream now enforces cluster-wide vCPU and pod caps from a signed, ed25519-verified license. Without a license the cluster runs on the free tier (8 vCPU / 2 pods cluster-wide); a valid license unlocks higher caps. The upgrade path for paying customers is a single S3 file drop — no restart, no helm upgrade, no environment variable changes.
46+
47+
#### What's new for operators
48+
49+
- `boilstream-admin license install <path-to-license.jwt>` — locally validates the signature, the bucket/prefix binding, and the cluster-secret hash, then PUTs the license to `s3://<bucket>/<prefix>cluster_state/license.json`. The leader picks it up within 30 s without a restart.
50+
- `boilstream-admin license status` — prints the installed license (tier, expiry, caps), and the cluster's current usage in vCPU and active pods.
51+
- `boilstream-admin license request` — prints the bucket / prefix / `cluster_secret_hash` triple a customer pastes into an email to `licenses@boilstream.com` to receive a signed license.
52+
- `boilstream-admin license remove` — deletes the license file (interactive confirm). The cluster reverts to free tier on the next heartbeat.
53+
54+
#### What's new under the hood
55+
56+
- Each broker reports its physical-vCPU count to S3 in its registration record. The leader sums vCPU and pod count across non-stale brokers and rejects new registrations that would exceed the effective cap with a structured error: `License cap exceeded: cluster currently uses N vCPU / M pods, license allows X vCPU / Y pods, this pod would push to N+k / M+1`.
57+
- Existing pods (heartbeat refresh, leader↔worker flip, restart) are never rejected — only NEW registrations are gated. Failover semantics preserved.
58+
- 14-day grace period after a license expires (configurable). During grace, the leader logs WARN per heartbeat but keeps running the licensed tier. Past grace, the cluster falls back to free tier.
59+
- ±300 s clock-skew tolerance for `iat` and `exp`.
60+
- License binding to bucket + prefix + `sha256(cluster_secret.json)` prevents cross-cluster license reuse.
61+
62+
#### Free tier limits
63+
64+
| Tier | vCPU cap | Pod cap |
65+
| --------- | -------- | ------- |
66+
| community | 8 | 2 |
67+
68+
### Notes
69+
70+
- Chart version **0.3.28** tracks appVersion `0.10.22`.
71+
- License enforcement only activates when the cluster coordinator is built with a non-empty bucket name (i.e., real cluster mode). Single-node / standalone deployments are unaffected.
72+
873
## [0.10.21] - 2026-04-26
974

1075
### Fixes

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ See [GitHub releases](https://github.com/boilingdata/boilstream/releases) for th
4343
# linux-aarch64 Linux ARM64 — AWS Graviton-tuned (fastest on AWS EC2 Graviton 2/3/4)
4444
# linux-x64 Linux x86_64
4545
# windows-x64 Windows
46-
# Replace {VERSION} with the latest release (see GitHub releases above, e.g. 0.10.21)
46+
# Replace {VERSION} with the latest release (see GitHub releases above, e.g. 0.10.24)
4747
curl -L -o boilstream https://www.boilstream.com/binaries/darwin-aarch64/boilstream-{VERSION}
4848
curl -L -o boilstream-admin https://www.boilstream.com/binaries/darwin-aarch64/boilstream-admin-{VERSION}
4949
chmod +x boilstream boilstream-admin

charts/boilstream/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ description: |
66
support. Each pod participates in S3-based leader election and serves
77
per-user catalogs; failed pods are recovered from S3 backups.
88
type: application
9-
version: 0.3.28
10-
appVersion: "0.10.21"
9+
version: 0.3.31
10+
appVersion: "0.10.24"
1111
kubeVersion: ">=1.27.0"
1212
keywords:
1313
- streaming

charts/boilstream/values-hetzner-example.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# helm install boilstream ./charts/boilstream \
1313
# -f charts/boilstream/values-hetzner-example.yaml \
1414
# --set image.repository=<your-cfcr-tenant>.europe.registry.cloudfleet.dev/boilstream \
15-
# --set image.tag=aarch64-generic-linux-0.10.21 \
15+
# --set image.tag=aarch64-generic-linux-0.10.24 \
1616
# --set superadmin.existingSecret=boilstream-superadmin
1717

1818
replicas: 2 # 2 nodes, 1 pod each
@@ -25,7 +25,7 @@ image:
2525
# Ampere A1 / other non-Graviton-3+ ARM64 hosts need to avoid SIGILL on
2626
# SHA3 / SHA512 paths.
2727
repository: docker.io/boilinginsights/boilstream
28-
tag: aarch64-generic-linux-0.10.21
28+
tag: aarch64-generic-linux-0.10.24
2929
pullPolicy: IfNotPresent
3030
pullSecrets: [] # Docker Hub is public; no pull secret needed
3131

0 commit comments

Comments
 (0)