Files
archy/scripts/test-build-iso-fips-package.py
T

109 lines
4.2 KiB
Python

#!/usr/bin/env python3
"""Focused refusal and preservation checks for the ISO FIPS derivative."""
import importlib.util
import io
import hashlib
from pathlib import Path
import sys
import tarfile
import tempfile
import unittest
SOURCE = Path(__file__).with_name("build-iso-fips-package.py")
spec = importlib.util.spec_from_file_location("iso_fips_package", SOURCE)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
def tar(members):
buffer = io.BytesIO()
with tarfile.open(fileobj=buffer, mode="w:xz") as archive:
for name, content in members:
entry = tarfile.TarInfo("./" + name)
entry.mode = 0o644
entry.uid = entry.gid = 0
entry.size = len(content)
archive.addfile(entry, io.BytesIO(content))
return buffer.getvalue()
def fixture(*, version="0.4.1-1", nft=True, declared=True, md5sums=False):
controls = [
("control", f"Package: fips\nVersion: {version}\nArchitecture: amd64\n".encode()),
("conffiles", b"/etc/fips/hosts\n" + (b"/etc/fips/fips.nft\n" if declared else b"")),
("postinst", b"#!/bin/sh\nexit 0\n"),
]
if md5sums:
controls.append(("md5sums", b"deadbeef etc/fips/fips.nft\n"))
data = [("etc/fips/hosts", b"hosts\n")]
if nft:
data.append(("etc/fips/fips.nft", b"old nft\n"))
return module.write_ar([
("debian-binary", b"2.0\n"),
("control.tar.xz", tar(controls)),
("data.tar.xz", tar(data)),
])
class DerivativeTest(unittest.TestCase):
def test_only_declared_changes(self):
result, receipt = module.derive(fixture())
members = module.read_ar(result)
controls = dict((module.normalized(item.name), content)
for item, content in module.tar_items(members[1][1]))
data = dict((module.normalized(item.name), content)
for item, content in module.tar_items(members[2][1]))
self.assertIn(b"Version: 0.4.1-1+archy.iso1", controls["control"])
self.assertEqual(controls["conffiles"], b"/etc/fips/hosts\n")
self.assertEqual(controls["postinst"], b"#!/bin/sh\nexit 0\n")
self.assertEqual(data, {"etc/fips/hosts": b"hosts\n"})
self.assertEqual(receipt["unchanged_data_members"], 1)
def test_missing_file_refused(self):
with self.assertRaisesRegex(ValueError, "default fips.nft"):
module.derive(fixture(nft=False))
def test_missing_conffile_refused(self):
with self.assertRaisesRegex(ValueError, "conffile declaration"):
module.derive(fixture(declared=False))
def test_unreviewed_version_refused(self):
with self.assertRaisesRegex(ValueError, "package version"):
module.derive(fixture(version="0.5.3"))
def test_unreviewed_md5sums_refused(self):
with self.assertRaisesRegex(ValueError, "md5sums"):
module.derive(fixture(md5sums=True))
def test_reviewed_handoff_version(self):
_, receipt = module.derive(
fixture(version="0.5.3+archy.handoff1"),
"0.5.3+archy.handoff1", "0.5.3+archy.handoff1.iso1")
self.assertEqual(receipt["new_version"], "0.5.3+archy.handoff1.iso1")
def test_dangling_output_symlink_refused(self):
package = fixture()
digest = hashlib.sha256(package).hexdigest()
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
source, output, receipt = root / "source.deb", root / "output.deb", root / "receipt.json"
source.write_bytes(package)
output.symlink_to(root / "missing")
old_argv = sys.argv
module.REVIEWED_INPUTS[digest] = ("0.4.1-1", "0.4.1-1+archy.iso1")
sys.argv = [str(SOURCE), "--input", str(source), "--expected-input-sha256", digest,
"--output", str(output), "--receipt", str(receipt)]
try:
with self.assertRaises(FileExistsError):
module.main()
finally:
sys.argv = old_argv
del module.REVIEWED_INPUTS[digest]
self.assertFalse((root / "missing").exists())
self.assertFalse(receipt.exists())
if __name__ == "__main__":
unittest.main()