Skip to content

Commit 24b46aa

Browse files
Merge branch 'main' into redesign_config
2 parents 22e9094 + 39284b0 commit 24b46aa

File tree

85 files changed

+7858
-4734
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+7858
-4734
lines changed

.github/workflows/system-test.yml renamed to .github/workflows/e2e-test.yml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: System Test with Safety
1+
name: E2E Test with Safety
22

33
on:
44
push:
@@ -23,7 +23,7 @@ on:
2323
type: string
2424

2525
jobs:
26-
system-test:
26+
e2e-test:
2727
runs-on: ubuntu-latest
2828
timeout-minutes: 15
2929

@@ -80,18 +80,18 @@ jobs:
8080
- name: Run safety check
8181
run: |
8282
echo "🔒 Running pre-flight safety check..."
83-
chmod +x tests/system/check_safety.sh
84-
./tests/system/check_safety.sh
83+
chmod +x tests/e2e/check_safety.sh
84+
./tests/e2e/check_safety.sh
8585
86-
- name: Run system test with safety system
86+
- name: Run e2e test with safety system
8787
env:
8888
TEST_MODE: ${{ github.event.inputs.test_mode || 'tools' }}
8989
RUNS_PER_TOOL: ${{ github.event.inputs.runs_per_tool || '3' }}
9090
MCP_FUZZER_TIMEOUT: '30'
9191
MCP_FUZZER_SAFETY_ENABLED: 'true'
9292
MCP_FUZZER_FS_ROOT: '/tmp/mcp_fuzzer_sandbox'
9393
run: |
94-
echo "🧪 Running system test with safety system enabled"
94+
echo "🧪 Running e2e test with safety system enabled"
9595
echo "Test Mode: $TEST_MODE"
9696
echo "Runs per tool: $RUNS_PER_TOOL"
9797
echo "Working Directory: $(pwd)"
@@ -104,15 +104,15 @@ jobs:
104104
python --version
105105
node --version
106106
107-
# Run the system test
108-
chmod +x tests/system/test_desktop_commander_mcp.sh
109-
./tests/system/test_desktop_commander_mcp.sh
107+
# Run the e2e test
108+
chmod +x tests/e2e/test_desktop_commander_mcp.sh
109+
./tests/e2e/test_desktop_commander_mcp.sh
110110
111111
- name: Upload test results
112112
if: always()
113113
uses: actions/upload-artifact@v4
114114
with:
115-
name: system-test-results-${{ github.run_id }}
115+
name: e2e-test-results-${{ github.run_id }}
116116
path: |
117117
reports/
118118
test-results/
@@ -121,7 +121,7 @@ jobs:
121121
- name: Generate test summary
122122
if: always()
123123
run: |
124-
echo "## 🧪 System Test Results" >> $GITHUB_STEP_SUMMARY
124+
echo "## 🧪 E2E Test Results" >> $GITHUB_STEP_SUMMARY
125125
echo "" >> $GITHUB_STEP_SUMMARY
126126
127127
if [ -d "reports" ]; then

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ test.py
1616
sdks/
1717
doc_ref/
1818
# C extensions
19+
*REDESIGN*.md
20+
*FLOW.md
1921
*.so
2022
notes.md
2123
/reports/

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ The system is built with a modular architecture:
218218
- **Authentication**: Multiple auth provider support
219219
- **Reporting**: FuzzerReporter, Console/JSON/Text formatters, SafetyReporter
220220

221+
### Runtime Watchdog Overview
222+
223+
The watchdog supervises processes registered through `ProcessManager`, combining hang detection, signal dispatch, and registry-driven cleanup. For a deeper dive into lifecycle events, custom signal strategies, and registry wiring, see the [runtime management guide](docs/components/runtime-management.md).
224+
221225
### Understanding the Design Patterns
222226

223227
For developers (beginners to intermediate) who want to understand the design patterns used throughout the codebase, please refer to our comprehensive [Design Pattern Review](docs/design-pattern-review.md). This document provides:

docs/SECURITY_CI.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
### ✅ SAFE FOR CI/CD EXECUTION
66

7-
The system test script can be safely run in GitHub Actions with the following security measures:
7+
The e2e test script can be safely run in GitHub Actions with the following security measures:
88

99
## 🔒 Security Safeguards
1010

@@ -44,15 +44,15 @@ google-chrome, safari, edge, opera, brave
4444
### Recommended GitHub Actions Workflow
4545

