vigil-codeintel 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vigil_codeintel-0.1.0.dist-info/METADATA +780 -0
- vigil_codeintel-0.1.0.dist-info/RECORD +131 -0
- vigil_codeintel-0.1.0.dist-info/WHEEL +5 -0
- vigil_codeintel-0.1.0.dist-info/entry_points.txt +3 -0
- vigil_codeintel-0.1.0.dist-info/licenses/LICENSE +21 -0
- vigil_codeintel-0.1.0.dist-info/top_level.txt +3 -0
- vigil_forensic/__init__.py +224 -0
- vigil_forensic/_git_utils.py +178 -0
- vigil_forensic/_shared.py +510 -0
- vigil_forensic/_stubs.py +156 -0
- vigil_forensic/gate_checks/__init__.py +1 -0
- vigil_forensic/gate_checks/_ast_helpers.py +629 -0
- vigil_forensic/gate_checks/_deployment_detector.py +573 -0
- vigil_forensic/gate_checks/atomic_write_checks.py +1143 -0
- vigil_forensic/gate_checks/authority_checks.py +95 -0
- vigil_forensic/gate_checks/boundary_breach_checks.py +202 -0
- vigil_forensic/gate_checks/broad_except_checks.py +301 -0
- vigil_forensic/gate_checks/broad_except_hidden_sentinel_checks.py +365 -0
- vigil_forensic/gate_checks/common.py +253 -0
- vigil_forensic/gate_checks/config_safety_checks.py +704 -0
- vigil_forensic/gate_checks/config_ssot_checks.py +78 -0
- vigil_forensic/gate_checks/conflict_checks.py +193 -0
- vigil_forensic/gate_checks/context_fallback_checks.py +697 -0
- vigil_forensic/gate_checks/context_health_checks.py +289 -0
- vigil_forensic/gate_checks/contract_shape_drift_checks.py +459 -0
- vigil_forensic/gate_checks/dirty_baseline_check.py +274 -0
- vigil_forensic/gate_checks/duplication_checks.py +387 -0
- vigil_forensic/gate_checks/embedded_string_checks.py +123 -0
- vigil_forensic/gate_checks/empty_output_checks.py +87 -0
- vigil_forensic/gate_checks/encoding_checks.py +847 -0
- vigil_forensic/gate_checks/export_completeness_checks.py +156 -0
- vigil_forensic/gate_checks/fallback_checks.py +41 -0
- vigil_forensic/gate_checks/file_proliferation_checks.py +171 -0
- vigil_forensic/gate_checks/fix_without_test_checks.py +69 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/__init__.py +9 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/_helpers.py +71 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/advanced_checks.py +322 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/core.py +273 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/integrity_checks.py +203 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/quality_checks.py +666 -0
- vigil_forensic/gate_checks/forensic_clusters/__init__.py +193 -0
- vigil_forensic/gate_checks/forensic_clusters/allowlist.py +426 -0
- vigil_forensic/gate_checks/forensic_clusters/allowlist_writer.py +302 -0
- vigil_forensic/gate_checks/forensic_clusters/api_protocol.py +231 -0
- vigil_forensic/gate_checks/forensic_clusters/async_quality.py +1156 -0
- vigil_forensic/gate_checks/forensic_clusters/code_style.py +808 -0
- vigil_forensic/gate_checks/forensic_clusters/core.py +319 -0
- vigil_forensic/gate_checks/forensic_clusters/data_quality.py +763 -0
- vigil_forensic/gate_checks/forensic_clusters/dead_code.py +480 -0
- vigil_forensic/gate_checks/forensic_clusters/edit_mutation.py +842 -0
- vigil_forensic/gate_checks/forensic_clusters/exception_boundary.py +240 -0
- vigil_forensic/gate_checks/forensic_clusters/legacy_debt.py +556 -0
- vigil_forensic/gate_checks/forensic_clusters/static_analysis.py +834 -0
- vigil_forensic/gate_checks/forensic_clusters/structural_quality.py +298 -0
- vigil_forensic/gate_checks/god_object_zones_checks.py +173 -0
- vigil_forensic/gate_checks/hallucination_checks.py +566 -0
- vigil_forensic/gate_checks/hunter_artifact_completeness_check.py +139 -0
- vigil_forensic/gate_checks/implementation_overfit_checks.py +380 -0
- vigil_forensic/gate_checks/import_integrity_checks.py +233 -0
- vigil_forensic/gate_checks/imports_in_function_checks.py +283 -0
- vigil_forensic/gate_checks/ml_checks.py +318 -0
- vigil_forensic/gate_checks/performance_checks.py +106 -0
- vigil_forensic/gate_checks/project_specific_runner.py +691 -0
- vigil_forensic/gate_checks/provider_capability_checks.py +73 -0
- vigil_forensic/gate_checks/refactor_completeness_checks.py +274 -0
- vigil_forensic/gate_checks/reliability_checks.py +389 -0
- vigil_forensic/gate_checks/reporting_checks.py +55 -0
- vigil_forensic/gate_checks/runtime_behavior_checks.py +220 -0
- vigil_forensic/gate_checks/security_injection_checks.py +332 -0
- vigil_forensic/gate_checks/semantic_intent_checks.py +139 -0
- vigil_forensic/gate_checks/size_complexity_checks.py +336 -0
- vigil_forensic/gate_checks/stuck_feature_flag_checks.py +354 -0
- vigil_forensic/gate_checks/syntax_validity_checks.py +217 -0
- vigil_forensic/gate_checks/temporal_freshness_checks.py +79 -0
- vigil_forensic/gate_checks/test_quality_checks.py +946 -0
- vigil_forensic/gate_checks/testing_checks.py +149 -0
- vigil_forensic/gate_checks/toctou_checks.py +367 -0
- vigil_forensic/gate_checks/type_checking_checks.py +316 -0
- vigil_forensic/gate_models.py +392 -0
- vigil_forensic/gate_packs/__init__.py +1 -0
- vigil_forensic/gate_packs/universal.py +179 -0
- vigil_forensic/gate_profile.json +31 -0
- vigil_forensic/gate_registry.py +21 -0
- vigil_forensic/language_profiles.py +219 -0
- vigil_forensic/meta_findings.py +207 -0
- vigil_forensic/self_audit.py +725 -0
- vigil_forensic/source_analysis.py +175 -0
- vigil_mapper/__init__.py +103 -0
- vigil_mapper/_ast_helpers_minimal.py +229 -0
- vigil_mapper/_extract_imports_impl.py +123 -0
- vigil_mapper/_file_count_guard.py +129 -0
- vigil_mapper/_git_utils.py +178 -0
- vigil_mapper/_runtime_ast.py +438 -0
- vigil_mapper/_runtime_dispatch.py +137 -0
- vigil_mapper/_seed_helpers.py +82 -0
- vigil_mapper/authority_builder.py +1102 -0
- vigil_mapper/cli_entry.py +731 -0
- vigil_mapper/conflict_builder.py +818 -0
- vigil_mapper/data_contract_builder.py +446 -0
- vigil_mapper/findings_builder.py +716 -0
- vigil_mapper/fingerprint.py +53 -0
- vigil_mapper/hotspot_builder.py +539 -0
- vigil_mapper/map_common.py +449 -0
- vigil_mapper/map_errors.py +55 -0
- vigil_mapper/map_models.py +431 -0
- vigil_mapper/map_models_ext.py +206 -0
- vigil_mapper/map_models_findings.py +130 -0
- vigil_mapper/map_storage.py +455 -0
- vigil_mapper/parse_cache.py +795 -0
- vigil_mapper/refactor_boundary_builder.py +266 -0
- vigil_mapper/runtime_builder.py +527 -0
- vigil_mapper/runtime_tracer.py +243 -0
- vigil_mapper/runtime_tracer_entry.py +199 -0
- vigil_mapper/semantic_diff.py +71 -0
- vigil_mapper/source_adapters/__init__.py +109 -0
- vigil_mapper/source_adapters/_base.py +264 -0
- vigil_mapper/source_adapters/_ir.py +156 -0
- vigil_mapper/source_adapters/_lexer.py +309 -0
- vigil_mapper/source_adapters/_patterns.py +212 -0
- vigil_mapper/source_adapters/_treesitter.py +182 -0
- vigil_mapper/source_adapters/go.py +553 -0
- vigil_mapper/source_adapters/java.py +541 -0
- vigil_mapper/source_adapters/javascript.py +626 -0
- vigil_mapper/source_adapters/python.py +325 -0
- vigil_mapper/source_adapters/typescript.py +749 -0
- vigil_mapper/structural_builder.py +586 -0
- vigil_mcp/__init__.py +1 -0
- vigil_mcp/_jobs.py +587 -0
- vigil_mcp/_paths.py +93 -0
- vigil_mcp/forensic_server.py +419 -0
- vigil_mcp/map_server.py +452 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"""Exception handling and boundary validation. Clusters 31, 32, 33."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from .core import detect_language
|
|
5
|
+
from ...gate_models import (
|
|
6
|
+
EvidenceReference,
|
|
7
|
+
GateCategory,
|
|
8
|
+
GateFinding,
|
|
9
|
+
GateImpact,
|
|
10
|
+
GateSeverity,
|
|
11
|
+
RepairKind,
|
|
12
|
+
)
|
|
13
|
+
from ..common import build_finding
|
|
14
|
+
import logging
|
|
15
|
+
_log = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _extract_except_body(lines: list[str], except_line: int) -> str:
|
|
19
|
+
if except_line + 1 >= len(lines):
|
|
20
|
+
return ""
|
|
21
|
+
except_indent = len(lines[except_line]) - len(lines[except_line].lstrip())
|
|
22
|
+
body_parts = []
|
|
23
|
+
for j in range(except_line + 1, min(except_line + 10, len(lines))):
|
|
24
|
+
line = lines[j]
|
|
25
|
+
if not line.strip():
|
|
26
|
+
continue
|
|
27
|
+
line_indent = len(line) - len(line.lstrip())
|
|
28
|
+
if line_indent <= except_indent:
|
|
29
|
+
break
|
|
30
|
+
body_parts.append(line.strip())
|
|
31
|
+
return "\n".join(body_parts)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _is_swallowed(body: str) -> bool:
|
|
35
|
+
stripped = body.strip()
|
|
36
|
+
if not stripped or stripped == "pass":
|
|
37
|
+
return True
|
|
38
|
+
body_lines = [l.strip() for l in stripped.splitlines() if l.strip()]
|
|
39
|
+
if all(l in ("pass", "continue") for l in body_lines):
|
|
40
|
+
return True
|
|
41
|
+
if any(l.startswith("raise") for l in body_lines):
|
|
42
|
+
return False
|
|
43
|
+
if any(l.startswith("return ") for l in body_lines):
|
|
44
|
+
return False
|
|
45
|
+
log_only = all(
|
|
46
|
+
l.startswith(("log", "logger", "logging", "print(", "#", "warnings.warn")) # noqa: debug_print_scan # gate pattern reference, not a production print call
|
|
47
|
+
for l in body_lines
|
|
48
|
+
)
|
|
49
|
+
if log_only and len(body_lines) <= 2:
|
|
50
|
+
return False
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# Control-flow exceptions that are idiomatically caught-and-passed (NOT swallowed
|
|
55
|
+
# errors): broken pipe on closed stdout, clean Ctrl+C / shutdown, generator/async
|
|
56
|
+
# teardown, iteration end. Flagging `except KeyboardInterrupt: pass` as a swallowed
|
|
57
|
+
# error is a false positive.
|
|
58
|
+
_CONTROL_FLOW_EXCEPTIONS = frozenset({
|
|
59
|
+
"KeyboardInterrupt", "BrokenPipeError", "GeneratorExit", "SystemExit",
|
|
60
|
+
"StopIteration", "StopAsyncIteration", "CancelledError",
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def assess_exception_swallowing(file_path: str, content: str) -> list[GateFinding]:
|
|
65
|
+
"""Cluster 31: Detect swallowed exceptions."""
|
|
66
|
+
import re
|
|
67
|
+
|
|
68
|
+
if not content.strip():
|
|
69
|
+
return []
|
|
70
|
+
if detect_language(file_path) != "python":
|
|
71
|
+
return []
|
|
72
|
+
basename = file_path.replace("\\", "/").rsplit("/", 1)[-1] if "/" in file_path.replace("\\", "/") else file_path
|
|
73
|
+
if basename.startswith("test_") or basename.startswith("conftest"):
|
|
74
|
+
return []
|
|
75
|
+
|
|
76
|
+
lines = content.splitlines()
|
|
77
|
+
findings: list[GateFinding] = []
|
|
78
|
+
i = 0
|
|
79
|
+
while i < len(lines):
|
|
80
|
+
stripped = lines[i].strip()
|
|
81
|
+
if re.match(r'^except\s*:', stripped):
|
|
82
|
+
body = _extract_except_body(lines, i)
|
|
83
|
+
if _is_swallowed(body):
|
|
84
|
+
detail = f"Bare except with swallowed error (line {i + 1}): body is '{body.strip()[:60]}'"
|
|
85
|
+
findings.append(build_finding(
|
|
86
|
+
check_id="exception_swallow_scan",
|
|
87
|
+
category=GateCategory.RUNTIME_BEHAVIOR,
|
|
88
|
+
title=f"[exception_swallowing] {file_path}:{i + 1}",
|
|
89
|
+
severity=GateSeverity.HIGH,
|
|
90
|
+
impact=GateImpact.REVISE,
|
|
91
|
+
summary=detail,
|
|
92
|
+
recommendation="Use specific exception types and reraise or log+reraise.",
|
|
93
|
+
evidence=(EvidenceReference(kind="probe", path=file_path, detail=detail, ok=False),),
|
|
94
|
+
repair_kind=RepairKind.REPLACE_WITH_FAIL_LOUD.value,
|
|
95
|
+
executor_action=f"Fix swallowed exception at {file_path}:{i + 1}",
|
|
96
|
+
))
|
|
97
|
+
elif re.match(r'^except\s+(Exception|BaseException)(\s+as\s+\w+)?\s*:', stripped):
|
|
98
|
+
body = _extract_except_body(lines, i)
|
|
99
|
+
if _is_swallowed(body):
|
|
100
|
+
exc_m = re.match(r'^except\s+(Exception|BaseException)', stripped)
|
|
101
|
+
exc_type = exc_m.group(1) if exc_m else "Exception"
|
|
102
|
+
detail = f"Broad `except {exc_type}` with swallowed error (line {i + 1})"
|
|
103
|
+
findings.append(build_finding(
|
|
104
|
+
check_id="exception_swallow_scan",
|
|
105
|
+
category=GateCategory.RUNTIME_BEHAVIOR,
|
|
106
|
+
title=f"[exception_swallowing] {file_path}:{i + 1}",
|
|
107
|
+
severity=GateSeverity.HIGH,
|
|
108
|
+
impact=GateImpact.REVISE,
|
|
109
|
+
summary=detail,
|
|
110
|
+
recommendation="Add reraise (raise) after logging, or use a more specific exception type.",
|
|
111
|
+
evidence=(EvidenceReference(kind="probe", path=file_path, detail=detail, ok=False),),
|
|
112
|
+
repair_kind=RepairKind.REPLACE_WITH_FAIL_LOUD.value,
|
|
113
|
+
executor_action=f"Fix broad except at {file_path}:{i + 1}",
|
|
114
|
+
))
|
|
115
|
+
elif re.match(r'^except\s+\w', stripped):
|
|
116
|
+
body = _extract_except_body(lines, i)
|
|
117
|
+
exc_m = re.match(r'^except\s+([\w.]+)', stripped)
|
|
118
|
+
caught = exc_m.group(1).split(".")[-1] if exc_m else ""
|
|
119
|
+
if body.strip() == "pass" and caught not in _CONTROL_FLOW_EXCEPTIONS:
|
|
120
|
+
detail = f"Exception caught and silently passed (line {i + 1}): {stripped[:60]}"
|
|
121
|
+
findings.append(build_finding(
|
|
122
|
+
check_id="exception_swallow_scan",
|
|
123
|
+
category=GateCategory.RUNTIME_BEHAVIOR,
|
|
124
|
+
title=f"[exception_swallowing] {file_path}:{i + 1}",
|
|
125
|
+
severity=GateSeverity.MEDIUM,
|
|
126
|
+
impact=GateImpact.REVISE,
|
|
127
|
+
summary=detail,
|
|
128
|
+
recommendation="Log the exception and/or reraise it instead of passing silently.",
|
|
129
|
+
evidence=(EvidenceReference(kind="probe", path=file_path, detail=detail, ok=False),),
|
|
130
|
+
repair_kind=RepairKind.REPLACE_WITH_FAIL_LOUD.value,
|
|
131
|
+
executor_action=f"Fix silent pass at {file_path}:{i + 1}",
|
|
132
|
+
))
|
|
133
|
+
i += 1
|
|
134
|
+
return findings[:10]
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def assess_hardcoded_paths(file_path: str, content: str) -> list[GateFinding]:
|
|
138
|
+
"""Cluster 32: Detect hardcoded absolute paths that break portability."""
|
|
139
|
+
import re
|
|
140
|
+
|
|
141
|
+
if not content.strip():
|
|
142
|
+
return []
|
|
143
|
+
lang = detect_language(file_path)
|
|
144
|
+
if lang not in ("python", "javascript", "typescript", "go", "rust", "java", "shell"):
|
|
145
|
+
return []
|
|
146
|
+
basename = file_path.replace("\\", "/").rsplit("/", 1)[-1] if "/" in file_path.replace("\\", "/") else file_path
|
|
147
|
+
if basename.startswith("test_") or basename.startswith("conftest"):
|
|
148
|
+
return []
|
|
149
|
+
|
|
150
|
+
path_patterns = [
|
|
151
|
+
(r'''["'][A-Z]:\\[^"']{3,}["']''', "Windows absolute path"),
|
|
152
|
+
(r'''["']/home/\w+[^"']*["']''', "Unix home directory path"),
|
|
153
|
+
(r'''["']/tmp/[^"']+["']''', "Hardcoded /tmp path (use tempfile)"),
|
|
154
|
+
(r'''["']/usr/(?:local/|bin/)[^"']+["']''', "Hardcoded /usr path"),
|
|
155
|
+
(r'''["']/var/(?:log|run|lib)/[^"']+["']''', "Hardcoded /var path"),
|
|
156
|
+
(r'''["']/etc/[^"']+["']''', "Hardcoded /etc config path"),
|
|
157
|
+
(r'''["']/opt/[^"']+["']''', "Hardcoded /opt path"),
|
|
158
|
+
(r'''["']/(?:root|srv|mnt)/[^"']+["']''', "Hardcoded system path"),
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
findings: list[GateFinding] = []
|
|
162
|
+
for i, line in enumerate(content.splitlines(), 1):
|
|
163
|
+
stripped = line.strip()
|
|
164
|
+
if stripped.startswith("#") or stripped.startswith("//"):
|
|
165
|
+
continue
|
|
166
|
+
if stripped.startswith('"""') or stripped.startswith("'''"):
|
|
167
|
+
continue
|
|
168
|
+
if "http://" in line or "https://" in line or "ftp://" in line:
|
|
169
|
+
continue
|
|
170
|
+
if i == 1 and stripped.startswith("#!"):
|
|
171
|
+
continue
|
|
172
|
+
for pattern, description in path_patterns:
|
|
173
|
+
for m in re.finditer(pattern, line):
|
|
174
|
+
matched = m.group(0)
|
|
175
|
+
if "EXAMPLE" in stripped.upper() or "PLACEHOLDER" in stripped.upper():
|
|
176
|
+
continue
|
|
177
|
+
findings.append(build_finding(
|
|
178
|
+
check_id="hardcoded_path_scan",
|
|
179
|
+
category=GateCategory.CONTRACT,
|
|
180
|
+
title=f"[hardcoded_paths] {file_path}:{i}",
|
|
181
|
+
severity=GateSeverity.MEDIUM,
|
|
182
|
+
impact=GateImpact.REVISE,
|
|
183
|
+
summary=f"{description}: {matched[:80]}",
|
|
184
|
+
recommendation="Use os.path, pathlib.Path, or environment variables instead of hardcoded paths.",
|
|
185
|
+
evidence=(EvidenceReference(kind="probe", path=file_path, detail=f"{description}: {matched[:80]}", ok=False),),
|
|
186
|
+
repair_kind=RepairKind.FIX_CONTRACT.value,
|
|
187
|
+
executor_action=f"Replace hardcoded path at {file_path}:{i}",
|
|
188
|
+
))
|
|
189
|
+
break
|
|
190
|
+
if len(findings) >= 10:
|
|
191
|
+
break
|
|
192
|
+
return findings
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def assess_boundary_validation(file_path: str, content: str) -> list[GateFinding]:
|
|
196
|
+
"""Cluster 33: Detect unvalidated external input at system boundaries."""
|
|
197
|
+
import re
|
|
198
|
+
|
|
199
|
+
if not content.strip():
|
|
200
|
+
return []
|
|
201
|
+
if detect_language(file_path) != "python":
|
|
202
|
+
return []
|
|
203
|
+
basename = file_path.replace("\\", "/").rsplit("/", 1)[-1] if "/" in file_path.replace("\\", "/") else file_path
|
|
204
|
+
if basename.startswith("test_") or basename.startswith("conftest"):
|
|
205
|
+
return []
|
|
206
|
+
|
|
207
|
+
findings: list[GateFinding] = []
|
|
208
|
+
for i, line in enumerate(content.splitlines(), 1):
|
|
209
|
+
stripped = line.strip()
|
|
210
|
+
if stripped.startswith("#"):
|
|
211
|
+
continue
|
|
212
|
+
detail: str | None = None
|
|
213
|
+
if re.search(r'os\.(system|popen)\s*\(\s*f["\']', stripped):
|
|
214
|
+
detail = f"Potential command injection: os.system/popen with f-string (line {i})"
|
|
215
|
+
elif re.search(r'subprocess\.\w+\s*\(.*shell\s*=\s*True', stripped) and ('f"' in stripped or "f'" in stripped):
|
|
216
|
+
detail = f"Potential command injection: subprocess with shell=True + f-string (line {i})"
|
|
217
|
+
elif re.search(r'\.(execute|executemany|query)\s*\(\s*f["\']', stripped):
|
|
218
|
+
if re.search(r'(?i)(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER)', stripped):
|
|
219
|
+
detail = f"Potential SQL injection: .execute() with f-string SQL (line {i})"
|
|
220
|
+
elif re.search(r'\.(execute|query)\s*\(\s*["\'].*%s.*["\'].*%\s*\(', stripped):
|
|
221
|
+
if re.search(r'(?i)(SELECT|INSERT|UPDATE|DELETE)', stripped):
|
|
222
|
+
detail = f"Potential SQL injection: .execute() with % formatting (line {i})"
|
|
223
|
+
elif re.search(r'\b(eval|exec)\s*\(\s*(?!["\'(])', stripped):
|
|
224
|
+
detail = f"Dangerous eval/exec with variable input (line {i})"
|
|
225
|
+
if detail:
|
|
226
|
+
findings.append(build_finding(
|
|
227
|
+
check_id="boundary_validation_scan",
|
|
228
|
+
category=GateCategory.TRUTH_BOUNDARY,
|
|
229
|
+
title=f"[boundary_validation] {file_path}:{i}",
|
|
230
|
+
severity=GateSeverity.HIGH,
|
|
231
|
+
impact=GateImpact.REVISE,
|
|
232
|
+
summary=detail,
|
|
233
|
+
recommendation="Validate and sanitize all external input before use in system calls.",
|
|
234
|
+
evidence=(EvidenceReference(kind="probe", path=file_path, detail=detail, ok=False),),
|
|
235
|
+
repair_kind=RepairKind.ADD_BOUNDARY_CHECK.value,
|
|
236
|
+
executor_action=f"Fix boundary validation at {file_path}:{i}",
|
|
237
|
+
))
|
|
238
|
+
if len(findings) >= 10:
|
|
239
|
+
break
|
|
240
|
+
return findings
|