diff --git a/.github/workflows/build_images.yaml b/.github/workflows/build_images.yaml index 90145033..92086147 100644 --- a/.github/workflows/build_images.yaml +++ b/.github/workflows/build_images.yaml @@ -14,6 +14,10 @@ on: type: string description: Source short-sha, tag, branch-ref that will be used in the checkout and image tagging required: true + dereference_enabled: + type: boolean + description: Dereference the 'from' ref into a short sha before building. Defaults to true. + default: true flavors: type: string description: Flavor name/s | one (alone), several (separated by commas) @@ -130,6 +134,7 @@ jobs: output_results="build_images_results.yaml" type="${{ inputs.type }}" from="${{ inputs.from }}" + dereference_enabled="${{ inputs.dereference_enabled }}" workflow_run_id=${{ github.run_id}} workflow_run_url="https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}" login_required="true" diff --git a/firestarter/tests/test_build_images_functionality.py b/firestarter/tests/test_build_images_functionality.py index 11ed7966..2896e1f2 100644 --- a/firestarter/tests/test_build_images_functionality.py +++ b/firestarter/tests/test_build_images_functionality.py @@ -165,6 +165,81 @@ def test_dereference_from_input(mocker) -> None: assert result == TAG_INPUT +# The 'from' value is dereferenced by default, but can be disabled +def test_dereference_enabled_default(mocker) -> None: + mocker.patch('subprocess.run', side_effect=AssertionError("Should not be called")) + + assert builder.dereference_enabled is True + + +def test_dereference_enabled_true_dereferences_from(mocker) -> None: + BRANCH_INPUT = "test_branch" + SHORT_SHA_INPUT = "6a32377" + LONG_SHA_INPUT = "6a323778def4145d533dacafe003abb8df5bd5e0" + + mock_empty = mocker.MagicMock(returncode=0) + mock_empty.stdout = b"" + + mock_sha = mocker.MagicMock(returncode=0) + mock_sha.stdout = LONG_SHA_INPUT.encode() + + vars_with_dereference = vars.copy() + vars_with_dereference["from"] = BRANCH_INPUT + vars_with_dereference["dereference_enabled"] = "true" + + mocker.patch('subprocess.run', side_effect=[mock_empty, mock_sha]) + dereference_builder = BuildImages( + vars=vars_with_dereference, + secrets=secrets, + additional_build_args=additional_build_args, + config_file=config_file_path + ) + + assert dereference_builder.dereference_enabled is True + assert dereference_builder.from_version == SHORT_SHA_INPUT + + +def test_dereference_enabled_false_uses_raw_from(mocker) -> None: + BRANCH_INPUT = "test_branch" + + vars_without_dereference = vars.copy() + vars_without_dereference["from"] = BRANCH_INPUT + vars_without_dereference["dereference_enabled"] = "false" + + subprocess_run_mock = mocker.patch('subprocess.run') + no_dereference_builder = BuildImages( + vars=vars_without_dereference, + secrets=secrets, + additional_build_args=additional_build_args, + config_file=config_file_path + ) + + assert no_dereference_builder.dereference_enabled is False + assert no_dereference_builder.from_version == BRANCH_INPUT + subprocess_run_mock.assert_not_called() + + +# The 'from' value is never dereferenced when type is not snapshots +def test_non_snapshots_type_uses_raw_from(mocker) -> None: + BRANCH_INPUT = "test_branch" + + vars_with_releases_type = vars.copy() + vars_with_releases_type["from"] = BRANCH_INPUT + vars_with_releases_type["type"] = "releases" + + subprocess_run_mock = mocker.patch('subprocess.run') + releases_builder = BuildImages( + vars=vars_with_releases_type, + secrets=secrets, + additional_build_args=additional_build_args, + config_file=config_file_path + ) + + assert releases_builder.dereference_enabled is True + assert releases_builder.from_version == BRANCH_INPUT + subprocess_run_mock.assert_not_called() + + # Secrets are correctly solved, using the corresponding SecretResolver def test_resolve_secrets(mocker) -> None: mocker.patch.object(AzureKeyVaultManager, "get_secret") diff --git a/firestarter/workflows/build_images/README.md b/firestarter/workflows/build_images/README.md index b58bc7fe..e02c597a 100644 --- a/firestarter/workflows/build_images/README.md +++ b/firestarter/workflows/build_images/README.md @@ -25,6 +25,7 @@ Beyond the configuration file which is mandatory, there are some other extra var Additionally there are some optional variables: +* `dereference_enabled`: whether the `from` value is dereferenced into a short sha before building (defaults to `true`). It is only applied for `snapshots` builds; for other types the raw `from` value is always used as-is. * `container_structure_filename`: path of the [container-structure-test](https://github.com/GoogleContainerTools/container-structure-test) filename (if not set, no tests are checked) > Highly recommended! ⚠️ @@ -105,6 +106,7 @@ RUN echo "The additional build arg is: $YOUR_BUILD_ARG" from_point="${{ github.event.inputs.from }}" on_premises="${{ github.event.inputs.on_premises }}" container_structure_filename=".dagger/struct.yaml" + dereference_enabled="true" login_required=false secrets: | diff --git a/firestarter/workflows/build_images/build_images.py b/firestarter/workflows/build_images/build_images.py index 9416d815..7129314c 100644 --- a/firestarter/workflows/build_images/build_images.py +++ b/firestarter/workflows/build_images/build_images.py @@ -39,7 +39,14 @@ def __init__(self, **kwargs) -> None: self._type = self.vars.get('type', 'snapshots') # We checkout the correct sha/tag - self._from = self.dereference_from_input(self.vars.get('from')) + self._dereference_enabled = str( + self.vars.get('dereference_enabled', 'true') + ).lower() == 'true' + self._from = ( + self.dereference_from_input(self.vars.get('from')) + if self._dereference_enabled and self.type == 'snapshots' + else self.vars.get('from') + ) self._repo_name = self.vars.get('repo_name') self._snapshots_registry = self.vars.get('snapshots_registry') self._releases_registry = self.vars.get('releases_registry') @@ -105,6 +112,10 @@ def type(self): def from_version(self): return self._from + @property + def dereference_enabled(self): + return self._dereference_enabled + @property def workflow_run_id(self): return self._workflow_run_id