Add tiered LOTL mining onion and fleet recon so agents can fallback across execution tiers while operators see spread and vuln posture in Crucible. Includes triple-onion chain, spread cred graph, and full Go/TS/E2E test validation.

This commit is contained in:
AetherForge
2026-06-06 23:53:21 -07:00
parent 6372b07e6c
commit 3938bcd1c5
268 changed files with 21347 additions and 1130 deletions

View File

@@ -3,6 +3,7 @@
*/
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { cleanup, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { MemoryRouter } from 'react-router-dom';
import { mockAgent } from '../test/fixtures';
import { useWebSocket } from '../hooks/useWebSocket';
@@ -56,6 +57,14 @@ vi.mock('../components/Fleet/FleetGroupsStrip', () => ({
default: () => null,
}));
vi.mock('../hooks/useFleetBulkActions', () => ({
useFleetBulkActions: () => ({ bulkBusy: false, handleBulkAction: vi.fn() }),
}));
vi.mock('../components/Fleet/CrucibleAgentMeta', () => ({
default: () => null,
}));
vi.mock('../components/Presence/AlsoHere', () => ({
default: () => null,
}));
@@ -194,6 +203,23 @@ describe('CruciblePage terminal — command_result processing', () => {
expect(screen.getAllByText('first')).toHaveLength(1);
});
it('renders fleet filter toolbar when agents are registered', async () => {
const agent = mockAgent({ name: 'FilterNode', status: 'online' });
renderCrucible(makeWsValue({ agents: [agent] }));
await waitFor(() => {
expect(screen.getByPlaceholderText('Search name, IP, notes, tags…')).toBeInTheDocument();
});
expect(screen.getByText('FilterNode')).toBeInTheDocument();
});
it('shows filter empty hint when no nodes match', async () => {
const agent = mockAgent({ name: 'HiddenNode', tags: ['prod'] });
renderCrucible(makeWsValue({ agents: [agent] }));
await waitFor(() => expect(screen.getByPlaceholderText('Search name, IP, notes, tags…')).toBeInTheDocument());
await userEvent.setup().type(screen.getByPlaceholderText('Search name, IP, notes, tags…'), 'nomatchxyz');
expect(screen.getByText('No nodes match filters.')).toBeInTheDocument();
});
it('shows fallback line when command result message is empty', async () => {
const agent = mockAgent({ id: 'agent-empty-001', name: 'EmptyNode', status: 'online' });
renderCrucible(
@@ -209,6 +235,71 @@ describe('CruciblePage terminal — command_result processing', () => {
expect(screen.getByText('[pause] OK')).toBeInTheDocument();
});
});
it('renders mining diagnostics JSON in terminal', async () => {
const agent = mockAgent({ id: 'agent-diag-001', name: 'DiagNode', status: 'online' });
const diagnostics = {
generated_at: '2026-06-06T12:00:00.000Z',
platform: 'windows',
configured_execution: 'auto',
execution_mode: 'inprocess',
active_method: 'inprocess',
lotl_tier: 'inprocess',
mining_hashrate: 512,
lotl_attempts: [
{ tier: 'container', ok: false, error: 'docker not found', duration_ms: 600 },
{ tier: 'inprocess', ok: true, duration_ms: 1800 },
],
likely_blockers: [
'mining paused by remote command or healthy container delegation',
'Windows Defender real-time protection is ON — use Calibrate exclusion script or allowlist install path',
],
cpu: { remote_paused: true, has_job: false, hashrate_hps: 0 },
gpu: { enabled: false, active: false, paused: false },
};
const commandResults = [
{
agent_id: 'agent-diag-001',
action: 'mining_diagnostics',
success: true,
message: JSON.stringify(diagnostics, null, 2),
_seq: 1,
},
];
renderCrucible(makeWsValue({ agents: [agent], commandResults }));
await waitFor(() => {
expect(screen.getByText('MINING DIAGNOSTICS')).toBeInTheDocument();
expect(screen.getByText('LIKELY BLOCKERS')).toBeInTheDocument();
expect(
screen.getByText('mining paused by remote command or healthy container delegation'),
).toBeInTheDocument();
expect(
screen.getByText(
'Windows Defender real-time protection is ON — use Calibrate exclusion script or allowlist install path',
),
).toBeInTheDocument();
expect(screen.getByText('Execution')).toBeInTheDocument();
expect(screen.getAllByText('inprocess').length).toBeGreaterThanOrEqual(1);
expect(screen.getByText('LOTL TIER CHAIN')).toBeInTheDocument();
expect(screen.getByText('docker not found')).toBeInTheDocument();
expect(screen.getByText('600ms')).toBeInTheDocument();
});
});
it('shows LOTL tier badge on agent card when lotl_tier is set', async () => {
const agent = mockAgent({
id: 'agent-lotl-001',
name: 'LotlNode',
status: 'online',
lotl_tier: 'wsl',
});
renderCrucible(makeWsValue({ agents: [agent] }));
await waitFor(() => {
expect(screen.getByText('LOTL WSL')).toBeInTheDocument();
});
});
});
// ── Helper function tests ─────────────────────────────────────────────────