Repository: cekit/cekit
Pull request #928 (2024-11-09 09:02:37)

Fix overrides for args. Allow args to be injected first for the prima…
…ry image

[ Experiment for #915 - awaiting users opinions. The overrides for args fix is required regardless ]

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/cekit/cekit/pull/928?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cekit) Report
Attention: Patch coverage is `87.50000%` with `1 line` in your changes missing coverage. Please review.
> Project coverage is 90.29%. Comparing base [(`a03f762`)](https://app.codecov.io/gh/cekit/cekit/commit/a03f762095822e6e0dfa58e734da0aaf3c471753?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cekit) to head [(`204ce2a`)](https://app.codecov.io/gh/cekit/cekit/commit/204ce2a38542d22188eb0fffccd05ce9d191edd2?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cekit).

| [Files with missing lines](https://app.codecov.io/gh/cekit/cekit/pull/928?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cekit) | Patch % | Lines |
|---|---|---|
| [cekit/descriptor/image.py](https://app.codecov.io/gh/cekit/cekit/pull/928?src=pr&el=tree&filepath=cekit%2Fdescriptor%2Fimage.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cekit#diff-Y2VraXQvZGVzY3JpcHRvci9pbWFnZS5weQ==) | 87.50% | [1 Missing :warning: ](https://app.codecov.io/gh/cekit/cekit/pull/928?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cekit) |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##           develop     #928      +/-   ##
===========================================
- Coverage    90.29%   90.29%   -0.01%     
===========================================
  Files           42       42              
  Lines         3267     3275       +8     
===========================================
+ Hits          2950     2957       +7     
- Misses         317      318       +1     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/cekit/cekit/pull/928?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cekit).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cekit).


Patch:
diff --git a/.github/workflows/cekit.yml b/.github/workflows/cekit.yml
index a38be26..55b90a5 100644
--- a/.github/workflows/cekit.yml
+++ b/.github/workflows/cekit.yml
@@ -55,9 +55,8 @@ jobs:
       if: startsWith(matrix.os,'macos')
       run: |
         pip install "tox<4.0.0" setuptools
-        echo "Checking qemu info... $(brew list --versions qemu)"
         brew install podman
-        echo "PODMAN `which podman`"
+        echo "Podman `which podman`"
         podman machine init
         podman machine start  --log-level debug
         podman info
@@ -66,13 +65,14 @@ jobs:
         ln -s /usr/bin/true $HOME/bin/brew
         ln -s /usr/bin/true $HOME/bin/skopeo
         ln -s /usr/bin/true $HOME/bin/buildah
+        ln -s /usr/bin/true $HOME/bin/docker
     - name: Run tests
       run: |
         PV=${{ matrix.python-version }}
         echo "Running for Python version $PV ( ${PV/./} )"
         make test-py"${PV/./}"
     - name: Codecov
-      uses: codecov/codecov-action@v4
+      uses: codecov/codecov-action@v5
       with:
         token: ${{ secrets.CODECOV_TOKEN }}
         files: ./target/cov.xml
diff --git a/cekit/builders/buildah.py b/cekit/builders/buildah.py
index cf78392..7e88b4c 100644
--- a/cekit/builders/buildah.py
+++ b/cekit/builders/buildah.py
@@ -1,15 +1,14 @@
 import logging
-import os
 from typing import List
 
-from cekit.builder import Builder
+from cekit.builders.oci_builder import OCIBuilder
 from cekit.cekit_types import DependencyDefinition
-from cekit.tools import locate_binary, run_wrapper
+from cekit.tools import locate_binary
 
 LOGGER = logging.getLogger("cekit")
 
 
-class BuildahBuilder(Builder):
+class BuildahBuilder(OCIBuilder):
     """This class represents buildah builder in build-using-dockerfile mode."""
 
     def __init__(self, params):
@@ -25,42 +24,5 @@ class BuildahBuilder(Builder):
 
     def run(self) -> None:
         """Build container image using buildah."""
-        tags: List[str] = self.params.tags
         cmd: List[str] = [locate_binary("buildah"), "build-using-dockerfile"]
-        args: List[str] = self.params.args
-
-        if not tags:
-            tags = self.generator.get_tags()
-
-        if not self.params.no_squash:
-            cmd.append("--squash")
-
-        if self.params.trace:
-            cmd += ["--log-level", "debug"]
-
-        if self.params.pull:
-            cmd.append("--pull-always")
-
-        if self.params.platform:
-            cmd.append("--platform")
-            cmd.append(self.params.platform)
-
-        # Custom tags for the container image
-        LOGGER.debug("Building image with tags: '{}'".format("', '".join(tags)))
-
-        for tag in tags:
-            cmd.extend(["-t", tag])
-
-        if args:
-            for arg in args:
-                cmd.extend(["--build-arg=" + arg])
-
-        LOGGER.info("Building container image...")
-
-        cmd.append(os.path.join(self.target, "image"))
-
-        run_wrapper(cmd, False, f"Could not run buildah {cmd}")
-
-        LOGGER.info(
-            f"Image built and available under following tags: {', '.join(tags)}"
-        )
+        self.common_build("buildah", cmd)
diff --git a/cekit/builders/docker_builder.py b/cekit/builders/docker_builder.py
index 2f04b23..f075279 100644
--- a/cekit/builders/docker_builder.py
+++ b/cekit/builders/docker_builder.py
@@ -1,12 +1,15 @@
 import logging
 import os
 import re
+import tempfile
 import traceback
+from pathlib import Path
+from typing import List
 
-from cekit.builder import Builder
+from cekit.builders.oci_builder import OCIBuilder
 from cekit.cekit_types import DependencyDefinition
 from cekit.errors import CekitError
-from cekit.tools import parse_env_timeout
+from cekit.tools import locate_binary, parse_env_timeout
 
 LOGGER = logging.getLogger("cekit")
 
@@ -36,7 +39,7 @@ ANSI_ESCAPE = re.compile(r"\x1B\[[0-?]*[ -/]*[@-~]")
 DOCKER_API_VERSION = "1.35"
 
 
-class DockerBuilder(Builder):
+class DockerBuilder(OCIBuilder):
     """This class wraps docker build command to build and image"""
 
     def __init__(self, params):
@@ -66,11 +69,9 @@ class DockerBuilder(Builder):
         docker_args["path"] = os.path.join(self.target, "image")
         docker_args["pull"] = self.params.pull
         docker_args["rm"] = True
-        if self.params.platform:
-            docker_args["platform"] = self.params.platform
-        if self.params.args:
+        if self.params.build_args:
             buildargs = {}
-            for arg in self.params.args:
+            for arg in self.params.build_args:
                 if "=" in arg:
                     split = arg.split("=")
                     buildargs.update({split[0]: split[1]})
@@ -154,13 +155,17 @@ class DockerBuilder(Builder):
 
         return docker_layer_ids[-1]
 
-    def _squash(self, docker_client, image_id):
+    def _squash(self, docker_client, image_id, squash_all_layers=False):
         LOGGER.info(f"Squashing image {image_id}...")
 
+        if squash_all_layers:
+            layer = None
+        else:
+            layer = self.generator.image["from"]
         squash = Squash(
             docker=docker_client,
             log=LOGGER,
-            from_layer=self.generator.image["from"],
+            from_layer=layer,
             image=image_id,
             cleanup=True,
         )
@@ -239,16 +244,29 @@ class DockerBuilder(Builder):
 
         docker_client = self._docker_client()
 
-        # Build image
-        image_id = self._build_with_docker(docker_client)
-
-        # Squash only if --no-squash is NOT defined
-        if not self.params.no_squash:
-            image_id = self._squash(docker_client, image_id)
+        if self.params.platform or self.params.build_flag:
+            cmd: List[str] = [locate_binary("docker"), "build"]
+            with tempfile.NamedTemporaryFile() as tmp:
+                cmd.append(f"--iidfile={tmp.name}")
+                # Don't tag in the common_build as it leads to image reference issues
+                self.common_build("docker", cmd, False)
+                # Strip "sha256:" from the start
+                image_id = Path(tmp.name).read_text()[7:]
+            if not self.params.no_squash:
+                # Docker buildkit does not show history so squash without a from reference
+                # https://github.com/moby/buildkit/issues/1235
+                image_id = self._squash(docker_client, image_id, True)
+        else:
+            # Build image
+            image_id = self._build_with_docker(docker_client)
+
+            # Squash only if --no-squash is NOT defined
+            if not self.params.no_squash:
+                image_id = self._squash(docker_client, image_id)
 
         # Tag the image
         self._tag(docker_client, image_id, tags)
 
         LOGGER.info(
-            f"Image built and available under following tags: {', '.join(tags)}"
+            f"Image ID {image_id} built and available under following tags: {', '.join(tags)}"
         )
diff --git a/cekit/builders/oci_builder.py b/cekit/builders/oci_builder.py
new file mode 100644
index 0000000..6d7b4d9
--- /dev/null
+++ b/cekit/builders/oci_builder.py
@@ -0,0 +1,55 @@
+import logging
+import os
+from typing import List
+
+from cekit.builder import Builder
+from cekit.tools import run_wrapper
+
+LOGGER = logging.getLogger("cekit")
+
+
+class OCIBuilder(Builder):
+    def common_build(self, build_type: str, cmd: List[str], tagging=True):
+        tags: List[str] = self.params.tags
+        args: List[str] = self.params.build_args
+        generic_args: List[str] = self.params.build_flag
+
+        if tagging and not tags:
+            tags = self.generator.get_tags()
+
+        if not self.params.no_squash:
+            cmd.append("--squash")
+
+        if self.params.trace:
+            cmd += ["--log-level", "debug"]
+
+        if self.params.pull:
+            cmd.append("--pull-always")
+
+        if self.params.platform:
+            cmd.append("--platform")
+            cmd.append(self.params.platform)
+
+        # Custom tags for the container image
+        LOGGER.debug("Building image with tags: '{}'".format("', '".join(tags)))
+
+        for tag in tags:
+            cmd.extend(["-t", tag])
+
+        if args:
+            for arg in args:
+                cmd.extend(["--build-arg=" + arg])
+
+        if generic_args:
+            for arg in generic_args:
+                cmd.extend([arg])
+
+        LOGGER.info("Building container image...")
+
+        cmd.append(os.path.join(self.target, "image"))
+
+        run_wrapper(cmd, False, f"Could not run {build_type} {cmd}")
+
+        LOGGER.info(
+            f"Image built and available under following tags: {', '.join(tags)}"
+        )
diff --git a/cekit/builders/podman.py b/cekit/builders/podman.py
index f303544..762d3e4 100644
--- a/cekit/builders/podman.py
+++ b/cekit/builders/podman.py
@@ -1,15 +1,14 @@
 import logging
-import os
 from typing import List
 
-from cekit.builder import Builder
+from cekit.builders.oci_builder import OCIBuilder
 from cekit.cekit_types import DependencyDefinition
-from cekit.tools import locate_binary, run_wrapper
+from cekit.tools import locate_binary
 
 LOGGER = logging.getLogger("cekit")
 
 
-class PodmanBuilder(Builder):
+class PodmanBuilder(OCIBuilder):
     """This class represents podman builder in build mode."""
 
     def __init__(self, params):
@@ -26,42 +25,5 @@ class PodmanBuilder(Builder):
     def run(self):
         """Build container image using podman."""
 
-        tags: List[str] = self.params.tags
         cmd: List[str] = [locate_binary("podman"), "build"]
-        args: List[str] = self.params.args
-
-        if not tags:
-            tags = self.generator.get_tags()
-
-        if self.params.trace:
-            cmd += ["--log-level", "debug"]
-
-        if self.params.pull:
-            cmd.append("--pull-always")
-
-        if not self.params.no_squash:
-            cmd.append("--squash")
-
-        if self.params.platform:
-            cmd.append("--platform")
-            cmd.append(self.params.platform)
-
-        # Custom tags for the container image
-        LOGGER.debug("Building image with tags: '{}'".format("', '".join(tags)))
-
-        for tag in tags:
-            cmd.extend(["-t", tag])
-
-        if args:
-            for arg in args:
-                cmd.extend(["--build-arg=" + arg])
-
-        LOGGER.info("Building container image...")
-
-        cmd.append(os.path.join(self.target, "image"))
-
-        run_wrapper(cmd, False, f"Could not run podman {cmd}")
-
-        LOGGER.info(
-            f"Image built and available under following tags: {', '.join(tags)}"
-        )
+        self.common_build("podman", cmd)
diff --git a/cekit/cli.py b/cekit/cli.py
index 2e3a324..1b1b787 100644
--- a/cekit/cli.py
+++ b/cekit/cli.py
@@ -169,17 +169,24 @@ def build(validate, dry_run, container_file, overrides):
 )
 @click.option(
     "--build-arg",
-    "args",
+    "build_args",
     metavar="ARG[=VALUE]",
     help="Pass specified build-arg to the build process, can be specified multiple times.",
     multiple=True,
 )
