Skip to content

Commit 4764bd5

Browse files
committed
RHOAIENG-21740: Perform filesystem permission check on images
This adds a simple test to scan our final images for the crucial directories for their ownership and permissions configuration.
1 parent 02e6ef3 commit 4764bd5

File tree

3 files changed

+42
-1
lines changed

3 files changed

+42
-1
lines changed

tests/containers/base_image_test.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import testcontainers.core.waiting_utils
1616

1717
from tests.containers import docker_utils
18+
from tests.containers import utils
1819

1920
import pytest
2021

@@ -219,6 +220,30 @@ def test_oc_command_runs_fake_fips(self, image: str, subtests: pytest_subtests.S
219220
finally:
220221
docker_utils.NotebookContainer(container).stop(timeout=0)
221222

223+
def test_file_permissions(self, image: str, subtests: pytest_subtests.SubTests):
224+
"""Checks the permissions and ownership for some selected files/directories."""
225+
226+
app_root_path = "/opt/app-root"
227+
expected_uid = "1001" # default
228+
expected_gid = "0" # root
229+
# Directories to assert permissions and ownerships as we did in ODS-CI
230+
directories_to_check: list[str] = [
231+
[f"{app_root_path}/lib", "775", expected_gid, expected_uid],
232+
]
233+
if not utils.is_rstudio_image(image):
234+
# RStudio image doesn't have '/opt/app-root/share' directory
235+
directories_to_check.append([f"{app_root_path}/share", "775", expected_gid, expected_uid])
236+
237+
def test_fn(container: testcontainers.core.container.DockerContainer):
238+
for item in directories_to_check:
239+
with subtests.test(f"Checking permissions of the: {item[0]}"):
240+
_, output = container.exec(["stat", "--format='%a:%g:%u'", f"{item[0]}"])
241+
logging.debug(output.decode())
242+
cleaned_output = output.decode().strip().strip("'")
243+
assert cleaned_output == f"{item[1]}:{item[2]}:{item[3]}"
244+
245+
self._run_test(image=image, test_fn=test_fn)
246+
222247
def encode_python_function_execution_command_interpreter(python: str, function: Callable[..., Any], *args: list[Any]) -> list[str]:
223248
"""Returns a cli command that will run the given Python function encoded inline.
224249
All dependencies (imports, ...) must be part of function body."""

tests/containers/conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import docker.types
1717

1818
from tests.containers import docker_utils
19+
from tests.containers import utils
1920

2021
if TYPE_CHECKING:
2122
from pytest import ExitCode, Session, Parser, Metafunc
@@ -92,7 +93,7 @@ def jupyterlab_image(image: str) -> docker.models.images.Image:
9293
@pytest.fixture(scope="function")
9394
def rstudio_image(image: str) -> docker.models.images.Image:
9495
image_metadata = skip_if_not_workbench_image(image)
95-
if "-rstudio-" not in image_metadata.labels['name']:
96+
if not utils.is_rstudio_image(image):
9697
pytest.skip(
9798
f"Image {image} does not have '-rstudio-' in {image_metadata.labels['name']=}'")
9899

tests/containers/utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import docker.errors
2+
import docker.models.images
3+
import testcontainers.core.container
4+
5+
def is_rstudio_image(my_image: str) -> bool:
6+
label = "-rstudio-"
7+
8+
client = testcontainers.core.container.DockerClient()
9+
try:
10+
image_metadata = client.client.images.get(my_image)
11+
except docker.errors.ImageNotFound:
12+
image_metadata = client.client.images.pull(my_image)
13+
assert isinstance(image_metadata, docker.models.images.Image)
14+
15+
return label in image_metadata.labels['name']

0 commit comments

Comments
 (0)