diff --git a/docs/index.rst b/docs/index.rst index dc19cad0..61b9253a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -120,3 +120,4 @@ Collection maintainers can learn to correctly declare dependencies for their col scenario_guides/scenario_copy scenario_guides/scenario_using_env scenario_guides/scenario_custom + scenario_guides/scenario_secret_passing diff --git a/docs/scenario_guides/scenario_secret_passing.rst b/docs/scenario_guides/scenario_secret_passing.rst new file mode 100644 index 00000000..522e7e79 --- /dev/null +++ b/docs/scenario_guides/scenario_secret_passing.rst @@ -0,0 +1,32 @@ +.. _secret_passing: + +Passing Secrets +=============== + +When creating an Execution Environment, it may be useful to use `build secrets `_. +This can be done with a combination of the use of :ref:`additional_build_steps` within the EE definition file, and the +:ref:`extra-build-cli-args` CLI option. + +Use the :ref:`extra-build-cli-args` CLI option to pass a build CLI argument that defines the secret: + +.. code:: + + ansible-builder build --extra-build-cli-args="--secret id=mytoken,src=my_secret_file.txt" + +Then, use a custom ``RUN`` command within your EE definition file that references this secret: + +.. code:: yaml + + --- + version: 3 + + images: + base_image: + name: quay.io/centos/centos:stream9 + + additional_build_steps: + prepend_base: + - RUN --mount=type=secret,id=mytoken TOKEN=$(cat /run/secrets/mytoken) some_command + + options: + skip_ansible_check: true diff --git a/docs/usage.rst b/docs/usage.rst index f4f9f3be..2f18087b 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -167,6 +167,21 @@ Specifies the container image validation policy to use. Valid only when :ref:`co Specifies the path to a GPG keyring file to use for validating container image signatures. +.. _extra-build-cli-args: + +``--extra-build-cli-args`` +************************** + +.. note:: Added in version 3.1 + +This option allows the user to pass any additional command line arguments to the container engine +build command (``docker build`` or ``podman build``). Take care when using this option as there is +no attempt to identify or resolve conflicting argument values from this option and arguments +normally added by ``ansible-builder``. + +.. code:: + + $ ansible-builder build --extra-build-cli-args='--pull --env=MY_ENV_VAR' ``--verbosity`` *************** diff --git a/src/ansible_builder/cli.py b/src/ansible_builder/cli.py index f4562e06..b3a6a784 100644 --- a/src/ansible_builder/cli.py +++ b/src/ansible_builder/cli.py @@ -150,6 +150,11 @@ def add_container_options(parser): help='Squash layers in the final image (choices: %(choices)s). Defaults to "%(default)s". (podman only)' ) + build_command_parser.add_argument( + '--extra-build-cli-args', + help='Extra arguments to pass to the container build CLI command', + ) + for p in [create_command_parser, build_command_parser]: p.add_argument('-f', '--file', diff --git a/src/ansible_builder/main.py b/src/ansible_builder/main.py index 920d2bae..ac3e6f7d 100644 --- a/src/ansible_builder/main.py +++ b/src/ansible_builder/main.py @@ -2,6 +2,7 @@ import logging import os +import shlex from . import constants from .containerfile import Containerfile @@ -31,6 +32,7 @@ def __init__(self, container_policy: str | None = None, container_keyring: str | None = None, squash: str | None = None, + extra_build_cli_args: str | None = None, ) -> None: """ Initialize the AnsibleBuilder object. @@ -101,6 +103,7 @@ def __init__(self, container_keyring ) self.squash = squash + self.extra_build_cli_args = extra_build_cli_args or "" def _handle_image_validation_opts(self, policy: str | None, @@ -240,6 +243,7 @@ def build_command(self) -> list[str]: if self.container_policy != PolicyChoices.IGNORE: command.append('--pull-always') + command.extend(shlex.split(self.extra_build_cli_args)) command.append(self.build_context) return command diff --git a/test/data/v3/extra_build_cli_args/execution-environment.yml b/test/data/v3/extra_build_cli_args/execution-environment.yml new file mode 100644 index 00000000..11793238 --- /dev/null +++ b/test/data/v3/extra_build_cli_args/execution-environment.yml @@ -0,0 +1,17 @@ +version: 3 + +additional_build_steps: + prepend_base: + - RUN --mount=type=secret,id=mytoken cat /run/secrets/mytoken + +images: + base_image: + name: quay.io/centos/centos:stream9 + +dependencies: + python_interpreter: + python_path: '/usr/libexec/platform-python' + +options: + package_manager_path: '/bin/true' + skip_ansible_check: true diff --git a/test/integration/test_build.py b/test/integration/test_build.py index 00a5297e..ed82b23b 100644 --- a/test/integration/test_build.py +++ b/test/integration/test_build.py @@ -266,3 +266,19 @@ def test_galaxy_signing_extra_args(cli, runtime, data_dir, ee_tag, tmp_path): assert "--ignore-signature-status-code NODATA" in result.stdout assert "--required-valid-signature-count 3" in result.stdout + + +@pytest.mark.test_all_runtimes +def test_extra_build_cli_args(cli, runtime, data_dir, ee_tag, tmp_path): + secret_string = "AAbbCCddEE" + secret_file = tmp_path / "mysecret" + secret_file.write_text(f"{secret_string}\n") + + ee_def = data_dir / 'v3' / 'extra_build_cli_args' / 'execution-environment.yml' + + result = cli(f'ansible-builder build --no-cache -c {tmp_path} -f {ee_def} -t {ee_tag} ' + f'--container-runtime {runtime} -v 3 ' + f'--extra-build-cli-args="--secret id=mytoken,src={str(secret_file)}"', + allow_error=True) + + assert secret_string in result.stdout diff --git a/test/unit/test_cli.py b/test/unit/test_cli.py index 919f8bcb..4ac285ec 100644 --- a/test/unit/test_cli.py +++ b/test/unit/test_cli.py @@ -1,7 +1,8 @@ import os import runpy -import pytest +import shlex +import pytest from ansible_builder import constants from ansible_builder.main import AnsibleBuilder @@ -372,3 +373,18 @@ def test_invalid_verbosity(exec_env_definition_file, tmp_path, verbosity_opt): path = str(exec_env_definition_file(content=content)) with pytest.raises(ValueError, match=f'maximum verbosity is {constants.max_verbosity}'): prepare(['create', '-f', path, '-c', str(tmp_path), verbosity_opt]) + + +def test_extra_build_cli_args(exec_env_definition_file, tmp_path): + content = {'version': 3, 'images': {'base_image': {'name': 'base_image:latest'}}} + path = str(exec_env_definition_file(content=content)) + extras = ['--cache-ttl', '--mount=type=secret,id=mytoken', '--compress', '--env=TEST="blah blah"'] + + aee = prepare(['build', + '-f', path, + '-c', str(tmp_path), + '--extra-build-cli-args', shlex.join(extras), + ]) + + for extra in extras: + assert extra in aee.build_command