+@click.option(
+    "--build-flag",
+    "build_flag",
+    metavar="ARG[=VALUE]",
+    help="Pass arbitrary arguments to the underlying build process, can be specified multiple times.",
+    multiple=True,
+)
 @click.option(
     "--platform",
     help="Set the ARCH of the image to the provided value instead of the architecture of the host.",
 )
 @click.pass_context
-def build_docker(ctx, pull, no_squash, tags, args, platform):
+def build_docker(ctx, pull, no_squash, tags, build_args, build_flag, platform):
     """
     DESCRIPTION
 
@@ -206,17 +213,24 @@ def build_docker(ctx, pull, no_squash, tags, args, platform):
 )
 @click.option(
     "--build-arg",
-    "args",
+    "build_args",
     metavar="ARG[=VALUE]",
     help="Pass specified build-arg to the build process, can be specified multiple times.",
     multiple=True,
 )
+@click.option(
+    "--build-flag",
+    "build_flag",
+    metavar="ARG[=VALUE]",
+    help="Pass arbitrary arguments to the underlying build process, can be specified multiple times.",
+    multiple=True,
+)
 @click.option(
     "--platform",
     help="Set the ARCH of the image to the provided value instead of the architecture of the host.",
 )
 @click.pass_context
-def build_buildah(ctx, pull, no_squash, tags, args, platform):
+def build_buildah(ctx, pull, no_squash, tags, build_args, build_flag, platform):
     """
     DESCRIPTION
 
