#!/usr/bin/env python3 """Static repository references; no privilege, network or host inventory reads.""" from pathlib import Path import re import sys root = Path(sys.argv[1]) errors = [] def error(value): errors.append(value) def lines(path): try: return (root/path).read_text(encoding='utf-8').splitlines() except OSError as exc: error(f'{path}: {exc}'); return [] for name in ('pacman','aur','orphans'): path = f'pkglist/{name}.txt' values = lines(path) if values != sorted(set(values)) or any(not re.fullmatch(r'[A-Za-z0-9@._+:-]+', x) for x in values): error(f'{path}: tri, doublon ou nom invalide') if set(lines('pkglist/pacman.txt')) & set(lines('pkglist/aur.txt')): error('paquet présent dans les deux listes') for name in ('system-services','system-timers','on-demand-system-services'): path = f'manifests/{name}.txt' values = lines(path) suffix = '.timer' if name == 'system-timers' else '.service' if values != sorted(set(values)) or any(not re.fullmatch(r'[A-Za-z0-9@._:-]+', x) or not x.endswith(suffix) for x in values): error(f'{path}: unité invalide, désordre ou doublon') for name,needles in { 'templates/fstab.btrfs':('@ROOT_UUID@','@EFI_UUID@','subvol=/@/.snapshots'), 'templates/limine.conf':('@ROOT_UUID@',), 'templates/sudoers.d/batlimit':('@USER@',), 'templates/sudoers.d/vmware-stack':('@USER@',), }.items(): value='\n'.join(lines(name)) for needle in needles: if needle not in value: error(f'{name}: {needle} absent') for path in [root/'README.md',*sorted((root/'docs').rglob('*.md'))]: try: text=path.read_text(encoding='utf-8') except OSError as exc: error(str(exc)); continue for target in re.findall(r'\]\(([^)]+)\)',text): if '://' in target or target.startswith('#') or target.startswith('mailto:'): continue local=target.split('#',1)[0].split(' ',1)[0] if local: candidate=(path.parent/local).resolve() if not candidate.is_relative_to(root.resolve()) or not candidate.exists(): error(f'{path.relative_to(root)}: lien local absent ou hors dépôt {target}') for path in root.rglob('*'): if '.git' in path.parts or not path.is_file(): continue if path.suffix in ('.key','.pem','.p12','.sqlite','.sqlite3','.db') or path.name == '.netrc': error(f'fichier potentiellement sensible : {path.relative_to(root)}') for forbidden in ('userfs','inventory/packages','rootfs/etc/sudoers.d'): if (root/forbidden).exists(): error(f'répertoire interdit : {forbidden}') for item in errors: print('[!] '+item,file=sys.stderr) print(f'Contrôle des listes, manifests, modèles et liens : {len(errors)} erreur(s).') sys.exit(bool(errors))