Skip to content

Commit 77de380

Browse files
pombredanneSt0rmingBr4in
authored andcommitted
Add md5sums file list to distroless container (bazelbuild#2065)
* Add md5sums file list to distroless container This ensures that a "distroless" container layer tarball built from Debian packages contains not only the control file of each package, but also the md5sums file that lists original files included in a package. If present, we extract the md5sums file and save is side-by-side with the package control file under this path: var/lib/dpkg/status.d/<package-name>.md5sums Reference: bazelbuild#1876 Signed-off-by: Philippe Ombredanne <pombredanne@nexb.com> * Remove trailing whitespaces Signed-off-by: Philippe Ombredanne <pombredanne@nexb.com>
1 parent d0eaa5f commit 77de380

2 files changed

Lines changed: 58 additions & 9 deletions

File tree

container/build_tar.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class DebError(Exception):
3939
PKG_NAME_RE = re.compile(r'Package:\s*(?P<pkg_name>\w+).*')
4040
DPKG_STATUS_DIR = '/var/lib/dpkg/status.d'
4141
PKG_METADATA_FILE = 'control'
42+
PKG_MD5SUMS_FILE = 'md5sums'
4243

4344
@staticmethod
4445
def parse_pkg_name(metadata, filename):
@@ -222,20 +223,36 @@ def write_temp_file(self, data, suffix='tar', mode='wb'):
222223
os.remove(tmpfile)
223224

224225
def add_pkg_metadata(self, metadata_tar, deb):
226+
"""
227+
Extract the package ``control`` metadata file from a Debian `metadata_tar`
228+
tarball file to the status.d directory. Also extract the ``md5sums`` files
229+
list file if present.
230+
"""
225231
try:
226232
with tarfile.open(metadata_tar) as tar:
233+
tar_members = tar.getmembers()
227234
# Metadata is expected to be in a file.
228-
control_file_member = list(filter(lambda f: os.path.basename(f.name) == TarFile.PKG_METADATA_FILE, tar.getmembers()))
235+
control_file_member = list(filter(lambda f: os.path.basename(f.name) == TarFile.PKG_METADATA_FILE, tar_members))
229236
if not control_file_member:
230-
raise self.DebError(deb + ' does not Metadata File!')
237+
raise self.DebError(deb + ' does not contain a control Metadata File!')
231238
control_file = tar.extractfile(control_file_member[0])
232-
metadata = b''.join(control_file.readlines())
233-
destination_file = os.path.join(TarFile.DPKG_STATUS_DIR,
234-
TarFile.parse_pkg_name(metadata.decode("utf-8"), deb))
239+
metadata = control_file.read()
240+
pkg_name = TarFile.parse_pkg_name(metadata.decode('utf-8'), deb)
241+
destination_file = os.path.join(TarFile.DPKG_STATUS_DIR, pkg_name)
235242
with self.write_temp_file(data=metadata) as metadata_file:
236243
self.add_file(metadata_file, destination_file)
244+
245+
# Extract the md5sums file listing of package files if present
246+
md5sums_file_member = list(filter(lambda f: os.path.basename(f.name) == TarFile.PKG_MD5SUMS_FILE, tar_members))
247+
if md5sums_file_member:
248+
md5sums_file = tar.extractfile(md5sums_file_member[0])
249+
md5sums = md5sums_file.read()
250+
destination_file = os.path.join(TarFile.DPKG_STATUS_DIR, '{0}.md5sums'.format(pkg_name))
251+
with self.write_temp_file(data=md5sums) as files_list:
252+
self.add_file(files_list, destination_file)
253+
237254
except (KeyError, TypeError) as e:
238-
raise self.DebError(deb + ' contains invalid Metadata! Exeception {0}'.format(e))
255+
raise self.DebError(deb + ' contains invalid Metadata! Exception {0}'.format(e))
239256
except Exception as e:
240257
raise self.DebError('Unknown Exception {0}. Please report an issue at'
241258
' github.com/bazelbuild/rules_docker.'.format(e))
@@ -473,9 +490,9 @@ def validate_link(l):
473490
parser.add_argument('--xz_path', type=str,
474491
help='Specify the path to xz as a fallback when the Python '
475492
'lzma module is unavailable.')
476-
493+
477494
parser.add_argument('--force_posixpath', type=bool, default=False,
478-
help='Force the use of posixpath when normalizing file paths. This is useful'
495+
help='Force the use of posixpath when normalizing file paths. This is useful'
479496
'when building in a non-posix environment.')
480497

481498
main(parser.parse_args())

tests/container/build_tar_test.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,44 @@ def testPkgMetadataStatusFileName(self):
8484

8585
self.assertIn('./var/lib/dpkg/status.d/test', contained_names)
8686

87-
8887
def testPackageNameParserInvalidMetadata(self):
8988
metadata = "Package Name: Invalid"
9089
self.assertEqual('test-invalid-pkg',
9190
TarFile.parse_pkg_name(metadata, "some/path/test-invalid-pkg.deb"))
9291

92+
def testPkgMetadataMd5sumsFileName(self):
93+
metadata = """Package: test
94+
Description: Dummy
95+
Version: 1.2.4
96+
"""
97+
md5sums ="""4006d28dbf6dfbe2c0fe695839e64cb3 usr/lib/python3/dist-packages/docutils/languages/cs.py
98+
"""
99+
with tempfile.TemporaryDirectory() as tmp:
100+
# write control file into a metadata tar
101+
control_file_name = path.join(tmp, "control")
102+
with open(control_file_name, "w") as control_file:
103+
control_file.write(metadata)
104+
# write md5sums file into a metadata tar
105+
md5sums_file_name = path.join(tmp, "md5sums")
106+
with open(md5sums_file_name, "w") as md5sums_file:
107+
md5sums_file.write(md5sums)
108+
metadata_tar_file_name = path.join(tmp, "metadata.tar")
109+
110+
with tarfile.open(metadata_tar_file_name, "w") as metadata_tar_file:
111+
metadata_tar_file.add(control_file_name, arcname="control")
112+
metadata_tar_file.add(md5sums_file_name, arcname="md5sums")
113+
114+
output_file_name = path.join(tmp, "output.tar")
115+
with TarFile(output_file_name, directory="/", compression=None, root_directory="./", default_mtime=None,
116+
enable_mtime_preservation=False, xz_path="", force_posixpath=False) as output_file:
117+
output_file.add_pkg_metadata(metadata_tar_file_name, "ignored.deb")
118+
119+
with tarfile.open(output_file_name) as output_file:
120+
contained_names = output_file.getnames()
121+
122+
self.assertIn('./var/lib/dpkg/status.d/test', contained_names)
123+
self.assertIn('./var/lib/dpkg/status.d/test.md5sums', contained_names)
124+
93125

94126
if __name__ == '__main__':
95127
unittest.main()

0 commit comments

Comments
 (0)