Skip to content
This repository was archived by the owner on Aug 12, 2025. It is now read-only.

Commit fea68f0

Browse files
taylormadorebrunoapimentel
authored andcommitted
refactor gomod vetting of local file dependencies
Since we no longer care if file deps are allowed, condense the path checking into a single function that verifies that paths are not either absolute or lead outside the repository Signed-off-by: Taylor Madore <tmadore@redhat.com>
1 parent 3457213 commit fea68f0

File tree

2 files changed

+34
-75
lines changed

2 files changed

+34
-75
lines changed

cachito/workers/pkg_managers/gomod.py

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -459,10 +459,10 @@ def go_list_deps(pattern: Literal["./...", "all"]) -> Iterator[GoPackage]:
459459
}
460460
main_packages.append({"pkg": main_pkg, "pkg_deps": pkg_deps})
461461

462-
_vet_local_deps(main_module_deps, main_module_name, app_source_path, git_dir_path)
462+
_vet_local_file_dep_paths(main_module_deps, app_source_path, git_dir_path)
463463
for package in main_packages:
464464
# Local dependencies are always relative to the main module, even for subpackages
465-
_vet_local_deps(package["pkg_deps"], main_module_name, app_source_path, git_dir_path)
465+
_vet_local_file_dep_paths(package["pkg_deps"], app_source_path, git_dir_path)
466466
_set_full_local_dep_relpaths(package["pkg_deps"], main_module_deps)
467467

