diff --git a/codewiki/cli/utils/repo_validator.py b/codewiki/cli/utils/repo_validator.py index 3e17d031..84e81c1c 100644 --- a/codewiki/cli/utils/repo_validator.py +++ b/codewiki/cli/utils/repo_validator.py @@ -4,12 +4,16 @@ from pathlib import Path from typing import Tuple, List +import logging import os from codewiki.cli.utils.errors import RepositoryError from codewiki.cli.utils.validation import validate_repository_path, detect_supported_languages +logger = logging.getLogger(__name__) + + # Supported file extensions by language SUPPORTED_EXTENSIONS = { '.py', # Python @@ -146,6 +150,7 @@ def get_git_commit_hash(repo_path: Path) -> str: repo = git.Repo(repo_path) return repo.head.commit.hexsha except Exception: + logger.debug("Failed to read git commit hash for %s", repo_path, exc_info=True) return "" @@ -167,6 +172,7 @@ def get_git_branch(repo_path: Path) -> str: repo = git.Repo(repo_path) return repo.active_branch.name except Exception: + logger.debug("Failed to read git branch for %s", repo_path, exc_info=True) return "" diff --git a/codewiki/src/fe/github_processor.py b/codewiki/src/fe/github_processor.py index a31ce6b8..53fb33e6 100644 --- a/codewiki/src/fe/github_processor.py +++ b/codewiki/src/fe/github_processor.py @@ -71,6 +71,8 @@ def clone_repository(clone_url: str, target_dir: str, commit_id: str = None) -> if result.returncode != 0: logger.error(f"Error cloning repository: {result.stderr}") + if os.path.isdir(target_dir): + shutil.rmtree(target_dir, ignore_errors=True) return False # Checkout specific commit @@ -91,6 +93,8 @@ def clone_repository(clone_url: str, target_dir: str, commit_id: str = None) -> if result.returncode != 0: logger.error(f"Error cloning repository: {result.stderr}") + if os.path.isdir(target_dir): + shutil.rmtree(target_dir, ignore_errors=True) return False return True @@ -99,3 +103,4 @@ def clone_repository(clone_url: str, target_dir: str, commit_id: str = None) -> if os.path.isdir(target_dir): shutil.rmtree(target_dir, ignore_errors=True) return False + diff --git a/codewiki/src/fe/routes.py b/codewiki/src/fe/routes.py index 4750c21c..5f110462 100644 --- a/codewiki/src/fe/routes.py +++ b/codewiki/src/fe/routes.py @@ -242,10 +242,19 @@ async def serve_generated_docs(self, job_id: str, filename: str = "overview.md") pass # Serve the requested file - docs_path_resolved = docs_path.resolve() - file_path = (docs_path / filename).resolve() - if docs_path_resolved != file_path and docs_path_resolved not in file_path.parents: + if not filename.endswith('.md'): raise HTTPException(status_code=400, detail="Invalid file path") + + try: + docs_path_resolved = docs_path.resolve() + file_path = (docs_path / filename).resolve() + if not file_path.is_relative_to(docs_path_resolved): + raise HTTPException(status_code=400, detail="Invalid file path") + except HTTPException: + raise + except Exception: + raise HTTPException(status_code=400, detail="Invalid file path") + if not file_path.exists(): raise HTTPException(status_code=404, detail=f"File {filename} not found") @@ -304,3 +313,4 @@ def cleanup_old_jobs(self): for job_id in expired_jobs: if job_id in self.background_worker.job_status: del self.background_worker.job_status[job_id] +