arch-system/scripts/check-repo-data.py

53 lines
2.7 KiB
Python
Executable file

#!/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))