Skip to content

Commit 92b48f9

Browse files
authored
Merge pull request #7 from RedTanny/multi_req_llm
add concurrent to executor
2 parents 9db09ed + b45df62 commit 92b48f9

File tree

3 files changed

+67
-24
lines changed

3 files changed

+67
-24
lines changed

src/concurrent_executor.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
#!/usr/bin/env python3
22
import logging
33
from concurrent.futures.thread import ThreadPoolExecutor
4+
from typing import TYPE_CHECKING
45

5-
from execution import Execution
6-
6+
if TYPE_CHECKING:
7+
from execution import Execution
78

89
logger = logging.getLogger(__name__)
910

@@ -39,7 +40,7 @@ class ConcurrentExecutor:
3940
num_of_processes: Number of concurrent requests that will be sent at once to agent, by default, it's 2.
4041
4142
"""
42-
def __init__(self, execution: Execution, num_of_processes: int = 2):
43+
def __init__(self, execution: 'Execution', num_of_processes: int = 2):
4344

4445
self.execution = execution
4546
self.num_of_process = num_of_processes
@@ -50,6 +51,9 @@ def execute_one_request(self, payload_data: ExecutionInput):
5051
:return: output object containing result from agent, or crafted output object
5152
in case error was intercepted on invocation.
5253
"""
54+
# Import here to avoid circular import
55+
from execution import Execution
56+
5357
try:
5458
logger.info(f"Sending Request of test #{payload_data.number},"
5559
f"Test-id={Execution.generate_test_id(payload_data.payload)}")

src/execution.py

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import copy
1515
import requests
1616
import time
17+
from concurrent_executor import ConcurrentExecutor, ExecutionInput
1718
logger = logging.getLogger(__name__)
1819

1920

@@ -423,7 +424,7 @@ def run(self) -> None:
423424
"""
424425
Main execution method that orchestrates the workflow.
425426
426-
Reads scan configuration, generates payloads, sends requests,
427+
Reads scan configuration, generates payloads, sends requests concurrently,
427428
and saves results for each test and iteration.
428429
"""
429430
logger.info("Starting vulnerability automation execution")
@@ -433,38 +434,39 @@ def run(self) -> None:
433434

434435
logger.info(f"Found {len(tests)} test(s) with {iterations} iteration(s) each")
435436

436-
# Process each test
437+
# Phase 1: Collect all payloads for all test/iteration combinations
438+
execution_payloads = []
437439
for test_idx, test in enumerate(tests, 1):
438-
logger.info(f"Processing test {test_idx}/{len(tests)}: "
440+
logger.info(f"Preparing test {test_idx}/{len(tests)}: "
439441
f"language={test.get('language')}, "
440442
f"vuln_id={test.get('vuln_id')}")
441443

442-
# Run iterations for this test
444+
# Generate payloads for all iterations of this test
443445
for iteration in range(1, iterations + 1):
444-
logger.info(f"Running iteration {iteration}/{iterations}")
445-
446446
try:
447447
# Generate payload
448448
payload, scan_id = self.generate_payload(test, iteration)
449449

450-
# Send request
451-
result = self.send_request(payload)
452-
453-
# Save successful result
454-
self.save_result(result, scan_id, iteration, failed=False)
455-
456-
logger.info(f"Successfully completed iteration {iteration} "
457-
f"for test {test_idx}")
450+
# Create unique number encoding test_idx and iteration
451+
unique_number = test_idx * 1000 + iteration
458452

453+
execution_payloads.append(
454+
ExecutionInput(
455+
number=unique_number,
456+
test=test,
457+
payload=payload,
458+
request_id=scan_id
459+
)
460+
)
461+
logger.debug(f"Prepared payload for test {test_idx}, iteration {iteration}")
459462

460463
except Exception as e:
461-
logger.error(f"Failed iteration {iteration} for test {test_idx}: {e}")
464+
logger.error(f"Failed generating payload for test {test_idx}, "
465+
f"iteration {iteration}: {e}")
462466

463-
# Save failed result if we have a scan_id
467+
# Save failed result for payload generation error
464468
try:
465-
# Generate scan_id if not already generated
466-
if 'scan_id' not in locals():
467-
scan_id = self.generate_scan_id()
469+
scan_id = self.generate_scan_id()
468470

469471
# Create error result
470472
error_result = {
@@ -479,6 +481,43 @@ def run(self) -> None:
479481
except Exception as save_error:
480482
logger.error(f"Failed to save error result: {save_error}")
481483

484+
# Phase 2: Execute all requests concurrently
485+
if execution_payloads:
486+
logger.info(f"Executing {len(execution_payloads)} request(s) concurrently")
487+
concurrent_executor = ConcurrentExecutor(execution=self, num_of_processes=2)
488+
responses = concurrent_executor.run_requests(execution_payloads)
489+
490+
# Phase 3: Process results and save them
491+
for result in responses:
492+
# Extract test_idx and iteration from unique number
493+
test_idx = result.number // 1000
494+
iteration = result.number % 1000
495+
496+
if result.intercepted_error and result.intercepted_error.strip() != "":
497+
# Request execution failed
498+
logger.error(f"Failed iteration {iteration} for test {test_idx}: "
499+
f"{result.intercepted_error}")
500+
501+
# Create error result
502+
error_result = {
503+
'error': result.intercepted_error,
504+
'scan_id': result.request_id,
505+
'iteration': iteration,
506+
'test': result.test
507+
}
508+
self.save_result(
509+
error_result, result.request_id, iteration, failed=True
510+
)
511+
else:
512+
# Request succeeded
513+
self.save_result(
514+
result.response, result.request_id, iteration, failed=False
515+
)
516+
logger.info(f"Successfully completed iteration {iteration} "
517+
f"for test {test_idx}")
518+
else:
519+
logger.warning("No payloads to execute")
520+
482521
logger.info("Vulnerability automation execution completed")
483522

484523
except FileNotFoundError as e:

src/vulnerability_main_automation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
import logging
1111

1212
try:
13-
from .config import Configuration, GoogleSheetsConfig, GoogleSheetsManager
13+
from .config import GoogleSheetsConfig
1414
from .execution import Execution
1515
from .data_extractor import DataExtractor
1616
from .analysis import Analysis, GoogleSheetsDataLoader
1717
from .cleanup import Cleanup
1818
except ImportError:
19-
from config import Configuration, GoogleSheetsConfig
19+
from config import GoogleSheetsConfig
2020
from execution import Execution
2121
from data_extractor import DataExtractor
2222
from analysis import Analysis, GoogleSheetsDataLoader

0 commit comments

Comments
 (0)