diff --git a/Makefile b/Makefile index 666b42cd07..c6a524b4c4 100644 --- a/Makefile +++ b/Makefile @@ -318,23 +318,28 @@ update-user-guides: ## Run the page layout tests to regenerate screenshots. ########### .PHONY: build-debs -build-debs: ## Build and test SecureDrop Debian packages. - @echo "Building SecureDrop Debian packages..." +build-debs: ## Build and test SecureDrop Debian packages (for Xenial) + @echo "Building SecureDrop Debian packages for Xenial..." @$(SDROOT)/devops/scripts/build-debs.sh @echo .PHONY: build-debs-notest -build-debs-notest: ## Build SecureDrop Debian packages without running tests. - @echo "Building SecureDrop Debian packages; skipping tests..." +build-debs-notest: ## Build SecureDrop Debian packages (for Xenial) without running tests. + @echo "Building SecureDrop Debian packages for Xenial; skipping tests..." @$(SDROOT)/devops/scripts/build-debs.sh notest @echo .PHONY: build-debs-focal -build-debs-focal: ## Build and test SecureDrop Debian packages. - @echo "Building SecureDrop Debian packages..." - @$(SDROOT)/devops/scripts/build-debs.sh notest focal +build-debs-focal: ## Build and test SecureDrop Debian packages (for Focal) + @echo "Building SecureDrop Debian packages for Focal..." + @$(SDROOT)/devops/scripts/build-debs.sh test focal @echo +.PHONY: build-debs-notest-focal +build-debs-notest-focal: ## Build SecureDrop Debian packages (for Focal) without running tests. + @echo "Building SecureDrop Debian packages for Focal; skipping tests..." + @$(SDROOT)/devops/scripts/build-debs.sh notest focal + @echo ######################## diff --git a/install_files/ansible-base/roles/build-ossec-deb-pkg/defaults/main.yml b/install_files/ansible-base/roles/build-ossec-deb-pkg/defaults/main.yml index 16f545fd96..b8cb5ad7e0 100644 --- a/install_files/ansible-base/roles/build-ossec-deb-pkg/defaults/main.yml +++ b/install_files/ansible-base/roles/build-ossec-deb-pkg/defaults/main.yml @@ -1,5 +1,7 @@ --- -build_ossec_deb_pkg_dependencies: ['libevent1-dev','libpcre2-dev'] +build_ossec_deb_pkg_dependencies: + - "libpcre2-dev" + - "{{ 'libevent-dev' if securedrop_build_focal_support else 'libevent1-dev' }}" ossec_server_hostname: ossec-server ossec_version: 3.6.0 @@ -23,3 +25,8 @@ ossec_build_rsync_ansible_hack_opt: - "--rsync-path='sudo rsync'" ossec_source_checksum: sha256:653828a19137b8a7e98af65e873318f7bb48137fe1e61b80577e13c316e04708 + +# Default is xenial. +securedrop_build_focal_support: False +securedrop_package_dist: "{{ 'focal' if securedrop_build_focal_support else 'xenial' }}" + diff --git a/install_files/securedrop-ossec-agent/DEBIAN/control b/install_files/ansible-base/roles/build-ossec-deb-pkg/files/control-focal similarity index 100% rename from install_files/securedrop-ossec-agent/DEBIAN/control rename to install_files/ansible-base/roles/build-ossec-deb-pkg/files/control-focal diff --git a/install_files/ansible-base/roles/build-ossec-deb-pkg/templates/agent_control.j2 b/install_files/ansible-base/roles/build-ossec-deb-pkg/templates/agent_control.j2 index 920f04d0e3..37de46b302 100644 --- a/install_files/ansible-base/roles/build-ossec-deb-pkg/templates/agent_control.j2 +++ b/install_files/ansible-base/roles/build-ossec-deb-pkg/templates/agent_control.j2 @@ -6,6 +6,10 @@ Homepage: http://ossec.net Package: ossec-agent Version: {{ ossec_version }} Architecture: amd64 +{% if securedrop_build_focal_support %} +Depends: libc6,libssl1.1,expect,inotify-tools,adduser +{% else %} Depends: libc6,libssl1.0.0,expect,inotify-tools,adduser +{% endif %} Conflicts: ossec-server Description: Installs the generic ossec agent diff --git a/install_files/ansible-base/roles/build-ossec-deb-pkg/templates/server_control.j2 b/install_files/ansible-base/roles/build-ossec-deb-pkg/templates/server_control.j2 index 58253f7c32..6b98c87ef7 100644 --- a/install_files/ansible-base/roles/build-ossec-deb-pkg/templates/server_control.j2 +++ b/install_files/ansible-base/roles/build-ossec-deb-pkg/templates/server_control.j2 @@ -6,6 +6,10 @@ Homepage: http://ossec.net Package: ossec-server Version: {{ ossec_version }} Architecture: amd64 +{% if securedrop_build_focal_support %} +Depends: libc6 (>=2.7),libssl1.1,adduser,expect,inotify-tools +{% else %} Depends: libc6,libssl1.0.0,adduser,expect,libc6 (>= 2.7),inotify-tools +{% endif %} Conflicts: ossec-agent Description: Installs generic OSSEC server diff --git a/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/defaults/main.yml b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/defaults/main.yml index 23fb2cb720..c00ce97484 100644 --- a/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/defaults/main.yml +++ b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/defaults/main.yml @@ -8,11 +8,6 @@ securedrop_code_filtered: "{{ securedrop_app_code_prep_dir }}/var/www/securedrop securedrop_pip_requirements: "{{ securedrop_code_filtered }}/requirements/python3/securedrop-app-code-requirements.txt" -# SecureDrop virtualenv location -securedrop_venv: "/opt/venvs/securedrop-app-code" -securedrop_venv_bin: "{{ securedrop_venv }}/bin" -securedrop_venv_site_packages: "{{ securedrop_venv }}/lib/python3.5/site-packages" - # SecureDrop code installation directory securedrop_code: /var/www/securedrop @@ -45,4 +40,16 @@ securedrop_app_rsync_opts: securedrop_local_build: "../../build" -securedrop_package_dist: xenial +# Default is xenial. +securedrop_build_focal_support: False +securedrop_package_dist: "{{ 'focal' if securedrop_build_focal_support else 'xenial' }}" + +# SecureDrop virtualenv location +securedrop_venv: "/opt/venvs/securedrop-app-code" +securedrop_venv_bin: "{{ securedrop_venv }}/bin" +securedrop_python_version: "{{ '3.8' if securedrop_build_focal_support else '3.5' }}" +securedrop_venv_site_packages: "{{ securedrop_venv }}/lib/python{{ securedrop_python_version }}/site-packages" + +securedrop_app_focal_files: + - src: securedrop-app-code.triggers-focal + dest: "{{ securedrop_app_code_prep_dir }}/debian/securedrop-app-code.triggers" diff --git a/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/changelog-focal b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/changelog-focal new file mode 100644 index 0000000000..7459a02977 --- /dev/null +++ b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/changelog-focal @@ -0,0 +1,5 @@ +securedrop-app-code (1.6.0~rc1+focal) focal; urgency=medium + + * + + -- SecureDrop Team Thu, 18 Jun 2020 21:58:23 +0000 diff --git a/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/securedrop-app-code.triggers-focal b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/securedrop-app-code.triggers-focal new file mode 100644 index 0000000000..8962f21aa5 --- /dev/null +++ b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/securedrop-app-code.triggers-focal @@ -0,0 +1,7 @@ +# Register interest in Python interpreter changes; and +# don't make the Python package dependent on the virtualenv package +# processing (noawait) +interest-noawait /usr/bin/python3.8 + +# Also provide a symbolic trigger for all dh-virtualenv packages +interest dh-virtualenv-interpreter-update diff --git a/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/usr.sbin.apache2 b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/usr.sbin.apache2 index 90a7796566..897a3266f3 100644 --- a/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/usr.sbin.apache2 +++ b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/files/usr.sbin.apache2 @@ -70,6 +70,7 @@ /etc/magic r, /etc/mime.types r, /etc/python3.5/sitecustomize.py r, + /etc/python3.8/sitecustomize.py r, /etc/services r, /etc/timezone r, /lib/x86_64-linux-gnu/libbz2.so.* mr, @@ -87,6 +88,7 @@ /run/apache2/wsgi.*.sock rw, /run/lock/apache2/rewrite-map.* rw, /run/lock/apache2/ssl-cache.* rwk, + /run/systemd/userdb/io.systemd.DynamicUser r, /run/shm rw, /sbin/ldconfig rix, /sbin/ldconfig.real rix, @@ -107,6 +109,9 @@ /opt/venvs/securedrop-app-code/bin/python3 r, /opt/venvs/securedrop-app-code/lib/python3.5/ r, /opt/venvs/securedrop-app-code/lib/python3.5/** rm, + /opt/venvs/securedrop-app-code/lib/python3.8/ r, + /opt/venvs/securedrop-app-code/lib/python3.8/** rm, + /opt/venvs/securedrop-app-code/pyvenv.cfg r, /var/lib/securedrop/ r, /var/lib/securedrop/db.sqlite kw, /var/lib/securedrop/db.sqlite rwk, diff --git a/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/tasks/main.yml b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/tasks/main.yml index 184ffe9b68..c1a5ba7f37 100644 --- a/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/tasks/main.yml +++ b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/tasks/main.yml @@ -57,6 +57,18 @@ src: "changelog-{{ securedrop_package_dist }}" dest: "{{ securedrop_app_code_prep_dir }}/debian/changelog" +- name: Replace the files required for focal package + copy: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + with_items: "{{ securedrop_app_focal_files }}" + when: securedrop_build_focal_support + +- name: Create the control file based on distribution + template: + src: "control.j2" + dest: "{{ securedrop_app_code_prep_dir }}/debian/control" + - name: Create lib/systemd/services directory in prep directory file: state: directory @@ -107,7 +119,7 @@ environment: DH_PIP_EXTRA_ARGS: "--verbose --ignore-installed --no-deps --no-binary=:all: --no-cache-dir" DH_UPGRADE_SETUPTOOLS: "46.0.0" - DH_VIRTUALENV_ARGUMENTS: "--python=/usr/bin/python3.5 --setuptools" + DH_VIRTUALENV_ARGUMENTS: "{{ '--python=/usr/bin/python3.8 --setuptools 46.0.0' if securedrop_build_focal_support else '--python=/usr/bin/python3.5 --setuptools' }}" DH_VIRTUALENV_INSTALL_ROOT: "/opt/venvs" - name: Find newly built Debian package diff --git a/install_files/securedrop-app-code/debian/control b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/templates/control.j2 similarity index 74% rename from install_files/securedrop-app-code/debian/control rename to install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/templates/control.j2 index 07d1ea6274..5c264cf9a9 100644 --- a/install_files/securedrop-app-code/debian/control +++ b/install_files/ansible-base/roles/build-securedrop-app-code-deb-pkg/templates/control.j2 @@ -5,11 +5,14 @@ Maintainer: SecureDrop Team Homepage: https://securedrop.org Build-Depends: debhelper (>= 9), dh-python, python3-all, python3-setuptools, dh-systemd, dh-virtualenv Standards-Version: 3.9.8 -X-Python3-Version: >= 3.5 Package: securedrop-app-code Architecture: amd64 Conflicts: libapache2-mod-wsgi,supervisor Replaces: libapache2-mod-wsgi,supervisor +{% if securedrop_build_focal_support %} +Depends: ${dist:Depends}, ${misc:Depends}, ${python3:Depends}, apache2, apparmor-utils, coreutils, gnupg2, haveged, libapache2-mod-xsendfile, libpython3.8, paxctld, python3, redis-server, securedrop-config, securedrop-keyring, sqlite3 +{% else %} Depends: ${dist:Depends}, ${misc:Depends}, ${python3:Depends}, apache2, apparmor-utils, coreutils, gnupg2, haveged, libapache2-mod-xsendfile, libpython3.5, paxctld, python3 (>= 3.5), python3 (<< 3.6), redis-server, securedrop-config, securedrop-keyring, sqlite3 +{% endif %} Description: SecureDrop application code, dependencies, Apache configuration, systemd services, and AppArmor profiles. This package will put the AppArmor profiles in enforce mode. diff --git a/install_files/securedrop-ossec-agent/DEBIAN/control.j2 b/install_files/securedrop-ossec-agent/DEBIAN/control.j2 new file mode 100644 index 0000000000..47a577c9ae --- /dev/null +++ b/install_files/securedrop-ossec-agent/DEBIAN/control.j2 @@ -0,0 +1,18 @@ +Source: ossec.net +Section: web +Priority: optional +Maintainer: SecureDrop Team +Homepage: https://securedrop.org +Package: securedrop-ossec-agent +Version: 3.6.0+1.6.0~rc1 +Architecture: amd64 +{% if securedrop_build_focal_support %} +Depends: libevent-2.1.7,libpcre2-8-0,ossec-agent,securedrop-keyring,securedrop-config +{% else %} +Depends: libevent-1.4-2,libpcre2-8-0,ossec-agent,securedrop-keyring,securedrop-config +{% endif %} +Replaces: ossec-agent +Conflicts: securedrop-ossec-server +Description: Installs the securedrop pre-configured OSSEC agent + This package installs an OSSEC agent pre-configured for the + SecureDrop app server. diff --git a/install_files/securedrop-ossec-server/DEBIAN/control b/install_files/securedrop-ossec-server/DEBIAN/control.j2 similarity index 82% rename from install_files/securedrop-ossec-server/DEBIAN/control rename to install_files/securedrop-ossec-server/DEBIAN/control.j2 index 9efe3420b0..b21053159d 100644 --- a/install_files/securedrop-ossec-server/DEBIAN/control +++ b/install_files/securedrop-ossec-server/DEBIAN/control.j2 @@ -6,7 +6,11 @@ Homepage: https://securedrop.org Package: securedrop-ossec-server Version: 3.6.0+1.6.0~rc1 Architecture: amd64 +{% if securedrop_build_focal_support %} +Depends: libevent-2.1.7,libpcre2-8-0,ossec-server,securedrop-keyring,securedrop-config +{% else %} Depends: libevent-1.4-2,libpcre2-8-0,ossec-server,securedrop-keyring,securedrop-config +{% endif %} Replaces: ossec-server Conflicts: securedrop-ossec-agent Description: Installs the pre-packaged OSSEC server diff --git a/molecule/builder-focal/molecule.yml b/molecule/builder-focal/molecule.yml index fb3b221a17..80809ce8b1 100644 --- a/molecule/builder-focal/molecule.yml +++ b/molecule/builder-focal/molecule.yml @@ -74,6 +74,8 @@ verifier: n: auto env: SECUREDROP_TARGET_PLATFORM: focal - directory: tests/ + SECUREDROP_PYTHON_VERSION: "3.8" + # Reuse the same test suite for all packages + directory: ../builder-xenial/tests/ lint: name: flake8 diff --git a/molecule/builder-focal/tests/conftest.py b/molecule/builder-focal/tests/conftest.py deleted file mode 100644 index da01aa9600..0000000000 --- a/molecule/builder-focal/tests/conftest.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Import variables from vars.yml and inject into pytest namespace -""" - -import os -import io -import yaml - - -def pytest_namespace(): - """ Return dict of vars imported as 'securedrop_test_vars' into pytest - global namespace - """ - filepath = os.path.join(os.path.dirname(__file__), "vars.yml") - with io.open(filepath, 'r') as f: - securedrop_test_vars = yaml.safe_load(f) - - # Tack on target OS for use in tests - securedrop_target_platform = os.environ.get("SECUREDROP_TARGET_PLATFORM") - securedrop_test_vars["securedrop_target_platform"] = securedrop_target_platform - # Wrapping the return value to accommodate for pytest namespacing - return dict(securedrop_test_vars=securedrop_test_vars) diff --git a/molecule/builder-focal/tests/test_build_dependencies.py b/molecule/builder-focal/tests/test_build_dependencies.py deleted file mode 100644 index 6cfce29ba3..0000000000 --- a/molecule/builder-focal/tests/test_build_dependencies.py +++ /dev/null @@ -1,40 +0,0 @@ -import pytest -import os - - -SECUREDROP_TARGET_PLATFORM = os.environ.get("SECUREDROP_TARGET_PLATFORM") -testinfra_hosts = [ - "docker://{}-sd-app".format(SECUREDROP_TARGET_PLATFORM) -] - - -def test_sass_gem_installed(host): - """ - Ensure the `sass` Ruby gem is installed, for compiling SASS to CSS. - """ - c = host.run("gem list") - assert "sass (3.4.23)" in c.stdout - assert c.rc == 0 - - -def test_pip_dependencies_installed(host): - """ - Ensure the development pip dependencies are installed - """ - c = host.run("pip3 list installed") - assert "Flask-Babel" in c.stdout - assert c.rc == 0 - - -@pytest.mark.xfail(reason="This check conflicts with the concept of pegging" - "dependencies") -def test_build_all_packages_updated(host): - """ - Ensure a dist-upgrade has already been run, by checking that no - packages are eligible for upgrade currently. This will ensure that - all upgrades, security and otherwise, have been applied to the VM - used to build packages. - """ - c = host.run('aptitude --simulate -y dist-upgrade') - assert c.rc == 0 - assert "No packages will be installed, upgraded, or removed." in c.stdout diff --git a/molecule/builder-focal/tests/test_legacy_paths.py b/molecule/builder-focal/tests/test_legacy_paths.py deleted file mode 100644 index 8b02df9171..0000000000 --- a/molecule/builder-focal/tests/test_legacy_paths.py +++ /dev/null @@ -1,20 +0,0 @@ -import pytest - - -@pytest.mark.parametrize('build_path', [ - '/tmp/build-', - '/tmp/rsync-filter', - '/tmp/src_install_files', - '/tmp/build-securedrop-keyring', - '/tmp/build-securedrop-ossec-agent', - '/tmp/build-securedrop-ossec-server', -]) -def test_build_ossec_apt_dependencies(host, build_path): - """ - Ensure that unwanted build paths are absent. Most of these were created - as unwanted side-effects during CI-related changes to the build scripts. - - All paths are rightly considered "legacy" and should never be present on - the build host. This test is strictly for guarding against regressions. - """ - assert not host.file(build_path).exists diff --git a/molecule/builder-focal/tests/test_securedrop_deb_package.py b/molecule/builder-focal/tests/test_securedrop_deb_package.py deleted file mode 100644 index 0f88c24b78..0000000000 --- a/molecule/builder-focal/tests/test_securedrop_deb_package.py +++ /dev/null @@ -1,484 +0,0 @@ -import pytest -import os -import re -import tempfile - - -SECUREDROP_TARGET_PLATFORM = os.environ.get("SECUREDROP_TARGET_PLATFORM") -testinfra_hosts = [ - "docker://{}-sd-dpkg-verification".format(SECUREDROP_TARGET_PLATFORM) -] -securedrop_test_vars = pytest.securedrop_test_vars - - -def extract_package_name_from_filepath(filepath): - """ - Helper function to infer intended package name from - the absolute filepath, using a rather garish regex. - E.g., given: - securedrop-ossec-agent-2.8.2+0.3.10-amd64.deb - - retuns: - - securedrop-ossec-agent - - which can then be used for comparisons in dpkg output. - """ - deb_basename = os.path.basename(filepath) - package_name = re.search(r'^([a-z\-]+(?!\d))', deb_basename).groups()[0] - assert deb_basename.startswith(package_name) - return package_name - - -def get_deb_packages(): - """ - Helper function to retrieve module-namespace test vars and format - the strings to interpolate version info. Keeps the test vars DRY - in terms of version info, and required since we can't rely on - Jinja-based evaluation of the YAML files (so we can't trivially - reuse vars in other var values, as is the case with Ansible). - """ - substitutions = dict( - securedrop_version=securedrop_test_vars.securedrop_version, - ossec_version=securedrop_test_vars.ossec_version, - keyring_version=securedrop_test_vars.keyring_version, - config_version=securedrop_test_vars.config_version, - grsec_version=securedrop_test_vars.grsec_version, - securedrop_target_platform=securedrop_test_vars.securedrop_target_platform, - ) - - deb_packages = [d.format(**substitutions) for d - in securedrop_test_vars.build_deb_packages] - return deb_packages - - -deb_packages = get_deb_packages() - - -def get_deb_tags(): - """ - Helper function to build array of package and tag tuples - for lintian. - """ - deb_tags = [] - - for deb in get_deb_packages(): - for tag in securedrop_test_vars.lintian_tags: - deb_tags.append((deb, tag)) - - return deb_tags - - -deb_tags = get_deb_tags() - - -@pytest.mark.parametrize("deb", deb_packages) -def test_build_deb_packages(host, deb): - """ - Sanity check the built Debian packages for Control field - values and general package structure. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - assert deb_package.is_file - - -@pytest.mark.parametrize("deb", deb_packages) -def test_deb_packages_appear_installable(host, deb): - """ - Confirms that a dry-run of installation reports no errors. - Simple check for valid Debian package structure, but not thorough. - When run on a malformed package, `dpkg` will report: - - dpkg-deb: error: `foo.deb' is not a debian format archive - - Testing application behavior is left to the functional tests. - """ - - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - - deb_basename = os.path.basename(deb_package.path) - package_name = extract_package_name_from_filepath(deb_package.path) - assert deb_basename.startswith(package_name) - - # sudo is required to call `dpkg --install`, even as dry-run. - with host.sudo(): - c = host.run("dpkg --install --dry-run {}".format(deb_package.path)) - assert "Selecting previously unselected package {}".format( - package_name) in c.stdout - regex = "Preparing to unpack [./]+{} ...".format( - re.escape(deb_basename)) - assert re.search(regex, c.stdout, re.M) - assert c.rc == 0 - - -@pytest.mark.parametrize("deb", deb_packages) -def test_deb_package_control_fields(host, deb): - """ - Ensure Debian Control fields are populated as expected in the package. - These checks are rather superficial, and don't actually confirm that the - .deb files are not broken. At a later date, consider integration tests - that actually use these built files during an Ansible provisioning run. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - package_name = extract_package_name_from_filepath(deb_package.path) - # The `--field` option will display all fields if none are specified. - c = host.run("dpkg-deb --field {}".format(deb_package.path)) - - assert "Maintainer: SecureDrop Team " in c.stdout - # The securedrop-config package is architecture indepedent - if package_name == "securedrop-config": - assert "Architecture: all" in c.stdout - else: - assert "Architecture: amd64" in c.stdout - - assert "Package: {}".format(package_name) in c.stdout - assert c.rc == 0 - - -@pytest.mark.parametrize("deb", deb_packages) -def test_deb_package_control_fields_homepage(host, deb): - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - # The `--field` option will display all fields if none are specified. - c = host.run("dpkg-deb --field {}".format(deb_package.path)) - # The OSSEC source packages will have a different homepage; - # all other packages should set securedrop.org as homepage. - if os.path.basename(deb_package.path).startswith('ossec-'): - assert "Homepage: http://ossec.net" in c.stdout - else: - assert "Homepage: https://securedrop.org" in c.stdout - - -@pytest.mark.parametrize("deb", deb_packages) -def test_deb_package_contains_no_config_file(host, deb): - """ - Ensures the `securedrop-app-code` package does not ship a `config.py` - file. Doing so would clobber the site-specific changes made via Ansible. - - Somewhat lazily checking all deb packages, rather than just the app-code - package, but it accomplishes the same in a DRY manner. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - c = host.run("dpkg-deb --contents {}".format(deb_package.path)) - assert not re.search(r"^ ./var/www/securedrop/config.py$", c.stdout, re.M) - - -@pytest.mark.parametrize("deb", deb_packages) -def test_deb_package_contains_pot_file(host, deb): - """ - Ensures the `securedrop-app-code` package has the - messages.pot file - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - c = host.run("dpkg-deb --contents {}".format(deb_package.path)) - # Only relevant for the securedrop-app-code package: - if "securedrop-app-code" in deb_package.path: - assert re.search("^.*messages.pot$", c.stdout, re.M) - - -@pytest.mark.parametrize("deb", deb_packages) -def test_deb_package_contains_mo_file(host, deb): - """ - Ensures the `securedrop-app-code` package has at least one - compiled mo file. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - c = host.run("dpkg-deb --contents {}".format(deb_package.path)) - # Only relevant for the securedrop-app-code package: - if "securedrop-app-code" in deb_package.path: - assert re.search(r"^.*messages\.mo$", c.stdout, re.M) - - -@pytest.mark.parametrize("deb", deb_packages) -def test_deb_package_contains_no_generated_assets(host, deb): - """ - Ensures the `securedrop-app-code` package does not ship minified - static assets, which are built automatically via Flask-Assets, and - may be present in the source directory used to build from. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - - # Only relevant for the securedrop-app-code package: - if "securedrop-app-code" in deb_package.path: - c = host.run("dpkg-deb --contents {}".format(deb_package.path)) - # static/gen/ directory should exist - assert re.search(r"^.*\./var/www/securedrop" - "/static/gen/$", c.stdout, re.M) - # static/gen/ directory should be empty - assert not re.search(r"^.*\./var/www/securedrop" - "/static/gen/.+$", c.stdout, re.M) - - # static/.webassets-cache/ directory should exist - assert re.search(r"^.*\./var/www/securedrop" - "/static/.webassets-cache/$", c.stdout, re.M) - # static/.webassets-cache/ directory should be empty - assert not re.search(r"^.*\./var/www/securedrop" - "/static/.webassets-cache/.+$", c.stdout, re.M) - - # no SASS files should exist; only the generated CSS files. - assert not re.search("^.*sass$", c.stdout, re.M) - - # no .map files should exist; only the generated CSS files. - assert not re.search("^.*css.map$", c.stdout, re.M) - - -@pytest.mark.parametrize("deb", deb_packages) -def test_deb_package_contains_expected_conffiles(host, deb): - """ - 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. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - - # For the securedrop-app-code package: - if "securedrop-app-code" in deb_package.path: - tmpdir = tempfile.mkdtemp() - # 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 "securedrop-config" in deb_package.path: - c = host.run("dpkg-deb -I {}".format(deb)) - assert "conffiles" not in c.stdout - - -@pytest.mark.parametrize("deb", deb_packages) -def test_deb_package_contains_css(host, deb): - """ - Ensures the `securedrop-app-code` package contains files that - are generated during the `sass` build process. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - - # Only relevant for the securedrop-app-code package: - if "securedrop-app-code" in deb_package.path: - c = host.run("dpkg-deb --contents {}".format(deb_package.path)) - - for css_type in ['journalist', 'source']: - assert re.search(r"^.*\./var/www/securedrop/static/" - "css/{}.css$".format(css_type), c.stdout, re.M) - - -@pytest.mark.parametrize("deb, tag", deb_tags) -def test_deb_package_lintian(host, deb, tag): - """ - Ensures lintian likes our Debian packages. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - c = host.run("lintian --tags {} --no-tag-display-limit {}".format( - tag, deb_package.path)) - assert len(c.stdout) == 0 - - -@pytest.mark.parametrize("deb", deb_packages) -def test_deb_app_package_contains_https_validate_dir(host, deb): - """ - Ensures the `securedrop-app-code` package ships with a validation - '.well-known/pki-validation' directory - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - - # Only relevant for the securedrop-app-code package: - if "securedrop-app-code" in deb_package.path: - c = host.run("dpkg-deb --contents {}".format(deb_package.path)) - # well-known/pki-validation directory should exist - assert re.search(r"^.*\./var/www/securedrop/" - ".well-known/pki-validation/$", c.stdout, re.M) - - -@pytest.mark.parametrize("deb", deb_packages) -def test_grsec_metapackage(host, deb): - """ - Sanity checks on the securedrop-grsec metapackage. Mostly checks - for presence of PaX flags hook and sysctl settings. - Does not validate file contents, just presence. - """ - - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - - if "securedrop-grsec" in deb_package.path: - c = host.run("dpkg-deb --contents {}".format(deb_package.path)) - # Custom sysctl options should be present - assert re.search(r"^.*\./etc/sysctl.d/30-securedrop.conf$", - c.stdout, re.M) - c = host.run("dpkg-deb --contents {}".format(deb_package.path)) - # Post-install kernel hook for managing PaX flags must exist. - assert re.search(r"^.*\./etc/kernel/postinst.d/paxctl-grub$", - c.stdout, re.M) - - -@pytest.mark.parametrize("deb", deb_packages) -def test_control_helper_files_are_present(host, deb): - """ - Inspect the package info to get a list of helper scripts - that should be shipped with the package, e.g. postinst, prerm, etc. - Necessary due to package build logic retooling. - - Example output from package info, for reference: - - $ dpkg-deb --info securedrop-app-code_0.12.0~rc1_amd64.deb - new debian package, version 2.0. - size 13583186 bytes: control archive=11713 bytes. - 62 bytes, 2 lines conffiles - 657 bytes, 10 lines control - 26076 bytes, 298 lines md5sums - 5503 bytes, 159 lines * postinst #!/bin/bash - - Note that the actual output will have trailing whitespace, removed - from this text description to satisfy linters. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - # Only relevant for the securedrop-app-code package: - if "securedrop-app-code" in deb_package.path: - wanted_files = [ - "conffiles", - "config", - "control", - "postinst", - "postrm", - "preinst", - "prerm", - "templates", - ] - c = host.run("dpkg-deb --info {}".format(deb_package.path)) - for wanted_file in wanted_files: - assert re.search(r"^\s+?\d+ bytes,\s+\d+ lines[\s*]+"+wanted_file+r"\s+.*$", - c.stdout, re.M) - - -@pytest.mark.parametrize("deb", deb_packages) -def test_jinja_files_not_present(host, deb): - """ - Make sure that jinja (.j2) files were not copied over - as-is into the debian packages. - """ - - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - - c = host.run("dpkg-deb --contents {}".format(deb_package.path)) - # There shouldn't be any files with a .j2 ending - assert not re.search(r"^.*\.j2$", c.stdout, re.M) - - -@pytest.mark.parametrize("deb", deb_packages) -def test_ossec_binaries_are_present_agent(host, deb): - """ - Inspect the package contents to ensure all ossec agent binaries are properly - included in the package. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.ossec_version)) - # Only relevant for the ossec-agent package and not securedrop-ossec-agent: - if "ossec-agent" in deb_package.path and "securedrop" not in deb_package.path: - wanted_files = [ - "/var/ossec/bin/agent-auth", - "/var/ossec/bin/ossec-syscheckd", - "/var/ossec/bin/ossec-agentd", - "/var/ossec/bin/manage_agents", - "/var/ossec/bin/ossec-control", - "/var/ossec/bin/ossec-logcollector", - "/var/ossec/bin/util.sh", - "/var/ossec/bin/ossec-execd", - ] - c = host.run("dpkg-deb -c {}".format(deb_package.path)) - for wanted_file in wanted_files: - assert wanted_file in c.stdout - - -@pytest.mark.parametrize("deb", deb_packages) -def test_ossec_binaries_are_present_server(host, deb): - """ - Inspect the package contents to ensure all ossec server binaries are properly - included in the package. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.ossec_version)) - # Only relevant for the ossec-agent package and not securedrop-ossec-agent: - if "ossec-server" in deb_package.path and "securedrop" not in deb_package.path: - wanted_files = [ - "/var/ossec/bin/ossec-maild", - "/var/ossec/bin/ossec-remoted", - "/var/ossec/bin/ossec-syscheckd", - "/var/ossec/bin/ossec-makelists", - "/var/ossec/bin/ossec-logtest", - "/var/ossec/bin/syscheck_update", - "/var/ossec/bin/ossec-reportd", - "/var/ossec/bin/ossec-agentlessd", - "/var/ossec/bin/manage_agents", - "/var/ossec/bin/rootcheck_control", - "/var/ossec/bin/ossec-control", - "/var/ossec/bin/ossec-dbd", - "/var/ossec/bin/ossec-csyslogd", - "/var/ossec/bin/ossec-regex", - "/var/ossec/bin/agent_control", - "/var/ossec/bin/ossec-monitord", - "/var/ossec/bin/clear_stats", - "/var/ossec/bin/ossec-logcollector", - "/var/ossec/bin/list_agents", - "/var/ossec/bin/verify-agent-conf", - "/var/ossec/bin/syscheck_control", - "/var/ossec/bin/util.sh", - "/var/ossec/bin/ossec-analysisd", - "/var/ossec/bin/ossec-execd", - "/var/ossec/bin/ossec-authd", - ] - c = host.run("dpkg-deb --contents {}".format(deb_package.path)) - for wanted_file in wanted_files: - assert wanted_file in c.stdout - - -@pytest.mark.parametrize("deb", deb_packages) -def test_config_package_contains_expected_files(host, deb): - """ - Inspect the package contents to ensure all config files are included in - the package. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - if "securedrop-config" in deb_package.path: - wanted_files = [ - "/etc/cron-apt/action.d/9-remove", - "/etc/profile.d/securedrop_additions.sh", - ] - c = host.run("dpkg-deb --contents {}".format(deb_package.path)) - for wanted_file in wanted_files: - assert wanted_file in c.stdout - - -@pytest.mark.parametrize("deb", deb_packages) -def test_app_package_does_not_contain_custom_logo(host, deb): - """ - Inspect the package contents to ensure custom_logo.png is not present. This - is because custom_logo.png superceeds logo.png. - """ - deb_package = host.file(deb.format( - securedrop_test_vars.securedrop_version)) - if "securedrop-app-code" in deb_package.path: - c = host.run("dpkg-deb --contents {}".format(deb_package.path)) - assert "/var/www/static/i/custom_logo.png" not in c.stdout diff --git a/molecule/builder-focal/tests/test_security_updates.py b/molecule/builder-focal/tests/test_security_updates.py deleted file mode 100644 index 654ac6b717..0000000000 --- a/molecule/builder-focal/tests/test_security_updates.py +++ /dev/null @@ -1,43 +0,0 @@ -import os -from subprocess import check_output -import re -import pytest - -SECUREDROP_TARGET_PLATFORM = os.environ.get("SECUREDROP_TARGET_PLATFORM") -testinfra_hosts = [ - "docker://{}-sd-sec-update".format(SECUREDROP_TARGET_PLATFORM) -] - - -def test_should_run(): - command = ["git", "describe", "--all"] - version = check_output(command).decode("utf8")[0:-1] - candidates = (r"(^tags/[\d]+\.[\d]+\.[\d]+-rc[\d]+)|" - r"(^tags/[\d]+\.[\d]+\.[\d]+)|" - r"(^heads/release/[\d]+\.[\d]+\.[\d]+)|" - r"(^heads/update-builder.*)") - result = re.match(candidates, version) - if result: - return True - else: - return False - - -@pytest.mark.skipif(not test_should_run(), reason="Only tested for RCs and builder updates") -def test_ensure_no_updates_avail(host): - """ - Test to make sure that there are no security-updates in the - base builder container. - """ - # Filter out all the security repos to their own file - # without this change all the package updates appeared as if they were - # coming from normal ubuntu update channel (since they get posted to both) - host.run('egrep "^deb.*security" /etc/apt/sources.list > /tmp/sec.list') - - dist_upgrade_simulate = host.run('apt-get -s dist-upgrade ' - '-oDir::Etc::Sourcelist=/tmp/sec.list ' - '|grep "^Inst" |grep -i security') - - # If the grep was successful that means security package updates found - # otherwise we get a non-zero exit code so no updates needed. - assert dist_upgrade_simulate.rc != 0 diff --git a/molecule/builder-focal/tests/vars.yml b/molecule/builder-focal/tests/vars.yml deleted file mode 100644 index 35f8932cba..0000000000 --- a/molecule/builder-focal/tests/vars.yml +++ /dev/null @@ -1,36 +0,0 @@ ---- -securedrop_version: "1.5.0~rc1" -ossec_version: "3.6.0" -keyring_version: "0.1.4" -config_version: "0.1.3" -grsec_version: "4.14.175" - -# These values will be interpolated with values populated above -# via helper functions in the tests. -build_directories: - # The build scripts for securedrop-app-code run separate from the others, - # i.e. lacking the `/tmp/build` pardir. - - /tmp/securedrop-app-code-{securedrop_version}_amd64/ - - /tmp/build/securedrop-keyring-{keyring_version}+{securedrop_version}-amd64/ - - /tmp/build/securedrop-config-{config_version}+{securedrop_version}-amd64/ - - /tmp/build/securedrop-ossec-agent-{ossec_version}+{securedrop_version}-amd64/ - - /tmp/build/securedrop-ossec-server-{ossec_version}+{securedrop_version}-amd64/ - - /tmp/build/ossec-agent-{ossec_version}-amd64/ - - /tmp/build/ossec-server-{ossec_version}-amd64/ - - /tmp/build - -build_deb_packages: - - /tmp/build/securedrop-app-code_{securedrop_version}+{securedrop_target_platform}_amd64.deb - - /tmp/build/securedrop-ossec-agent-{ossec_version}+{securedrop_version}-amd64.deb - - /tmp/build/securedrop-ossec-server-{ossec_version}+{securedrop_version}-amd64.deb - - /tmp/build/ossec-server-{ossec_version}-amd64.deb - - /tmp/build/ossec-agent-{ossec_version}-amd64.deb - - /tmp/build/securedrop-keyring-{keyring_version}+{securedrop_version}-amd64.deb - - /tmp/build/securedrop-config-{config_version}+{securedrop_version}-amd64.deb - - /tmp/build/securedrop-grsec-{grsec_version}-amd64.deb - -lintian_tags: - # - non-standard-file-perm - - package-contains-vcs-control-file - - package-installs-python-bytecode - # - wrong-file-owner-uid-or-gid diff --git a/molecule/builder-xenial/molecule.yml b/molecule/builder-xenial/molecule.yml index 4ed6a362b5..1a81064e2f 100644 --- a/molecule/builder-xenial/molecule.yml +++ b/molecule/builder-xenial/molecule.yml @@ -72,6 +72,7 @@ verifier: n: auto env: SECUREDROP_TARGET_PLATFORM: xenial + SECUREDROP_PYTHON_VERSION: "3.5" directory: tests/ lint: name: flake8