diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3d6a78a9..b7dbbdbb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: # Run the formatter. - id: ruff-format - repo: https://github.com/teemtee/tmt.git - rev: 1.39.0 + rev: 1.60.0 hooks: - id: tmt-lint - repo: https://github.com/pre-commit/mirrors-mypy diff --git a/podman/domain/images_build.py b/podman/domain/images_build.py index 8713d1b6..7d8f2983 100644 --- a/podman/domain/images_build.py +++ b/podman/domain/images_build.py @@ -68,6 +68,7 @@ def build(self, **kwargs) -> tuple[Image, Iterator[bytes]]: outputformat (str) - The format of the output image's manifest and configuration data. manifest (str) - add the image to the specified manifest list. Creates manifest list if it does not exist. + secrets (list[str]) - Secret files/envs to expose to the build Returns: first item is the podman.domain.images.Image built @@ -209,6 +210,9 @@ def _render_params(kwargs) -> dict[str, list[Any]]: if "labels" in kwargs: params["labels"] = json.dumps(kwargs.get("labels")) + if "secrets" in kwargs: + params["secrets"] = json.dumps(kwargs.get("secrets")) + if params["dockerfile"] is None: params["dockerfile"] = f".containerfile.{random.getrandbits(160):x}" diff --git a/podman/tests/integration/test_images.py b/podman/tests/integration/test_images.py index e910a651..5711e2b2 100644 --- a/podman/tests/integration/test_images.py +++ b/podman/tests/integration/test_images.py @@ -15,16 +15,17 @@ """Images integration tests.""" import io +import os import platform import tarfile +import tempfile import types import unittest import podman.tests.integration.base as base from podman import PodmanClient from podman.domain.images import Image -from podman.errors import APIError, ImageNotFound, PodmanError - +from podman.errors import APIError, ContainerError, ImageNotFound, PodmanError # @unittest.skipIf(os.geteuid() != 0, 'Skipping, not running as root') @@ -197,6 +198,41 @@ def add_file(name: str, content: str): self.assertIsNotNone(image) self.assertIsNotNone(image.id) + def test_build_with_secret(self): + with tempfile.TemporaryDirectory() as context_dir: + dockerfile_path = os.path.join(context_dir, "Dockerfile") + with open(dockerfile_path, "w") as f: + f.write(""" + FROM quay.io/libpod/alpine_labels:latest + RUN --mount=type=secret,id=example cat /run/secrets/example > /output.txt + """) + + secret_path = os.path.join(context_dir, "build-secret.txt") + with open(secret_path, "w") as f: + f.write("secret123") + + image, _ = self.client.images.build( + path=context_dir, + secrets=["id=example,src=build-secret.txt"], + dockerfile="Dockerfile", + ) + + self.assertIsNotNone(image) + self.assertIsNotNone(image.id) + + # Verify secret was passed and stored in file (NOT RECOMMENDED for real use cases) + container_out = self.client.containers.run( + image.id, command=["cat", "/output.txt"], remove=True, log_config={"Type": "json-file"} + ) + self.assertIn(b"secret123", container_out) + + # Verify mounted secret file is not present in image + with self.assertRaises(ContainerError) as exc: + self.client.containers.run( + image.id, command=["cat", "/run/secrets/example"], remove=True + ) + self.assertIn("No such file or directory", b"".join(exc.exception.stderr).decode("utf-8")) + @unittest.skipIf(platform.architecture()[0] == "32bit", "no 32-bit image available") def test_pull_stream(self): generator = self.client.images.pull("ubi8", tag="latest", stream=True) diff --git a/podman/tests/unit/test_build.py b/podman/tests/unit/test_build.py index 5015e269..e83238ce 100644 --- a/podman/tests/unit/test_build.py +++ b/podman/tests/unit/test_build.py @@ -67,7 +67,8 @@ def test_build(self, mock_prepare_containerfile, mock_create_tar): "&cpuperiod=10" "&extrahosts=%7B%22database%22%3A+%22127.0.0.1%22%7D" "&labels=%7B%22Unittest%22%3A+%22true%22%7D" - "&manifest=example%3Av1.2.3", + "&manifest=example%3Av1.2.3" + "&secrets=%5B%22id%3Dexample%2Csrc%3Dpodman-build-secret123%22%5D", text=buffer.getvalue(), ) mock.get( @@ -100,6 +101,7 @@ def test_build(self, mock_prepare_containerfile, mock_create_tar): extra_hosts={"database": "127.0.0.1"}, labels={"Unittest": "true"}, manifest="example:v1.2.3", + secrets=["id=example,src=podman-build-secret123"], ) self.assertIsInstance(image, Image) self.assertEqual(image.id, "032b8b2855fc")