fix: 2026-06-04 audit pass — README, USB pack, multi-area fixes
WS ticket dashboard auth, builder universal signing/size limits/fusion obfuscation/dropper bundles, Path Tracer WireGuard topology, SessionGate degraded mode and download timeouts, server bootstrap (data dir, cloudflared dedupe, config port precedence), agent mesh/miner/spread fixes. README refreshed; usb bundle repacked; PROBLEMS.md audit log updated.
This commit is contained in:
@@ -65,15 +65,22 @@ vi.mock('../context/ForgeContext', () => ({
|
||||
useForge: vi.fn(() => ({ forging: false, stage: '' })),
|
||||
}));
|
||||
|
||||
vi.mock('../api/download', () => ({
|
||||
downloadApiFile: vi.fn(),
|
||||
downloadAuthedFile: vi.fn(),
|
||||
}));
|
||||
vi.mock('../api/download', () => {
|
||||
const downloadAuthedFile = vi.fn();
|
||||
return {
|
||||
downloadAuthedFile,
|
||||
downloadApiFile: downloadAuthedFile,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('../api/auth', () => ({
|
||||
getStoredAuth: vi.fn(),
|
||||
setStoredAuth: vi.fn(),
|
||||
}));
|
||||
vi.mock('../api/auth', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('../api/auth')>();
|
||||
return {
|
||||
...actual,
|
||||
getStoredAuth: vi.fn(),
|
||||
setStoredAuth: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('qrcode', () => ({
|
||||
default: {
|
||||
@@ -174,9 +181,7 @@ describe('DownloadButton', () => {
|
||||
);
|
||||
const btn = screen.getByRole('button', { name: 'Save' });
|
||||
await userEvent.setup().click(btn);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('button', { name: 'Downloading…' })).toBeDisabled();
|
||||
});
|
||||
expect(screen.getByRole('button', { name: 'Downloading…' })).toBeDisabled();
|
||||
await waitFor(() => expect(downloadApiFileMock).toHaveBeenCalledWith('/api/x', 'a.bin'));
|
||||
});
|
||||
|
||||
@@ -283,7 +288,7 @@ describe('SessionGate', () => {
|
||||
|
||||
it('renders children when stored auth validates', async () => {
|
||||
getStoredAuthMock.mockReturnValue('dGVzdA==');
|
||||
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true }));
|
||||
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true, status: 200 }));
|
||||
render(
|
||||
<SessionGate>
|
||||
<div>protected</div>
|
||||
@@ -291,6 +296,18 @@ describe('SessionGate', () => {
|
||||
);
|
||||
await waitFor(() => expect(screen.getByText('protected')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('keeps session on network blip during startup validation', async () => {
|
||||
getStoredAuthMock.mockReturnValue('dGVzdA==');
|
||||
vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new Error('ECONNREFUSED')));
|
||||
render(
|
||||
<SessionGate>
|
||||
<div>protected</div>
|
||||
</SessionGate>
|
||||
);
|
||||
await waitFor(() => expect(screen.getByText('protected')).toBeInTheDocument());
|
||||
expect(screen.getByRole('status')).toHaveTextContent(/Cannot reach server/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GaugeRing', () => {
|
||||
@@ -320,7 +337,7 @@ describe('HashrateChart', () => {
|
||||
it('shows empty state when data is empty', () => {
|
||||
render(<HashrateChart data={[]} title="Fleet Hash" />);
|
||||
expect(screen.getByText('Fleet Hash')).toBeInTheDocument();
|
||||
expect(screen.getByText(/Calibrating chart telemetry/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/No live data yet/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders chart with validated sample series', () => {
|
||||
@@ -329,14 +346,14 @@ describe('HashrateChart', () => {
|
||||
render(
|
||||
<HashrateChart
|
||||
data={sample}
|
||||
displayMode="sample"
|
||||
displayMode="live"
|
||||
title="Fleet Hash"
|
||||
color="#00f5ff"
|
||||
unit="H/s"
|
||||
/>
|
||||
);
|
||||
expect(screen.getByText(/PEAK/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/PROJECTION/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/LIVE/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders chart with data points', () => {
|
||||
|
||||
Reference in New Issue
Block a user