diff --git a/pre_commit/languages/docker.py b/pre_commit/languages/docker.py index 086e874d..39bf2e75 100644 --- a/pre_commit/languages/docker.py +++ b/pre_commit/languages/docker.py @@ -4,6 +4,8 @@ import functools import hashlib import json import os +import re +import socket from collections.abc import Sequence from pre_commit import lang_base @@ -21,9 +23,11 @@ in_env = lang_base.no_env # no special environment for docker def _is_in_docker() -> bool: try: with open('/proc/1/cgroup', 'rb') as f: - return b'docker' in f.read() + if b'docker' in f.read(): + return True except FileNotFoundError: - return False + pass + return os.path.exists('/.dockerenv') def _get_container_id() -> str: @@ -34,6 +38,9 @@ def _get_container_id() -> str: for line in f.readlines(): if line.split(b':')[1] == b'cpuset': return os.path.basename(line.split(b':')[2]).strip().decode() + hostname = socket.gethostname() + if re.match(r'^[0-9a-f]{12}$', hostname): + return hostname raise RuntimeError('Failed to find the container ID in /proc/1/cgroup.') diff --git a/tests/languages/docker_test.py b/tests/languages/docker_test.py index 03235c46..ce535302 100644 --- a/tests/languages/docker_test.py +++ b/tests/languages/docker_test.py @@ -30,8 +30,13 @@ DOCKER_CGROUP_EXAMPLE = b'''\ 0::/system.slice/containerd.service ''' # noqa: E501 +DOCKER_CGROUPV2_EXAMPLE = b"""\ +0::/ +""" + # The ID should match the above cgroup example. CONTAINER_ID = 'c33988ec7651ebc867cb24755eaf637a6734088bc7eef59d5799293a9e5450f7' # noqa: E501 +SHORT_CONTAINER_ID = CONTAINER_ID[:12] NON_DOCKER_CGROUP_EXAMPLE = b'''\ 12:perf_event:/ @@ -117,8 +122,17 @@ def test_in_docker_docker_in_file(): assert docker._is_in_docker() is True +def _mock_dockerenv(exists): + return mock.patch('os.path.exists', return_value=exists) + + +def test_in_docker_cgroupv2(): + with _mock_open(DOCKER_CGROUPV2_EXAMPLE), _mock_dockerenv(True): + assert docker._is_in_docker() is True + + def test_in_docker_docker_not_in_file(): - with _mock_open(NON_DOCKER_CGROUP_EXAMPLE): + with _mock_open(NON_DOCKER_CGROUP_EXAMPLE), _mock_dockerenv(False): assert docker._is_in_docker() is False @@ -127,8 +141,16 @@ def test_get_container_id(): assert docker._get_container_id() == CONTAINER_ID +def test_get_container_id_cgroupv2(): + with _mock_open(DOCKER_CGROUPV2_EXAMPLE), \ + mock.patch('socket.gethostname', return_value=SHORT_CONTAINER_ID): + assert docker._get_container_id() == SHORT_CONTAINER_ID + + def test_get_container_id_failure(): - with _mock_open(b''), pytest.raises(RuntimeError): + with _mock_open(b''), \ + mock.patch('socket.gethostname', return_value='foo'), \ + pytest.raises(RuntimeError): docker._get_container_id()