@@ -241,17 +255,24 @@ def build_buildah(ctx, pull, no_squash, tags, args, platform):
 )
 @click.option(
     "--build-arg",
-    "args",
+    "build_args",
     metavar="ARG[=VALUE]",
     help="Pass specified build-arg to the build process, can be specified multiple times.",
     multiple=True,
 )
+@click.option(
+    "--build-flag",
+    "build_flag",
+    metavar="ARG[=VALUE]",
+    help="Pass arbitrary arguments to the underlying build process, can be specified multiple times.",
+    multiple=True,
+)
 @click.option(
     "--platform",
     help="Set the ARCH of the image to the provided value instead of the architecture of the host.",
 )
 @click.pass_context
-def build_podman(ctx, pull, no_squash, tags, args, platform):
+def build_podman(ctx, pull, no_squash, tags, build_args, build_flag, platform):
     """
     DESCRIPTION
 
diff --git a/cekit/descriptor/image.py b/cekit/descriptor/image.py
index 1df40c8..0ee4519 100644
--- a/cekit/descriptor/image.py
+++ b/cekit/descriptor/image.py
@@ -83,6 +83,7 @@ class Image(Descriptor):
         self._descriptor["labels"] = [
             Label(x) for x in self._descriptor.get("labels", [])
         ]
+        self._descriptor["args"] = [Arg(x) for x in self._descriptor.get("args", [])]
         self._descriptor["envs"] = [Env(x) for x in self._descriptor.get("envs", [])]
         self._descriptor["ports"] = [Port(x) for x in self._descriptor.get("ports", [])]
         if "run" in self._descriptor:
@@ -267,6 +268,15 @@ class Image(Descriptor):
                     labels[name] = label
             self._descriptor["labels"] = list(labels.values())
 
+            args = Image._to_dict(self.args)
+            for argument in override.args:
+                name = argument.name
+                if name in args:
+                    args[name] = argument.merge(args[name])
+                else:
+                    args[name] = argument
+            self._descriptor["args"] = list(args.values())
+
             envs = Image._to_dict(self.envs)
             for env in override.envs:
                 name = env.name
diff --git a/cekit/templates/template.jinja b/cekit/templates/template.jinja
index d089b0e..f2ad9b1 100644
--- a/cekit/templates/template.jinja
+++ b/cekit/templates/template.jinja
@@ -78,6 +78,24 @@ rm -rf "/var/cache/yum" "/var/lib/dnf" "/var/cache/apt" "/var/cache/dnf"
     {% endif %}
 {%- endmacro -%}
 
+
+{#
+ # Handle processing ARGS
+ #}
+{%- macro process_args(module) -%}
+{% if module.args|count > 0 %}
+    {% for arg in module.args|sort(attribute='name') %}
+    {% if 'value' in arg %}
+        ARG {{ arg.name }}="{{ arg.value }}"
+    {% else %}
+        ARG {{ arg.name }}
+    {% endif -%}
+    {% endfor %}
+
+{% endif %}
+{%- endmacro -%}
+
+
 {#
  # Macro for processing content of a module (or image).
  #
@@ -140,19 +158,11 @@ rm -rf "/var/cache/yum" "/var/lib/dnf" "/var/cache/apt" "/var/cache/dnf"
         # Reinstall packages defined in the '{{ module.name }}' {{ module_type }}
         RUN {{ pkg_reinstall(parent_image.packages.manager, parent_image.packages.manager_flags, module.packages.reinstall) }}
         {% endif -%}
-        {% endif -%}
 
-        {% if module.args|count > 0 %}
-        {% for arg in module.args|sort(attribute='name') %}
-        {% if 'value' in arg %}
-        ARG {{ arg.name }}="{{ arg.value }}"
-        {% else %}
-        ARG {{ arg.name }}
         {% endif -%}
-        {% endfor %}
-
+        {% if module_type == 'module' %}
+        {{- process_args(module) -}}
         {% endif -%}
-
         {% if module.envs|selectattr("value")|list|length > 0 %}
         # Set '{{ module.name }}' {{ module_type }} defined environment variables
         ENV \
@@ -228,6 +238,7 @@ rm -rf "/var/cache/yum" "/var/lib/dnf" "/var/cache/apt" "/var/cache/dnf"
     {% endfor %}
     {% endif %}
 
+    {{- process_args(animage) }}
     {% for to_install in animage.modules.install %}
 {{ process_module(helper.module(to_install), animage) }}
     {% endfor %}
diff --git a/docs/handbook/building/builder-engines.rst b/docs/handbook/building/builder-engines.rst
index a8b542f..91ae463 100644
--- a/docs/handbook/building/builder-engines.rst
+++ b/docs/handbook/building/builder-engines.rst
@@ -22,15 +22,24 @@ Input format
 Parameters
     ``--pull``
         Ask a builder engine to check and fetch latest base image
+    ``--no-squash``
+        Do not squash the image after build is done.
     ``--tag`` <tag-name>
         Use specified tag to tag the image after the build. (can be specified multiple times). If not specified
         then the image will be tagged with ``<name>:<version>`` and ``<name>:latest`` using keys from the image
         descriptor.
-    ``--no-squash``
-        Do not squash the image after build is done.
+    ``--build-arg`` <ARG=VALUE>
+        Pass specified build-arg to the build process, can be specified multiple times.
+    ``--build-flag`` <ARG=VALUE>
+        Pass arbitrary arguments to the build process, can be specified multiple times.
     ``--platform``
         Set the ARCH of the image to the provided value(s).
 
+.. note::
+        If ``--platform`` or ``--build-flag`` is passed in the build will be invoke by calling the Docker CLI
+        directly instead of using the `Python API <https://docker-py.readthedocs.io/en/stable>`_.  This is due to
+        https://github.com/docker/docker-py/issues/2230
+
 Example
     Building Docker image
 
@@ -194,12 +203,16 @@ Input format
 Parameters
     ``--pull``
         Ask a builder engine to check and fetch latest base image
+    ``--no-squash``
+        Do not squash the image after build is done.
     ``--tag`` <tag-name>
         Use specified tag to tag the image after the build. (can be specified multiple times). If not specified
         then the image will be tagged with ``<name>:<version>`` and ``<name>:latest`` using keys from the image
         descriptor.
-    ``--no-squash``
-        Do not squash the image after build is done.
+    ``--build-arg`` <ARG=VALUE>
+        Pass specified build-arg to the build process, can be specified multiple times.
+    ``--build-flag`` <ARG=VALUE>
+        Pass arbitrary arguments to the build process, can be specified multiple times.
     ``--platform``
         Set the ARCH of the image to the provided value(s).
 
@@ -254,12 +267,16 @@ Input format
 Parameters
     ``--pull``
         Ask a builder engine to check and fetch latest base image
+    ``--no-squash``
+        Do not squash the image after build is done.
     ``--tag`` <tag-name>
         Use specified tag to tag the image after the build. (can be specified multiple times). If not specified
         then the image will be tagged with ``<name>:<version>`` and ``<name>:latest`` using keys from the image
         descriptor.
-    ``--no-squash``
-        Do not squash the image after build is done.
+    ``--build-arg`` <ARG=VALUE>
+        Pass specified build-arg to the build process, can be specified multiple times.
+    ``--build-flag`` <ARG=VALUE>
+        Pass arbitrary arguments to the build process, can be specified multiple times.
     ``--platform``
         Set the ARCH of the image to the provided value(s).
 
@@ -276,6 +293,12 @@ Example
 
         $ cekit build podman --pull
 
+    Build image using Podman
+
+    .. code-block:: bash
+
+        $ cekit build podman --pull --build-arg=FOO=BAR --build-flag=--secret=id=id,src=path
+
 Podman environment variables
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/docs/handbook/modules/image_order.rst b/docs/handbook/modules/image_order.rst
index a9c9b66..c304908 100644
--- a/docs/handbook/modules/image_order.rst
+++ b/docs/handbook/modules/image_order.rst
@@ -37,6 +37,7 @@ describes how the image processing interacts with the module processing.
                 bgcolor="lightgrey"
                 label="Image Rendering";
                 cachito [label="Cachito Support", rank=same];
+                arg [label="Main image ARG handling"];
                 repo [label="Repository Management"];
                 module [label="Included Module Processing"];
                 complete_image [label="Final Image stages", href="#final-image-stages"];
@@ -54,7 +55,7 @@ describes how the image processing interacts with the module processing.
 
         // graph control
         builder -> from -> extra -> image -> cleanup -> final;
-        cachito -> repo -> module -> complete_image;
+        cachito -> repo -> arg -> module -> complete_image;
         artifact -> pkg_install -> ports -> run -> volumes;
 
         // subgraph links
@@ -73,5 +74,10 @@ This encompasses defining the ``USER``, the ``WORKDIR``, and ``ENTRYPOINT``. Fin
 Final Image Stages
 """""""""""""""""""""""
 
