Skip to content

Commit 681cff0

Browse files
committed
refactor: replace test_executor with http_executor for clarity and functionality
- Updated references in the codebase to replace `test_executor` with `http_executor` to better reflect the new functionality. - Enhanced the CONTRIBUTING.md to clarify the interaction between components in the pipeline. - Introduced a new `http_executor.py` file to handle HTTP requests for proactive testing. - Added a `scenario_parser.py` for parsing YAML scenario files, improving the configuration management for testing workflows. - Updated related tests to ensure compatibility with the new HTTP execution logic.
1 parent c9ea112 commit 681cff0

12 files changed

Lines changed: 56 additions & 40 deletions

File tree

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ SecNode relies heavily on its `ai/` package (`understand`, `generate`, `validate
7777

7878
### Quick Guide
7979

80-
1. **Understand Pipeline Flow:** Familiarize yourself with how `schema_fetcher`, `ai_engine`, and `test_executor` interact.
80+
1. **Understand Pipeline Flow:** Familiarize yourself with how `schema_fetcher`, `ai_engine`, and `http_executor` interact.
8181
2. **Improve System Prompts:** If adding support for new vulnerability classes, update the system prompts inside `generate_test_cases()`.
8282
3. **Refine Heuristics:** If the engine is flagging false positives, refine the Chain-of-Thought heuristics inside `_evaluate_single_result()`.
8383
4. **Submit via PR** with clear descriptions of the accuracy/coverage improvement.

src/secnodeapi/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def _configure_logging(verbose: bool = False) -> None:
6868
write_report,
6969
)
7070
from .services.controller import ControllerService
71-
from .test_executor import execute_proactive_tests
71+
from .http_executor import execute_proactive_tests
7272
from .policy import build_policy
7373

7474

src/secnodeapi/config.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
"""
2-
Runtime configuration for SecNode CLI execution.
2+
CLI runtime configuration for SecNode.
3+
4+
Provides RuntimeConfig (SSL, etc.) and has_supported_provider_key() for
5+
LLM provider validation. Use config_loader for layered config merge;
6+
use infra.config for Redis, Postgres, queue backends.
37
"""
48
import os
59
from dataclasses import dataclass

src/secnodeapi/config_loader.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
"""
22
Layered configuration system for SecNode API.
33
4-
Precedence: CLI > scenario.yaml > env vars > defaults
4+
Merges CLI args, scenario.yaml, and env vars into SecNodeConfig.
5+
Precedence: CLI > scenario.yaml > env vars > defaults.
6+
7+
Use config.py for CLI runtime (RuntimeConfig); use infra.config for
8+
infrastructure backends (Redis, Postgres, queue).
59
"""
610
import os
711
from pathlib import Path
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""
2-
Test Executor engine for SecNode API Pentester.
2+
HTTP executor for SecNode API Pentester.
3+
34
Asynchronously fires HTTP requests based on generated test cases.
5+
Renamed from test_executor to avoid confusion with pytest tests.
46
"""
57

68
import asyncio
@@ -147,7 +149,7 @@ async def _run_and_track(tc: TestCase):
147149

148150
for outcome in outcomes:
149151
if isinstance(outcome, Exception):
150-
logger.error("Uncaught exception in test executor worker", exc_info=outcome)
152+
logger.error("Uncaught exception in http executor worker", exc_info=outcome)
151153
elif outcome is not None:
152154
results.append(outcome)
153155

src/secnodeapi/infra/config.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
"""Environment-based backend selection for infrastructure adapters."""
1+
"""
2+
Infrastructure configuration from environment variables.
3+
4+
Provides Redis URL, Postgres DSN, queue/storage backends, semantic memory
5+
settings. Use config.py for CLI runtime; use config_loader for layered
6+
application config (target, auth, etc.).
7+
"""
28
import os
39

410

src/secnodeapi/pipeline/scenario.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from ..agents.coordinator import AgentCoordinator, WorkerDispatcher
99
from ..contracts import ReportArtifact
10-
from ..scenario_parser import ScenarioConfig, ScenarioParser
10+
from .scenario_parser import ScenarioConfig, ScenarioParser
1111
from ..services.controller.service import ControllerService
1212
from ..services.skill_engine.registry import SkillRegistry
1313

src/secnodeapi/scenario_parser.py renamed to src/secnodeapi/pipeline/scenario_parser.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,59 +30,59 @@ class ScenarioConfig(BaseModel):
3030
"""Complete scenario configuration parsed from YAML."""
3131
# Target specification
3232
target: str = ""
33-
33+
3434
# Users for authentication
3535
users: List[ScenarioUser] = Field(default_factory=list)
36-
36+
3737
# Variables for templating
3838
variables: Dict[str, str] = Field(default_factory=dict)
39-
39+
4040
# Instructions to execute
4141
instructions: List[str] = Field(default_factory=list)
42-
42+
4343
# Execution settings
4444
mode: str = "agent"
4545
concurrency: int = 5
4646
request_budget: int = 400
47-
47+
4848
# Network settings
4949
proxy: Optional[str] = None
5050
insecure: bool = False
5151

5252

5353
class ScenarioParser:
5454
"""Parser for scenario.yaml files."""
55-
55+
5656
@staticmethod
5757
def parse_file(file_path: str) -> ScenarioConfig:
5858
"""Parse a scenario.yaml file.
59-
59+
6060
Args:
6161
file_path: Path to the scenario.yaml file
62-
62+
6363
Returns:
6464
ScenarioConfig object with parsed data
65-
65+
6666
Raises:
6767
FileNotFoundError: If file doesn't exist
6868
ValueError: If file contains invalid YAML
6969
"""
7070
path = Path(file_path)
7171
if not path.exists():
7272
raise FileNotFoundError(f"Scenario file not found: {file_path}")
73-
73+
7474
with open(path, "r", encoding="utf-8") as f:
7575
data = yaml.safe_load(f) or {}
76-
76+
7777
return ScenarioParser.parse_dict(data)
78-
78+
7979
@staticmethod
8080
def parse_dict(data: Dict[str, Any]) -> ScenarioConfig:
8181
"""Parse a dictionary as scenario configuration.
82-
82+
8383
Args:
8484
data: Dictionary containing scenario configuration
85-
85+
8686
Returns:
8787
ScenarioConfig object
8888
"""
@@ -92,14 +92,14 @@ def parse_dict(data: Dict[str, Any]) -> ScenarioConfig:
9292
for user_data in data["users"]:
9393
if isinstance(user_data, dict):
9494
users.append(ScenarioUser(**user_data))
95-
95+
9696
# Process instructions
9797
instructions: List[str] = []
9898
if "instructions" in data:
9999
instr_list = data["instructions"]
100100
if isinstance(instr_list, list):
101101
instructions = [str(i) for i in instr_list]
102-
102+
103103
# Build config
104104
config_data = {
105105
"target": data.get("target", ""),
@@ -112,28 +112,28 @@ def parse_dict(data: Dict[str, Any]) -> ScenarioConfig:
112112
"proxy": data.get("proxy"),
113113
"insecure": data.get("insecure", False),
114114
}
115-
115+
116116
return ScenarioConfig(**config_data)
117-
117+
118118
@staticmethod
119119
def validate_file(file_path: str) -> tuple[bool, Optional[str]]:
120120
"""Validate a scenario.yaml file.
121-
121+
122122
Args:
123123
file_path: Path to the scenario.yaml file
124-
124+
125125
Returns:
126126
Tuple of (is_valid, error_message)
127127
"""
128128
try:
129129
config = ScenarioParser.parse_file(file_path)
130-
130+
131131
# Basic validation
132132
if not config.target and not config.users:
133133
return False, "Scenario must have at least a target or users defined"
134-
134+
135135
return True, None
136-
136+
137137
except FileNotFoundError as e:
138138
return False, str(e)
139139
except yaml.YAMLError as e:
@@ -144,10 +144,10 @@ def validate_file(file_path: str) -> tuple[bool, Optional[str]]:
144144

145145
def parse_scenario(file_path: str) -> ScenarioConfig:
146146
"""Convenience function to parse a scenario file.
147-
147+
148148
Args:
149149
file_path: Path to scenario.yaml
150-
150+
151151
Returns:
152152
ScenarioConfig object
153153
"""
@@ -156,10 +156,10 @@ def parse_scenario(file_path: str) -> ScenarioConfig:
156156

157157
def validate_scenario(file_path: str) -> tuple[bool, Optional[str]]:
158158
"""Convenience function to validate a scenario file.
159-
159+
160160
Args:
161161
file_path: Path to scenario.yaml
162-
162+
163163
Returns:
164164
Tuple of (is_valid, error_message)
165165
"""

src/secnodeapi/services/pipeline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
)
1919
from ..report_generator import generate_reports
2020
from ..schema_fetcher import analyze_api_structure, fetch_schema
21-
from ..test_executor import execute_proactive_tests, execute_proactive_tests_detailed
21+
from ..http_executor import execute_proactive_tests, execute_proactive_tests_detailed
2222
from ..vulnerability_models import (
2323
APIEndpoint,
2424
Finding,

tests/integration/test_scenario_pipeline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from pathlib import Path
44

55
from secnodeapi.contracts import ParsedFinding
6-
from secnodeapi.scenario_parser import ScenarioParser
6+
from secnodeapi.pipeline.scenario_parser import ScenarioParser
77

88

99
@pytest.fixture

0 commit comments

Comments
 (0)