From 63fe0aae7fb6164908e6c2f404894f6ca4beef40 Mon Sep 17 00:00:00 2001 From: Kristian Hartikainen Date: Mon, 20 Jul 2026 14:14:48 +0200 Subject: [PATCH] Allow local jobs to omit `gcloud` mounts Local container jobs currently mount the host's entire `~/.config/gcloud` directory at `/root/.config/gcloud` unconditionally. This commit adds `DockerOptions.mount_gcloud_config`, defaulting to `True` for compatibility. Setting it to `False` allows credential-free containers to reject ambient host configuration. The launch path also copies user-provided `volumes` before adding implicit mounts, avoiding mutation of caller-owned state. --- xmanager/xm_local/execution.py | 11 +++--- xmanager/xm_local/execution_test.py | 60 +++++++++++++++++++++++++++++ xmanager/xm_local/executors.py | 4 ++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/xmanager/xm_local/execution.py b/xmanager/xm_local/execution.py index ee8eba3..9535178 100644 --- a/xmanager/xm_local/execution.py +++ b/xmanager/xm_local/execution.py @@ -65,11 +65,12 @@ async def _launch_loaded_container_image( env_vars = {**executable.env_vars, **job.env_vars} options = executor.docker_options or executors.DockerOptions() - volumes = options.volumes or {} - # Add GCP credentials to Local Executor. - local_gcloud_config_path = os.path.expanduser('~/.config/gcloud') - image_gcloud_config_path = '/root/.config/gcloud' - volumes[local_gcloud_config_path] = image_gcloud_config_path + volumes = dict(options.volumes or {}) + if options.mount_gcloud_config: + # Add GCP credentials to Local Executor. + local_gcloud_config_path = os.path.expanduser('~/.config/gcloud') + image_gcloud_config_path = '/root/.config/gcloud' + volumes[local_gcloud_config_path] = image_gcloud_config_path if options.mount_gcs_path and os.path.isdir(os.path.expanduser('~/gcs')): local_gcs_path = os.path.expanduser('~/gcs') diff --git a/xmanager/xm_local/execution_test.py b/xmanager/xm_local/execution_test.py index 2847c47..9fb0727 100644 --- a/xmanager/xm_local/execution_test.py +++ b/xmanager/xm_local/execution_test.py @@ -122,6 +122,66 @@ async def test_container_launch_dispatcher( interactive=interactive, ) + async def _launched_volumes( + self, docker_options: local_executors.DockerOptions + ) -> dict[str, str]: + executable = local_executables.LoadedContainerImage( + name='test', + image_id='test-image', + args=xm.SequentialArgs.from_collection({}), + env_vars={}, + ) + job = xm.Job( + name='test-job', + executable=executable, + executor=local_executors.Local(docker_options=docker_options), + ) + adapter = mock.MagicMock() + adapter.has_network.return_value = True + adapter.run_container.return_value = mock.sentinel.container + + with mock.patch.object(docker_adapter, 'instance', return_value=adapter): + await execution._launch_loaded_container_image( # pylint: disable=protected-access + lambda name: name, + job, + executable, + ) + + return adapter.run_container.call_args.kwargs['volumes'] + + async def test_can_disable_gcloud_config_mount(self): + configured_volumes = {'a': 'b'} + + launched_volumes = await self._launched_volumes( + local_executors.DockerOptions( + volumes=configured_volumes, + mount_gcs_path=False, + mount_gcloud_config=False, + ) + ) + + self.assertEqual(launched_volumes, {'a': 'b'}) + self.assertEqual(configured_volumes, {'a': 'b'}) + + async def test_gcloud_config_mount_remains_enabled_by_default(self): + configured_volumes = {'a': 'b'} + + launched_volumes = await self._launched_volumes( + local_executors.DockerOptions( + volumes=configured_volumes, + mount_gcs_path=False, + ) + ) + + self.assertEqual( + launched_volumes, + { + 'a': 'b', + os.path.expanduser('~/.config/gcloud'): '/root/.config/gcloud', + }, + ) + self.assertEqual(configured_volumes, {'a': 'b'}) + @parameterized.product( mount_gcs_path=[True, False], gcs_dir_exists=[True, False], diff --git a/xmanager/xm_local/executors.py b/xmanager/xm_local/executors.py index 97441da..7b66ca5 100644 --- a/xmanager/xm_local/executors.py +++ b/xmanager/xm_local/executors.py @@ -48,12 +48,16 @@ class DockerOptions: mount_gcs_path: If True, checks for the `~/gcs` directory on the host and mounts it (if found) at `/gcs` in the container. Defaults to True. interactive: If True, requests a run with interactive shell. + mount_gcloud_config: If True, mounts the host's `~/.config/gcloud` + directory at `/root/.config/gcloud` in the container. Defaults to True + for compatibility. """ ports: Optional[docker_adapter.Ports] = None volumes: Optional[Dict[str, str]] = None mount_gcs_path: bool = True interactive: bool = False + mount_gcloud_config: bool = True @attr.s(auto_attribs=True)