@mmmbuto/nexuscrew 0.9.3 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,106 @@
2
2
 
3
3
  All notable changes to NexusCrew are tracked here.
4
4
 
5
+ ## 0.9.5 — 2026-08-17 — "Measured From Where It Breaks"
6
+
7
+ Almost everything in this release was already broken before it, and none of it
8
+ was found by the tests that were supposed to cover it. The pattern repeats often
9
+ enough to be worth naming: a check that runs from a convenient place reports
10
+ success for a mechanism it never actually crossed. The panel tunnel was declared
11
+ ready by measuring a local bind and never a request through it. A public key was
12
+ called valid by our own parser rather than by the program that would authenticate
13
+ with it. A test that promised "leaves no orphans" left one. Each of them was
14
+ green for weeks.
15
+
16
+ - **The per-cell panel could not load, and the interface said it was ready.**
17
+ The viewing cookie was issued with `Path=/api/panel/<cell>`, but the dedicated
18
+ panel port serves `/panel/<cell>` — the control-plane prefix is not there. A
19
+ browser stores that cookie and never sends it back: the first request enters
20
+ with its ticket, and every sub-resource of the panel is refused, as is the
21
+ WebSocket upgrade, which looks for exactly that cookie. The panel stays blank.
22
+
23
+ The cookie path now follows the mount the request actually entered through,
24
+ taken from the router rather than from a constant, with a strict allow-list —
25
+ an unrecognised mount fails closed instead of guessing a scope, and it is
26
+ checked *before* the single-use ticket is spent, so a misconfiguration cannot
27
+ burn a ticket belonging to someone who did nothing wrong.
28
+
29
+ Present since the panel port was separated. It survived because a neighbouring
30
+ function in the same file already handled *both* prefixes: someone had thought
31
+ of the case, in one place out of two.
32
+
33
+ - **Deriving a public key could hang the foreground service for five seconds.**
34
+ Reading a key ran `ssh-keygen -y -f`, with stdin closed and the askpass helper
35
+ disabled. Neither matters: OpenSSH does not read a passphrase from stdin, it
36
+ opens `/dev/tty`. Against an encrypted key on a terminal, the call waited out
37
+ its whole timeout — and the pairing path calls it synchronously, so the event
38
+ loop stopped with it.
39
+
40
+ Now the prompt is forced away from the terminal and onto a helper that cannot
41
+ run, so the attempt fails in a tenth of a second instead of five seconds.
42
+ Below OpenSSH 8.4 that control does not exist and the timeout remains the net:
43
+ slow, but never stuck. The limit is stated in the code rather than assumed.
44
+
45
+ This one was invisible by construction: automated runs have no controlling
46
+ terminal, so `/dev/tty` does not exist and the defect cannot appear. The test
47
+ now **brings its own** terminal rather than skipping, and the probe *measures*
48
+ whether it got one instead of trusting that it did.
49
+
50
+ - **The panel tunnel was authorised to fail.** The generated `authorized_keys`
51
+ line restricted forwarding to the node port and never listed the panel port,
52
+ which had been separated in an earlier release — so pairing negotiated the
53
+ port, reserved the local side, wrote the line, and the server refused the
54
+ channel. "Forward ready" was reported after checking the local bind only,
55
+ which is the half that always succeeds. The channel is now exercised, the
56
+ probe gives up on a budget instead of retrying forever, and when a key cannot
57
+ be determined the product no longer promises a line it cannot produce.
58
+
59
+ - **A public key is now derived from the private one, not read from beside it.**
60
+ Three rounds of hardening had gone into validating the `.pub` file, which
61
+ proves that a file contains *a* valid key — never that it is *the* key for
62
+ that identity. Deriving it removes the question. Relatedly, whether a key is
63
+ acceptable is now decided by the program that will use it, not by our parser.
64
+
65
+ - **Replacing a degraded forwarding channel no longer leaves stray processes.**
66
+ Stopping and waiting now happen at a single point before any replacement.
67
+ The test that certified this used to leave an orphan of its own, and its
68
+ guard identified processes by number rather than by what they were — a
69
+ recycled id could satisfy it.
70
+
71
+ - **A pidfile declares its identity at birth**, its schema marker is one-way,
72
+ and an obstacle to writing that marker now closes the window instead of
73
+ holding it open forever. A refusal that was uniform across two different
74
+ causes used to break updates; the two are separated.
75
+
76
+ - **A remote cell's row resolves against its own node's sessions.** Both the
77
+ sidebar row and the popup could show data from a same-named local session.
78
+
79
+ ### Notes for anyone reading the tests
80
+
81
+ Several fixes here are in tests that were passing while proving nothing: a guard
82
+ that matched too loosely to ever fail, a timing assertion that measured a
83
+ stopwatch instead of the signal it cared about, a cleanup check that read a file
84
+ it had already deleted, and one that could not fail because the shell it relied
85
+ on rejected the syntax it used. If a test has never been seen red for the right
86
+ reason, it has not been seen at all.
87
+
88
+ ## 0.9.4 — 2026-08-17 — "The Interface Was Last Week's"
89
+
90
+ - **The published interface is the one this version was built from.** 0.9.3
91
+ shipped a `frontend/dist` compiled eight hours before the interface work it
92
+ was supposed to contain: the popup with its three sources, the telemetry
93
+ line, the tier labels and the panel origin fix were all in the source and
94
+ none of them in the bundle. The server was 0.9.3 and the interface was
95
+ 0.9.2, and everything about it looked fine — the package installed, the
96
+ service started, the pages loaded.
97
+
98
+ What caught it is worth stating: the product's own guard did, by comparing
99
+ the version the interface declares against the version the server is running
100
+ and refusing to pretend they were the same. Not a test, and not the release
101
+ check — which verified that the fixes were present in `lib/` and never looked
102
+ at the bundle. A smoke test that inspects only the half it thinks of is a
103
+ smoke test with a blind side.
104
+
5
105
  ## 0.9.3 — 2026-08-16 — "A Receipt Is Not an Outcome"
6
106
 
7
107
  The previous release fixed the Desktop engine and shipped the fix inert. Pulling