refactor!: port shell scripts to Python package

Bash scripts were untestable and duplicated device/LUKS/mount logic;
the lim/ package centralizes it behind one subprocess wrapper and a
YAML image catalog (single point of truth).

BREAKING CHANGE: scripts/*.sh removed. Use `lim --type <cmd>`; new
types mount/umount/single-boot/raid1-boot/lock/unlock/import/export
replace direct script calls. --extra is deprecated and ignored.

- distributions.yml + lim/catalog.py hold the image catalog (PyYAML)
- pytest suite: 102 tests with mocked subprocess (tests/unit) and a
  250-line max file-length guard (tests/lint)
- ruff strict (select ALL), GitHub Actions CI, Dependabot; Travis gone
- Makefile: install (symlink ~/.local/bin/lim) and test targets
- fixes over bash: SUDO_USER-aware chown, mmcblk/nvme partition paths,
  sha512 checksum support, whole-pipeline failure detection, blkid
  UUID fallback for pre-mounted images, conditional fstab seeding for
  PARTUUID/LABEL images, clean errors for missing binaries
This commit is contained in:
Kevin Veen-Birkenbach
2026-07-14 11:27:49 +02:00
parent c420dd164d
commit ccdef065df
77 changed files with 3402 additions and 1614 deletions

59
tests/unit/test_luks.py Normal file
View File

@@ -0,0 +1,59 @@
import pytest
from lim import luks
from lim.errors import LimError
LUKS_DUMP = """\
LUKS header information
Version: 2
UUID: 1234-abcd-5678
"""
def test_luks_uuid_parsed_from_dump(fake_runner):
fake_runner.outputs["luksDump"] = LUKS_DUMP
assert luks.luks_uuid("/dev/sda1") == "1234-abcd-5678"
def test_luks_uuid_missing_raises(fake_runner):
fake_runner.outputs["luksDump"] = "no uuid here"
with pytest.raises(LimError):
luks.luks_uuid("/dev/sda1")
def test_update_fstab_is_idempotent(tmp_path):
fstab = tmp_path / "fstab"
fstab.write_text("# existing\n")
luks.update_fstab("/dev/mapper/x", "/media/x", fstab_path=fstab)
luks.update_fstab("/dev/mapper/x", "/media/x", fstab_path=fstab)
lines = fstab.read_text().splitlines()
assert lines.count("/dev/mapper/x /media/x btrfs defaults 0 2") == 1
def test_create_luks_key_and_update_crypttab(tmp_path, fake_runner):
fake_runner.outputs["luksDump"] = LUKS_DUMP
key_dir = tmp_path / "luks-keys"
crypttab = tmp_path / "crypttab"
luks.create_luks_key_and_update_crypttab(
"encrypteddrive-sda",
"/dev/sda1",
key_directory=key_dir,
crypttab_path=crypttab,
)
keyfile = key_dir / "encrypteddrive-sda.keyfile"
assert len(fake_runner.find("dd", "if=/dev/urandom", f"of={keyfile}")) == 1
assert len(fake_runner.find("cryptsetup", "luksAddKey", "/dev/sda1")) == 1
assert len(fake_runner.find("cryptsetup", "luksOpen", f"--key-file={keyfile}")) == 1
expected_entry = f"encrypteddrive-sda UUID=1234-abcd-5678 {keyfile} luks"
assert expected_entry in crypttab.read_text().splitlines()
# A second run must not duplicate the crypttab entry.
luks.create_luks_key_and_update_crypttab(
"encrypteddrive-sda",
"/dev/sda1",
key_directory=key_dir,
crypttab_path=crypttab,
)
assert crypttab.read_text().splitlines().count(expected_entry) == 1