71 lines
2.2 KiB
Python
Executable file
71 lines
2.2 KiB
Python
Executable file
#!/usr/bin/python3
|
|
# Validate basic syntax of shell script and yaml.
|
|
|
|
import os
|
|
import re
|
|
import stat
|
|
import subprocess
|
|
import yaml
|
|
|
|
INITRD_SERVICES_WITHOUT_BEFORE = {
|
|
# Depended on by other services
|
|
'coreos-livepxe-rootfs.service',
|
|
}
|
|
|
|
validated=0
|
|
|
|
def openat(dirfd, name, mode='r'):
|
|
def opener(path, flags):
|
|
return os.open(path, flags, dir_fd=dirfd)
|
|
return open(name, mode, opener=opener)
|
|
|
|
|
|
def validate_initrd_service(rootfd, name):
|
|
with openat(rootfd, name) as fh:
|
|
if ([l for l in fh.readlines() if l.startswith('Before=')] or
|
|
name in INITRD_SERVICES_WITHOUT_BEFORE):
|
|
global validated
|
|
validated += 1
|
|
else:
|
|
raise Exception(
|
|
f'{name} has no Before= and may race with switch-root'
|
|
)
|
|
|
|
|
|
BASH_UNBRACKETED_IF = re.compile(r'\sif\s+"?\$')
|
|
def validate_shell(rootfd, name):
|
|
subprocess.check_call(['bash', '-n', name], preexec_fn=lambda: os.fchdir(rootfd))
|
|
with openat(rootfd, name) as fh:
|
|
if BASH_UNBRACKETED_IF.search(fh.read()):
|
|
raise Exception(f'Possible unbracketed conditional in {name}')
|
|
global validated
|
|
validated +=1
|
|
|
|
|
|
for root, dirs, files, rootfd in os.fwalk('.'):
|
|
# Skip .git
|
|
if '.git' in dirs:
|
|
dirs.remove('.git')
|
|
for name in files:
|
|
print(f"[+] Looking at {name}")
|
|
if name.endswith(('.yaml', '.yml')):
|
|
with open(os.open(name, dir_fd=rootfd, flags=os.O_RDONLY)) as f:
|
|
yaml.safe_load(f)
|
|
validated +=1
|
|
continue
|
|
elif name.endswith('.sh'):
|
|
validate_shell(rootfd, name)
|
|
continue
|
|
elif 'dracut/modules.d' in root and name.endswith('.service'):
|
|
validate_initrd_service(rootfd, name)
|
|
stbuf = os.lstat(name, dir_fd=rootfd)
|
|
if not stat.S_ISREG(stbuf.st_mode):
|
|
continue
|
|
if not stbuf.st_mode & stat.S_IXUSR:
|
|
continue
|
|
mimetype = subprocess.check_output(['file', '-b', '--mime-type', name], encoding='UTF-8',
|
|
preexec_fn=lambda: os.fchdir(rootfd)).strip()
|
|
if mimetype == 'text/x-shellscript':
|
|
validate_shell(rootfd, name)
|
|
|
|
print(f"Validated {validated} files")
|