4646
```yaml
47-
name: System Test with Safety
47+
name: E2E Test with Safety
4848
on:
4949
push:
5050
branches: [ main, develop ]
5151
pull_request:
5252
branches: [ main ]
5353

5454
jobs:
55-
system-test:
55+
e2e-test:
5656
runs-on: ubuntu-latest
5757
timeout-minutes: 15
5858

@@ -70,13 +70,13 @@ jobs:
7070
cd testing-servers/DesktopCommanderMCP
7171
npm ci && npm run build
7272
73-
- name: Run system test
73+
- name: Run e2e test
7474
env:
7575
MCP_FUZZER_SAFETY_ENABLED: 'true'
7676
MCP_FUZZER_TIMEOUT: '30'
7777
run: |
78-
chmod +x tests/system/test_desktop_commander_mcp.sh
79-
./tests/system/test_desktop_commander_mcp.sh
78+
chmod +x tests/e2e/test_desktop_commander_mcp.sh
79+
./tests/e2e/test_desktop_commander_mcp.sh
8080
8181
- name: Upload results
8282
uses: actions/upload-artifact@v4
@@ -142,12 +142,12 @@ MCP_FUZZER_FS_ROOT=/tmp/mcp_fuzzer_sandbox
142142

143143
## 🎯 Conclusion
144144

145-
**The system test script is SAFE for GitHub Actions execution** with:
145+
**The e2e test script is SAFE for GitHub Actions execution** with:
146146

147147
- ✅ **Comprehensive safety system** preventing dangerous operations
148148
- ✅ **CI environment isolation** providing additional security layer
149149
- ✅ **Resource controls** preventing resource exhaustion
150150
- ✅ **Artifact isolation** controlling data exposure
151151
- ✅ **Automatic cleanup** preventing persistent state
152152

153-
The combination of the MCP fuzzer's built-in safety system and GitHub Actions' security model provides multiple layers of protection, making this system test suitable for automated CI/CD pipelines.
153+
The combination of the MCP fuzzer's built-in safety system and GitHub Actions' security model provides multiple layers of protection, making this e2e test suitable for automated CI/CD pipelines.

docs/components/process-management-guide.md

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This guide provides comprehensive information on managing processes, configuring
77
### Starting Processes
88

99
When starting processes with the ProcessManager, follow these best practices:
10+
Use `ProcessManager.from_config(...)` for the default runtime wiring, or build your own dependencies and pass them to the `ProcessManager` constructor when you need custom registries, signal strategies, or watchdog settings.
1011

1112
#### 1. Use Descriptive Names
1213

@@ -105,7 +106,7 @@ async def periodic_activity_update(manager, pid, interval=5.0):
105106

106107
```python
107108
async def graceful_shutdown_example():
108-
manager = ProcessManager()
109+
manager = ProcessManager.from_config()
109110

110111
# Start process
111112
config = ProcessConfig(command=["python", "server.py"], name="server")
@@ -135,7 +136,7 @@ if not success:
135136
### Basic Configuration
136137

137138
```python
138-
from mcp_fuzzer.fuzz_engine.runtime.watchdog import WatchdogConfig
139+
from mcp_fuzzer.fuzz_engine.runtime import WatchdogConfig
139140

140141
# Conservative settings for production
141142
production_config = WatchdogConfig(
@@ -201,7 +202,7 @@ prod_config = WatchdogConfig(
201202
```python
202203
async def managed_process_example():
203204
watchdog_config = WatchdogConfig(auto_kill=True)
204-
manager = ProcessManager(watchdog_config)
205+
manager = ProcessManager.from_config(watchdog_config)
205206

206207
# Processes are automatically registered with watchdog
207208
config = ProcessConfig(command=["python", "server.py"], name="server")
@@ -215,25 +216,36 @@ async def managed_process_example():
215216

216217
#### Standalone Watchdog
217218

219+
```python
220+
import asyncio
221+
import logging
222+
223+
from mcp_fuzzer.fuzz_engine.runtime import (
224+
ProcessConfig,
225+
ProcessRegistry,
226+
ProcessWatchdog,
227+
SignalDispatcher,
228+
WatchdogConfig,
229+
)
230+
231+
logger = logging.getLogger(__name__)
232+
```
233+
218234
```python
219235
async def standalone_watchdog_example():
220-
watchdog = ProcessWatchdog(WatchdogConfig())
236+
registry = ProcessRegistry()
237+
signals = SignalDispatcher(registry, logging.getLogger(__name__))
238+
watchdog = ProcessWatchdog(registry, signals, WatchdogConfig())
221239

222-
# Start monitoring
223240
await watchdog.start()
224-
225-
# Register existing process
226241
process = await asyncio.create_subprocess_exec("python", "server.py")
227-
await watchdog.register_process(
242+
await registry.register(
228243
process.pid,
229244
process,
230-
None, # No activity callback
231-
"server"
245+
ProcessConfig(command=["python", "server.py"], name="server"),
232246
)
233-
234-
# Monitor for a while
247+
await watchdog.update_activity(process.pid)
235248
await asyncio.sleep(30)
236-
237249
await watchdog.stop()
238250
```
239251

docs/components/process-management.md

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -84,40 +84,47 @@ asyncio.run(main())
8484

8585
### ProcessWatchdog
8686

87-
The core watchdog system that monitors processes for hanging behavior.
87+
The core watchdog system that monitors processes for hanging behavior. It reads
88+
from a shared `ProcessRegistry` instead of keeping its own process table.
8889

