Repository: osbuild/osbuild
Pull request #1763 (2024-04-29 11:08:19)

stages/skopeo:  Fix the remove-signatures option
It's defined on the options level, not on the destination level. The first commit adds a quick and dirty test for this, the second commit fixes that.

achilleas-k: I merged #1761 just now so... CONFLICT \o/

Patch:
diff --git a/sources/org.osbuild.curl b/sources/org.osbuild.curl
index 670717a4..6a8293f2 100755
--- a/sources/org.osbuild.curl
+++ b/sources/org.osbuild.curl
@@ -20,6 +20,7 @@ up the download.
 
 import concurrent.futures
 import os
+import platform
 import subprocess
 import sys
 import tempfile
@@ -153,6 +154,7 @@ class CurlSource(sources.SourceService):
             # some mirrors are sometimes broken. retry manually, because we could be
             # redirected to a different, working, one on retry.
             return_code = 0
+            arch = platform.machine()
             for _ in range(10):
                 curl_command = [
                     "curl",
@@ -161,6 +163,7 @@ class CurlSource(sources.SourceService):
                     "--connect-timeout", "30",
                     "--fail",
                     "--location",
+                    "--header", f"User-Agent: osbuild (Linux.{arch}; https://osbuild.org/)",
                     "--output", checksum,
                 ]
                 if proxy:
diff --git a/stages/org.osbuild.skopeo b/stages/org.osbuild.skopeo
index ec62c595..45bb98db 100755
--- a/stages/org.osbuild.skopeo
+++ b/stages/org.osbuild.skopeo
@@ -13,7 +13,7 @@ def main(inputs, output, options):
 
     destination = options["destination"]
     dest_type = destination["type"]
-    remove_signatures = destination.get("remove-signatures")
+    remove_signatures = options.get("remove-signatures")
 
     for image in images.values():
         with containers.container_source(image) as (image_name, image_source):


Test patch:
diff --git a/sources/test/test_curl_source.py b/sources/test/test_curl_source.py
index 49813ad0..47c7849c 100644
--- a/sources/test/test_curl_source.py
+++ b/sources/test/test_curl_source.py
@@ -208,3 +208,20 @@ def test_curl_download_proxy(mocked_run, tmp_path, monkeypatch, sources_service,
             assert args[0][idx:idx + 2] == ["--proxy", "http://my-proxy"]
         else:
             assert "--proxy" not in args[0]
+
+
+@patch("subprocess.run")
+def test_curl_user_agent(mocked_run, tmp_path, sources_service):
+    test_sources = make_test_sources(tmp_path, 80, 2,)
+    fake_curl_downloader = FakeCurlDownloader(test_sources)
+    mocked_run.side_effect = fake_curl_downloader.faked_run
+
+    sources_service.cache = tmp_path / "curl-cache"
+    sources_service.cache.mkdir()
+    sources_service.fetch_all(test_sources)
+
+    for call_args in mocked_run.call_args_list:
+        args, _kwargs = call_args
+        idx = args[0].index("--header")
+        assert "User-Agent: osbuild" in args[0][idx + 1]
+        assert "https://osbuild.org/" in args[0][idx + 1]
diff --git a/stages/test/test_skopeo.py b/stages/test/test_skopeo.py
index 119e9ad4..13f897c0 100644
--- a/stages/test/test_skopeo.py
+++ b/stages/test/test_skopeo.py
@@ -118,3 +118,28 @@ def test_skopeo_copy_oci(tmp_path, stage_module):
     data_digest = data["manifests"][0]["digest"].split(':')
     manifest_file = result_path / "blobs" / data_digest[0] / data_digest[1]
     assert_manifest_file(manifest_file)
+
+
+@pytest.mark.parametrize("remove_signatures", [True, False])
+def test_skopeo_copy_remove_signatures(tmp_path, stage_module, remove_signatures):
+    # We are completely faking everything here, because we mock out skopeo
+    fake_oci_path = tmp_path / "fake-container"
+    inputs = make_fake_images_inputs(fake_oci_path, "some-name")
+
+    with testutil.mock_command("skopeo", "") as args:
+        options = {
+            "destination": {
+                "type": "oci",
+                "path": "/tmp/test-output-skopeo-dir",
+            },
+            "remove-signatures": remove_signatures,
+        }
+        output_dir = tmp_path / "output"
+        stage_module.main(inputs, output_dir, options)
+
+        if remove_signatures:
+            # Check that skopeo has --remove-signatures right after the copy subcommand
+            assert args.call_args_list[0][0:2] == ["copy", "--remove-signatures"]
+        else:
+            # Check that --remove-signatures is not present in the skopeo command
+            assert "--remove-signatures" not in args.call_args_list[0]