From e771304eaf1626ad9d8db9ee6b3dd5b8ca4d5ef8 Mon Sep 17 00:00:00 2001 From: Bruno Pimentel Date: Fri, 12 Jul 2024 14:34:22 -0300 Subject: [PATCH] Explicitly forbid workspace vendoring The ability to vendor dependencies in projects that make use of workspaces was introduced in Go 1.22. Cachito currently does not support the use of "go work vendor", so this commit introduces an explicit check for that scenario and a clearer error message. Note that by design, Go does not allow the use of "go mod vendor" if workspaces are present, so the check assumes that the existence of a vendor folder in a project with workspaces means that workspace vendoring is being used. For more info, see: - https://go.dev/doc/go1.22#tools - https://github.com/golang/go/issues/60056 Signed-off-by: Bruno Pimentel --- cachito/workers/pkg_managers/gomod.py | 13 +++++++ .../test_pkg_managers/test_gomod.py | 39 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/cachito/workers/pkg_managers/gomod.py b/cachito/workers/pkg_managers/gomod.py index 8a2d0b633..5c0c62c9c 100644 --- a/cachito/workers/pkg_managers/gomod.py +++ b/cachito/workers/pkg_managers/gomod.py @@ -382,6 +382,7 @@ def resolve_gomod( flags, app_source_path, worker_config.cachito_gomod_strict_vendor ) if should_vendor: + _vet_workspace_vendoring(go, run_params) downloaded_modules = _vendor_deps(go, run_params, can_make_changes, git_dir_path) else: log.info("Downloading the gomod dependencies") @@ -506,6 +507,18 @@ def go_list_deps(pattern: Literal["./...", "all"]) -> Iterator[GoPackage]: } +def _vet_workspace_vendoring(go: Go, run_params: dict[str, Any]) -> None: + go_work_file = go(["env", "GOWORK"], run_params).rstrip() + + if not go_work_file or go_work_file == "off": + return + + vendor_dir = Path(go_work_file).parent / "vendor" + + if vendor_dir.is_dir(): + raise UnsupportedFeature("Workspace vendoring introduced in Go 1.22 is not supported") + + def _set_local_modules_versions( local_modules: LocalModules, git_dir_path: Path, diff --git a/tests/test_workers/test_pkg_managers/test_gomod.py b/tests/test_workers/test_pkg_managers/test_gomod.py index a6c43fbb1..7768166a0 100644 --- a/tests/test_workers/test_pkg_managers/test_gomod.py +++ b/tests/test_workers/test_pkg_managers/test_gomod.py @@ -211,7 +211,9 @@ def test_resolve_gomod( @mock.patch("cachito.workers.pkg_managers.gomod.GoCacheTemporaryDirectory") @mock.patch("subprocess.run") @mock.patch("cachito.workers.pkg_managers.gomod.RequestBundleDir") +@mock.patch("cachito.workers.pkg_managers.gomod._vet_workspace_vendoring") def test_resolve_gomod_vendor_dependencies( + mock_vet_workspace_vendoring: mock.Mock, mock_bundle_dir: mock.Mock, mock_run: mock.Mock, mock_temp_dir: mock.Mock, @@ -881,6 +883,43 @@ def test_vet_local_file_dep_paths_outside_repo(): gomod._vet_local_file_dep_paths(dependencies, app_dir, git_dir) +@pytest.mark.parametrize( + "go_work_env", + [ + pytest.param("go.work", id="go_work_set"), + pytest.param("off", id="go_work_off"), + pytest.param("", id="go_work_empty"), + ], +) +def test_vet_workspace_vendoring( + go_work_env: str, + tmp_path: Path, +): + go = mock.Mock() + + # workspaces are enabled, no vendoring exists + if go_work_env == "go.work": + go.return_value = str(tmp_path / "go.work") + + # workspaces are not enabled, vendoring exists + else: + go.return_value = go_work_env + (tmp_path / "vendor").mkdir() + + gomod._vet_workspace_vendoring(go, {}) + go.assert_called_once_with(["env", "GOWORK"], {}) + + +def test_vet_workspace_vendoring_fails(tmp_path: Path): + go = mock.Mock() + go.return_value = str(tmp_path / "go.work") + (tmp_path / "vendor").mkdir() + + expect_error = "Workspace vendoring introduced in Go 1.22 is not supported" + with pytest.raises(UnsupportedFeature, match=expect_error): + gomod._vet_workspace_vendoring(go, {}) + + @pytest.mark.parametrize( "main_module_deps, pkg_deps_pre, pkg_deps_post", [