Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8a4af02

Browse files
authored
Merge pull request #3446 from matthewhughes934/fix-docker-rootless-permission-mounts
Fix permission errors for mounts in rootless docker
2 parents d2b61d0 + 466f6c4 commit 8a4af02

2 files changed

Lines changed: 73 additions & 0 deletions

File tree

pre_commit/languages/docker.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import functools
34
import hashlib
45
import json
56
import os
@@ -101,7 +102,32 @@ def install_environment(
101102
os.mkdir(directory)
102103

103104

105+
@functools.lru_cache(maxsize=1)
106+
def _is_rootless() -> bool: # pragma: win32 no cover
107+
retcode, out, _ = cmd_output_b(
108+
'docker', 'system', 'info', '--format', '{{ json . }}',
109+
)
110+
if retcode != 0:
111+
return False
112+
113+
info = json.loads(out)
114+
try:
115+
return (
116+
# docker:
117+
# https://docs.docker.com/reference/api/engine/version/v1.48/#tag/System/operation/SystemInfo
118+
'name=rootless' in info.get('SecurityOptions', ()) or
119+
# podman:
120+
# https://docs.podman.io/en/latest/_static/api.html?version=v5.4#tag/system/operation/SystemInfoLibpod
121+
info['host']['security']['rootless']
122+
)
123+
except KeyError:
124+
return False
125+
126+
104127
def get_docker_user() -> tuple[str, ...]: # pragma: win32 no cover
128+
if _is_rootless():
129+
return ()
130+
105131
try:
106132
return ('-u', f'{os.getuid()}:{os.getgid()}')
107133
except AttributeError:

tests/languages/docker_test.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,42 @@ def invalid_attribute():
6262
assert docker.get_docker_user() == ()
6363

6464

65+
@pytest.fixture(autouse=True)
66+
def _avoid_cache():
67+
with mock.patch.object(
68+
docker,
69+
'_is_rootless',
70+
docker._is_rootless.__wrapped__,
71+
):
72+
yield
73+
74+
75+
@pytest.mark.parametrize(
76+
'info_ret',
77+
(
78+
(0, b'{"SecurityOptions": ["name=rootless","name=cgroupns"]}', b''),
79+
(0, b'{"host": {"security": {"rootless": true}}}', b''),
80+
),
81+
)
82+
def test_docker_user_rootless(info_ret):
83+
with mock.patch.object(docker, 'cmd_output_b', return_value=info_ret):
84+
assert docker.get_docker_user() == ()
85+
86+
87+
@pytest.mark.parametrize(
88+
'info_ret',
89+
(
90+
(0, b'{"SecurityOptions": ["name=cgroupns"]}', b''),
91+
(0, b'{"host": {"security": {"rootless": false}}}', b''),
92+
(0, b'{"respone_from_some_other_container_engine": true}', b''),
93+
(1, b'', b''),
94+
),
95+
)
96+
def test_docker_user_non_rootless(info_ret):
97+
with mock.patch.object(docker, 'cmd_output_b', return_value=info_ret):
98+
assert docker.get_docker_user() != ()
99+
100+
65101
def test_in_docker_no_file():
66102
with mock.patch.object(builtins, 'open', side_effect=FileNotFoundError):
67103
assert docker._is_in_docker() is False
@@ -195,3 +231,14 @@ def test_docker_hook(tmp_path):
195231

196232
ret = run_language(tmp_path, docker, 'echo hello hello world')
197233
assert ret == (0, b'hello hello world\n')
234+
235+
236+
@xfailif_windows # pragma: win32 no cover
237+
def test_docker_hook_mount_permissions(tmp_path):
238+
dockerfile = '''\
239+
FROM ubuntu:22.04
240+
'''
241+
tmp_path.joinpath('Dockerfile').write_text(dockerfile)
242+
243+
retcode, _ = run_language(tmp_path, docker, 'touch', ('README.md',))
244+
assert retcode == 0

0 commit comments

Comments
 (0)