-This encompasses the final part of the generation for the image descriptor which may include e.g. package installation.
-Note that this happens **after** modules have been included and processed.
+This encompasses the final part of the generation for the image descriptor which may include e.g. package
+installation or artifact handling.
+
+.. note::
+    Note that the main image handling happens **after** modules have been included and processed.
+
+    The only exception to this is ``args`` which are injected first.
\ No newline at end of file


Test patch:
diff --git a/tests/test_builder.py b/tests/test_builder.py
index 74b2de5..31bfc41 100644
--- a/tests/test_builder.py
+++ b/tests/test_builder.py
@@ -996,8 +996,8 @@ def test_podman_builder_run_pull(mocker):
         [
             shutil.which("podman"),
             "build",
-            "--pull-always",
             "--squash",
+            "--pull-always",
             "-t",
             "foo",
             "-t",
@@ -1025,8 +1025,8 @@ def test_podman_builder_run_platform(mocker):
         [
             shutil.which("podman"),
             "build",
-            "--pull-always",
             "--squash",
+            "--pull-always",
             "--platform",
             "linux/amd64,linux/arm64",
             "-t",
@@ -1150,7 +1150,7 @@ def test_buildah_builder_with_squashing_disabled(mocker):
 
 
 def test_buildah_builder_with_build_arg(mocker):
-    params = {"tags": ["foo", "bar"], "no_squash": True, "args": ["KEY=VALUE"]}
+    params = {"tags": ["foo", "bar"], "no_squash": True, "build_args": ["KEY=VALUE"]}
     run = mocker.patch.object(subprocess, "run")
     builder = create_builder_object(mocker, "buildah", params)
     builder.run()
@@ -1207,7 +1207,7 @@ def test_podman_builder_with_squashing_disabled(mocker):
 
 
 def test_podman_builder_with_build_arg(mocker):
-    params = {"args": ["KEY=VALUE"]}
+    params = {"build_args": ["KEY=VALUE"]}
     run = mocker.patch.object(subprocess, "run")
     builder = create_builder_object(mocker, "podman", params)
     builder.generator = DockerGenerator("", "", "", [])
@@ -1241,6 +1241,41 @@ def test_podman_builder_with_build_arg(mocker):
     )
 
 
+def test_podman_builder_with_build_flag(mocker):
+    params = {"build_flag": ["--compress"]}
+    run = mocker.patch.object(subprocess, "run")
+    builder = create_builder_object(mocker, "podman", params)
+    builder.generator = DockerGenerator("", "", "", [])
+    builder.generator.image = Image(
+        yaml.safe_load(
+            """
+    name: foo
+    version: 1.9
+    """
+        ),
+        "foo",
+    )
+    builder.run()
+
+    run.assert_called_once_with(
+        [
+            shutil.which("podman"),
+            "build",
+            "--squash",
+            "-t",
+            "foo:1.9",
+            "-t",
+            "foo:latest",
+            "--compress",
+            "something/image",
+        ],
+        stderr=None,
+        stdout=None,
+        check=True,
+        universal_newlines=True,
+    )
+
+
 def test_docker_squashing_disabled_dependencies(mocker, tmpdir, caplog):
     caplog.set_level(logging.DEBUG, logger="cekit")
 
diff --git a/tests/test_dockerfile.py b/tests/test_dockerfile.py
index 2479718..72cd2ae 100644
--- a/tests/test_dockerfile.py
+++ b/tests/test_dockerfile.py
@@ -10,6 +10,7 @@ from cekit.cli import cli
 from cekit.config import Config
 from cekit.descriptor import Repository
 from cekit.tools import Chdir
+from cekit.version import __version__
 from cekit.version import __version__ as cekit_version
 
 basic_config = {"release": 1, "version": 1, "from": "fromimage", "name": "testimage"}
@@ -597,23 +598,84 @@ def test_dockerfile_copy_modules_if_modules_defined(tmpdir, caplog):
 
     with open(module_yaml_path, "w") as outfile:
         yaml.dump(
-            {"name": "foo", "version": "1.0", "execute": [{"script": "configure.sh"}]},
+            {
+                "name": "foo",
+                "version": "1.0",
+                "execute": [{"script": "configure.sh"}],
+                "args": [
+                    {"name": "modulearg", "value": "modulebar"},
+                    {"name": "modulelabel"},
+                ],
+            },
             outfile,
             default_flow_style=False,
         )
 
     generate(
         target,
-        ["-v", "--work-dir", target, "build", "--dry-run", "podman"],
+        [
+            "-v",
+            "--work-dir",
+            target,
+            "build",
+            "--overrides",
+            "{'args': [{'name': 'foo', 'value': 'NEW'}]}",
+            "--dry-run",
+            "podman",
+        ],
         descriptor={
+            "args": [{"name": "foo", "value": "bar"}, {"name": "labela"}],
             "modules": {
                 "repositories": [{"name": "modules", "path": "modules"}],
                 "install": [{"name": "foo"}],
-            }
+            },
         },
     )
 
