diff --git a/docs/Extensions.md b/docs/Extensions.md index 70ba6c58..a5eb82b7 100644 --- a/docs/Extensions.md +++ b/docs/Extensions.md @@ -282,3 +282,21 @@ to `["--infra=false", "--share="]`. This setting can also be changed by setting `PODMAN_COMPOSE_POD_ARGS` environment variable. + +## TLS verification for registry operations + +By default, podman-compose requires TLS verification when contacting a registry +for `pull`, `push`, and `build` operations. Use the `--tls-verify` flag to +override this: + +``` +podman-compose --tls-verify=false up +``` + +Valid values are `true` (default) and `false`. Setting it to `false` passes +`--tls-verify=false` to every `podman pull`, `podman push`, and `podman build` +invocation, which is useful when using self-signed certificates or registries +behind a corporate VPN. + +Refer to the [podman-pull documentation](https://docs.podman.io/en/latest/markdown/podman-pull.1.html) +for details on TLS verification in Podman. diff --git a/newsfragments/tls_verify_registry.feature b/newsfragments/tls_verify_registry.feature new file mode 100644 index 00000000..f60720a4 --- /dev/null +++ b/newsfragments/tls_verify_registry.feature @@ -0,0 +1 @@ +Add global --tls-verify flag to disable TLS verification for registry operations (pull, push, build). diff --git a/podman_compose.py b/podman_compose.py index fd64e9ab..22685fcc 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -2112,6 +2112,12 @@ def get_podman_args(self, cmd: str) -> list[str]: cmd_args = self.global_args.__dict__.get(f"podman_{cmd_norm}_args", []) for args in cmd_args: xargs.extend(shlex.split(args)) + if getattr(self.global_args, "tls_verify", "true") == "false" and cmd in ( + "pull", + "push", + "build", + ): + xargs.append("--tls-verify=false") return xargs async def run(self, argv: list[str] | None = None) -> None: @@ -2735,6 +2741,17 @@ def _init_global_parser(parser: argparse.ArgumentParser) -> None: action="append", default=[], ) + parser.add_argument( + "--tls-verify", + help=( + "tls verification for registry commands (pull/push/build):\n" + " 'true' - verify TLS (default)\n" + " 'false' - skip verification (e.g. self-signed registries)" + ), + metavar="tls_verify", + choices=("true", "false"), + default="true", + ) parser.add_argument( "--no-ansi", help="Do not print ANSI control characters", diff --git a/tests/unit/test_get_podman_args_tls_verify.py b/tests/unit/test_get_podman_args_tls_verify.py new file mode 100644 index 00000000..ada6fb7f --- /dev/null +++ b/tests/unit/test_get_podman_args_tls_verify.py @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: GPL-2.0 + +import argparse +import unittest + +from parameterized import parameterized + +from podman_compose import PodmanCompose + + +def compose_with_tls_verify(tls_verify: str) -> PodmanCompose: + compose = PodmanCompose() + compose.global_args = argparse.Namespace( + podman_args=[], + tls_verify=tls_verify, + podman_pull_args=[], + podman_push_args=[], + podman_build_args=[], + podman_run_args=[], + podman_inspect_args=[], + podman_start_args=[], + podman_stop_args=[], + podman_rm_args=[], + podman_volume_args=[], + ) + return compose + + +class TestGetPodmanArgsTlsVerify(unittest.TestCase): + @parameterized.expand([ + ("pull",), + ("push",), + ("build",), + ]) + def test_tls_verify_true_registry_commands_no_tls_flag(self, cmd: str) -> None: + compose = compose_with_tls_verify("true") + xargs = compose.get_podman_args(cmd) + self.assertNotIn("--tls-verify=false", xargs) + + @parameterized.expand([ + ("pull",), + ("push",), + ("build",), + ]) + def test_tls_verify_false_registry_commands_injects_flag(self, cmd: str) -> None: + compose = compose_with_tls_verify("false") + xargs = compose.get_podman_args(cmd) + self.assertIn("--tls-verify=false", xargs) + self.assertEqual(len([a for a in xargs if a.startswith("--tls-verify")]), 1) + + @parameterized.expand([ + ("run",), + ("start",), + ("stop",), + ("rm",), + ("inspect",), + ("volume",), + ]) + def test_tls_verify_false_non_registry_commands_no_tls_flag(self, cmd: str) -> None: + compose = compose_with_tls_verify("false") + xargs = compose.get_podman_args(cmd) + self.assertNotIn("--tls-verify=false", xargs) + + def test_tls_verify_false_with_podman_pull_args(self) -> None: + compose = compose_with_tls_verify("false") + compose.global_args.podman_pull_args = ["--quiet"] + xargs = compose.get_podman_args("pull") + self.assertIn("--tls-verify=false", xargs) + self.assertIn("--quiet", xargs)