Skip to content

Commit cea7932

Browse files
committed
Fix has_manifest_files failing to match root-level manifest files
PurePath.match("**/package.json") returns False for root-level files in Python 3.12+ because ** requires at least one directory component. The function was unconditionally prepending **/ to all patterns, causing root-level manifests like package.json and package-lock.json to never match. This forced every scan into full scan mode instead of diff scan mode, which meant MR/PR comments were never posted. Fix by trying the direct pattern match first, then falling back to the **/ prefixed pattern for subdirectory matching. Fixes Zendesk #2447
1 parent b8b49f5 commit cea7932

File tree

2 files changed

+76
-6
lines changed

2 files changed

+76
-6
lines changed

socketsecurity/core/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -414,15 +414,15 @@ def has_manifest_files(self, files: list) -> bool:
414414
# Expand brace patterns for each manifest pattern
415415
expanded_patterns = Core.expand_brace_pattern(pattern_str)
416416
for exp_pat in expanded_patterns:
417-
# If pattern doesn't contain '/', prepend '**/' to match files in any subdirectory
418-
# This ensures patterns like '*requirements.txt' match '.test/requirements.txt'
419-
if '/' not in exp_pat:
420-
exp_pat = f"**/{exp_pat}"
421-
422417
for file in norm_files:
423-
# Use PurePath.match for glob-like matching
418+
# Match the pattern as-is first (handles root-level files
419+
# like "package.json" matching pattern "package.json")
424420
if PurePath(file).match(exp_pat):
425421
return True
422+
# Also try with **/ prefix to match files in subdirectories
423+
# (e.g. "src/requirements.txt" matching "*requirements.txt")
424+
if '/' not in exp_pat and PurePath(file).match(f"**/{exp_pat}"):
425+
return True
426426
return False
427427

428428
def check_file_count_limit(self, file_count: int) -> dict:
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from pathlib import PurePath
2+
from unittest.mock import patch
3+
4+
from socketsecurity.core import Core
5+
6+
7+
# Minimal patterns matching what the Socket API returns
8+
MOCK_PATTERNS = {
9+
"npm": {
10+
"packagejson": {"pattern": "package.json"},
11+
"packagelockjson": {"pattern": "package-lock.json"},
12+
"yarnlock": {"pattern": "yarn.lock"},
13+
},
14+
"pypi": {
15+
"requirements": {"pattern": "*requirements.txt"},
16+
"requirementsin": {"pattern": "*requirements*.txt"},
17+
"setuppy": {"pattern": "setup.py"},
18+
},
19+
"maven": {
20+
"pomxml": {"pattern": "pom.xml"},
21+
},
22+
}
23+
24+
25+
@patch.object(Core, "get_supported_patterns", return_value=MOCK_PATTERNS)
26+
@patch.object(Core, "__init__", lambda self, *a, **kw: None)
27+
class TestHasManifestFiles:
28+
def test_root_level_package_json(self, mock_patterns):
29+
core = Core.__new__(Core)
30+
assert core.has_manifest_files(["package.json"]) is True
31+
32+
def test_root_level_package_lock_json(self, mock_patterns):
33+
core = Core.__new__(Core)
34+
assert core.has_manifest_files(["package-lock.json"]) is True
35+
36+
def test_subdirectory_package_json(self, mock_patterns):
37+
core = Core.__new__(Core)
38+
assert core.has_manifest_files(["libs/ui/package.json"]) is True
39+
40+
def test_root_level_requirements_txt(self, mock_patterns):
41+
core = Core.__new__(Core)
42+
assert core.has_manifest_files(["requirements.txt"]) is True
43+
44+
def test_subdirectory_requirements_txt(self, mock_patterns):
45+
core = Core.__new__(Core)
46+
assert core.has_manifest_files(["src/requirements.txt"]) is True
47+
48+
def test_prefixed_requirements_txt(self, mock_patterns):
49+
core = Core.__new__(Core)
50+
assert core.has_manifest_files(["dev-requirements.txt"]) is True
51+
52+
def test_no_manifest_files(self, mock_patterns):
53+
core = Core.__new__(Core)
54+
assert core.has_manifest_files(["README.md", "src/app.py"]) is False
55+
56+
def test_mixed_files_with_manifest(self, mock_patterns):
57+
core = Core.__new__(Core)
58+
assert core.has_manifest_files([".gitlab-ci.yml", "package.json", "src/app.tsx"]) is True
59+
60+
def test_empty_list(self, mock_patterns):
61+
core = Core.__new__(Core)
62+
assert core.has_manifest_files([]) is False
63+
64+
def test_dot_slash_prefix_normalized(self, mock_patterns):
65+
core = Core.__new__(Core)
66+
assert core.has_manifest_files(["./package.json"]) is True
67+
68+
def test_pom_xml_root(self, mock_patterns):
69+
core = Core.__new__(Core)
70+
assert core.has_manifest_files(["pom.xml"]) is True

0 commit comments

Comments
 (0)