468468
return {
@@ -641,53 +641,31 @@ def _vendor_changed(git_dir: Path, app_dir: str) -> bool:
641641
return False
642642

643643

644-
def _vet_local_deps(
644+
def _vet_local_file_dep_paths(
645645
dependencies: List[dict],
646-
module_name: str,
647646
app_source_path: Path,
648647
git_dir_path: Path,
649648
) -> None:
650-
"""Fail if any local file dependency path is either absolute or outside the repository."""
649+
"""Fail if any local file dependency path is either outside the repository or absolute."""
651650
for dep in dependencies:
652-
name = dep["name"]
653651
version = dep["version"]
654652

655-
if not version:
656-
continue # go stdlib
653+
if not version: # go stdlib
654+
continue
657655

658656
if version.startswith("."):
659-
log.debug(
660-
"Module %s wants to replace %s with a local dependency: %s",
661-
module_name,
662-
name,
663-
version,
664-
)
665-
_validate_local_dependency_path(app_source_path, git_dir_path, version)
657+
resolved_dep_path = Path(app_source_path, version).resolve()
658+
if not resolved_dep_path.is_relative_to(git_dir_path.resolve()):
659+
raise ValidationError(
660+
f"The local file dependency path {version} is outside the repository"
661+
)
666662
elif version.startswith("/") or PureWindowsPath(version).root:
667663
# This will disallow paths starting with '/', '\' or '<drive letter>:\'
668664
raise UnsupportedFeature(
669665
f"Absolute paths to gomod dependencies are not supported: {version}"
670666
)
671667

672668

673-
def _validate_local_dependency_path(
674-
app_source_path: Path, git_dir_path: Path, dep_path: str
675-
) -> None:
676-
"""
677-
Validate that the local dependency path is not outside the repository.
678-
679-
:param Path app_source_path: the full path to the application source code
680-
:param Path git_dir_path: the full path to the git repository
681-
:param str dep_path: the relative path for local replacements (the dep version)
682-
:raise ValidationError: if the local dependency path is invalid
683-
"""
684-
try:
685-
resolved_dep_path = Path(app_source_path, dep_path).resolve()
686-
resolved_dep_path.relative_to(git_dir_path.resolve())
687-
except ValueError:
688-
raise ValidationError(f"The local dependency path {dep_path} is outside the repository")
689-
690-
691669
def _set_full_local_dep_relpaths(pkg_deps: List[dict], main_module_deps: List[dict]):
692670
"""
693671
Set full relative paths for all local go-package dependencies.

tests/test_workers/test_pkg_managers/test_gomod.py

Lines changed: 23 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,13 @@ def go_mod_file(tmp_path: Path, request: pytest.FixtureRequest) -> Path:
7373
@mock.patch("cachito.workers.pkg_managers.gomod.get_golang_version")
7474
@mock.patch("cachito.workers.pkg_managers.gomod.GoCacheTemporaryDirectory")
7575
@mock.patch("cachito.workers.pkg_managers.gomod._merge_bundle_dirs")
76-
@mock.patch("cachito.workers.pkg_managers.gomod._vet_local_deps")
76+
@mock.patch("cachito.workers.pkg_managers.gomod._vet_local_file_dep_paths")
7777
@mock.patch("cachito.workers.pkg_managers.gomod._set_full_local_dep_relpaths")
7878
@mock.patch("subprocess.run")
7979
def test_resolve_gomod(
8080
mock_run: mock.Mock,
8181
mock_set_full_relpaths: mock.Mock,
82-
mock_vet_local_deps: mock.Mock,
82+
mock_vet_local_file_dep_paths: mock.Mock,
8383
mock_merge_tree: mock.Mock,
8484
mock_temp_dir: mock.Mock,
8585
mock_golang_version: mock.Mock,
@@ -182,16 +182,14 @@ def test_resolve_gomod(
182182
str(RequestBundleDir(request["id"]).gomod_download_dir),
183183
)
184184

185-
expect_module_name = expect_gomod["module"]["name"]
186185
expect_module_deps = expect_gomod["module_deps"]
187186
expect_pkg_deps = expect_gomod["packages"][0]["pkg_deps"]
188187

189-
mock_vet_local_deps.assert_has_calls(
188+
mock_vet_local_file_dep_paths.assert_has_calls(
190189
[
191-
mock.call(expect_module_deps, expect_module_name, module_dir, module_dir),
190+
mock.call(expect_module_deps, module_dir, module_dir),
192191
mock.call(
193192
expect_pkg_deps,
194-
expect_module_name,
195193
module_dir,
196194
module_dir,
197195
),
@@ -687,26 +685,17 @@ def test_merge_files(file_1_content, file_2_content, result_file_content):
687685
assert_directories_equal(dir_2, dir_3)
688686

689687

690-
@mock.patch("cachito.workers.pkg_managers.gomod._validate_local_dependency_path")
691-
def test_vet_local_deps(mock_validate_dep_path):
688+
def test_vet_local_file_dep_paths():
692689
dependencies = [
693-
{"name": "foo", "version": "./local/foo"},
694-
{"name": "bar", "version": "v1.0.0"},
695-
{"name": "baz", "version": "./local/baz"},
690+
{"name": "stdlib-dep", "version": None},
691+
{"name": "versioned-dep", "version": "v1.0.0"},
692+
{"name": "local-file-dep", "version": "./local/foo"},
693+
{"name": "local-file-dep-parent-dir", "version": "../local/bar"},
696694
]
697-
module_name = "some-module"
698695
app_dir = Path("/repo/some-module")
699696
git_dir = Path("/repo")
700-
mock_validate_dep_path.return_value = None
701697

702-
gomod._vet_local_deps(dependencies, module_name, app_dir, git_dir)
703-
704-
mock_validate_dep_path.assert_has_calls(
705-
[
706-
mock.call(app_dir, git_dir, "./local/foo"),
707-
mock.call(app_dir, git_dir, "./local/baz"),
708-
],
709-
)
698+
gomod._vet_local_file_dep_paths(dependencies, app_dir, git_dir)
710699

711700

712701
@pytest.mark.parametrize(
@@ -717,37 +706,29 @@ def test_vet_local_deps(mock_validate_dep_path):
717706
"C:\\Users\\user\\go\\src\\k8s.io\\kubectl",
718707
],
719708
)
720-
def test_vet_local_deps_abspath(platform_specific_path):
709+
def test_vet_local_file_dep_paths_abspath(platform_specific_path):
721710
dependencies = [{"name": "foo", "version": platform_specific_path}]
722711
app_dir = Path("/some/path")
723712

724713
expect_error = re.escape(
725714
f"Absolute paths to gomod dependencies are not supported: {platform_specific_path}"
726715
)
727716
with pytest.raises(UnsupportedFeature, match=expect_error):
728-
gomod._vet_local_deps(dependencies, "some-module", app_dir, app_dir)
717+
gomod._vet_local_file_dep_paths(dependencies, app_dir, app_dir)
729718

730719

731-
@pytest.mark.parametrize(
732-
"app_dir, git_dir, dep_path, expect_error",
733-
[
734-
("foo", "foo", "./..", True),
735-
("foo/bar", "foo", "./..", False),
736-
("foo/bar", "foo", "./../..", True),
737-
],
738-
)
739-
def test_validate_local_dependency_path(
740-
tmp_path: Path, app_dir: str, git_dir: str, dep_path: str, expect_error: bool
741-
):
742-
tmp_git_dir = tmp_path / git_dir
743-
tmp_app_dir = tmp_path / app_dir
744-
tmp_app_dir.mkdir(parents=True, exist_ok=True)
720+
def test_vet_local_file_dep_paths_outside_repo():
721+
dependencies = [
722+
{"name": "local-file-dep", "version": "../../local/foo"},
723+
]
724+
app_dir = Path("/repo/some-module")
725+
git_dir = Path("/repo")
745726

746-
if expect_error:
747-
with pytest.raises(ValidationError):
748-
gomod._validate_local_dependency_path(tmp_app_dir, tmp_git_dir, dep_path)
749-
else:
750-
gomod._validate_local_dependency_path(tmp_app_dir, tmp_git_dir, dep_path)
727+
expect_error = re.escape(
728+
f"The local file dependency path {dependencies[0]['version']} is outside the repository"
729+
)
730+
with pytest.raises(ValidationError, match=expect_error):
731+
gomod._vet_local_file_dep_paths(dependencies, app_dir, git_dir)
751732

752733

753734
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)