diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ac24c41..2914dabc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,23 @@ All notable changes to this project will be documented in this file. --- +## [0.26.9] - 2026-01-27 + +### Fixed (0.26.9) + +- **GitHub Remote Detection**: Extended URL pattern matching to support all valid GitHub URL formats + - **Added Support**: Now detects `ssh://git@github.com/owner/repo.git` and `git://github.com/owner/repo.git` formats + - **Root Cause**: Previous regex only matched `https?://` and scp-style `git@host:path` URLs, causing regression for repos using `ssh://` or `git://` schemes + - **Solution**: Extended regex pattern to include `ssh://` and `git://` schemes, with proper URL parsing for hostname validation + - **Impact**: All valid GitHub URL formats are now properly detected, ensuring GitHub adapter is selected correctly + +- **Code Scanning Vulnerabilities**: Mitigated all 13 code scanning findings + - **ReDoS Fix**: Replaced regex-based section removal with line-by-line processing in `github_mapper.py` + - **URL Sanitization**: Replaced substring matching with proper URL parsing using `urllib.parse.urlparse()` in multiple files + - **Workflow Permissions**: Added explicit `permissions: contents: read` blocks to 7 GitHub Actions jobs + - **SSH Host Aliases**: Added support for `ssh.github.com` SSH host alias detection + - **Test Fixes**: Fixed async cleanup issues in test mode for progress display utilities + ## [0.26.8] - 2026-01-27 ### Fixed (0.26.8) diff --git a/pyproject.toml b/pyproject.toml index 2dcf0768..ebed91a7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "specfact-cli" -version = "0.26.8" +version = "0.26.9" description = "Brownfield-first CLI: Reverse engineer legacy Python → specs → enforced contracts. Automate legacy code documentation and prevent modernization regressions." readme = "README.md" requires-python = ">=3.11" diff --git a/src/specfact_cli/adapters/github.py b/src/specfact_cli/adapters/github.py index f7eb3cb8..bae8cf18 100644 --- a/src/specfact_cli/adapters/github.py +++ b/src/specfact_cli/adapters/github.py @@ -450,21 +450,27 @@ def detect(self, repo_path: Path, bridge_config: BridgeConfig | None = None) -> config_content = git_config.read_text(encoding="utf-8") # Use proper URL parsing to avoid substring matching vulnerabilities # Look for URL patterns in git config and validate the hostname - url_pattern = re.compile(r"url\s*=\s*(https?://[^\s]+|git@[^:]+:[^\s]+)") + # Match: https?://, ssh://, git://, and scp-style git@host:path URLs + url_pattern = re.compile(r"url\s*=\s*(https?://[^\s]+|ssh://[^\s]+|git://[^\s]+|git@[^:]+:[^\s]+)") # Official GitHub SSH hostnames github_ssh_hosts = {"github.com", "ssh.github.com"} for match in url_pattern.finditer(config_content): url_str = match.group(1) - # Handle git@ format: git@github.com:user/repo.git or git@ssh.github.com:user/repo.git + # Handle scp-style git@ format: git@github.com:user/repo.git or git@ssh.github.com:user/repo.git if url_str.startswith("git@"): - host_part = url_str.split(":")[0].replace("git@", "") + host_part = url_str.split(":")[0].replace("git@", "").lower() if host_part in github_ssh_hosts: return True else: - # Parse HTTP/HTTPS URLs properly + # Parse HTTP/HTTPS/SSH/GIT URLs properly parsed = urlparse(url_str) - if parsed.hostname and parsed.hostname.lower() == "github.com": - return True + if parsed.hostname: + hostname_lower = parsed.hostname.lower() + # Check for GitHub hostnames (github.com for all schemes, ssh.github.com for SSH) + if hostname_lower == "github.com": + return True + if parsed.scheme == "ssh" and hostname_lower == "ssh.github.com": + return True except Exception: pass