From b3ae9bc11541f8e86bb76df07a3d30e53806d3d2 Mon Sep 17 00:00:00 2001 From: shanevcantwell Date: Fri, 25 Sep 2026 02:01:01 +0000 Subject: [PATCH] Fix fresh-init SQL permission failure --- ops/Dockerfile.db | 1 + tests/cli/test_deterministic_images.py | 49 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/ops/Dockerfile.db b/ops/Dockerfile.db index bcb0fde06..ae47a77a0 100644 --- a/ops/Dockerfile.db +++ b/ops/Dockerfile.db @@ -51,3 +51,4 @@ RUN rm -rf /tmp/* && \ # Run schema/init on first database startup. COPY db/*.sql /docker-entrypoint-initdb.d/ +RUN chmod 0644 /docker-entrypoint-initdb.d/*.sql diff --git a/tests/cli/test_deterministic_images.py b/tests/cli/test_deterministic_images.py index 8120753a2..5de6dd231 100644 --- a/tests/cli/test_deterministic_images.py +++ b/tests/cli/test_deterministic_images.py @@ -1,5 +1,6 @@ from __future__ import annotations +import re from pathlib import Path @@ -22,6 +23,54 @@ def test_python_runtime_images_install_only_from_committed_uv_lock(): assert "sha256sum" in dockerfile +def test_database_image_makes_init_scripts_world_readable_and_non_executable(): + instructions = [ + line.strip() + for line in (ROOT / "ops/Dockerfile.db").read_text().splitlines() + if line.strip() and not line.lstrip().startswith("#") + ] + + copy_index = next( + ( + index + for index, instruction in enumerate(instructions) + if re.fullmatch( + r"COPY\s+db/\*\.sql\s+/docker-entrypoint-initdb\.d/?", + instruction, + re.IGNORECASE, + ) + ), + None, + ) + assert copy_index is not None + + chmod_pattern = re.compile( + r"RUN\s+chmod\s+(?P0?[0-7]{3})\s+" + r"/docker-entrypoint-initdb\.d/\*\.sql", + re.IGNORECASE, + ) + chmod_instruction = next( + ( + (index, match) + for index, instruction in enumerate(instructions) + if (match := chmod_pattern.fullmatch(instruction)) + ), + None, + ) + + assert chmod_instruction is not None + chmod_index, chmod_match = chmod_instruction + assert copy_index < chmod_index + assert not any( + "/docker-entrypoint-initdb.d" in instruction + for instruction in instructions[chmod_index + 1 :] + ) + + mode = int(chmod_match.group("mode"), 8) + assert mode & 0o444 == 0o444 + assert mode & 0o111 == 0 + + def test_uv_lock_covers_runtime_and_channel_only_dependencies(): lock = (ROOT / "uv.lock").read_text()