Ship ShadowBroker v0.9.83 with live Infonet gate messaging and DM protocols.

Gate hashchain replication, Tor/SOCKS transport hardening, terminal session teardown, v0.9.83 UI/changelog, and release digest pins for seamless updater verification.
This commit is contained in:
BigBodyCobain
2026-06-15 15:37:29 -06:00
parent 8fcb01276c
commit 5ede669a12
35 changed files with 589 additions and 263 deletions
@@ -9,12 +9,12 @@ import {
} from '@/lib/updateRuntime';
const RELEASE: GitHubLatestRelease = {
html_url: 'https://github.com/BigBodyCobain/Shadowbroker/releases/tag/v0.9.82',
html_url: 'https://github.com/BigBodyCobain/Shadowbroker/releases/tag/v0.9.83',
assets: [
{ name: 'ShadowBroker_0.9.82_x64_en-US.msi', browser_download_url: 'https://example.test/windows.msi' },
{ name: 'ShadowBroker_0.9.82_x64-setup.exe', browser_download_url: 'https://example.test/windows-setup.exe' },
{ name: 'ShadowBroker_0.9.82_aarch64.dmg', browser_download_url: 'https://example.test/macos.dmg' },
{ name: 'ShadowBroker_0.9.82_amd64.AppImage', browser_download_url: 'https://example.test/linux.AppImage' },
{ name: 'ShadowBroker_0.9.83_x64_en-US.msi', browser_download_url: 'https://example.test/windows.msi' },
{ name: 'ShadowBroker_0.9.83_x64-setup.exe', browser_download_url: 'https://example.test/windows-setup.exe' },
{ name: 'ShadowBroker_0.9.83_aarch64.dmg', browser_download_url: 'https://example.test/macos.dmg' },
{ name: 'ShadowBroker_0.9.83_amd64.AppImage', browser_download_url: 'https://example.test/linux.AppImage' },
],
};
@@ -51,6 +51,8 @@ const controlPlaneFetch = vi.fn();
vi.mock('@/mesh/wormholeIdentityClient', () => ({
fetchWormholeStatus,
prepareWormholeInteractiveLane,
isWormholePrepAbortedError: (error: unknown) =>
error instanceof Error && error.message === 'wormhole_prep_aborted',
}));
vi.mock('@/mesh/wormholeClient', () => ({
@@ -76,6 +78,7 @@ vi.mock('@/mesh/controlPlaneStatusClient', () => ({
vi.mock('@/lib/meshTerminalLauncher', () => ({
requestMeshTerminalOpen,
subscribeSecureMeshTerminalLauncherOpen,
subscribeInfonetSessionEnd: vi.fn(() => () => {}),
}));
vi.mock('@/lib/updateRuntime', () => ({
@@ -1,9 +1,5 @@
/**
* Sprint 4D behavioral tests — page.tsx wormhole teardown and layer sync.
*
* These tests exercise actual runtime logic:
* 1. teardownWormholeOnClose — calls leaveWormhole only when state is ready or running
* 2. Layer sync first-mount suppression — initial sync does NOT dispatch LAYER_TOGGLE_EVENT
*/
import { describe, expect, it, vi, beforeEach } from 'vitest';
import fs from 'node:fs';
@@ -11,80 +7,29 @@ import path from 'node:path';
import { teardownWormholeOnClose } from '@/lib/wormholeTeardown';
import { LAYER_TOGGLE_EVENT } from '@/hooks/useDataPolling';
// ─── teardownWormholeOnClose ──────────────────────────────────────────────
const endInfonetTerminalSession = vi.fn(async () => {});
vi.mock('@/lib/infonetTerminalSession', () => ({
endInfonetTerminalSession: (...args: unknown[]) => endInfonetTerminalSession(...args),
}));
describe('page.tsx behavior — teardownWormholeOnClose', () => {
let fetchState: ReturnType<typeof vi.fn>;
let leave: ReturnType<typeof vi.fn>;
beforeEach(() => {
fetchState = vi.fn();
leave = vi.fn().mockResolvedValue({});
endInfonetTerminalSession.mockClear();
});
it('calls leaveWormhole when state is ready', async () => {
fetchState.mockResolvedValue({ ready: true, running: false });
await teardownWormholeOnClose(fetchState, leave);
expect(fetchState).toHaveBeenCalledWith(false);
expect(leave).toHaveBeenCalledTimes(1);
});
it('calls leaveWormhole when state is running', async () => {
fetchState.mockResolvedValue({ ready: false, running: true });
await teardownWormholeOnClose(fetchState, leave);
expect(leave).toHaveBeenCalledTimes(1);
});
it('calls leaveWormhole when state is both ready and running', async () => {
fetchState.mockResolvedValue({ ready: true, running: true });
await teardownWormholeOnClose(fetchState, leave);
expect(leave).toHaveBeenCalledTimes(1);
});
it('does NOT call leaveWormhole when state is neither ready nor running', async () => {
fetchState.mockResolvedValue({ ready: false, running: false });
await teardownWormholeOnClose(fetchState, leave);
expect(fetchState).toHaveBeenCalledWith(false);
expect(leave).not.toHaveBeenCalled();
});
it('does NOT call leaveWormhole when state is null', async () => {
fetchState.mockResolvedValue(null);
await teardownWormholeOnClose(fetchState, leave);
expect(leave).not.toHaveBeenCalled();
});
it('swallows fetchState errors gracefully', async () => {
fetchState.mockRejectedValue(new Error('network down'));
await teardownWormholeOnClose(fetchState, leave);
expect(leave).not.toHaveBeenCalled();
// No error thrown — handler is best-effort
});
it('swallows leaveWormhole errors gracefully', async () => {
fetchState.mockResolvedValue({ ready: true });
leave.mockRejectedValue(new Error('leave failed'));
await teardownWormholeOnClose(fetchState, leave);
// No error thrown — handler is best-effort
});
it('always passes force=false to fetchState', async () => {
fetchState.mockResolvedValue({ ready: true });
await teardownWormholeOnClose(fetchState, leave);
expect(fetchState).toHaveBeenCalledWith(false);
expect(fetchState).not.toHaveBeenCalledWith(true);
it('ends the infonet terminal session on close', async () => {
await teardownWormholeOnClose();
expect(endInfonetTerminalSession).toHaveBeenCalledTimes(1);
});
});
// ─── Layer sync first-mount suppression ───────────────────────────────────
describe('page.tsx behavior — layer sync first-mount suppression', () => {
it('LAYER_TOGGLE_EVENT is the expected string constant', () => {
expect(LAYER_TOGGLE_EVENT).toBe('sb:layer-toggle');
});
it('first-mount ref pattern suppresses dispatch, subsequent calls dispatch', () => {
// Simulate the initialLayerSyncRef pattern from page.tsx
const initialSyncDone = { current: false };
const dispatched: boolean[] = [];
@@ -96,7 +41,6 @@ describe('page.tsx behavior — layer sync first-mount suppression', () => {
}
};
// First call (mount): should pass false → no dispatch
if (!initialSyncDone.current) {
initialSyncDone.current = true;
syncLayers(false);
@@ -105,7 +49,6 @@ describe('page.tsx behavior — layer sync first-mount suppression', () => {
}
expect(dispatched).toEqual([false]);
// Second call (layer change): should pass true → dispatch
if (!initialSyncDone.current) {
initialSyncDone.current = true;
syncLayers(false);
@@ -114,7 +57,6 @@ describe('page.tsx behavior — layer sync first-mount suppression', () => {
}
expect(dispatched).toEqual([false, true]);
// Third call (another layer change): should still dispatch
if (!initialSyncDone.current) {
initialSyncDone.current = true;
syncLayers(false);
@@ -2,7 +2,7 @@
* Sprint 4B regression tests — page.tsx decomposition boundary checks.
*
* These tests validate the frozen contract for page.tsx decomposition:
* 1. InfonetTerminal onClose still calls leaveWormhole when wormhole is ready/running
* 1. InfonetTerminal onClose ends the terminal session (wormhole + node + tor)
* 2. Initial /api/layers sync does NOT dispatch LAYER_TOGGLE_EVENT on first mount
* 3. launchMeshChatTab preserves atomic leftOpen + leftMeshExpanded + meshChatLaunchRequest
* 4. LocateBar extracted to page-local module
@@ -60,30 +60,19 @@ describe('page.tsx decomposition — extraction targets', () => {
describe('page.tsx decomposition — InfonetTerminal onClose wormhole teardown', () => {
const page = readAppFile('page.tsx');
it('InfonetTerminal onClose delegates to teardownWormholeOnClose', () => {
it('InfonetTerminal onClose ends the terminal session', () => {
const infonetSection = page.slice(
page.indexOf('<InfonetTerminal'),
page.indexOf('</InfonetTerminal>') !== -1
? page.indexOf('</InfonetTerminal>')
: page.indexOf('/>', page.indexOf('<InfonetTerminal')) + 2,
);
expect(infonetSection).toContain('teardownWormholeOnClose');
expect(infonetSection).toContain('fetchWormholeState');
expect(infonetSection).toContain('leaveWormhole');
expect(infonetSection).toContain('endInfonetTerminalSession');
});
it('page.tsx imports teardownWormholeOnClose from wormholeTeardown', () => {
it('page.tsx imports endInfonetTerminalSession from infonetTerminalSession', () => {
expect(page).toMatch(
/import\s*\{[^}]*teardownWormholeOnClose[^}]*\}\s*from\s+['"]@\/lib\/wormholeTeardown['"]/,
);
});
it('page.tsx imports leaveWormhole and fetchWormholeState from wormholeClient', () => {
expect(page).toMatch(
/import\s*\{[^}]*leaveWormhole[^}]*\}\s*from\s+['"]@\/mesh\/wormholeClient['"]/,
);
expect(page).toMatch(
/import\s*\{[^}]*fetchWormholeState[^}]*\}\s*from\s+['"]@\/mesh\/wormholeClient['"]/,
/import\s*\{[^}]*endInfonetTerminalSession[^}]*\}\s*from\s+['"]@\/lib\/infonetTerminalSession['"]/,
);
});
});