8990
```python
90-
from mcp_fuzzer.fuzz_engine.runtime import ProcessWatchdog, WatchdogConfig
9191
import asyncio
92-
import asyncio.subprocess as asp
92+
import logging
93+
from mcp_fuzzer.fuzz_engine.runtime import (
94+
ProcessConfig,
95+
ProcessRegistry,
96+
ProcessWatchdog,
97+
SignalDispatcher,
98+
WatchdogConfig,
99+
)
100+
93101

94102
async def main():
95-
# Custom configuration
96-
config = WatchdogConfig(
97-
check_interval=1.0, # Check every second
98-
process_timeout=30.0, # Process timeout after 30 seconds
99-
extra_buffer=5.0, # Extra 5 seconds before killing
100-
max_hang_time=60.0, # Force kill after 60 seconds
101-
auto_kill=True, # Automatically kill hanging processes
103+
registry = ProcessRegistry()
104+
signals = SignalDispatcher(registry, logging.getLogger(__name__))
105+
watchdog = ProcessWatchdog(
106+
registry,
107+
signals,
108+
WatchdogConfig(check_interval=1.0, process_timeout=30.0, auto_kill=True),
102109
)
103-
104-
watchdog = ProcessWatchdog(config)
105110
await watchdog.start()
106111

107-
# Launch a subprocess to register
108-
process = await asp.create_subprocess_exec("python", "-c", "import time; time.sleep(60)")
109-
110-
# Register a process for monitoring
111-
await watchdog.register_process(
112+
process = await asyncio.create_subprocess_exec(
113+
"python", "-c", "import time; time.sleep(60)"
114+
)
115+
await registry.register(
112116
pid=process.pid,
113117
process=process,
114-
activity_callback=None,
115-
name="my_process",
118+
config=ProcessConfig(
119+
command=["python", "-c", "import time; time.sleep(60)"],
120+
name="my_process",
121+
),
116122
)
117-
118-
# Some time later...
123+
await watchdog.update_activity(process.pid)
124+
await watchdog.scan_once(await registry.snapshot())
119125
await watchdog.stop()
120126

127+
121128
asyncio.run(main())
122129
```
123130

@@ -130,7 +137,8 @@ from mcp_fuzzer.fuzz_engine.runtime import ProcessManager, ProcessConfig
130137
import asyncio
131138

132139
async def main():
133-
manager = ProcessManager()
140+
# Default wiring via factory (watchdog, registry, signals, lifecycle, monitor)
141+
manager = ProcessManager.from_config()
134142

135143
# Start a process
136144
config = ProcessConfig(
@@ -145,7 +153,7 @@ async def main():
145153
print(f"Process started with PID: {process.pid}")
146154

147155
# Wait for completion
148-
exit_code = await manager.wait_for_process(process.pid, timeout=120.0)
156+
exit_code = await manager.wait(process.pid, timeout=120.0)
149157

150158
# Get statistics
151159
stats = await manager.get_stats()
@@ -234,7 +242,7 @@ from mcp_fuzzer.fuzz_engine.runtime import ProcessManager, ProcessConfig
234242

235243
async def main():
236244
# Create manager
237-
manager = ProcessManager()
245+
manager = ProcessManager.from_config()
238246

239247
try:
240248
# Start a long-running process
@@ -268,7 +276,7 @@ import asyncio
268276
from mcp_fuzzer.fuzz_engine.runtime import ProcessManager, ProcessConfig
269277

270278
async def run_multiple_processes():
271-
manager = ProcessManager()
279+
manager = ProcessManager.from_config()
272280

273281
try:
274282
# Start multiple processes concurrently
@@ -284,7 +292,7 @@ async def run_multiple_processes():
284292
processes = await asyncio.gather(*tasks)
285293

286294
# Wait for all to complete
287-
wait_tasks = [manager.wait_for_process(process.pid) for process in processes]
295+
wait_tasks = [manager.wait(process.pid) for process in processes]
288296
results = await asyncio.gather(*wait_tasks)
289297
print(f"All processes completed with exit codes: {results}")
290298

@@ -317,7 +325,7 @@ class CustomProcess:
317325

318326
async def main():
319327
# Create process manager
320-
manager = ProcessManager()
328+
manager = ProcessManager.from_config()
321329

322330
# Create custom process
323331
custom_proc = CustomProcess()
@@ -353,7 +361,7 @@ import asyncio
353361
from mcp_fuzzer.fuzz_engine.runtime import ProcessManager, ProcessConfig
354362

355363
async def main():
356-
manager = ProcessManager()
364+
manager = ProcessManager.from_config()
357365

358366
try:
359367
# Start a long-running process
@@ -429,6 +437,6 @@ The Process Management system integrates seamlessly with the MCP Fuzzer architec
429437

430438
For complete API documentation, see the individual module docstrings:
431439

432-
- `mcp_fuzzer.fuzz_engine.runtime.watchdog`
440+
- `mcp_fuzzer.fuzz_engine.runtime`
433441
- `mcp_fuzzer.fuzz_engine.runtime.manager`
434442
- `mcp_fuzzer.fuzz_engine.executor`

0 commit comments

Comments
 (0)