Skip to content

Commit be55176

Browse files
author
Agent-Planner
committed
Fix all ruff linting errors
- Fix unused variables (F841) in stack_detector.py and chat session services - Fix blank line whitespace (W293) across multiple files - Fix trailing whitespace (W291) in multiple files - Fix f-string without placeholders (F541) in design_tokens router - Fix undefined names (F821) in templates router - Fix import order (I001) in templates router Resolves GitHub Actions CI failure due to ruff linting errors.
1 parent dde9d3e commit be55176

13 files changed

Lines changed: 52 additions & 48 deletions

analyzers/stack_detector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def detect(self) -> StackDetectionResult:
118118
all_endpoints.extend(analysis.get("endpoints", []))
119119
all_components.extend(analysis.get("components", []))
120120

121-
except Exception as e:
121+
except Exception:
122122
# Log but don't fail - continue with other analyzers
123123
logger.exception(f"Warning: {analyzer.stack_name} analyzer failed")
124124

design_tokens.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,19 @@ class ColorToken:
4747
def to_hsl(self) -> tuple[float, float, float]:
4848
"""Convert hex to HSL."""
4949
hex_color = self.value.lstrip("#")
50-
50+
5151
# Validate hex color format
5252
if not all(c in "0123456789abcdefABCDEF" for c in hex_color):
5353
raise ValueError(f"Invalid hex color format: {self.value}")
54-
54+
5555
hex_color = hex_color.lower()
56-
56+
5757
# Normalize short hex format (3 digits -> 6 digits)
5858
if len(hex_color) == 3:
5959
hex_color = "".join([c * 2 for c in hex_color])
6060
elif len(hex_color) != 6:
6161
raise ValueError(f"Hex color must be 3 or 6 digits, got {len(hex_color)}: {self.value}")
62-
62+
6363
# Parse RGB components
6464
r, g, b = tuple(int(hex_color[i : i + 2], 16) / 255 for i in (0, 2, 4))
6565
hue, lightness, sat = colorsys.rgb_to_hls(r, g, b)

