7.4 KiB
agent, status, timestamp, total_findings_raw, total_findings_deduped, p1_count, p2_count, p3_count, p4_count, devtrack_items_created, errors
| agent | status | timestamp | total_findings_raw | total_findings_deduped | p1_count | p2_count | p3_count | p4_count | devtrack_items_created | errors |
|---|---|---|---|---|---|---|---|---|---|---|
| fix-planner | COMPLETE | 2026-05-01T23:45:00Z | 15 | 13 | 1 | 2 | 3 | 2 |
Fix Plan — DevTrack #980: node_scanner.py ThreadPoolExecutor Parallelization
Summary
Consolidated findings from code-auditor (8 findings) and security-auditor (2 findings) for DevTrack #980.
Status: 7 fixes applied and verified. 2 HIGH/MEDIUM severity issues remain (run_scan.yml, estimate_scan_hours partial chunk logic). 4 low-priority items acceptable for backlog.
Fixes Applied ✓
Applied Fixes (Verified)
- [node_scanner.py:204-216] ThreadPoolExecutor parallelization in
scan_masscan_nmap()— 10 workers viaNMAP_WORKERSenv var (default 10) - [node_scanner.py:260-266] ThreadPoolExecutor parallelization in
scan_geo_scout()— same 10-worker pattern - [node_scanner.py:126] Bytes format bug fixed:
ip.encode()used directly instead of%bformat string - [node_scanner.py:145-192] Dead variable
targets_argremoved fromscan_nmap_only() - [provider_rates.py:55-63]
estimate_scan_hours()now acceptsscan_modeparameter for accurate nmap time estimation - [provider_rates.py:50-52] Constants added:
NMAP_TIME_PER_HOST_SEC=10,MASSCAN_HIT_RATE=0.01,_NMAP_WORKERS=10 - [provider_rates.py:104]
build_estimate_table()passesscan_modetoestimate_scan_hours()
Remaining Issues
P1 — Block Deploy
-
[HIGH] [run_scan.yml:14-18] Ansible template injection via unquoted variables | Sources: security-auditor | Effort: S | Status: NOT FIXED
Description: Arguments in
command:module use unquoted Ansible template vars ({{ scan_mode }},{{ ports_str }},{{ node_name }}). Ifnode_nameis injected with shell metacharacters (e.g.,node-1; rm -rf /), Ansible'scommand:module will execute shell commands.Attack vector: Operator misconfigures Ansible extra-vars with malicious node_name or ports_str → arbitrary command execution on cloud node.
Remediation: Use Ansible
command:as list form (args: [python3, script.py, --mode, "{{ scan_mode }}", ...]) or validate inputs upstream in deploy_webrunner.py.Risk: HIGH — affects production cloud deployment pipeline. Requires manual Ansible remediation (file not in Python audit scope).
P2 — Fix This Week
-
[HIGH] [provider_rates.py:91-118] Partial chunk cost overestimation in
build_estimate_table()| Sources: code-auditor | Effort: M | Status: NOT FIXEDDescription: Line 104 assumes each chunk costs the same time as
preset['chunk_size']IPs. Iftotal_ips % preset['chunk_size'] != 0, the last chunk is smaller, but cost calculation doesn't account for it. Example: 2.5M IPs across 2-chunk preset (2M chunks) = chunk 1 (2M hrs) + chunk 2 (0.5M hrs), but current code bills chunk 2 as 2M hrs.Current code:
hours = estimate_scan_hours(preset['chunk_size'], n_ports, mode_rate, scan_mode)— always uses full chunk_size.Fix: Calculate per-chunk IP count separately:
for i in range(n_chunks): chunk_ips = min(preset['chunk_size'], total_ips - i * preset['chunk_size']) hours = estimate_scan_hours(chunk_ips, n_ports, mode_rate, scan_mode) provider = providers[i % len(providers)] instance = DEFAULT_INSTANCE.get(provider, 'g6-standard-2') total_cost += node_cost(provider, instance, hours)Impact: Cost estimates 1.5-2x too high for non-aligned IP counts; may oversell capacity planning.
-
[MEDIUM] [node_scanner.py:225-239] Import inside function —
import yamlat line 232 | Sources: code-auditor | Effort: XS | Status: NOT FIXEDDescription:
import yamlappears insidescan_geo_scout()function. Move to top-level imports for clarity and consistency.Fix: Add
import yamlto line 16 (afterETimport), remove line 232.
P3 — Fix This Month
-
[MEDIUM] [node_scanner.py:21-23]
print()in production code —log()function usesprint()| Sources: code-auditor | Effort: S | Status: NOT FIXEDDescription: Line 23 calls
print()directly. Should use Pythonloggingmodule or Rich (per c2itall style guide).Fix: Replace
log()function with logging.info or Rich console output for consistency. -
[LOW] [node_scanner.py:139-192] Unused parameter
node_name— passed to all scan_* functions but never used | Sources: code-auditor | Effort: XS | Status: NOT FIXEDDescription: Parameter
node_nameappears inscan_masscan_only(),scan_nmap_only(),scan_masscan_nmap(),scan_geo_scout()signatures but is not referenced in function bodies. These functions don't write node metadata to results.Assessment: Intentionally kept for interface consistency (caller always passes it, avoids conditional logic).
Fix: Document as "reserved for future node metadata logging" or remove for clarity. Non-blocking.
-
[LOW] [provider_rates.py:76-88] Comment ambiguity — Tor multiplier description misleading | Sources: code-auditor | Effort: XS | Status: NOT FIXED
Description: Line 86 comment says "Tor adds ~5x latency overhead" but line 88 sets
TOR_RATE_MULTIPLIER = 0.2(which is 1/5, not 5x). Comment is correct in spirit but confusingly worded.Fix: Change comment to "Tor reduces throughput to 1/5 (0.2x)" or "multiplier 0.2 ≈ 5x latency".
P4 — Backlog
-
[LOW] [provider_rates.py:57] Magic number 0.018 — Linode default rate hardcoded | Status: NOT FIXED
Description: Line 7 (
'g6-standard-2': 0.018) and line 67 (fallback rate) hardcode 0.018. Should be named constant.Fix: Add
DEFAULT_INSTANCE_RATE = 0.018and reference it. -
[LOW] [node_scanner.py] Missing docstrings — module + function docstrings absent | Status: NOT FIXED
Description: Module docstring present (line 2-4) but individual functions lack docstrings. Low impact — code is self-documenting.
Deduplication Notes
- Socket leak risk (probe_service): Marked as false alarm in code-auditor; context manager guarantees cleanup. No action needed.
- Thread safety (run_nmap concurrent writes): Verified safe — per-IP XML files unique (
nmap_{ip.replace('.', '_')}.xml). No collision risk. - XXE/entity expansion in ET.parse(): PASS — ET default config disables external entity expansion. nmap output is trusted. No action needed.
- Resource exhaustion (socket connections): MEDIUM severity in security-auditor. Noted as acceptable risk for current sequential structure. ThreadPoolExecutor 10-worker design with 3-second socket timeout is within system limits. Semaphore capping recommended for future scaling but not blocking.
Action Items
Critical Path (Block #980 deployment):
- run_scan.yml: Convert Ansible
command:module to list form OR validate node_name upstream - provider_rates.py: Fix partial-chunk cost calculation in
build_estimate_table()
Nice-to-have (P3-P4):
- Move
import yamlto top level - Replace
print()with logging/Rich - Add Tor multiplier comment clarity
- Extract 0.018 magic number to constant
Test Coverage
- Unit tests for
estimate_scan_hours()with partial chunks should verify cost accuracy - Ansible playbook syntax validation required for run_scan.yml
- Manual integration test with non-aligned IP count (e.g., 2.5M across 2M presets)