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.
277 lines
10 KiB
TypeScript
277 lines
10 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { runForgeCompatibilityChecks } from './forgeCompatibility';
|
|
import { runForgePreflight } from './forgeValidation';
|
|
import { FORGE_BUILD_DEFAULTS } from './forgeDefaults';
|
|
import type { BuildRequest } from '../types';
|
|
|
|
/** Valid mainnet-style Monero address (95 chars, starts with 4). */
|
|
const VALID_WALLET = '4' + 'A'.repeat(94);
|
|
|
|
function baseForm(overrides: Partial<BuildRequest> = {}): BuildRequest {
|
|
return {
|
|
worker_name: 'pc-lab-1',
|
|
server_url: 'http://192.168.1.10:8989',
|
|
wallet: VALID_WALLET,
|
|
pool_host: 'pool.supportxmr.com',
|
|
pool_port: 3333,
|
|
pool_tls: true,
|
|
pool_pass: 'x',
|
|
...FORGE_BUILD_DEFAULTS,
|
|
...overrides,
|
|
} as BuildRequest;
|
|
}
|
|
|
|
function hasCheck(form: BuildRequest, fusionPrep: boolean, id: string, level?: string) {
|
|
const checks = runForgeCompatibilityChecks(form, fusionPrep);
|
|
const match = checks.find((c) => c.id === id);
|
|
if (!match) return false;
|
|
return level === undefined || match.level === level;
|
|
}
|
|
|
|
describe('runForgeCompatibilityChecks', () => {
|
|
it('returns no errors for a fully valid form', () => {
|
|
const checks = runForgeCompatibilityChecks(baseForm(), false);
|
|
const errors = checks.filter((c) => c.level === 'error');
|
|
expect(errors).toHaveLength(0);
|
|
expect(checks.some((c) => c.id === 'forge_ready' && c.level === 'ok')).toBe(true);
|
|
});
|
|
|
|
describe('stealth and display', () => {
|
|
it('errors when stealth mode uses visible display', () => {
|
|
expect(
|
|
hasCheck(baseForm({ stealth_mode: true, display_mode: 'visible' }), false, 'stealth_display', 'error')
|
|
).toBe(true);
|
|
});
|
|
|
|
it('errors when stealth mode enables file logging', () => {
|
|
expect(hasCheck(baseForm({ stealth_mode: true, file_logging: true }), false, 'stealth_logs', 'error')).toBe(
|
|
true
|
|
);
|
|
});
|
|
|
|
it('errors when fusion uses visible display', () => {
|
|
expect(
|
|
hasCheck(baseForm({ fusion_enabled: true, display_mode: 'visible' }), false, 'fusion_display', 'error')
|
|
).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('idle mining mode', () => {
|
|
it('errors when idle threshold is out of range', () => {
|
|
expect(
|
|
hasCheck(baseForm({ mining_mode: 'idle', idle_threshold_pct: 0 }), false, 'idle_threshold', 'error')
|
|
).toBe(true);
|
|
expect(
|
|
hasCheck(baseForm({ mining_mode: 'idle', idle_threshold_pct: 101 }), false, 'idle_threshold', 'error')
|
|
).toBe(true);
|
|
});
|
|
|
|
it('errors when idle duration is below 1 minute', () => {
|
|
expect(
|
|
hasCheck(baseForm({ mining_mode: 'idle', idle_duration_minutes: 0 }), false, 'idle_duration', 'error')
|
|
).toBe(true);
|
|
});
|
|
|
|
it('does not check idle fields when mining mode is not idle', () => {
|
|
expect(hasCheck(baseForm({ mining_mode: 'always', idle_threshold_pct: 0 }), false, 'idle_threshold')).toBe(
|
|
false
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('scheduled mining mode', () => {
|
|
it('errors when schedule times are missing', () => {
|
|
expect(
|
|
hasCheck(
|
|
baseForm({ mining_mode: 'scheduled', schedule_start: '', schedule_end: '' }),
|
|
false,
|
|
'schedule',
|
|
'error'
|
|
)
|
|
).toBe(true);
|
|
});
|
|
|
|
it('passes when both schedule times are set', () => {
|
|
expect(
|
|
hasCheck(
|
|
baseForm({ mining_mode: 'scheduled', schedule_start: '22:00', schedule_end: '06:00' }),
|
|
false,
|
|
'schedule'
|
|
)
|
|
).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('threads and CPU limits', () => {
|
|
it('warns when adapt_to_hardware is on with fixed thread mode', () => {
|
|
expect(
|
|
hasCheck(baseForm({ thread_mode: 'fixed', adapt_to_hardware: true }), false, 'adapt_fixed', 'warn')
|
|
).toBe(true);
|
|
});
|
|
|
|
it('errors when thread percent is out of range', () => {
|
|
expect(
|
|
hasCheck(baseForm({ thread_mode: 'percent', thread_percent: 0 }), false, 'thread_percent_range', 'error')
|
|
).toBe(true);
|
|
expect(
|
|
hasCheck(baseForm({ thread_mode: 'percent', thread_percent: 101 }), false, 'thread_percent_range', 'error')
|
|
).toBe(true);
|
|
});
|
|
|
|
it('errors when max CPU usage is out of range', () => {
|
|
expect(hasCheck(baseForm({ max_cpu_usage_pct: 0 }), false, 'max_cpu', 'error')).toBe(true);
|
|
expect(hasCheck(baseForm({ max_cpu_usage_pct: 101 }), false, 'max_cpu', 'error')).toBe(true);
|
|
});
|
|
|
|
it('errors when max memory is out of range', () => {
|
|
expect(hasCheck(baseForm({ max_memory_percent: 9 }), false, 'max_mem', 'error')).toBe(true);
|
|
expect(hasCheck(baseForm({ max_memory_percent: 96 }), false, 'max_mem', 'error')).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('pool configuration', () => {
|
|
it('errors when pool port is out of range', () => {
|
|
expect(hasCheck(baseForm({ pool_port: 0 }), false, 'pool_port', 'error')).toBe(true);
|
|
expect(hasCheck(baseForm({ pool_port: 70000 }), false, 'pool_port', 'error')).toBe(true);
|
|
});
|
|
|
|
it('warns on port 443 without TLS', () => {
|
|
expect(hasCheck(baseForm({ pool_port: 443, pool_tls: false }), false, 'pool_tls_443', 'warn')).toBe(true);
|
|
});
|
|
|
|
it('warns on TLS with port 3333', () => {
|
|
expect(hasCheck(baseForm({ pool_port: 3333, pool_tls: true }), false, 'pool_tls_3333', 'warn')).toBe(true);
|
|
});
|
|
|
|
it('warns when pool password is empty', () => {
|
|
expect(hasCheck(baseForm({ pool_pass: ' ' }), false, 'pool_pass', 'warn')).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('run mode and AI', () => {
|
|
it('warns when run_as is service', () => {
|
|
expect(hasCheck(baseForm({ run_as: 'service' }), false, 'run_as_service', 'warn')).toBe(true);
|
|
});
|
|
|
|
it('warns when AI uses 127.0.0.1 endpoint', () => {
|
|
expect(
|
|
hasCheck(
|
|
baseForm({ ai_enabled: true, ai_ollama_endpoint: 'http://127.0.0.1:11434' }),
|
|
false,
|
|
'ai_localhost',
|
|
'warn'
|
|
)
|
|
).toBe(true);
|
|
});
|
|
|
|
it('warns when AI is enabled without self-healing', () => {
|
|
expect(hasCheck(baseForm({ ai_enabled: true, self_healing: false }), false, 'ai_no_heal', 'warn')).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('identity fields', () => {
|
|
it('errors when process name is empty', () => {
|
|
expect(hasCheck(baseForm({ process_name: ' ' }), false, 'process_name_empty', 'error')).toBe(true);
|
|
});
|
|
|
|
it('warns when process name has unusual characters', () => {
|
|
expect(hasCheck(baseForm({ process_name: 'bad name!' }), false, 'process_name', 'warn')).toBe(true);
|
|
});
|
|
|
|
it('errors when worker name is empty (preflight)', () => {
|
|
const checks = runForgePreflight(baseForm({ worker_name: '' }), false);
|
|
expect(checks.find((c) => c.id === 'worker')?.level).toBe('error');
|
|
});
|
|
|
|
it('errors when server URL uses localhost (preflight)', () => {
|
|
const checks = runForgePreflight(baseForm({ server_url: 'http://localhost:8989' }), false);
|
|
expect(checks.find((c) => c.id === 'server')?.level).toBe('error');
|
|
});
|
|
|
|
it('errors when server URL uses 127.0.0.1 (preflight)', () => {
|
|
const checks = runForgePreflight(baseForm({ server_url: 'http://127.0.0.1:8989' }), false);
|
|
expect(checks.find((c) => c.id === 'server')?.level).toBe('error');
|
|
});
|
|
|
|
it('warns when wallet does not match Monero format (preflight)', () => {
|
|
const checks = runForgePreflight(baseForm({ wallet: 'not-a-wallet' }), false);
|
|
expect(checks.find((c) => c.id === 'wallet')?.level).toBe('warn');
|
|
});
|
|
|
|
it('accepts minimum-length wallet (90 chars) in preflight', () => {
|
|
const wallet = '4' + 'A'.repeat(89);
|
|
expect(wallet.length).toBe(90);
|
|
const checks = runForgePreflight(baseForm({ wallet }), false);
|
|
expect(checks.find((c) => c.id === 'wallet')?.level).toBe('ok');
|
|
});
|
|
|
|
it('accepts subaddress starting with 8 in preflight', () => {
|
|
const subaddress = '8' + 'B'.repeat(94);
|
|
const checks = runForgePreflight(baseForm({ wallet: subaddress }), false);
|
|
expect(checks.find((c) => c.id === 'wallet')?.level).toBe('ok');
|
|
});
|
|
|
|
it('emits forge_ready when core config is coherent', () => {
|
|
const checks = runForgeCompatibilityChecks(baseForm(), false);
|
|
const ready = checks.find((c) => c.id === 'forge_ready');
|
|
expect(ready?.level).toBe('ok');
|
|
expect(ready?.message).toContain('Core miner config looks coherent');
|
|
});
|
|
});
|
|
|
|
describe('fusion and deliverables', () => {
|
|
it('emits fusion_ready when prep is attached', () => {
|
|
expect(hasCheck(baseForm({ fusion_enabled: true }), true, 'fusion_ready', 'ok')).toBe(true);
|
|
});
|
|
|
|
it('errors when spread kit targets non-universal OS', () => {
|
|
expect(
|
|
hasCheck(baseForm({ spread_kit: true, target_os: 'windows' }), false, 'spread_kit_os', 'error')
|
|
).toBe(true);
|
|
});
|
|
|
|
it('errors when spread kit and fusion are both enabled', () => {
|
|
expect(
|
|
hasCheck(baseForm({ spread_kit: true, fusion_enabled: true }), false, 'spread_fusion', 'error')
|
|
).toBe(true);
|
|
});
|
|
|
|
it('warns when universal has no spread kit or fusion', () => {
|
|
expect(
|
|
hasCheck(
|
|
baseForm({ target_os: 'universal', spread_kit: false, fusion_enabled: false }),
|
|
false,
|
|
'universal_deliverable',
|
|
'warn'
|
|
)
|
|
).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('platform-specific constraints', () => {
|
|
it('errors when process hollowing is set on Linux', () => {
|
|
expect(
|
|
hasCheck(baseForm({ target_os: 'linux', process_hollowing: true }), false, 'hollow_unix', 'error')
|
|
).toBe(true);
|
|
});
|
|
|
|
it('errors when process hollowing is set on macOS', () => {
|
|
expect(
|
|
hasCheck(baseForm({ target_os: 'darwin', process_hollowing: true }), false, 'hollow_unix', 'error')
|
|
).toBe(true);
|
|
});
|
|
|
|
it('errors when sign_build is set on Linux', () => {
|
|
expect(hasCheck(baseForm({ target_os: 'linux', sign_build: true }), false, 'sign_unix', 'error')).toBe(
|
|
true
|
|
);
|
|
});
|
|
|
|
it('errors when sign_build is set on macOS', () => {
|
|
expect(hasCheck(baseForm({ target_os: 'darwin', sign_build: true }), false, 'sign_unix', 'error')).toBe(
|
|
true
|
|
);
|
|
});
|
|
});
|
|
});
|