fix(claude-code): allow dot-prefixed segments in git-subdir paths

This commit is contained in:
Devin AI 2026-07-27 13:08:44 +00:00
parent 24123269cc
commit 57aa8113f1
2 changed files with 38 additions and 4 deletions

View file

@ -126,10 +126,12 @@ async def get_marketplace():
# Allowlist for git-subdir paths: one or more segments separated by '/'.
# Each segment must start with an alphanumeric character and contain only
# alphanumeric characters, dots, hyphens, and underscores.
# This implicitly blocks '..', leading '/', backslashes, and percent-encoded sequences.
_VALID_GIT_SUBDIR_PATH_RE = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9._-]*(/[a-zA-Z0-9][a-zA-Z0-9._-]*)*$")
# Each segment contains only alphanumeric characters, dots, hyphens, and
# underscores, and may start with a dot (e.g. '.claude/skills/my-skill').
# The negative lookahead rejects the '.' and '..' segments so leading '/',
# backslashes, percent-encoded sequences, and path traversal are still blocked.
_GIT_SUBDIR_SEGMENT = r"(?!\.{1,2}(?:/|$))[a-zA-Z0-9._-]+"
_VALID_GIT_SUBDIR_PATH_RE = re.compile(rf"^{_GIT_SUBDIR_SEGMENT}(?:/{_GIT_SUBDIR_SEGMENT})*$")
def _validate_plugin_source(source: Dict[str, Any]) -> None:

View file

@ -170,6 +170,33 @@ async def test_register_plugin_git_subdir_empty_path():
assert "path" in exc_info.value.detail["error"]
@pytest.mark.asyncio
@pytest.mark.parametrize(
"path",
[
".claude/skills/my-skill",
".github/workflows",
".config",
"plugins/.hidden/my-plugin",
],
)
async def test_register_plugin_git_subdir_dot_prefixed_path(path):
"""git-subdir paths with dot-prefixed segments (e.g. .claude/) register successfully."""
request = RegisterPluginRequest(
name="dot-prefixed-plugin",
source={
"source": "git-subdir",
"url": "https://github.com/org/monorepo.git",
"path": path,
},
)
response = await register_plugin(request=request, user_api_key_dict=_USER)
assert response["status"] == "success"
assert response["plugin"]["source"]["path"] == path
@pytest.mark.asyncio
async def test_register_plugin_git_subdir_path_traversal():
"""git-subdir with path traversal segments raises HTTP 400."""
@ -181,6 +208,11 @@ async def test_register_plugin_git_subdir_path_traversal():
"plugins/%2e%2e/secrets", # percent-encoded traversal
"plugins/%2E%2E/secrets", # uppercase percent-encoded traversal
"plugins/%252e%252e/secrets", # double-encoded traversal
"..", # bare parent segment
".", # bare current-dir segment
"plugins/..", # trailing parent traversal
".claude/../secrets", # dot-prefixed segment followed by traversal
"plugins/./secrets", # embedded current-dir segment
]:
request = RegisterPluginRequest(
name="bad-plugin",