kicad-mcp/kicad_mcp/utils/file_utils.py
Lauri Gates bd08a47a6f feat: add comprehensive security and input validation system
- Add PathValidator class for preventing path traversal attacks
- Add SecureSubprocessRunner for safe command execution
- Replace unsafe XML parsing with defusedxml for security
- Add comprehensive input validation tools for circuit generation
- Include security dependencies (defusedxml, bandit) in pyproject.toml
- Add security scanning job to CI/CD pipeline
- Add comprehensive test coverage for security utilities
- Add timeout constants for safe operation limits
- Add boundary validation for component positioning

This establishes a strong security foundation for the KiCad MCP server
by implementing defense-in-depth security measures across all input
vectors and external process interactions.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-17 21:34:16 +03:00

72 lines
2.1 KiB
Python

"""
File handling utilities for KiCad MCP Server.
"""
import json
import os
from typing import Any
from kicad_mcp.utils.kicad_utils import get_project_name_from_path
def get_project_files(project_path: str) -> dict[str, str]:
"""Get all files related to a KiCad project.
Args:
project_path: Path to the .kicad_pro file
Returns:
Dictionary mapping file types to file paths
"""
from kicad_mcp.config import DATA_EXTENSIONS, KICAD_EXTENSIONS
project_dir = os.path.dirname(project_path)
project_name = get_project_name_from_path(project_path)
files = {}
# Check for standard KiCad files
for file_type, extension in KICAD_EXTENSIONS.items():
if file_type == "project":
# We already have the project file
files[file_type] = project_path
continue
file_path = os.path.join(project_dir, f"{project_name}{extension}")
if os.path.exists(file_path):
files[file_type] = file_path
# Check for data files
try:
for ext in DATA_EXTENSIONS:
for file in os.listdir(project_dir):
if file.startswith(project_name) and file.endswith(ext):
# Extract the type from filename (e.g., project_name-bom.csv -> bom)
file_type = file[len(project_name) :].strip("-_")
file_type = file_type.split(".")[0]
if not file_type:
file_type = ext[1:] # Use extension if no specific type
files[file_type] = os.path.join(project_dir, file)
except (OSError, FileNotFoundError):
# Directory doesn't exist or can't be accessed - return what we have
pass
return files
def load_project_json(project_path: str) -> dict[str, Any] | None:
"""Load and parse a KiCad project file.
Args:
project_path: Path to the .kicad_pro file
Returns:
Parsed JSON data or None if parsing failed
"""
try:
with open(project_path) as f:
return json.load(f)
except Exception:
return None