def test_deb_package_contains_expected_conffiles(host: Host, deb: Path): """ Ensures the `securedrop-app-code` package declares only whitelisted `conffiles`. Several files in `/etc/` would automatically be marked conffiles, which would break unattended updates to critical package functionality such as AppArmor profiles. This test validates overrides in the build logic to unset those conffiles. """ # For the securedrop-app-code package: if deb.name.startswith("securedrop-app-code"): mktemp = host.run("mktemp -d") tmpdir = mktemp.stdout.strip() # The `--raw-extract` flag includes `DEBIAN/` dir with control files host.run("dpkg-deb --raw-extract {} {}".format(deb, tmpdir)) conffiles_path = os.path.join(tmpdir, "DEBIAN", "conffiles") f = host.file(conffiles_path) assert f.is_file # Ensure that the entirety of the file lists only the logo as conffile; # effectively ensures e.g. AppArmor profiles are not conffiles. conffiles = f.content_string.rstrip() assert conffiles == "/var/www/securedrop/static/i/logo.png" # For the securedrop-config package, we want to ensure there are no # conffiles so securedrop_additions.sh is squashed every time if deb.name.startswith("securedrop-config"): c = host.run("dpkg-deb -I {}".format(deb)) assert "conffiles" not in c.stdout
def test_build_deb_packages(host: Host, deb: Path) -> None: """ Sanity check the built Debian packages for Control field values and general package structure. """ deb_package = host.file(str(deb)) assert deb_package.is_file
def test_system_time(host: Host) -> None: if host.system_info.codename == "xenial": assert host.package("ntp").is_installed assert host.package("ntpdate").is_installed # TODO: The staging setup timing is too erratic for the # following check. If we do want to reinstate it before # dropping Xenial support, it should be done in a loop to give # ntpd time to sync after the machines are created. # c = host.run("ntpq -c rv") # assert "leap_none" in c.stdout # assert "sync_ntp" in c.stdout # assert "refid" in c.stdout else: assert not host.package("ntp").is_installed assert not host.package("ntpdate").is_installed s = host.service("systemd-timesyncd") assert s.is_running assert s.is_enabled assert not s.is_masked # File will be touched on every successful synchronization, # see 'man systemd-timesyncd'` assert host.file("/run/systemd/timesync/synchronized").exists c = host.run("timedatectl show") assert "NTP=yes" in c.stdout assert "NTPSynchronized=yes" in c.stdout
def resolve_symlink(host: Host, file_: Union[str, GNUFile], resolve_depth: int = 20) -> str: """ Resolve symlink until actual file or fail in case if symlink is broken. Parameters ---------- host: Host file_: str | GNUFile Input symlink to resolve resolve_depth: int The depth of symlink resolution (failsafe if symlink is circular) Returns ------- GNUFile Path to the resolved file """ resolve_items = [] if isinstance(file_, GNUFile): initial_file = file_.path new_file = file_ else: initial_file = file_ new_file = host.file(file_) while new_file.exists and new_file.is_symlink and resolve_depth > 0: new_path = new_file.linked_to resolve_items.append(f'{new_file.path} is linked to {new_path}') new_file = host.file(new_path) if not new_file.is_symlink: return new_file.path resolve_depth -= 1 resolve_out = '\n'.join(resolve_items) raise ValueError(f'Broken or circular symlink found: {initial_file}\n' f'Full resolution output:\n{resolve_out}')
def test_system_time(host: Host) -> None: assert not host.package("ntp").is_installed assert not host.package("ntpdate").is_installed s = host.service("systemd-timesyncd") assert s.is_running assert s.is_enabled assert not s.is_masked # File will be touched on every successful synchronization, # see 'man systemd-timesyncd'` assert host.file("/run/systemd/timesync/synchronized").exists c = host.run("timedatectl show") assert "NTP=yes" in c.stdout assert "NTPSynchronized=yes" in c.stdout
def test_default_command(host: Host) -> None: f = host.file("/usr/bin/git") assert f.is_file