"""Shared Debian baseline. Callers own the exclusive initialization lock.""" from __future__ import annotations from contextlib import contextmanager import fcntl from functools import wraps import hashlib import json import os from pathlib import Path import re import shutil import stat import subprocess import tempfile import urllib.request import uuid class BaselineError(RuntimeError): """A required baseline postcondition could not be established.""" def expected_errors(operation): @wraps(operation) def guarded(*args, **kwargs): try: return operation(*args, **kwargs) except (OSError, ValueError) as exc: raise BaselineError("Baseline filesystem or saved state is invalid; inspect the target before retrying.") from exc return guarded BASE_PACKAGES = ("curl", "wget", "git", "rsyslog", "ufw") ADMIN_PACKAGES = ( "tcpdump", "socat", "rsync", "bind9-dnsutils", "iproute2", "net-tools", "traceroute", "ca-certificates", "jq", "sed", "gawk", "tar", "gzip", "bzip2", "xz-utils", "unzip", "htop", "iotop", "strace", "lsof", "sysstat", "parted", "fdisk", "pciutils", "usbutils", "smartmontools", "tmux", "vim", "less", "tree", "bash-completion", "python3", "python3-minimal", "python3-yaml", "sudo", "cron", "iptables", "ipset", "debian-archive-keyring", "kmod", ) DOCKER_PACKAGES = ("docker-ce", "docker-ce-cli", "containerd.io", "docker-buildx-plugin", "docker-compose-plugin") SECURITY_PACKAGES = ("crowdsec", "crowdsec-firewall-bouncer-iptables") DOCKER_CONFLICTS = ("docker.io", "docker-doc", "docker-compose", "docker-buildx", "podman-docker", "containerd", "runc") DOCKER_CONFIG = {"data-root": "/srv/docker", "log-driver": "json-file", "log-opts": {"max-size": "20m", "max-file": "3"}} HELPER_REVISION = "020a8699f95592561f254d8d4ad1bb40d401dfc7" HELPER_URL = f"https://raw.githubusercontent.com/chaifeng/ufw-docker/{HELPER_REVISION}/ufw-docker" HELPER_SHA256 = "643e56b080567c567b4aa28650196849b2a2da5dd0473fd3e5216b0886035ab0" POLICY = Path("/usr/sbin/policy-rc.d") POLICY_STATE = Path("/usr/sbin/.apex-policy-rc.d") SECURITY_STATE = Path("/var/lib/apex/baseline-security.json") SECURITY_SERVICES = {"ufw": "ufw", "crowdsec": "crowdsec", "crowdsec-firewall-bouncer-iptables": "crowdsec-firewall-bouncer"} SECURITY_CONDITION = "[Unit]\nConditionPathExists=/dev/null/apex-security-start-allowed\n" APT = ["apt-get", "-o", "DPkg::Lock::Timeout=60", "-o", "Acquire::Retries=2", "-o", "Acquire::http::Timeout=30", "-o", "Acquire::https::Timeout=30"] def run(args, *, check=True, timeout=300): try: result = subprocess.run(args, text=True, capture_output=True, timeout=timeout, env={**os.environ, "LC_ALL": "C", "DEBIAN_FRONTEND": "noninteractive"}) except (OSError, subprocess.TimeoutExpired) as exc: raise BaselineError(f"Cannot complete {args[0]}: {exc}") from exc if check and result.returncode: raise BaselineError(f"{args[0]} failed with exit status {result.returncode}; inspect target system logs.") return result def preflight(*, strict=True): if os.geteuid() != 0: raise BaselineError("Baseline requires root.") if not strict: if not Path("/etc/debian_version").is_file(): raise BaselineError("Base policy requires a Debian-based system.") return if not Path("/etc/os-release").is_file(): raise BaselineError("Supported target is Debian 13 amd64 only.") release = dict(line.split("=", 1) for line in Path("/etc/os-release").read_text().splitlines() if "=" in line and not line.startswith("#")) if (release.get("ID", "").strip('"') != "debian" or release.get("VERSION_ID", "").strip('"') != "13" or run(["dpkg", "--print-architecture"]).stdout.strip() != "amd64"): raise BaselineError("Supported target is Debian 13 amd64 only.") def package_versions(): architecture = run(["dpkg", "--print-architecture"]).stdout.strip() result = run(["dpkg-query", "-W", "-f=${binary:Package}\t${Status}\t${Version}\n"]) installed = {} for line in result.stdout.splitlines(): fields = line.split("\t") if len(fields) == 3 and fields[1].split()[1:] == ["ok", "installed"]: installed[fields[0].removesuffix(":" + architecture)] = fields[2] return installed def write_managed(path, content, mode=0o644): path = Path(path) for parent in (path, *path.parents): if parent.is_symlink(): raise BaselineError(f"Refusing managed symlink: {parent}") payload = content.encode() if isinstance(content, str) else content if path.exists() and path.read_bytes() == payload: if path.stat().st_mode & 0o777 != mode: path.chmod(mode) return False path.parent.mkdir(parents=True, exist_ok=True) fd, temporary = tempfile.mkstemp(prefix=".apex-", dir=path.parent) try: with os.fdopen(fd, "wb") as stream: stream.write(payload) stream.flush() os.fsync(stream.fileno()) os.chmod(temporary, mode) os.replace(temporary, path) finally: if os.path.exists(temporary): os.unlink(temporary) return True def restore_service_policy(): if not POLICY_STATE.exists(): return backup = POLICY_STATE / "original" if (POLICY_STATE.is_symlink() or POLICY_STATE.stat().st_uid != os.geteuid()): raise BaselineError("Refusing untrusted service policy recovery state.") if (POLICY_STATE / "ready").exists() and POLICY.exists(): original_matches = (backup.exists() and not POLICY.is_symlink() and POLICY.read_bytes() == backup.read_bytes()) symlink_matches = (backup.is_symlink() and POLICY.is_symlink() and os.readlink(backup) == os.readlink(POLICY)) guard_matches = not POLICY.is_symlink() and POLICY.read_bytes() == b"#!/bin/sh\nexit 101\n" if not (original_matches or symlink_matches or guard_matches): raise BaselineError("Service policy changed outside APEX; recovery requires explicit reconciliation.") if backup.exists() or backup.is_symlink(): # Copy first: an interrupted restoration must retain its recovery copy. temporary = POLICY_STATE / "restoring" if temporary.exists() or temporary.is_symlink(): temporary.unlink() shutil.copy2(backup, temporary, follow_symlinks=False) os.replace(temporary, POLICY) elif (POLICY_STATE / "absent").exists(): POLICY.unlink(missing_ok=True) elif (POLICY_STATE / "ready").exists(): raise BaselineError("Service policy recovery is incomplete; inspect /usr/sbin/.apex-policy-rc.d.") shutil.rmtree(POLICY_STATE) @contextmanager def service_start_guard(): lock_path = Path("/run/lock/apex-package-policy.lock") lock_path.parent.mkdir(parents=True, exist_ok=True) with lock_path.open("a") as lock: try: fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB) except BlockingIOError: raise BaselineError("Another APEX package operation is running.") from None with _service_start_guard(): yield @contextmanager def _service_start_guard(): restore_service_policy() POLICY_STATE.mkdir(mode=0o700) try: if POLICY.exists() or POLICY.is_symlink(): shutil.copy2(POLICY, POLICY_STATE / "original", follow_symlinks=False) else: (POLICY_STATE / "absent").touch() (POLICY_STATE / "ready").touch() # Replace the path itself, preserving any original symlink in the backup. temporary = POLICY_STATE / "guard" temporary.write_text("#!/bin/sh\nexit 101\n") temporary.chmod(0o755) os.replace(temporary, POLICY) yield finally: restore_service_policy() @contextmanager def security_service_guard(packages): """Guard new security units without occupying package-owned unit paths.""" record = json.loads(SECURITY_STATE.read_text()) if SECURITY_STATE.exists() else {"version": 2, "services": {}} if not isinstance(record, dict) or record.get("version") != 2: raise BaselineError("Legacy security service guard state requires explicit reconciliation.") managed = record.get("services") if not isinstance(managed, dict) or any(SECURITY_SERVICES.get(key) != value for key, value in managed.items()): raise BaselineError("Invalid baseline security service recovery state.") installed = package_versions() for package, service in SECURITY_SERVICES.items(): if package in packages and package not in installed and package not in managed: if run(["systemctl", "is-enabled", service], check=False).stdout.strip() == "masked": continue managed[package] = service write_managed(SECURITY_STATE, json.dumps({"version": 2, "services": managed}), 0o600) for service in managed.values(): dropin = Path(f"/etc/systemd/system/{service}.service.d/99-apex-bootstrap-guard.conf") if dropin.exists() and dropin.read_text() != SECURITY_CONDITION: raise BaselineError("Security service guard changed outside APEX; reconcile it explicitly.") # /dev/null cannot have children: this condition stays false after reboot. write_managed(dropin, SECURITY_CONDITION) if managed: run(["systemctl", "daemon-reload"]) try: yield finally: installed = package_versions() for package, service in managed.items(): unit_exists = any(Path(f"{directory}/{service}.service").exists() for directory in ("/etc/systemd/system", "/usr/lib/systemd/system", "/lib/systemd/system")) run(["systemctl", "disable", service], check=package in installed or unit_exists) dropin = Path(f"/etc/systemd/system/{service}.service.d/99-apex-bootstrap-guard.conf") if dropin.exists(): if dropin.is_symlink() or dropin.read_text() != SECURITY_CONDITION: raise BaselineError("Security service guard changed outside APEX; reconcile it explicitly.") dropin.unlink() if managed: run(["systemctl", "daemon-reload"]) SECURITY_STATE.unlink(missing_ok=True) def install_missing(packages): installed = package_versions() missing = [package for package in packages if package not in installed] if not missing: return [] run([*APT, "update", "--error-on=any"]) command = [*APT, "install", "-y", "--no-install-recommends", "--no-upgrade", "--no-remove", *missing] plan = run([*command, "--simulate"]).stdout if any(line.startswith("Remv ") or re.match(r"^Inst \S+ \[", line) for line in plan.splitlines()): raise BaselineError("Missing packages require an upgrade/removal; reconcile packages explicitly before retrying.") # Package writes must settle even after coordinator loss; stages gate later work. run(command, timeout=None) remaining = set(missing) - package_versions().keys() if remaining: raise BaselineError("Required packages not installed: " + ", ".join(sorted(remaining))) return missing def base_policy(): return {"packages": list(BASE_PACKAGES), "files": { "/etc/apt/apt.conf.d/99-apex": 'APT::Keep-Downloaded-Packages "0";\n', "/etc/systemd/journald.conf.d/99-apex.conf": "[Journal]\nSystemMaxUse=200M\n", }, "helper": {"url": HELPER_URL, "sha256": HELPER_SHA256}} def configure_common(): policy = base_policy() for legacy in ("/etc/apt/apt.conf.d/01clean", "/etc/systemd/journald.conf.d/maxuse.conf"): path = Path(legacy) if path.exists() or path.is_symlink(): path.unlink() for path, content in policy["files"].items(): changed = write_managed(path, content) if changed and path.endswith("99-apex.conf"): run(["systemctl", "restart", "systemd-journald"]) target = Path("/usr/local/bin/ufw-docker") if (not target.is_file() or hashlib.sha256(target.read_bytes()).hexdigest() != HELPER_SHA256): try: with urllib.request.urlopen(HELPER_URL, timeout=30) as response: data = response.read() except OSError as exc: raise BaselineError("Unable to download pinned ufw-docker helper.") from exc if hashlib.sha256(data).hexdigest() != HELPER_SHA256: raise BaselineError("Pinned ufw-docker checksum mismatch.") write_managed(target, data, 0o755) elif target.is_symlink(): raise BaselineError("Refusing a symlinked ufw-docker helper.") else: target.chmod(0o755) def docker_preflight(installed): conflicts = sorted(set(DOCKER_CONFLICTS) & installed.keys()) if conflicts: raise BaselineError("Conflicting Docker packages require explicit reconciliation: " + ", ".join(conflicts)) path = Path("/etc/docker/daemon.json") try: config = json.loads(path.read_text()) if path.exists() else {} except (OSError, ValueError) as exc: raise BaselineError("Cannot validate existing Docker daemon configuration.") from exc if not isinstance(config, dict): raise BaselineError("Docker daemon configuration must be an object.") for name, value in DOCKER_CONFIG.items(): if name in config and config[name] != value: raise BaselineError(f"Conflicting Docker {name}; reconcile explicitly before initialization.") old_data = Path("/var/lib/docker") if old_data.exists() and any(old_data.iterdir()): raise BaselineError("Existing /var/lib/docker data must be reconciled explicitly; no data migration is automatic.") data = Path("/srv/docker") if data.is_symlink() or data.parent.is_symlink(): raise BaselineError("Refusing a redirected Docker data-root.") if data.exists() and any(data.iterdir()) and config.get("data-root") != "/srv/docker": raise BaselineError("Unmanaged /srv/docker data requires explicit reconciliation.") if "docker-ce" in installed: active = run(["systemctl", "is-active", "--quiet", "docker"], check=False).returncode == 0 if active: root = run(["docker", "info", "--format", "{{.DockerRootDir}}"] ).stdout.strip() if root != "/srv/docker" or any(config.get(key) != value for key, value in DOCKER_CONFIG.items()): raise BaselineError("Running Docker has incompatible data-root/log policy; reconcile it before retrying.") return {**config, **DOCKER_CONFIG} DOCKER_KEY_SHA256 = "1500c1f56fa9e26b9b8f42452a553675796ade0807cdce11975eb98170b3a570" LOCAL_DOCKER = ["docker", "--host", "unix:///var/run/docker.sock"] def _docker_source(arch): key = Path("/etc/apt/keyrings/apex-docker.asc") source = Path("/etc/apt/sources.list.d/apex-docker.sources") content = ("Types: deb\nURIs: https://download.docker.com/linux/debian\nSuites: trixie\n" f"Components: stable\nArchitectures: {arch}\nSigned-By: {key}\n") for path in (key, source): if any(part.is_symlink() for part in (path, *path.parents)): raise BaselineError(f"Refusing redirected APT path: {path}") if source.exists() and source.read_text() != content: raise BaselineError(f"Reconcile existing Docker repository configuration: {source}") if key.exists(): data = key.read_bytes() else: url = "https://download.docker.com/linux/debian/gpg" with urllib.request.urlopen(url, timeout=30) as response: # noqa: S310 data = response.read(1024 * 1024) if hashlib.sha256(data).hexdigest() != DOCKER_KEY_SHA256: raise BaselineError("Docker repository signing key differs from the pinned release key.") write_managed(key, data) write_managed(source, content) def _docker_capabilities(root, *, complete_plugins=False): capabilities = {"docker_data_root": root} plugins = {"docker-compose-plugin": ("compose", ["compose", "version", "--short"]), "docker-buildx-plugin": ("buildx", ["buildx", "version"])} missing = [] for package, (name, args) in plugins.items(): result = run([*LOCAL_DOCKER, *args], check=False) if result.returncode or not result.stdout.strip(): missing.append(package) else: capabilities[name] = result.stdout.strip() if missing: if complete_plugins and "docker-ce" in package_versions(): with service_start_guard(): install_missing(missing) return _docker_capabilities(root) raise BaselineError("Existing Docker needs functional plugins: " + ", ".join(missing)) if not root: raise BaselineError("Unable to verify the local Docker data-root.") return capabilities @expected_errors def apply_docker_policy(): if Path("/usr/bin/pveversion").exists(): raise BaselineError("Docker installation on a Proxmox host requires separate administration.") release = dict(line.split("=", 1) for line in Path("/etc/os-release").read_text().splitlines() if "=" in line and not line.startswith("#")) arch = run(["dpkg", "--print-architecture"]).stdout.strip() if (release.get("ID", "").strip('"') != "debian" or release.get("VERSION_ID", "").strip('"') != "13" or arch not in ("amd64", "arm64")): raise BaselineError("Docker installation supports stock Debian 13 amd64 or arm64.") info = [*LOCAL_DOCKER, "info", "--format", "{{.DockerRootDir}}"] if shutil.which("docker"): current = run(info, check=False) if current.returncode == 0: return _docker_capabilities(current.stdout.strip(), complete_plugins=True) installed = package_versions() source = Path("/etc/apt/sources.list.d/apex-docker.sources") if (not source.exists() and (shutil.which("docker") or set(DOCKER_PACKAGES).intersection(installed))): raise BaselineError("Existing Docker installation is inactive; reconcile it before retrying.") config = docker_preflight(installed) with service_start_guard(): install_missing(("ca-certificates",)) _docker_source(arch) write_managed("/etc/docker/daemon.json", json.dumps(config, indent=2) + "\n") install_missing(DOCKER_PACKAGES) ensure_service("containerd") ensure_service("docker") root = run(info).stdout.strip() if root != DOCKER_CONFIG["data-root"]: raise BaselineError("Docker started with an unexpected data-root; inspect its configuration.") return _docker_capabilities(root) def configure_sources(): write_managed("/etc/apt/sources.list.d/apex-zfs.sources", "Types: deb\nURIs: https://deb.debian.org/debian\nSuites: trixie\n" "Components: contrib\nArchitectures: amd64\n" "Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg\n") for name, key_url, uri, suite, component in ( ("docker", "https://download.docker.com/linux/debian/gpg", "https://download.docker.com/linux/debian", "trixie", "stable"), ("crowdsec", "https://packagecloud.io/crowdsec/crowdsec/gpgkey", "https://packagecloud.io/crowdsec/crowdsec/any", "any", "main"), ): key = Path(f"/etc/apt/keyrings/apex-{name}.asc") if not key.exists(): try: # Both repository key URLs above are fixed HTTPS endpoints. with urllib.request.urlopen(key_url, timeout=30) as response: # noqa: S310 data = response.read() except OSError as exc: raise BaselineError(f"Cannot download {name} repository signing key.") from exc if not data.startswith(b"-----BEGIN PGP PUBLIC KEY BLOCK-----"): raise BaselineError(f"Invalid {name} repository signing key.") write_managed(key, data) write_managed(f"/etc/apt/sources.list.d/apex-{name}.sources", f"Types: deb\nURIs: {uri}\nSuites: {suite}\nComponents: {component}\n" f"Architectures: amd64\nSigned-By: {key}\n") def ensure_service(name): if run(["systemctl", "is-enabled", "--quiet", name], check=False).returncode: run(["systemctl", "enable", name]) if run(["systemctl", "is-active", "--quiet", name], check=False).returncode: run(["systemctl", "start", name]) def repair_bouncer_credentials(): """Repair package placeholders without rewriting administrator YAML settings.""" config = Path("/etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml") identity = config.with_suffix(".yaml.id") for path in (config, identity): if any(parent.is_symlink() for parent in (path, *path.parents)): raise BaselineError("Refusing redirected CrowdSec bouncer credential paths.") if path.exists(): metadata = path.stat() if (not stat.S_ISREG(metadata.st_mode) or metadata.st_nlink != 1 or metadata.st_uid != os.geteuid()): raise BaselineError("Refusing untrusted CrowdSec bouncer credential files.") if not config.exists(): raise BaselineError("CrowdSec bouncer configuration is missing; reconcile the package installation.") content = config.read_text() entries = list(re.finditer(r"^(?:api_key|'api_key'|\"api_key\"):[^\r\n]*", content, re.MULTILINE)) if len(entries) != 1: raise BaselineError("CrowdSec bouncer requires one explicit api_key; reconcile its configuration.") entry = entries[0] for following in content[entry.end():].splitlines(): if not following.strip() or following.lstrip().startswith("#"): continue if following[:1].isspace(): raise BaselineError("Multiline CrowdSec bouncer api_key requires explicit reconciliation.") break scalar = re.fullmatch(r"(?:api_key|'api_key'|\"api_key\"):[ \t]*(?P\"[^\"]*\"|'[^']*'|[^ \t#'\"]*)(?:[ \t]+(?:#.*)?)?", entry.group()) if scalar is None: raise BaselineError("Unsupported CrowdSec bouncer api_key; reconcile its configuration.") value = scalar.group("value") uninitialized = value in ("null", "Null", "NULL", "~") if value[:1] in ("'", '"'): value = value[1:-1] if not uninitialized and value not in ("", "", "$API_KEY", "${API_KEY}"): return metadata = config.stat() registration = "cs-firewall-bouncer-apex-" + uuid.uuid4().hex key = run(["cscli", "-oraw", "bouncers", "add", registration]).stdout.strip() if not re.fullmatch(r"[A-Za-z0-9_+/=-]{24,256}", key): raise BaselineError("CrowdSec bouncer registration did not return a usable API key.") start, end = scalar.span("value") separator = " " if entry.group()[start - 1] == ":" else "" updated = content[:entry.start() + start] + separator + key + content[entry.start() + end:] def publish(path, payload, mode, owner): fd, temporary = tempfile.mkstemp(prefix=".apex-", dir=path.parent) try: with os.fdopen(fd, "w") as stream: os.fchown(stream.fileno(), *owner) os.fchmod(stream.fileno(), mode) stream.write(payload) stream.flush() os.fsync(stream.fileno()) os.replace(temporary, path) directory = os.open(path.parent, os.O_RDONLY | os.O_DIRECTORY) try: os.fsync(directory) finally: os.close(directory) finally: if os.path.exists(temporary): os.unlink(temporary) # Publish the key last: interruption can orphan a registration, but retries # replace the placeholder and its package bookkeeping together in this order. owner = (metadata.st_uid, metadata.st_gid) publish(identity, registration + "\n", 0o600, owner) publish(config, updated, (stat.S_IMODE(metadata.st_mode) & 0o640) | 0o600, owner) if config.read_text() != updated or identity.read_text().strip() != registration: raise BaselineError("CrowdSec bouncer credential publication did not converge.") @expected_errors def apply_base_policy(): """Apply the base package, logging, and firewall policy.""" preflight(strict=False) with service_start_guard(), security_service_guard(BASE_PACKAGES): install_missing(BASE_PACKAGES) configure_common() ensure_service("rsyslog") run(["/usr/local/bin/ufw-docker", "install"]) return {"packages": {key: value for key, value in package_versions().items() if key in BASE_PACKAGES}} @expected_errors def apply_baseline(): """Converge baseline and return verified package versions and capabilities.""" preflight() installed = package_versions() docker_config = docker_preflight(installed) kernel = run(["uname", "-r"]).stdout.strip() if not re.fullmatch(r"[A-Za-z0-9.+_-]+", kernel): raise BaselineError("Unsupported running kernel release.") packages = (*BASE_PACKAGES, *ADMIN_PACKAGES, *DOCKER_PACKAGES, *SECURITY_PACKAGES, "linux-headers-amd64", f"linux-headers-{kernel}", "zfsutils-linux", "zfs-dkms") with service_start_guard(), security_service_guard(packages): install_missing((*BASE_PACKAGES, *ADMIN_PACKAGES)) configure_sources() install_missing(("crowdsec",)) install_missing(packages) repair_bouncer_credentials() configure_common() write_managed("/etc/docker/daemon.json", json.dumps(docker_config, indent=2) + "\n") Path("/srv/docker").mkdir(parents=True, exist_ok=True) ensure_service("containerd") ensure_service("docker") ensure_service("rsyslog") ensure_service("cron") root = run(["docker", "info", "--format", "{{.DockerRootDir}}"] ).stdout.strip() if root != "/srv/docker": raise BaselineError("Docker did not activate the required /srv/docker data-root.") compose = run(["docker", "compose", "version", "--short"]).stdout.strip() if not compose: raise BaselineError("Docker Compose capability is unavailable.") module = run(["modprobe", "zfs"], check=False) if module.returncode: raise BaselineError(f"ZFS unavailable for running kernel {kernel}; install matching headers/module or reboot into the supported kernel, then retry. No automatic reboot was performed.") zfs = run(["zfs", "version"]).stdout.strip() versions = package_versions() if set(packages) - versions.keys(): raise BaselineError("Baseline package verification failed.") return {"packages": {name: versions[name] for name in packages}, "capabilities": {"docker_data_root": root, "compose": compose, "zfs": zfs, "kernel": kernel, "ufw_docker_sha256": HELPER_SHA256}, "sources": {"docker": "docker.com/debian trixie stable", "crowdsec": "packagecloud.io/crowdsec/crowdsec/any any main", "zfs": "Debian trixie contrib"}} if __name__ == "__main__": import argparse from .state import ProvisionError, exclusive_lock parser = argparse.ArgumentParser(description=__doc__) scope = parser.add_mutually_exclusive_group() scope.add_argument("--base-policy", action="store_true") scope.add_argument("--docker-policy", action="store_true") args = parser.parse_args() try: preflight(strict=not (args.base_policy or args.docker_policy)) with exclusive_lock("/var/lib/apex-init/init.lock"): if args.docker_policy: result = apply_docker_policy() elif args.base_policy: result = apply_base_policy() else: result = apply_baseline() print(json.dumps(result, sort_keys=True)) except (BaselineError, OSError, ProvisionError) as exc: parser.exit(1, f"Baseline failed: {exc}\n")