parallel_orchestrator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,11 +1210,11 @@ def cleanup(self) -> None:
12101210
"""
12111211
if self._engine is None:
12121212
return # Already cleaned up, idempotent safe
1213-
1213+
12141214
# Capture engine and clear reference immediately to make cleanup idempotent
12151215
engine = self._engine
12161216
self._engine = None
1217-
1217+
12181218
try:
12191219
debug_log.log("CLEANUP", "Forcing WAL checkpoint before dispose")
12201220
with engine.connect() as conn:

quality_gates.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def _detect_js_linter(project_dir: Path) -> tuple[str, list[str]] | None:
8585
eslint_path = shutil.which("eslint")
8686
if eslint_path:
8787
return ("eslint", [eslint_path, ".", "--max-warnings=0"])
88-
88+
8989
# Check for eslint in node_modules/.bin (fallback for non-global installs)
9090
node_eslint = project_dir / "node_modules/.bin/eslint"
9191
if node_eslint.exists():
@@ -95,7 +95,7 @@ def _detect_js_linter(project_dir: Path) -> tuple[str, list[str]] | None:
9595
biome_path = shutil.which("biome")
9696
if biome_path:
9797
return ("biome", [biome_path, "lint", "."])
98-
98+
9999
# Check for biome in node_modules/.bin (fallback for non-global installs)
100100
node_biome = project_dir / "node_modules/.bin/biome"
101101
if node_biome.exists():
@@ -133,20 +133,23 @@ def _detect_python_linter(project_dir: Path) -> tuple[str, list[str]] | None:
133133
return ("flake8", [flake8_path, "."])
134134

135135
# Check in virtual environment for both Unix and Windows paths
136-
venv_paths = [
136+
venv_ruff_paths = [
137137
project_dir / "venv/bin/ruff",
138-
project_dir / "venv/Scripts/ruff.exe",
138+
project_dir / "venv/Scripts/ruff.exe"
139+
]
140+
141+
venv_flake8_paths = [
139142
project_dir / "venv/bin/flake8",
140143
project_dir / "venv/Scripts/flake8.exe"
141144
]
142-
145+
143146
# Check for ruff in venv
144-
for venv_ruff in venv_paths:
147+
for venv_ruff in venv_ruff_paths:
145148
if venv_ruff.exists():
146149
return ("ruff", [str(venv_ruff), "check", "."])
147150

148-
# Check for flake8 in venv
149-
for venv_flake8 in venv_paths:
151+
# Check for flake8 in venv
152+
for venv_flake8 in venv_flake8_paths:
150153
if venv_flake8.exists():
151154
return ("flake8", [str(venv_flake8), "."])
152155

@@ -314,10 +317,10 @@ def run_custom_script(
314317
# Determine the appropriate command and runner based on platform and script extension
315318
script_str = str(script_full_path)
316319
script_ext = script_full_path.suffix.lower()
317-
320+
318321
# Platform detection
319322
is_windows = os.name == "nt" or platform.system() == "Windows"
320-
323+
321324
if is_windows:
322325
# Windows: check script extension and use appropriate runner
323326
if script_ext == ".ps1":
@@ -342,7 +345,6 @@ def run_custom_script(
342345
else:
343346
# Last resort: try to execute directly
344347
command = [script_str]
345-
346348
exit_code, output, duration_ms = _run_command(
347349
command,
348350
project_dir,

security.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,12 @@ def get_denied_commands(limit: int = 50) -> list[dict[str, Any]]:
9999
# Convert to list and reverse for most-recent-first
100100
commands = list(_denied_commands)[-limit:]
101101
commands.reverse()
102-
102+
103103
def redact_string(s: str, max_preview: int = 20) -> str:
104104
if len(s) <= max_preview * 2:
105105
return s
106106
return f"{s[:max_preview]}...{s[-max_preview:]}"
107-
107+
108108
return [
109109
{
110110
"timestamp": cmd.timestamp,

server/routers/design_tokens.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,15 @@ def get_project_dir(project_name: str) -> Path:
128128

129129
# For arbitrary paths, resolve and validate
130130
path = Path(project_name).resolve()
131-
131+
132132
# Security: Check if path is in a blocked location
133133
from .filesystem import is_path_blocked
134134
if is_path_blocked(path):
135135
raise HTTPException(
136136
status_code=404,
137137
detail=f"Project not found or access denied: {project_name}"
138138
)
139-
139+
140140
# Ensure the path exists and is a directory
141141
if not path.exists() or not path.is_dir():
142142
raise HTTPException(status_code=404, detail=f"Project not found: {project_name}")
@@ -146,18 +146,18 @@ def get_project_dir(project_name: str) -> Path:
146146

147147
def _validate_project_path(path: Path) -> None:
148148
"""Validate that a project path is not blocked.
149-
149+
150150
Args:
151151
path: The resolved project path to validate
152-
152+
153153
Raises:
154154
HTTPException: If the path is blocked
155155
"""
156156
from .filesystem import is_path_blocked
157157
if is_path_blocked(path):
158158
raise HTTPException(
159159
status_code=404,
160-
detail=f"Project access denied: Path is in a restricted location"
160+
detail="Project access denied: Path is in a restricted location"
161161
)
162162

163163

@@ -253,14 +253,16 @@ async def generate_token_files(project_name: str, output_dir: Optional[str] = No
253253
# Resolve and validate output_dir to prevent directory traversal
254254
target = (project_dir / output_dir).resolve()
255255
project_resolved = project_dir.resolve()
256-
257-
# Validate that target is within project_dir
258-
if not str(target).startswith(str(project_resolved)):
256+
257+
# Validate that target is within project_dir using proper path containment
258+
try:
259+
target.relative_to(project_resolved)
260+
except ValueError:
259261
raise HTTPException(
260-
status_code=400,
262+
status_code=400,
261263
detail=f"Invalid output directory: '{output_dir}'. Directory must be within the project directory."
262264
)
263-
265+
264266
result = manager.generate_all(target)
265267
else:
266268
result = manager.generate_all()

server/routers/documentation.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,28 +109,28 @@ def get_project_dir(project_name: str) -> Path:
109109

110110
def _validate_project_path(path: Path) -> None:
111111
"""Validate that a project path is within allowed boundaries.
112-
112+
113113
Args:
114114
path: The resolved project path to validate
115-
115+
116116
Raises:
117117
HTTPException: If the path is outside allowed boundaries
118118
"""
119119
# Use current working directory as the allowed projects root
120120
# This prevents directory traversal attacks
121121
allowed_root = Path.cwd().resolve()
122-
122+
123123
try:
124124
# Check if the path is within the allowed root directory
125125
if not path.is_relative_to(allowed_root):
126126
raise HTTPException(
127-
status_code=403,
127+
status_code=403,
128128
detail=f"Access denied: Project path '{path}' is outside allowed directory boundary"
129129
)
130130
except ValueError:
131131
# Handle case where path comparison fails
132132
raise HTTPException(
133-
status_code=403,
133+
status_code=403,
134134
detail=f"Access denied: Project path '{path}' is outside allowed directory boundary"
135135
)
136136

@@ -234,7 +234,7 @@ async def get_doc_content(project_name: str, filename: str):
234234
filename: Documentation file path (e.g., "README.md" or "docs/API.md")
235235
"""
236236
project_dir = get_project_dir(project_name)
237-
237+
238238
# Resolve both paths to handle symlinks and get absolute paths
239239
resolved_project_dir = project_dir.resolve()
240240
resolved_file_path = (project_dir / filename).resolve()
@@ -321,7 +321,7 @@ async def delete_doc(project_name: str, filename: str):
321321
filename: Documentation file path
322322
"""
323323
project_dir = get_project_dir(project_name)
324-
324+
325325
# Resolve both paths to handle symlinks and get absolute paths
326326
resolved_project_dir = project_dir.resolve()
327327
resolved_file_path = (project_dir / filename).resolve()

server/routers/review.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ async def delete_report(project_name: str, filename: str):
325325
# Validate filename to prevent path traversal before using it in path construction
326326
if ".." in filename or "/" in filename or "\\" in filename:
327327
raise HTTPException(status_code=400, detail="Invalid filename")
328-
328+
329329
project_dir = get_project_dir(project_name)
330330
report_path = project_dir / ".autocoder" / "review-reports" / filename
331331

server/routers/templates.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,17 @@
1919
from fastapi import APIRouter, HTTPException
2020
from pydantic import BaseModel, Field
2121

22-
logger = logging.getLogger(__name__)
23-
2422
# Setup sys.path for imports
2523
# Compute project root and ensure it's in sys.path
2624
project_root = Path(__file__).parent.parent.parent.parent
2725
if str(project_root) not in sys.path:
2826
sys.path.insert(0, str(project_root))
2927

28+
from templates.library import generate_app_spec, generate_features
29+
from templates.library import get_template as get_template_data
30+
31+
logger = logging.getLogger(__name__)
32+
3033
router = APIRouter(prefix="/api/templates", tags=["templates"])
3134

3235

@@ -165,7 +168,7 @@ async def get_template(template_id: str):
165168
Get detailed information about a specific template.
166169
"""
167170
try:
168-
template = get_template(template_id)
171+
template = get_template_data(template_id)
169172

