fuzzer: harden runner, fail-closed validation, job isolation and fix AI handoff

This commit is contained in:
Dushnilin
2026-09-16 08:20:17 +03:00
parent 5e9ffa2a01
commit cd584a100f
8 changed files with 1118 additions and 765 deletions
File diff suppressed because it is too large Load Diff
@@ -183,6 +183,42 @@ describe('TachyonShellMethods Fuzzer Actions', () => {
}
});
it('starts fuzzer with custom_file from AI synthesis', async () => {
mocks.executeShellCommand.mockResolvedValueOnce({
stdout: JSON.stringify({
success: true,
job_id: 'fuzz_ai_42',
engine: 'zapret2',
target: 'youtube',
}),
stderr: '',
code: 0,
});
const res = await TachyonShellMethods.startFuzzer(
'zapret2',
'youtube',
'',
'rule_1',
'/var/run/tachyon/fuzzer_ai_strategies.json',
'ai_custom',
);
expect(res.success).toBe(true);
expect(mocks.executeShellCommand).toHaveBeenCalledWith(
expect.objectContaining({
args: [
'fuzzer_start',
'zapret2',
'youtube',
'',
'rule_1',
'/var/run/tachyon/fuzzer_ai_strategies.json',
'ai_custom',
],
}),
);
});
it('gets fuzzer patterns configuration', async () => {
mocks.executeShellCommand.mockResolvedValueOnce({
stdout: JSON.stringify({
@@ -19,6 +19,8 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
let currentState: Tachyon.FuzzerState | null = null;
let resultFilter: 'all' | 'success' | 'fast' = 'all';
let autoApplyEnabled = false;
let autoAppliedJobId: string | null = null;
let stoppedManually = false;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let currentDpiDetection: Tachyon.FuzzerDpiDetection | null = null;
@@ -1677,9 +1679,18 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
lastRenderedFinishedAt = finishedAt;
}
if (!isRunning) {
// Auto-apply best strategy if enabled
if (autoApplyEnabled && currentState?.best_strategy) {
if (!isRunning && !stoppedManually) {
// Auto-apply best strategy only if benchmark completed 100%, without abort, and not already applied for this job
if (
autoApplyEnabled &&
currentState?.progress_pct === 100 &&
!currentState?.aborted &&
!currentState?.error &&
currentState?.best_strategy &&
currentState.job_id &&
autoAppliedJobId !== currentState.job_id
) {
autoAppliedJobId = currentState.job_id;
try {
const applyRes =
await TachyonShellMethods.autoApplyFuzzerStrategy(
@@ -1803,6 +1814,7 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
const handleToggleRun = async () => {
if (isRunning) {
stoppedManually = true;
(startBtn as HTMLButtonElement).disabled = true;
startBtn.innerText = _('⏳ Stopping...');
await TachyonShellMethods.stopFuzzer();
@@ -1813,6 +1825,7 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
return;
}
stoppedManually = false;
(startBtn as HTMLButtonElement).disabled = true;
startBtn.innerText = _('🛑 Stop Benchmark');
@@ -1932,6 +1945,7 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
activeTab = 'benchmark';
updateTabVisibility();
stoppedManually = false;
(startBtn as HTMLButtonElement).disabled = true;
startBtn.innerText = _('🛑 Stop Benchmark');
@@ -1940,6 +1954,8 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
selectedTarget,
customUrl,
selectedRuleSection,
res.data.custom_file,
'ai_custom',
);
if (startRes.success) {
+2
View File
@@ -1120,6 +1120,7 @@ export namespace Tachyon {
results: FuzzerStrategyResult[];
best_strategy?: FuzzerStrategyResult | null;
error?: string | null;
aborted?: boolean;
started_at: number;
finished_at: number;
dpi_detection?: FuzzerDpiDetection | null;
@@ -1147,6 +1148,7 @@ export namespace Tachyon {
target?: string;
target_url?: string;
analysis?: string;
custom_file?: string;
strategies?: FuzzerStrategyItem[];
error?: string;
}