-    regex_dockerfile(target, "COPY modules/foo /tmp/scripts/foo", "Containerfile")
+    with open(os.path.join(target, "target", "image", "Containerfile"), "r") as fd:
+        dockerfile_content = fd.read()
+        print(f"docker is \n{dockerfile_content}")
+        assert (
+            """## START target image testimage:1
+## \\
+    FROM fromimage
+
+
+    USER root
+        ARG foo="NEW"
+        ARG labela
+
+
+###### START module 'foo:1.0'
+###### \\
+        # Copy 'foo' module content
+        COPY modules/foo /tmp/scripts/foo
+        ARG modulearg="modulebar"
+        ARG modulelabel
+
+        # Custom scripts from 'foo' module
+        USER root
+        RUN [ "sh", "-x", "/tmp/scripts/foo/configure.sh" ]
+###### /
+###### END module 'foo:1.0'
+
+###### START image 'testimage:1'
+###### \\
+        # Set 'testimage' image defined labels
+        LABEL \\
+            io.cekit.version="VVVVV"
+###### /
+###### END image 'testimage:1'
+
+
+
+    # Switch to 'root' user and remove artifacts and modules
+    USER root
+""".replace(
+                "VVVVV", __version__
+            )
+            in dockerfile_content
+        )
 
 
 def test_dockerfile_destination_of_artifact(mocker, tmpdir):