170173
if not template:
171174
raise HTTPException(status_code=404, detail=f"Template not found: {template_id}")
@@ -209,7 +212,7 @@ async def preview_template(request: PreviewRequest):
209212
Does not create any files - just returns the content.
210213
"""
211214
try:
212-
template = get_template(request.template_id)
215+
template = get_template_data(request.template_id)
213216
if not template:
214217
raise HTTPException(status_code=404, detail=f"Template not found: {request.template_id}")
215218

@@ -244,7 +247,7 @@ async def apply_template(request: ApplyRequest):
244247
Does NOT register the project or create features - use the projects API for that.
245248
"""
246249
try:
247-
template = get_template(request.template_id)
250+
template = get_template_data(request.template_id)
248251
if not template:
249252
raise HTTPException(status_code=404, detail=f"Template not found: {request.template_id}")
250253

@@ -309,7 +312,7 @@ async def get_template_features(template_id: str):
309312
Returns features in bulk_create format.
310313
"""
311314
try:
312-
template = get_template(template_id)
315+
template = get_template_data(template_id)
313316
if not template:
314317
raise HTTPException(status_code=404, detail=f"Template not found: {template_id}")
315318

server/routers/visual_regression.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ def get_project_dir(project_name: str) -> Path:
159159
status_code=403,
160160
detail="Access to this path is forbidden"
161161
)
162-
162+
163163
if path.exists() and path.is_dir():
164164
return path
165165

0 commit comments

Comments
 (0)