From e31084e5209667ad3c2baf9e201d6d66ddcf1bc1 Mon Sep 17 00:00:00 2001 From: Achilleas Koutsou Date: Fri, 11 Jul 2025 17:07:04 +0200 Subject: [PATCH] stages/tar: add --numeric-owner option The numeric-owner option omits the inclusion of user and group names in the archive metadata. This is often desirable since name and group mappings can change the ownership of files during extraction. The test uses the tarfile module to check that the uname and gname attributes in the tar archive itself are empty, which is the intended effect of enabling numeric-owner [1]. RHEL-102854 [1] https://www.gnu.org/software/tar//manual/html_section/Attributes.html --- stages/org.osbuild.tar | 3 +++ stages/org.osbuild.tar.meta.json | 4 ++++ stages/test/test_tar.py | 22 ++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/stages/org.osbuild.tar b/stages/org.osbuild.tar index 258eabbb..0a88420a 100755 --- a/stages/org.osbuild.tar +++ b/stages/org.osbuild.tar @@ -37,6 +37,9 @@ def main(inputs, output_dir, options): if transform: extra_args += ["--transform", transform] + if options.get("numeric-owner", False): + extra_args += ["--numeric-owner"] + compression = options.get("compression", "auto") if compression == "auto": diff --git a/stages/org.osbuild.tar.meta.json b/stages/org.osbuild.tar.meta.json index c0611821..1225d362 100644 --- a/stages/org.osbuild.tar.meta.json +++ b/stages/org.osbuild.tar.meta.json @@ -113,6 +113,10 @@ "transform": { "type": "string", "description": "Used to transform filenames and directly passed to --transform" + }, + "numeric-owner": { + "type": "boolean", + "description": "Always use numbers for user/group names" } } }, diff --git a/stages/test/test_tar.py b/stages/test/test_tar.py index 1ad26dcb..1d0b3f0d 100644 --- a/stages/test/test_tar.py +++ b/stages/test/test_tar.py @@ -3,6 +3,7 @@ import os.path import re import subprocess +import tarfile import pytest @@ -190,3 +191,24 @@ def test_tar_compress(tmp_path, stage_module, fake_inputs, filename, compression assert os.path.exists(tar_path) output = subprocess.check_output(["file", tar_path], encoding="utf-8") assert expected in output.lower() + + +@pytest.mark.skipif(not has_executable("tar"), reason="no tar executable") +@pytest.mark.parametrize("numeric_owner", [True, False,]) +def test_tar_numeric_owner(tmp_path, stage_module, fake_inputs, numeric_owner): + options = { + "filename": "out.tar", + "numeric-owner": numeric_owner, + } + stage_module.main(fake_inputs, tmp_path, options) + + tar_path = os.path.join(tmp_path, "out.tar") + assert os.path.exists(tar_path) + + # read the tar archive directly instead of relying on parsing the human-readable verbose output + with tarfile.open(tar_path, mode="r") as archive: + for item in archive.getmembers(): + # when enabling numeric-owner, the uname and gname fields are empty + info = item.get_info() + assert (info["uname"] == "") == numeric_owner + assert (info["gname"] == "") == numeric_owner