Files
pulse/scripts/tests/test_auto_update_systemd.py
pulse-triage[bot] 5d748986b3 Keep native recovery proof aligned with bounded manual downloads
Admit only the manual helper's exact new curl envelope in the existing closed transport fixture. Require a signed emitted-helper round trip and reject altered deadlines, retries and TLS flags through the registered installer suite; do not widen the adapter or execute a native journey.

Change-source: pulse-maintainer
2026-10-25 06:38:18 +00:00

806 lines
50 KiB
Python

#!/usr/bin/env python3
"""Discriminating controls for the native CI recipe; no host manager/root use."""
import contextlib
import importlib.util
import io
import json
import os
from pathlib import Path
import re
import shutil
import subprocess
import sys
import tempfile
import unittest
from unittest.mock import patch
ROOT = Path(__file__).resolve().parents[2]
SPEC = importlib.util.spec_from_file_location("native_updater", ROOT / "scripts/installtests/auto_update_systemd.py")
native = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(native)
WORKFLOW = ROOT / ".github/workflows/build-and-test.yml"
STEP = "Check current-source unattended recovery on native systemd"
FIXTURE_COMMANDS = ("bash", "tar", "chmod", "mv", "timeout", "cmp")
LINUX_CONTROL = "test_connected_signed_archive_and_recovery_controls_without_host_manager"
LINUX_ONLY_REASON = "Linux server ELF execution; portable controls remain required on macOS"
def selected_fixture_commands():
# The containing native job has already supplied its Linux-only tools.
# Capture only these executables, not the whole ambient PATH or environment.
commands = {name: shutil.which(name) for name in FIXTURE_COMMANDS}
for name, executable in commands.items():
if executable is None:
raise ValueError("missing installer fixture tool: " + name)
return commands
def recipe(source):
job = re.search(r"(?ms)^ frontend:\n(.*?)(?=^ [a-z][a-z0-9-]*:|\Z)", source)[1]
steps = dict(re.findall(r"(?ms)^ - name: ([^\n]+)\n(.*?)(?=^ - name:|\Z)", job))
order = list(steps)
assert order.index("Verify backend with real frontend embed") < order.index(STEP) < order.index("Require frontend dependency audit")
step = steps[STEP]
assert not re.search(r"^ (if|continue-on-error|working-directory):", step, re.M)
assert "runs-on: ubuntu-24.04" in job and "timeout-minutes: 30" in job
assert "persist-credentials: false" in steps["Checkout repository"]
assert "EXPECTED_SOURCE_SHA: ${{ github.sha }}" in step
shell = re.search(r"(?ms)^ run: \|\n((?: [^\n]*\n)+)", step)[1]
shell = "\n".join(line[10:] for line in shell.splitlines()) + "\n"
for command in ('test "$(git rev-parse HEAD)" = "$EXPECTED_SOURCE_SHA"',
"git diff --quiet HEAD",
"diff -qr --no-dereference frontend-modern/dist internal/api/frontend-modern/dist",
"-ldflags='-X main.Version=v0.0.1'", "-ldflags='-X main.Version=v0.0.2'",
"go build -mod=readonly -p=2", "sudo env -i",
"GITHUB_ACTIONS=true RUNNER_ENVIRONMENT=github-hosted GITHUB_REPOSITORY=rcourtman/Pulse",
"python3 scripts/installtests/auto_update_systemd.py",
'--receipt "$RUNNER_TEMP/pulse-native-updater.json"'):
assert command in shell, command
assert "GH_TOKEN" not in shell and "secrets." not in step
retention = steps["Retain bounded native updater receipt"]
assert "if: always()" in retention and "retention-days: 7" in retention
assert "path: ${{ runner.temp }}/pulse-native-updater.json" in retention
assert "*.log" not in retention and "pulse-native-before" not in retention
return shell
class NativeContracts(unittest.TestCase):
def test_fixture_command_selection_refuses_missing_tools_without_fallback(self):
for missing in FIXTURE_COMMANDS:
with self.subTest(missing=missing), patch.object(shutil, "which", side_effect=
lambda name: None if name == missing else "/supplied/" + name):
with self.assertRaisesRegex(ValueError, "missing installer fixture tool: " + missing):
selected_fixture_commands()
def test_definition_boundary_is_exact_and_rejects_drift(self):
source = (ROOT / "install.sh").read_text()
definitions = native.installer_definitions(source)
self.assertEqual(definitions, source[:source.index(native.PARSE_MARKER)])
for changed in (source.replace(native.PARSE_MARKER, "# moved\n"),
source.replace(native.PARSE_MARKER, native.PARSE_MARKER * 2),
source.replace(native.PARSE_MARKER, native.PARSE_MARKER + "echo different entry\n")):
with self.assertRaises(ValueError): native.installer_definitions(changed)
def test_host_admission_requires_fresh_public_vm_not_worker_or_container(self):
env = dict(GITHUB_ACTIONS="true", RUNNER_ENVIRONMENT="github-hosted", GITHUB_REPOSITORY="rcourtman/Pulse")
with patch.object(Path, "exists", return_value=False):
native.hosted_admission(env, 0, "a" * 40)
for changed, uid, sha in ((env, 1000, "a" * 40), ({}, 0, "a" * 40),
({**env, "RUNNER_ENVIRONMENT": "self-hosted"}, 0, "a" * 40),
({**env, "GITHUB_REPOSITORY": "other/repo"}, 0, "a" * 40),
(env, 0, "main")):
with self.assertRaises(ValueError): native.hosted_admission(changed, uid, sha)
with patch.object(Path, "exists", return_value=True):
with self.assertRaises(ValueError): native.hosted_admission(env, 0, "a" * 40)
def test_transport_and_private_allocator_have_no_online_fallback(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory); (root / "tmp").mkdir()
script = root / "curl"; script.write_text(native.TRANSPORT); script.chmod(0o755)
(root / "installer").write_text("signed fixture\n")
(root / "installer.sshsig").write_text("signature sidecar\n")
env = {**os.environ, "PULSE_NATIVE_ROOT": str(root)}
for tag in ("latest/download", "download/v0.0.1", "download/v0.0.2"):
for suffix in ("", ".sshsig"):
result = subprocess.run([str(script), "-fsSL", f"https://github.com/rcourtman/Pulse/releases/{tag}/install.sh{suffix}"], env=env, capture_output=True)
self.assertEqual(result.returncode, 0)
self.assertEqual(result.stdout, (root / ("installer" + suffix)).read_bytes())
for url in ("https://example.com/install.sh", "https://github.com/rcourtman/Pulse/releases/download/v6.5.0/install.sh"):
result = subprocess.run([str(script), "-fsSL", url, "-o", str(root / "unexpected")], env=env, capture_output=True)
self.assertEqual(result.returncode, 97)
self.assertFalse((root / "unexpected").exists())
allocator = root / "mktemp"; allocator.write_text(native.TRANSPORT); allocator.chmod(0o755)
result = subprocess.run([str(allocator), "-d", "/tmp/pulse-backup.XXXXXX"], env=env, capture_output=True, check=True)
self.assertEqual(Path(result.stdout.decode().strip()).parent, root / "tmp")
def test_transport_accepts_actual_bounded_downloader_and_rejects_option_drift(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
script = root / "curl"; script.write_text(native.TRANSPORT); script.chmod(0o755)
payload = b"private signed fixture bytes\n"
(root / "installer").write_bytes(payload)
(root / "installer.sshsig").write_bytes(b"private signature sidecar\n")
env = {**os.environ, "PULSE_NATIVE_ROOT": str(root),
"PATH": str(root) + os.pathsep + os.environ["PATH"]}
url = "https://github.com/rcourtman/Pulse/releases/download/v0.0.2/install.sh"
shell = ('source "$1"; download_update_asset "$2" "$3"')
for suffix in ("", ".sshsig"):
target = root / "downloaded"
result = subprocess.run(["bash", "-c", shell, "fixture",
str(ROOT / "scripts/pulse-auto-update.sh"), url + suffix, str(target)],
env=env, capture_output=True)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertEqual(target.read_bytes(), (root / ("installer" + suffix)).read_bytes())
target.unlink()
flags = ["--disable", "-fsSL", "--connect-timeout", "5", "--max-time", "60",
"--proto", "=https", "--proto-redir", "=https"]
for changed in (flags[1:], [*flags, "--insecure"],
[arg if arg != "60" else "61" for arg in flags],
[arg if arg != "=https" else "=all" for arg in flags],
[*flags, "https://example.com/install.sh"],
[*flags, "--max-time", "60"]):
with self.subTest(flags=changed):
result = subprocess.run([str(script), *changed, url, "-o", str(root / "refused")],
env=env, capture_output=True)
self.assertEqual(result.returncode, 97)
self.assertFalse((root / "refused").exists())
def test_transport_accepts_emitted_manual_helper_and_rejects_option_drift(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
for leaf in ("tools", "tmp", "config"):
(root / leaf).mkdir(mode=0o700)
for name in ("curl", "mktemp"):
path = root / "tools" / name
path.write_text(native.TRANSPORT)
path.chmod(0o755)
installer = root / "installer"
installer.write_text('#!/bin/bash\nprintf "%s\\n" "$@" > "$PULSE_NATIVE_ROOT/executed"\n')
key = root / "key"
subprocess.run(["ssh-keygen", "-q", "-t", "ed25519", "-N", "", "-f", str(key)],
check=True, capture_output=True)
subprocess.run(["ssh-keygen", "-q", "-Y", "sign", "-f", str(key),
"-n", "pulse-install", str(installer)], check=True, capture_output=True)
Path(str(installer) + ".sig").rename(root / "installer.sshsig")
helper = root / "update"
env = {**os.environ, "PULSE_NATIVE_ROOT": str(root),
"FIXTURE_KEY": (root / "key.pub").read_text().strip(),
"PULSE_INSTALL_DIR": str(root), "PULSE_CONFIG_DIR": str(root / "config"),
"PULSE_UPDATE_HELPER_PATH": str(helper),
"PULSE_PROFILE_PATH": str(root / "profile"),
"PULSE_BASHRC_PATH": str(root / "bashrc"),
"PATH": str(root / "tools") + os.pathsep + os.environ["PATH"]}
generated = subprocess.run(["bash", "-c", 'source "$1"; '
'PINNED_RELEASE_SSH_PUBLIC_KEY="$FIXTURE_KEY"; setup_update_command',
"fixture", str(ROOT / "install.sh")], env=env, capture_output=True)
self.assertEqual(generated.returncode, 0, generated.stdout + generated.stderr)
result = subprocess.run(["bash", str(helper), "--version", "v0.0.1"],
env=env, capture_output=True, timeout=10)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertEqual((root / "executed").read_text(), "--version\nv0.0.1\n")
self.assertEqual(list((root / "tmp").iterdir()), [])
flags = ["-q", "-fsSL", "--connect-timeout", "10", "--max-time", "60"]
url = "https://github.com/rcourtman/Pulse/releases/latest/download/install.sh"
for changed in (flags[1:], [*flags, "--insecure"], [*flags, "--retry", "3"],
[arg if arg != "60" else "61" for arg in flags],
[arg if arg != "10" else "11" for arg in flags]):
with self.subTest(flags=changed):
target = root / "refused"
result = subprocess.run([str(root / "tools/curl"), *changed, url, "-o", str(target)],
env=env, capture_output=True, timeout=10)
self.assertEqual(result.returncode, 97)
self.assertFalse(target.exists())
def test_real_verifier_accepts_fixture_and_refuses_tampering(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
lab = native.NativeLab(root, ROOT, root / "a", root / "b", "a" * 40)
(root / "signer").mkdir()
lab.run("ssh-keygen", "-q", "-t", "ed25519", "-N", "", "-f", str(root / "signer/key"))
installer = root / "installer"; installer.write_text(native.INSTALLER)
lab.sign(installer)
shell = ('source "$PULSE_NATIVE_UPDATER"; '
'PINNED_RELEASE_SSH_PUBLIC_KEY=$(cat "$PULSE_NATIVE_ROOT/signer/key.pub"); '
'verify_release_signature "$PULSE_NATIVE_ROOT/installer" "$PULSE_NATIVE_ROOT/installer.sshsig" fixture')
self.assertEqual(lab.shell(shell).returncode, 0)
installer.write_text(native.INSTALLER + "# tampered\n")
result = subprocess.run(["/bin/bash", "-c", shell], env=lab.env, capture_output=True)
self.assertEqual(result.returncode, 1)
self.assertIn(b"Cryptographic signature verification failed", result.stdout)
def test_signer_failure_retains_operation_and_metadata_not_private_output(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
(root / "signer").mkdir(mode=0o700)
lab = native.NativeLab(root, ROOT, root / "a", root / "b", "a" * 40)
lab.signer_command("generate-ephemeral-key", "-q", "-t", "ed25519", "-N", "", "-f",
str(root / "signer/key"))
target = root / "installer"
target.write_text("closed synthetic fixture, not a release\n")
# A real OpenSSH refusal, not a simulated exit code or key read.
(root / "signer/key").chmod(0o644)
with self.assertRaisesRegex(RuntimeError, "native command failed"):
lab.sign(target)
failure = lab.receipt["command_failure"]
self.assertEqual(failure["operation"], "sign-installer")
self.assertEqual(failure["observed_exit"], 255)
self.assertIn("private-key-permissions", failure["observed_diagnostics"])
self.assertEqual(failure["signer_key_metadata"], {
"present": True, "regular_file": True, "mode": "0644", "owned_by_executor": True,
})
self.assertFalse(Path(str(target) + ".sshsig").exists())
retained = json.dumps(lab.receipt)
self.assertNotIn("PRIVATE KEY", retained)
self.assertNotIn(str(root), retained)
self.assertNotIn(lab._last_output.decode(), retained)
def test_prepare_owns_generated_signer_mode_before_first_real_signature(self):
# Reproduce the exact observed mode, not its unknown generation cause.
# Run real OpenSSH signing before stopping ahead of account/unit writes.
with tempfile.TemporaryDirectory() as directory:
base = Path(directory)
before, after = base / "a", base / "b"
before.write_bytes(b"before\n"); after.write_bytes(b"after\n")
lab = native.NativeLab(base / "lab", ROOT, before, after, "a" * 40)
lab.unit = base / "absent.service"
original_run = lab.run
def confined_run(*args, **kwargs):
if args[0] in (str(before), str(after)) and args[1:] == ("--version",):
tag = native.TAGS[0 if args[0] == str(before) else 1]
return subprocess.CompletedProcess(args, 0, ("Pulse " + tag + "\n").encode())
if args[0] != "ssh-keygen":
raise AssertionError("unexpected service/account operation")
result = original_run(*args, **kwargs)
if args[1] == "-q":
(lab.root / "signer/key").chmod(0o644)
return result
def first_signature(archive):
self.assertEqual((lab.root / "signer/key").stat().st_mode & 0o777, 0o600)
native.NativeLab.sign(lab, archive)
self.assertTrue(Path(str(archive) + ".sshsig").is_file())
raise RuntimeError("stop before account/unit mutation")
try:
with patch.object(lab, "state", return_value={"LoadState": "not-found"}), \
patch.object(lab, "run", side_effect=confined_run), \
patch.object(lab, "sign", side_effect=first_signature):
with self.assertRaisesRegex(RuntimeError, "stop before account/unit mutation"):
lab.prepare()
self.assertFalse(lab.owned_unit)
self.assertFalse(lab.owned_user)
finally:
lab.cleanup()
self.assertTrue(lab.receipt["cleanup"]["complete"])
def test_signer_creation_refuses_adoption_wrong_type_owner_or_failed_mode(self):
for mutation in ("existing", "symlink", "generated-symlink", "directory", "owner", "chmod", "mode-unchanged"):
with self.subTest(mutation=mutation), tempfile.TemporaryDirectory() as directory:
root = Path(directory); (root / "signer").mkdir(mode=0o700)
key = root / "signer/key"
marker = root / "keep"; marker.write_text("not a key; not ours\n")
lab = native.NativeLab(root, ROOT, root / "a", root / "b", "a" * 40)
if mutation == "existing": key.write_text("not a key; not ours\n")
if mutation == "symlink": key.symlink_to(marker)
def generate(*args):
if mutation == "generated-symlink": key.symlink_to(marker)
elif mutation == "directory": key.mkdir()
else: key.write_text("mode/type fixture; not a key\n")
with patch.object(lab, "signer_command", side_effect=generate) as command, \
patch.object(native.os, "geteuid", return_value=-1 if mutation == "owner" else os.getuid()), \
patch.object(Path, "chmod", side_effect=OSError("mode change unavailable") if mutation == "chmod" else None):
with self.assertRaises((ValueError, OSError)):
lab.create_signer()
if mutation in ("existing", "symlink"): command.assert_not_called()
else: command.assert_called_once()
self.assertEqual(marker.read_text(), "not a key; not ours\n")
def test_signer_timeout_does_not_attribute_stale_output_to_new_command(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
lab = native.NativeLab(root, ROOT, root / "a", root / "b", "a" * 40)
lab._last_output = b"UNPROTECTED PRIVATE KEY FILE from an earlier command"
def timeout(*args):
lab.receipt["command_failure"] = {"command": "ssh-keygen", "deadline_exceeded": True,
"observed_exit": -9}
raise RuntimeError("native command deadline exceeded")
with patch.object(lab, "run", side_effect=timeout), self.assertRaises(RuntimeError):
lab.signer_command("generate-ephemeral-key", "-q")
failure = lab.receipt["command_failure"]
self.assertEqual(failure["operation"], "generate-ephemeral-key")
self.assertEqual(failure["signer_key_metadata"], {"present": False})
self.assertNotIn("observed_diagnostics", failure)
def make_phase(self, directory, mutation=""):
root = Path(directory)
for name in ("install/bin", "data", "tmp"):
(root / name).mkdir(parents=True)
before, after = root / "a", root / "b"
before.write_bytes(b"baseline executable\n"); after.write_bytes(b"changed executable\n")
(root / "install/bin/pulse").write_bytes(after.read_bytes())
(root / "install/VERSION").write_text("v0.0.2\n")
(root / "data/sentinel").write_text("original\n")
lab = native.NativeLab(root, ROOT, before, after, "a" * 40)
lab.baseline_data = {"sentinel": native.digest(root / "data/sentinel")}
lab.baseline_mode = 0o644
lab.receipt["binaries"] = {"v0.0.1": native.digest(before), "v0.0.2": native.digest(after)}
states = [{"LoadState": "loaded", "ActiveState": "inactive", "UnitFileState": "disabled", "MainPID": "0"}] * 2
if mutation == "mask": states[1] = {**states[1], "LoadState": "masked", "UnitFileState": "masked"}
if mutation == "activity": states[1] = {**states[1], "ActiveState": "active", "MainPID": "123"}
lab.state = unittest.mock.Mock(side_effect=states)
def run(*args, **kwargs):
if mutation == "persistent": (root / "data/sentinel").write_text("changed\n")
if mutation == "binary": (root / "install/bin/pulse").write_text("different\n")
if mutation == "version": (root / "install/VERSION").write_text("v0.0.1\n")
if mutation == "backup": (root / "tmp/pulse-backup.extra").mkdir()
if mutation == "staging": (root / "install/bin/pulse.rollback.leak").write_text("leaked\n")
return subprocess.CompletedProcess(args, 0, b"fixture command, not native execution\n")
lab.run = run
return lab
def test_phase_cannot_accept_wrong_bytes_state_mask_persistence_or_backup(self):
for mutation in ("", "binary", "version", "mask", "activity", "persistent", "backup", "staging"):
with self.subTest(mutation=mutation), tempfile.TemporaryDirectory() as directory:
lab = self.make_phase(directory, mutation)
if mutation:
with self.assertRaises(RuntimeError): lab.phase("forward", "v0.0.2", active="inactive")
self.assertEqual(lab.receipt["phases"], [])
else:
lab.phase("forward", "v0.0.2", active="inactive")
self.assertTrue(lab.receipt["phases"][0]["passed"])
self.assertEqual(lab.operation, "forward")
def test_managed_process_identity_follows_served_readiness_and_rejects_residuals(self):
for mutation in ("", "process-bytes", "stopped-after-readiness", "inactive-pid"):
with self.subTest(mutation=mutation), tempfile.TemporaryDirectory() as directory:
lab = self.make_phase(directory)
state = dict(LoadState="loaded", ActiveState="active", UnitFileState="disabled", MainPID="1")
observed = {**state, "MainPID": "2"}
if mutation == "stopped-after-readiness":
observed.update(ActiveState="inactive", MainPID="0")
if mutation == "inactive-pid":
lab.state = unittest.mock.Mock(return_value={**state, "ActiveState": "inactive"})
with self.assertRaises(RuntimeError): lab.assert_runtime("v0.0.2", "inactive")
continue
lab.state = unittest.mock.Mock(side_effect=[state, observed, observed])
order = []
def response(url, **kwargs):
endpoint = url.rsplit("/", 1)[-1]
order.append(endpoint)
return io.BytesIO(json.dumps({"status": "healthy"} if endpoint == "health"
else {"version": "v0.0.2"}).encode())
actual_digest = native.digest
def process_digest(path):
if str(path).startswith("/proc/"):
order.append("process")
self.assertEqual(str(path), "/proc/2/exe")
return "wrong" if mutation == "process-bytes" else lab.receipt["binaries"]["v0.0.2"]
return actual_digest(path)
with patch.object(native.urllib.request, "urlopen", side_effect=response), patch.object(native, "digest", side_effect=process_digest):
if mutation:
with self.assertRaises(RuntimeError): lab.assert_runtime("v0.0.2", "active")
else:
self.assertEqual(lab.assert_runtime("v0.0.2", "active"), observed)
self.assertEqual(order[:2], ["health", "version"])
self.assertEqual(order[2:], [] if mutation == "stopped-after-readiness" else ["process"])
def test_runtime_readback_rejects_post_comparison_drift(self):
# Portable manager/API observations, never native acceptance. Keep the
# final oracle independent of the updater's own executable verifier.
mutations = ("", "pid", "activity", "load", "enablement", "installed",
"equally-wrong-bytes", "missing-process", "failed-readback")
for mutation in mutations:
with self.subTest(mutation=mutation), tempfile.TemporaryDirectory() as directory:
lab = self.make_phase(directory)
state = dict(LoadState="loaded", ActiveState="active", UnitFileState="disabled", MainPID="2")
final = state.copy()
changes = {
"pid": {"MainPID": "3"},
"activity": {"ActiveState": "inactive", "MainPID": "0"},
"load": {"LoadState": "not-found"},
"enablement": {"UnitFileState": "masked"},
}
final.update(changes.get(mutation, {}))
end = OSError("confined manager read failed") if mutation == "failed-readback" else final
lab.state = unittest.mock.Mock(side_effect=[state, state, end])
binary = lab.root / "install/bin/pulse"
expected = lab.receipt["binaries"]["v0.0.2"]
original_digest = native.digest
def process_digest(path):
if str(path) == "/proc/2/exe":
if mutation == "missing-process":
raise FileNotFoundError("confined missing process")
if mutation in ("installed", "equally-wrong-bytes"):
binary.write_bytes(b"changed during executable readback\n")
return original_digest(binary) if mutation == "equally-wrong-bytes" else expected
return original_digest(path)
def response(url, **kwargs):
return io.BytesIO(json.dumps({"status": "healthy"} if url.endswith("/health")
else {"version": "v0.0.2"}).encode())
with patch.object(native, "digest", side_effect=process_digest), \
patch.object(native.urllib.request, "urlopen", side_effect=response), \
patch.object(lab, "run", side_effect=AssertionError("readback cannot control a service")):
if mutation:
with self.assertRaises((RuntimeError, OSError)):
lab.assert_runtime("v0.0.2", "active")
self.assertEqual(lab.receipt["phases"], [])
else:
self.assertEqual(lab.assert_runtime("v0.0.2", "active"), state)
self.assertEqual(lab.state.call_count, 3)
# Refuse malformed or non-active manager identity before constructing
# a process path, even when a digest double would otherwise match.
for pid, load in (("0", "loaded"), ("-2", "loaded"), ("02", "loaded"),
("2/../1", "loaded"), ("unknown", "loaded"), ("2", "masked")):
with self.subTest(pid=pid, load=load), tempfile.TemporaryDirectory() as directory:
lab = self.make_phase(directory)
state = dict(LoadState=load, ActiveState="active", UnitFileState="disabled", MainPID=pid)
lab.state = unittest.mock.Mock(return_value=state)
original_digest = native.digest
def no_process_digest(path):
if str(path).startswith("/proc/"):
raise AssertionError("invalid manager identity reached process-byte read")
return original_digest(path)
def response(url, **kwargs):
return io.BytesIO(json.dumps({"status": "healthy"} if url.endswith("/health")
else {"version": "v0.0.2"}).encode())
with patch.object(native, "digest", side_effect=no_process_digest), \
patch.object(native.urllib.request, "urlopen", side_effect=response):
with self.assertRaises(RuntimeError): lab.assert_runtime("v0.0.2", "active")
def test_cleanup_never_deletes_preexisting_unowned_scratch(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory); marker = root / "prior"; marker.write_text("not ours\n")
lab = native.NativeLab(root, ROOT, root / "a", root / "b", "a" * 40)
with patch.object(lab, "run", side_effect=AssertionError("unowned manager operation")):
lab.cleanup()
self.assertTrue(marker.exists())
self.assertFalse(lab.receipt["cleanup"]["owned_fixture_removed"])
def test_prepare_allocates_scratch_before_child_home_initialisation(self):
# Model a child runtime that eagerly initialises HOME. This catches the
# macOS control's FileExistsError without pretending to run systemd.
for load in ("not-found", "loaded"):
with self.subTest(load=load), tempfile.TemporaryDirectory() as directory:
base = Path(directory)
before, after = base / "a", base / "b"
before.write_bytes(b"before\n"); after.write_bytes(b"after\n")
lab = native.NativeLab(base / "lab", ROOT, before, after, "a" * 40)
lab.unit = base / "absent.service"
def child_observation():
lab.root.mkdir(exist_ok=True)
(lab.root / "child-home-marker").write_text("runtime initialised HOME\n")
return {"LoadState": load}
def bounded_command(*args, **kwargs):
if args[0] in (str(before), str(after)) and args[1:] == ("--version",):
tag = native.TAGS[0 if args[0] == str(before) else 1]
return subprocess.CompletedProcess(args, 0, ("Pulse " + tag + "\n").encode())
raise RuntimeError("stop before signer or service mutation")
with patch.object(lab, "state", side_effect=child_observation) as observation, \
patch.object(lab, "run", side_effect=bounded_command):
expected = ValueError if load == "loaded" else RuntimeError
with self.assertRaises(expected):
lab.prepare()
observation.assert_called_once()
self.assertTrue(lab.owned_root)
self.assertTrue((lab.root / "child-home-marker").exists())
self.assertFalse(lab.owned_unit)
self.assertFalse(lab.owned_user)
lab.cleanup()
self.assertFalse(lab.root.exists())
self.assertTrue(lab.receipt["cleanup"]["complete"])
def test_prepare_refuses_existing_directory_or_symlink_before_child(self):
for symlink in (False, True):
with self.subTest(symlink=symlink), tempfile.TemporaryDirectory() as directory:
base = Path(directory); prior = base / "prior"; prior.mkdir()
marker = prior / "keep"; marker.write_text("not ours\n")
root = base / "lab" if symlink else prior
if symlink:
root.symlink_to(prior, target_is_directory=True)
lab = native.NativeLab(root, ROOT, base / "a", base / "b", "a" * 40)
lab.unit = base / "absent.service"
with patch.object(lab, "state", side_effect=AssertionError("unowned child")) as observation:
with self.assertRaises(FileExistsError):
lab.prepare()
observation.assert_not_called()
self.assertFalse(lab.owned_root)
lab.cleanup()
self.assertEqual(marker.read_text(), "not ours\n")
self.assertTrue(root.exists())
self.assertFalse(lab.receipt["cleanup"]["owned_fixture_removed"])
def run_recipe(self, failure="", mismatch=False):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory); tools = root / "tools"; tools.mkdir()
for name in ("frontend-modern/dist", "internal/api/frontend-modern/dist"):
(root / name).mkdir(parents=True); (root / name / "index.html").write_text("real-embed fixture\n")
trace = root / "trace"
fake = '''#!/usr/bin/python3
import json, os, pathlib, sys
args = sys.argv[1:]; name = pathlib.Path(sys.argv[0]).name
with pathlib.Path(os.environ["TRACE"]).open("a") as out: out.write(json.dumps([name, *args])+"\\n")
if name == "git":
if args == ["rev-parse", "HEAD"]: print("b"*40 if os.environ["MISMATCH"] == "true" else "a"*40)
elif args == ["diff", "--quiet", "HEAD"]:
if os.environ["FAIL_BUILD"] == "source-modified": sys.exit(49)
else: sys.exit(97)
if name == "go":
if args[args.index("-o")+1].endswith(os.environ["FAIL_BUILD"]) and os.environ["FAIL_BUILD"]: sys.exit(43)
pathlib.Path(args[args.index("-o")+1]).write_text("compiler double, not a product build\\n")
if name == "sudo":
if os.environ["FAIL_BUILD"] == "native": sys.exit(45)
pathlib.Path(os.environ["RUNNER_TEMP"]+"/pulse-native-updater.json").write_text("{}\\n")
'''
for name in ("git", "go", "sudo"):
path = tools / name; path.write_text(fake); path.chmod(0o755)
env = {**os.environ, "PATH": str(tools) + ":" + os.environ["PATH"], "TRACE": str(trace),
"RUNNER_TEMP": str(root), "EXPECTED_SOURCE_SHA": "a" * 40,
"FAIL_BUILD": failure, "MISMATCH": "true" if mismatch else "false"}
result = subprocess.run(["/bin/bash", "-c", recipe(WORKFLOW.read_text())], env=env, cwd=root, capture_output=True)
return result, [json.loads(line) for line in trace.read_text().splitlines()], (root / "pulse-native-updater.json").exists()
def test_exact_workflow_recipe_is_scrubbed_and_propagates_all_failures(self):
result, calls, receipt = self.run_recipe()
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual([call[0] for call in calls], ["git", "git", "go", "go", "sudo"])
self.assertTrue(receipt)
self.assertEqual(calls[-1][1:3], ["env", "-i"])
for failure, code, count in (("source-modified", 49, 2), ("before", 43, 3), ("after", 43, 4), ("native", 45, 5)):
result, calls, receipt = self.run_recipe(failure)
self.assertEqual(result.returncode, code)
self.assertEqual(len(calls), count)
self.assertFalse(receipt)
result, calls, receipt = self.run_recipe(mismatch=True)
self.assertEqual(result.returncode, 1)
self.assertEqual([call[0] for call in calls], ["git"])
self.assertFalse(receipt)
def test_connected_linux_control_is_required_without_macho_or_validator_bypass(self):
connected = getattr(NativeContracts, LINUX_CONTROL)
self.assertEqual(getattr(connected, "__unittest_skip__", False), not sys.platform.startswith("linux"))
# Import just the definitions as each platform would. No fixture is run
# under a false platform identity, and no production function is changed.
for platform in ("linux", "darwin"):
spec = importlib.util.spec_from_file_location("platform_contracts", Path(__file__))
module = importlib.util.module_from_spec(spec)
with patch.object(sys, "platform", platform): spec.loader.exec_module(module)
control = getattr(module.NativeContracts, LINUX_CONTROL)
self.assertEqual(getattr(control, "__unittest_skip__", False), platform != "linux")
for name in unittest.defaultTestLoader.getTestCaseNames(module.NativeContracts):
if name != LINUX_CONTROL:
self.assertFalse(getattr(getattr(module.NativeContracts, name), "__unittest_skip__", False), name)
@unittest.skipUnless(sys.platform.startswith("linux"), LINUX_ONLY_REASON)
def test_connected_signed_archive_and_recovery_controls_without_host_manager(self):
# Same orchestration and production shell functions, real signatures and
# ELF staging. This test replaces the manager, its process-byte readback,
# account/chown and unit path. /proc/123/exe maps only to the executable
# snapshot made by that simulated manager's start. Real owned /proc
# checks run separately; this is not native/real-Pulse acceptance.
manager = r'''#!/usr/bin/python3
import os, pathlib, shutil, sys
root = pathlib.Path(os.environ["PULSE_NATIVE_ROOT"])
# Tool startup must have an existing owned home, not create the lab before
# NativeLab has admitted and claimed its scratch root (as on macOS).
if not pathlib.Path(os.environ["HOME"]).is_dir(): sys.exit(96)
unit = root / "pulse-source-updater.service"
args = sys.argv[1:]
if any(".service" in a and a != "pulse-source-updater.service" for a in args): sys.exit(97)
load = "masked" if unit.is_symlink() else ("loaded" if unit.exists() else "not-found")
statefile = root / "manager-state"
active = statefile.read_text().strip() if statefile.exists() and load != "not-found" else "inactive"
values = dict(LoadState=load, ActiveState=active, UnitFileState="masked" if load == "masked" else "disabled", MainPID="123" if active == "active" else "0")
if args[0] == "show":
properties = [p for a in args if a.startswith("--property=") for p in a.split("=", 1)[1].split(",")]
if not properties or len(properties) != len(set(properties)) or any(p not in values for p in properties): sys.exit(97)
for p in properties: print(values[p] if "--value" in args else p+"="+values[p])
elif args[0] in ("start", "stop"):
if args[0] == "start" and load != "loaded": sys.exit(1)
statefile.write_text("active" if args[0] == "start" else "inactive")
process_bytes = root / "mock-managed-executable"
if args[0] == "start": shutil.copyfile(root / "install/bin/pulse", process_bytes)
else: process_bytes.unlink(missing_ok=True)
if args[0] == "start" and not (root / "data/.encryption.key").exists():
(root / "data/.encryption.key").write_text("synthetic persistence marker, not a key\n")
elif args[0] == "mask": unit.symlink_to("/dev/null")
elif args[0] == "unmask": unit.unlink()
elif args[0] not in ("daemon-reload", "reset-failed"): sys.exit(97)
'''
class FixtureLab(native.NativeLab):
def run(self, *args, **kwargs):
if args[0] == "/bin/bash":
args = (str(tools / "bash"), *args[1:])
return super().run(*args, **kwargs)
def assert_runtime(self, tag, active):
if native.digest(self.root / "install/bin/pulse") != self.receipt["binaries"][tag]:
raise RuntimeError("fixture executable mismatch")
if (self.root / "install/VERSION").read_text() != tag + "\n":
raise RuntimeError("fixture version mismatch")
state = self.state()
if state["ActiveState"] != active: raise RuntimeError("fixture activity mismatch")
return state
with tempfile.TemporaryDirectory() as directory:
base = Path(directory); tools = base / "tools"; tools.mkdir()
selected = selected_fixture_commands()
tool_trace = base / "selected-tools.jsonl"
for name, executable in selected.items():
# Record only tool identity, never shell arguments or key/log
# bytes. Execute the actual supplied GNU utility; only the
# manager double's fixed process path is redirected below.
tool = tools / name
tool.write_text(f'''#!{sys.executable}
import json, os, pathlib, sys
with pathlib.Path({str(tool_trace)!r}).open('a') as receipt:
receipt.write(json.dumps({name!r}) + '\\n')
arguments = sys.argv[1:]
if {name!r} == 'cmp' and '/proc/123/exe' in arguments:
arguments = [str(pathlib.Path(os.environ['PULSE_NATIVE_ROOT']) / 'mock-managed-executable')
if arg == '/proc/123/exe' else arg for arg in arguments]
os.execv({executable!r}, [{executable!r}, *arguments])
''')
tool.chmod(0o700)
path = tools / "systemctl"; path.write_text(manager); path.chmod(0o755)
account = r'''#!/usr/bin/python3
import os, pathlib, sys
marker = pathlib.Path(os.environ["PULSE_NATIVE_ROOT"]) / "fixture-user"
if pathlib.Path(sys.argv[0]).name == "id":
if sys.argv[1:] != ["-u", "pulse"]: sys.exit(97)
if not marker.exists(): sys.exit(1)
print("1234")
elif pathlib.Path(sys.argv[0]).name == "useradd":
if sys.argv[1:] != ["--system", "--home-dir", str(marker.parent / "install"), "--shell", "/bin/false", "pulse"]: sys.exit(97)
marker.write_text("owned confined fixture account\n")
elif pathlib.Path(sys.argv[0]).name == "userdel":
if sys.argv[1:] != ["pulse"]: sys.exit(97)
marker.unlink()
elif pathlib.Path(sys.argv[0]).name == "chown":
args = [arg for arg in sys.argv[1:] if arg != "-R"]
if len(args) < 2 or args[0] != "pulse:pulse": sys.exit(97)
if any(not pathlib.Path(p).is_relative_to(marker.parent) for p in args[1:]): sys.exit(97)
else: sys.exit(97)
'''
for name in ("id", "useradd", "userdel", "chown"):
tool = tools / name; tool.write_text(account); tool.chmod(0o755)
program = base / "fixture.go"
program.write_text('package main\nimport "fmt"\nvar Version string\nfunc main(){fmt.Println("Pulse " + Version)}\n')
binaries = []
for tag in native.TAGS:
binary = base / tag
subprocess.run(["go", "build", "-o", str(binary), "-ldflags=-X main.Version=" + tag, str(program)],
check=True, capture_output=True, timeout=60)
binaries.append(binary)
lab = FixtureLab(base / "lab", ROOT, *binaries, "a" * 40)
lab.unit = lab.root / "pulse-source-updater.service"
lab.env["HOME"] = str(base)
lab.env["PATH"] = str(lab.root / "tools") + ":" + str(tools) + ":/usr/sbin:/usr/bin:/sbin:/bin"
original_write = Path.write_text
def relocate(path, data, *args, **kwargs):
if path.name == "installer-definitions":
before = "cat > /etc/systemd/system/$SERVICE_NAME.service << EOF"
self.assertEqual(data.count(before), 1)
append = "cat >> /etc/systemd/system/$SERVICE_NAME.service << EOF"
self.assertEqual(data.count(append), 2)
data = data.replace(before, 'cat > "$PULSE_NATIVE_ROOT/pulse-source-updater.service" << EOF')
data = data.replace(append, 'cat >> "$PULSE_NATIVE_ROOT/pulse-source-updater.service" << EOF')
return original_write(path, data, *args, **kwargs)
try:
with patch.object(Path, "write_text", new=relocate), patch.object(native.time, "sleep"):
try:
lab.prepare()
self.assertEqual((lab.root / "data/.env").read_text(),
"PULSE_TELEMETRY=false\nBIND_ADDRESS=127.0.0.1\n")
lab.exercise()
except RuntimeError as error:
self.fail(str(error) + "\nConfined fixture output:\n" + lab._last_output.decode())
self.assertEqual([p["name"] for p in lab.receipt["phases"]],
["forward", "manual-reverse", "failed-active", "failed-inactive",
"failed-masked", "bad-signature", "incomplete-restore"])
self.assertTrue(lab.receipt["phases"][-1]["backup_retained"])
used = [json.loads(line) for line in tool_trace.read_text().splitlines()]
self.assertEqual(set(used), set(FIXTURE_COMMANDS),
"nested shell lost a containing-job fixture tool")
finally:
lab.cleanup()
self.assertTrue(lab.receipt["cleanup"]["complete"])
self.assertFalse(lab.root.exists())
def test_workflow_cannot_hide_or_rebind_native_step(self):
source = WORKFLOW.read_text()
for changed in (source.replace("- name: " + STEP + "\n", "- name: " + STEP + "\n continue-on-error: true\n"),
source.replace("sudo env -i", "sudo env"),
source.replace("main.Version=v0.0.2", "main.Version=v0.0.1"),
source.replace("EXPECTED_SOURCE_SHA: ${{ github.sha }}", "EXPECTED_SOURCE_SHA: main"),
source.replace("runs-on: ubuntu-24.04", "runs-on: self-hosted")):
with self.assertRaises(AssertionError): recipe(changed)
def run_receipt(self, primary, cleanup_fails):
# Execute the actual receipt producer, with real unprivileged failing
# children. Substitute only native admission and service/account work.
# These controls cannot provide a native transaction or cleanup proof.
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
receipt = root / "receipt.json"
lab = native.NativeLab(root, ROOT, root / "a", root / "b", "a" * 40)
owned_cleanup = lab.cleanup
def prepare():
lab.operation = "baseline-install"
if primary == "command":
lab.run("/bin/bash", "-c", "printf 'private-transaction-fixture'; exit 23")
if primary == "timeout":
lab.run(sys.executable, "-c", "import time; time.sleep(60)", timeout=0.05)
if primary == "assertion":
raise RuntimeError("confined persistence assertion")
def exercise():
lab.receipt["phases"] = [{"name": "confined-control"}] * 7
def cleanup():
lab.operation = "cleanup"
if cleanup_fails:
lab.run(sys.executable, "-c", "print('private-cleanup-fixture'); raise SystemExit(31)")
owned_cleanup() # Owns nothing; touches no manager.
argv = ["native-receipt-control", "--before", "unused-before", "--after", "unused-after",
"--receipt", str(receipt)]
with patch.dict(os.environ, {"EXPECTED_SOURCE_SHA": "a" * 40, "RUNNER_TEMP": str(root)}), \
patch.object(sys, "argv", argv), patch.object(native, "hosted_admission"), \
patch.object(native, "NativeLab", return_value=lab), \
patch.object(lab, "prepare", side_effect=prepare), \
patch.object(lab, "exercise", side_effect=exercise), \
patch.object(lab, "cleanup", side_effect=cleanup), \
contextlib.redirect_stdout(io.StringIO()):
if primary or cleanup_fails:
with self.assertRaises(SystemExit): native.main()
else:
native.main()
result = json.loads(receipt.read_text())
for private in ("private-transaction-fixture", "private-cleanup-fixture", str(root)):
self.assertNotIn(private, json.dumps(result))
return result
def test_primary_command_survives_successful_or_failed_cleanup(self):
for cleanup_fails in (False, True):
with self.subTest(cleanup_fails=cleanup_fails):
result = self.run_receipt("command", cleanup_fails)
self.assertEqual(result["command_failure"]["observed_exit"], 23)
self.assertEqual(result["command_failure"]["command"], "bash")
self.assertEqual(result["command_failure"]["operation"], "baseline-install")
self.assertEqual(result["failure"]["operation"], "baseline-install")
self.assertEqual(result["phases"], [])
self.assertEqual(result["cleanup"]["complete"], not cleanup_fails)
if cleanup_fails:
self.assertEqual(result["cleanup"]["command_failure"]["observed_exit"], 31)
self.assertEqual(result["cleanup"]["command_failure"]["operation"], "cleanup")
else:
self.assertNotIn("command_failure", result["cleanup"])
def test_primary_timeout_is_not_replaced_by_cleanup_exit(self):
result = self.run_receipt("timeout", True)
self.assertTrue(result["command_failure"]["deadline_exceeded"])
self.assertLess(result["command_failure"]["observed_exit"], 0)
self.assertEqual(result["command_failure"]["operation"], "baseline-install")
self.assertNotIn("output_sha256", result["command_failure"])
self.assertEqual(result["cleanup"]["command_failure"]["observed_exit"], 31)
self.assertEqual(result["phases"], [])
def test_assertion_and_cleanup_only_errors_do_not_invent_primary_command(self):
for primary in ("assertion", ""):
with self.subTest(primary=primary):
result = self.run_receipt(primary, True)
self.assertNotIn("command_failure", result)
self.assertEqual(result["cleanup"]["command_failure"]["observed_exit"], 31)
self.assertFalse(result["cleanup"]["complete"])
if primary:
self.assertEqual(result["failure"]["operation"], "baseline-install")
self.assertEqual(result["phases"], [])
else:
self.assertNotIn("failure", result)
def test_successful_receipt_retains_no_failure_record(self):
result = self.run_receipt("", False)
self.assertNotIn("failure", result)
self.assertNotIn("command_failure", result)
self.assertNotIn("command_failure", result["cleanup"])
self.assertTrue(result["cleanup"]["complete"])
if __name__ == "__main__":
unittest.main()