diff --git a/tests/test_unit_args.py b/tests/test_unit_args.py
index 7de9ffd..2fc337a 100644
--- a/tests/test_unit_args.py
+++ b/tests/test_unit_args.py
@@ -24,7 +24,8 @@ def _get_class_by_name(clazz):
             ["--redhat", "build", "docker"],
             "cekit.builders.docker_builder.DockerBuilder",
             {
-                "args": (),
+                "build_args": (),
+                "build_flag": (),
                 "container_file": None,
                 "descriptor": "image.yaml",
                 "verbose": False,
@@ -48,7 +49,8 @@ def _get_class_by_name(clazz):
             ["--target", "custom-target", "build", "docker"],
             "cekit.builders.docker_builder.DockerBuilder",
             {
-                "args": (),
+                "build_args": (),
+                "build_flag": (),
                 "container_file": None,
                 "descriptor": "image.yaml",
                 "verbose": False,
@@ -72,7 +74,8 @@ def _get_class_by_name(clazz):
             ["--work-dir", "custom-workdir", "build", "docker"],
             "cekit.builders.docker_builder.DockerBuilder",
             {
-                "args": (),
+                "build_args": (),
+                "build_flag": (),
                 "container_file": None,
                 "descriptor": "image.yaml",
                 "verbose": False,
@@ -96,7 +99,8 @@ def _get_class_by_name(clazz):
             ["--config", "custom-config", "build", "docker"],
             "cekit.builders.docker_builder.DockerBuilder",
             {
-                "args": (),
+                "build_args": (),
+                "build_flag": (),
                 "container_file": None,
                 "descriptor": "image.yaml",
                 "verbose": False,
@@ -120,7 +124,8 @@ def _get_class_by_name(clazz):
             ["build", "docker"],
             "cekit.builders.docker_builder.DockerBuilder",
             {
-                "args": (),
+                "build_args": (),
+                "build_flag": (),
                 "container_file": None,
                 "descriptor": "image.yaml",
                 "verbose": False,
@@ -144,7 +149,8 @@ def _get_class_by_name(clazz):
             ["build", "--overrides", "foo", "--overrides-file", "bar", "docker"],
             "cekit.builders.docker_builder.DockerBuilder",
             {
-                "args": (),
+                "build_args": (),
+                "build_flag": (),
                 "container_file": None,
                 "descriptor": "image.yaml",
                 "verbose": False,
@@ -297,7 +303,8 @@ def _get_class_by_name(clazz):
             ["build", "docker", "--pull"],
             "cekit.builders.docker_builder.DockerBuilder",
             {
-                "args": (),
+                "build_args": (),
+                "build_flag": (),
                 "container_file": None,
                 "descriptor": "image.yaml",
                 "verbose": False,
@@ -346,7 +353,8 @@ def _get_class_by_name(clazz):
             ["build", "docker"],
             "cekit.builders.docker_builder.DockerBuilder",
             {
-                "args": (),
+                "build_args": (),
+                "build_flag": (),
                 "container_file": None,
                 "descriptor": "image.yaml",
                 "verbose": False,
@@ -383,7 +391,8 @@ def _get_class_by_name(clazz):
                 "overrides": (),
                 "pull": False,
                 "tags": (),
-                "args": (),
+                "build_args": (),
+                "build_flag": (),
                 "platform": None,
                 "no_squash": False,
             },
diff --git a/tests/test_unit_builder_docker.py b/tests/test_unit_builder_docker.py
index b42a52a..d5748e8 100644
--- a/tests/test_unit_builder_docker.py
+++ b/tests/test_unit_builder_docker.py
@@ -121,18 +121,15 @@ def test_docker_client_build(mocker, caplog):
         "Docker: This system is not receiving updates. You can use subscription-manager on the host to register and assign subscriptions."
         in caplog.text
     )
-    assert "Image built and available under following tags: foo, bar" in caplog.text
+    assert "built and available under following tags: foo, bar" in caplog.text
 
 
 def test_docker_client_build_platform(mocker, caplog):
     caplog.set_level(logging.DEBUG, logger="cekit")
 
     mocker.patch("cekit.builders.docker_builder.Squash")
-    docker_client_class = mocker.patch("cekit.builders.docker_builder.docker.APIClient")
-    docker_client = docker_client_class.return_value
-    docker_client_build = mocker.patch.object(
-        docker_client, "build", return_value=docker_success_output
-    )
+    mocker.patch("cekit.builders.docker_builder.docker.APIClient")
+    mocker.patch("subprocess.run")
 
     builder = DockerBuilder(
         Map(
@@ -146,15 +143,8 @@ def test_docker_client_build_platform(mocker, caplog):
     builder.generator = Map({"image": {"from": "FROM"}})
     builder.run()
 
-    docker_client_build.assert_called_once_with(
-        decode=True,
-        path="something/image",
-        platform="linux/amd64,linux/arm64",
-        pull=None,
-        rm=True,
-    )
     assert re.match(
-        ".*Running Docker build:.*'platform': 'linux/amd64,linux/arm64'.*",
+        ".*Executing.*docker build.*platform.*linux/amd64,linux/arm64.*",
         caplog.text,
         re.DOTALL,
     )