OverviewFilesCommitsIssuesDocsReleasesPeers

P2P-Hiverelay commits / 383f333

chore(release): prepare v0.25.0-rc.7 — security release
Ships the two unauthenticated-access fixes, which are currently committed but present in no tag, so every relay running services is still granting anonymous swarm peers the authenticated-user role. Also carries the three update-path gates (runtime preflight, agent self-update, watchdog drain whitelist), storage fail-closed on /health, capability-doc operator identity, the runtime service prober, and seven doc corrections. Version bump + changelog only; the channel promotion follows the signed tag. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
383f333b71f93e55268f7203f0823bfd688c5857
by bigdestiny2 <33146784+bigdestiny2@users.noreply.github.com> · 2026-07-28T15:44:33.000Z

Changed files (9) +96 -18

CHANGELOG.md +78 -0
……@@ -6,6 +6,84 @@ documented here. Dates in YYYY-MM-DD.
66
77The packages are versioned in lockstep.
88
9## [0.25.0-rc.7] — 2026-07-28
10
11**Security release. Supersedes rc.6 — deploy this.**
12
13### Fixed — security
14
15- **Every default relay granted anonymous swarm peers the `authenticated-user`
16 role.** Commit `9125f3c` ("default services to anonymous role") set
17 `'anonymous'` in `relay-node/index.js` and `bare-relay.js` but not in
18 `config/default.js` — and that is the file the CLI loads, merged last, so it
19 won. Any relay started from the CLI, which is every packaged path, silently
20 ran with the raised default.
21
22 Effect: `protocol.js` handed any unauthenticated peer the `authenticated-user`
23 role, and the service router then opened `arbitration.submit` — whose pending
24 Map is uncapped — to the whole swarm. Verified before and after with
25 `HOME=$(mktemp -d) loadConfig({})`: `"authenticated-user"` → `"anonymous"`.
26 No test asserted the value in either file, which is why the revert went
27 unnoticed; there is one now, and it asserts the *effective* value so it still
28 fails if precedence between the two defaults changes again.
29
30- **`dashboard-admin-operator` was an unauthenticated fleet-root control plane.**
31 It holds every relay's SSH key and its endpoints restart services, run
32 `git pull && npm install`, rewrite `config.json` and edit `/etc/fstab` — while
33 listening on `0.0.0.0` with zero authentication and wildcard CORS. Its own
34 README says "do not expose port 3458". Now binds `127.0.0.1`, requires a
35 shared secret (timing-safe) on every route including the SSE stream that
36 leaked the inventory, drops wildcard CORS, and uses `execFile(argv)` instead
37 of interpolating a caller-supplied `publicIp` into a shell command that the
38 probe re-ran every 60s. Host and name are validated at the `POST /api/relay`
39 boundary, which previously checked only truthiness.
40
41### Fixed — fleet update path
42
43- **Runtime preflight before the service restart.** `npm ci` reporting success
44 does not mean the relay can boot: utah-0.5gb's install exited 0 and the relay
45 then crash-looped 188 times, because a memory-starved install left
46 `node_modules` partially written and `require-addon` resolved the package root
47 to `/`. The updater now executes the runtime after the dependency install and
48 before the restart, and rolls back on failure instead of leaving a
49 crash-looping relay. Deliberately a `require` rather than a version check —
50 the fleet spans Node v18.19.1 to v22.23.1 and three relays share the exact
51 version of the box that failed.
52- **The agent self-updates.** It runs from `/usr/local/bin` and nothing
53 reinstalled it, so a bug in the update path could only be fixed by
54 hand-visiting every box — which is why rc.6's `--force` rollback fix reached
55 no relay. Installs atomically (temp + `bash -n` + rename) after the
56 supply-chain gate and a proven-good dependency install.
57- **The watchdog no longer kills a relay for answering honestly.** It used
58 `curl -f`, which discards the body on non-2xx, so a deliberate 503
59 `{"ok":false,"reason":"disk-critical"}` drain was indistinguishable from an
60 event-loop hang — and since a restart frees no disk, the box looped SIGKILL
61 every ~4 minutes. Any structured reply now proves the loop is turning.
62
63### Added
64
65- `storageAdmission.failClosed()` is reported on `/health` as
66 `reason: "storage-fail-closed"`. It previously set `_fatalReason` with no
67 emit, log or metric while `canAcknowledge()` returned false — so every gateway
68 drive read 404'd as "still replicating", actively misdirecting whoever was
69 debugging it.
70- Capability docs publish `operator` when declared. `quorum-selector` keys on
71 `r.operator || r.pubkey`, so an absent operator made every relay its own
72 operator — five boxes in one datacenter satisfied a `minOperators` floor of
73 five. Emitted only when set, so the default signable shape is unchanged.
74- `scripts/probe-fleet-services.mjs` reads `GET /api/v1/services` on every relay:
75 what is *loaded*, not what is configured. First run found `sing-1` and
76 `sing-2` on the same 1 GB tier running 3 and 9 services respectively, and
77 `shard-store` on a 2 GB box.
78
79### Docs
80
81Seven claims corrected, two of which *understated* what is built. Both headline
82packaging claims were inert: none of the `HIVERELAY_*` service or Tor variables
83have a reader on the Node runtime that Docker, systemd and Umbrel all launch —
84with all of them exported, `loadConfig()` still returns
85`enableServices: false, plugins: [], transports.tor: false`.
86
987## [0.25.0-rc.6] — 2026-07-28
1088
1189**Use this, not rc.5.** rc.5 cannot be installed by the fleet updater — see below.
README.md +2 -2
……@@ -14,7 +14,7 @@ and key-material fields at the schema boundary.
1414a one-page dashboard, first-run setup, wallet destination, service selection,
1515and persistent identity behind each platform's authenticated app proxy.
1616
17**Open source (Apache 2.0)** | **[GitHub](https://github.com/bigdestiny2/P2P-Hiverelay)** | **[npm](https://www.npmjs.com/package/p2p-hiverelay)** | **Status: v0.25.0-rc.6**
17**Open source (Apache 2.0)** | **[GitHub](https://github.com/bigdestiny2/P2P-Hiverelay)** | **[npm](https://www.npmjs.com/package/p2p-hiverelay)** | **Status: v0.25.0-rc.7**
1818
1919The four packages are versioned in lockstep:
2020
……@@ -34,7 +34,7 @@ and StartOS metadata so the published release surfaces agree.
3434
3535| Surface | Current source state | Publication/evidence boundary |
3636|---|---|---|
37| Core3 packages | Monorepo and package manifests are at `v0.25.0-rc.6`; the last release with a captured multi-arch GHCR digest is `v0.20.2` | A tag/release must run `npm run release:prepare` so versions, fleet channels, Umbrel, and StartOS metadata move together |
37| Core3 packages | Monorepo and package manifests are at `v0.25.0-rc.7`; the last release with a captured multi-arch GHCR digest is `v0.20.2` | A tag/release must run `npm run release:prepare` so versions, fleet channels, Umbrel, and StartOS metadata move together |
3838| Blindspark on Umbrel | In-repo package uses app proxy, persistent `/data`, review-mode default, and guarded setup/add-wallet/service-manager smoke paths with visible in-flight state | Official App Store inclusion still needs the upstream `getumbrel/umbrel-apps` PR/review plus real-device `umbrel-runtime-review-evidence.json` |
3939| StartOS | Source can build and verify a digest-pinned `.s9pk` from a published GHCR release image and publish to a configured registry | Current `v0.20.2` package proof is blocked until `ghcr.io/bigdestiny2/p2p-hiverelay:0.20.2` resolves to a multi-arch digest; registry proof requires `startos-registry-evidence.json`; marketplace/community inclusion remains Start9 review-controlled |
4040| Raw fleet | Pull updater, channel metadata, health gate, rollback, and rollout verifier are in-repo | A release is live on the selected fleet only when `fleet-rollout-evidence.json` proves target SHA, package version, `/health.version`, and relay health |
package-lock.json +8 -8
……@@ -1,12 +1,12 @@
11{
22 "name": "p2p-hiverelay-monorepo",
3 "version": "0.25.0-rc.6",
3 "version": "0.25.0-rc.7",
44 "lockfileVersion": 3,
55 "requires": true,
66 "packages": {
77 "": {
88 "name": "p2p-hiverelay-monorepo",
9 "version": "0.25.0-rc.6",
9 "version": "0.25.0-rc.7",
1010 "hasInstallScript": true,
1111 "license": "Apache-2.0",
1212 "workspaces": [
……@@ -8152,7 +8152,7 @@
81528152 },
81538153 "packages/client": {
81548154 "name": "p2p-hiverelay-client",
8155 "version": "0.25.0-rc.6",
8155 "version": "0.25.0-rc.7",
81568156 "license": "Apache-2.0",
81578157 "dependencies": {
81588158 "@noble/hashes": "^2.2.0",
……@@ -8166,7 +8166,7 @@
81668166 "corestore": "^7.11.0",
81678167 "hyperdrive": "^13.3.2",
81688168 "hyperswarm": "^4.17.0",
8169 "p2p-hiverelay": "^0.25.0-rc.6",
8169 "p2p-hiverelay": "^0.25.0-rc.7",
81708170 "sodium-universal": "^5.0.1"
81718171 },
81728172 "engines": {
……@@ -8206,7 +8206,7 @@
82068206 },
82078207 "packages/core": {
82088208 "name": "p2p-hiverelay",
8209 "version": "0.25.0-rc.6",
8209 "version": "0.25.0-rc.7",
82108210 "license": "Apache-2.0",
82118211 "dependencies": {
82128212 "@grpc/grpc-js": "^1.14.4",
……@@ -8282,14 +8282,14 @@
82828282 },
82838283 "packages/services": {
82848284 "name": "p2p-hiveservices",
8285 "version": "0.25.0-rc.6",
8285 "version": "0.25.0-rc.7",
82868286 "license": "Apache-2.0",
82878287 "dependencies": {
82888288 "@noble/curves": "^2.2.0",
82898289 "@noble/hashes": "^2.2.0",
82908290 "@noble/secp256k1": "^3.1.0",
82918291 "b4a": "^1.8.1",
8292 "p2p-hiverelay": "^0.25.0-rc.6",
8292 "p2p-hiverelay": "^0.25.0-rc.7",
82938293 "sodium-universal": "^5.0.1"
82948294 },
82958295 "engines": {
……@@ -8329,7 +8329,7 @@
83298329 },
83308330 "packages/verifier": {
83318331 "name": "p2p-hiverelay-verifier",
8332 "version": "0.25.0-rc.6",
8332 "version": "0.25.0-rc.7",
83338333 "license": "Apache-2.0",
83348334 "dependencies": {
83358335 "b4a": "^1.8.1"
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "p2p-hiverelay-monorepo",
3 "version": "0.25.0-rc.6",
3 "version": "0.25.0-rc.7",
44 "description": "Monorepo root for HiveRelay (Core + Services + Client)",
55 "private": true,
66 "type": "module",
packages/client/package.json +2 -2
……@@ -1,6 +1,6 @@
11{
22 "name": "p2p-hiverelay-client",
3 "version": "0.25.0-rc.6",
3 "version": "0.25.0-rc.7",
44 "description": "Unified client SDK for HiveRelay (Core + Services). Talks to either via capability flags advertised by relay nodes.",
55 "type": "module",
66 "main": "index.js",
……@@ -61,7 +61,7 @@
6161 "corestore": "^7.11.0",
6262 "hyperdrive": "^13.3.2",
6363 "hyperswarm": "^4.17.0",
64 "p2p-hiverelay": "^0.25.0-rc.6",
64 "p2p-hiverelay": "^0.25.0-rc.7",
6565 "sodium-universal": "^5.0.1"
6666 },
6767 "engines": {
packages/core/package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "p2p-hiverelay",
3 "version": "0.25.0-rc.6",
3 "version": "0.25.0-rc.7",
44 "description": "HiveRelay Core — minimal always-on P2P availability infrastructure (seeding, circuit relay, proof-of-relay, gateway)",
55 "type": "module",
66 "main": "core/index.js",
packages/services/package.json +2 -2
……@@ -1,6 +1,6 @@
11{
22 "name": "p2p-hiveservices",
3 "version": "0.25.0-rc.6",
3 "version": "0.25.0-rc.7",
44 "description": "HiveRelay Services — application-layer services (AI inference, identity, schemas, SLAs, storage CRUD) that ride on top of HiveRelay Core",
55 "type": "module",
66 "exports": {
……@@ -20,7 +20,7 @@
2020 "@noble/hashes": "^2.2.0",
2121 "@noble/secp256k1": "^3.1.0",
2222 "b4a": "^1.8.1",
23 "p2p-hiverelay": "^0.25.0-rc.6",
23 "p2p-hiverelay": "^0.25.0-rc.7",
2424 "sodium-universal": "^5.0.1"
2525 },
2626 "engines": {
packages/verifier/package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "p2p-hiverelay-verifier",
3 "version": "0.25.0-rc.6",
3 "version": "0.25.0-rc.7",
44 "description": "Independent reference verifier for HiveRelay — reads raw hypercores from multiple relays and reports divergence. Ships separately from the main client SDK so cross-client verification is meaningful (see docs/THREAT-MODEL.md action item #3).",
55 "type": "module",
66 "main": "index.js",
startos/README.md +1 -1
……@@ -167,7 +167,7 @@ Three paths, smallest to widest reach:
167167## Status
168168
169169Package source targets multi-arch image tarballs (x86_64 + aarch64),
170v0.25.0-rc.6, one-page dashboard via `HIVERELAY_UI_SIMPLE`, review-mode first boot,
170v0.25.0-rc.7, one-page dashboard via `HIVERELAY_UI_SIMPLE`, review-mode first boot,
171171and a first-boot-only 10 GB storage cap. Current `v0.20.2` package verification
172172is externally gated on the published GHCR image/tag and digest; once that image
173173exists, `make verify IMAGE_DIGEST=sha256:<multi-arch-digest>` is the release