Merge branch 'main' into new-everything-server

This commit is contained in:
Cliff Hall
2025-12-18 11:46:12 -05:00
committed by GitHub
4 changed files with 19 additions and 12 deletions

View File

@@ -69,6 +69,8 @@ jobs:
if: ${{ needs.create-metadata.outputs.npm_packages != '[]' || needs.create-metadata.outputs.pypi_packages != '[]' }}
runs-on: ubuntu-latest
environment: release
permissions:
contents: write
outputs:
changes_made: ${{ steps.commit.outputs.changes_made }}
steps:
@@ -130,7 +132,7 @@ jobs:
- name: Install dependencies
working-directory: src/${{ matrix.package }}
run: uv sync --locked --all-extras --dev
run: uv sync --frozen --all-extras --dev
- name: Run pyright
working-directory: src/${{ matrix.package }}

View File

@@ -97,6 +97,9 @@ class PyPiPackage:
with open(self.path / "pyproject.toml", "w") as f:
f.write(tomlkit.dumps(data))
# Regenerate uv.lock to match the updated pyproject.toml
subprocess.run(["uv", "lock"], cwd=self.path, check=True)
def has_changes(path: Path, git_hash: GitHash) -> bool:
"""Check if any files changed between current state and git hash"""

View File

@@ -13,6 +13,7 @@ from mcp.types import (
)
from enum import Enum
import git
from git.exc import BadName
from pydantic import BaseModel, Field
# Default number of context lines to show in diff output
@@ -119,7 +120,7 @@ def git_diff(repo: git.Repo, target: str, context_lines: int = DEFAULT_CONTEXT_L
# Defense in depth: reject targets starting with '-' to prevent flag injection,
# even if a malicious ref with that name exists (e.g. via filesystem manipulation)
if target.startswith("-"):
raise git.exc.BadName(f"Invalid target: '{target}' - cannot start with '-'")
raise BadName(f"Invalid target: '{target}' - cannot start with '-'")
repo.rev_parse(target) # Validates target is a real git ref, throws BadName if not
return repo.git.diff(f"--unified={context_lines}", target)
@@ -187,7 +188,7 @@ def git_checkout(repo: git.Repo, branch_name: str) -> str:
# Defense in depth: reject branch names starting with '-' to prevent flag injection,
# even if a malicious ref with that name exists (e.g. via filesystem manipulation)
if branch_name.startswith("-"):
raise git.exc.BadName(f"Invalid branch name: '{branch_name}' - cannot start with '-'")
raise BadName(f"Invalid branch name: '{branch_name}' - cannot start with '-'")
repo.rev_parse(branch_name) # Validates branch_name is a real git ref, throws BadName if not
repo.git.checkout(branch_name)
return f"Switched to branch '{branch_name}'"

View File

@@ -1,6 +1,7 @@
import pytest
from pathlib import Path
import git
from git.exc import BadName
from mcp_server_git.server import (
git_checkout,
git_branch,
@@ -40,7 +41,7 @@ def test_git_checkout_existing_branch(test_repository):
def test_git_checkout_nonexistent_branch(test_repository):
with pytest.raises(git.exc.BadName):
with pytest.raises(BadName):
git_checkout(test_repository, "nonexistent-branch")
def test_git_branch_local(test_repository):
@@ -316,25 +317,25 @@ def test_validate_repo_path_symlink_escape(tmp_path: Path):
def test_git_diff_rejects_flag_injection(test_repository):
"""git_diff should reject flags that could be used for argument injection."""
with pytest.raises(git.exc.BadName):
with pytest.raises(BadName):
git_diff(test_repository, "--output=/tmp/evil")
with pytest.raises(git.exc.BadName):
with pytest.raises(BadName):
git_diff(test_repository, "--help")
with pytest.raises(git.exc.BadName):
with pytest.raises(BadName):
git_diff(test_repository, "-p")
def test_git_checkout_rejects_flag_injection(test_repository):
"""git_checkout should reject flags that could be used for argument injection."""
with pytest.raises(git.exc.BadName):
with pytest.raises(BadName):
git_checkout(test_repository, "--help")
with pytest.raises(git.exc.BadName):
with pytest.raises(BadName):
git_checkout(test_repository, "--orphan=evil")
with pytest.raises(git.exc.BadName):
with pytest.raises(BadName):
git_checkout(test_repository, "-f")
@@ -398,7 +399,7 @@ def test_git_diff_rejects_malicious_refs(test_repository):
malicious_ref_path.write_text(sha)
# Even though the ref exists, it should be rejected
with pytest.raises(git.exc.BadName):
with pytest.raises(BadName):
git_diff(test_repository, "--output=evil.txt")
# Verify no file was created (the attack was blocked)
@@ -417,7 +418,7 @@ def test_git_checkout_rejects_malicious_refs(test_repository):
malicious_ref_path.write_text(sha)
# Even though the ref exists, it should be rejected
with pytest.raises(git.exc.BadName):
with pytest.raises(BadName):
git_checkout(test_repository, "--orphan=evil")
# Cleanup