"""Archive an approved Git commit, never the local working tree."""
import io
import os
from pathlib import Path
import re
import subprocess
import sys
import tempfile
import zipfile


def archive(repo, commit, output):
    if not re.fullmatch(r'[0-9a-f]{40}|[0-9a-f]{64}', commit):
        raise ValueError('Full approved commit SHA required')
    tree = subprocess.check_output(['git', '-C', repo, 'ls-tree', '-r', commit])
    if any(line.startswith(b'160000 ') for line in tree.splitlines()):
        raise ValueError('Submodules require an explicitly pinned export process')
    data = subprocess.check_output(['git', '-c', 'core.autocrlf=false', '-C', repo, 'archive', '--format=zip', commit])
    with zipfile.ZipFile(io.BytesIO(data)) as z:
        for item in z.infolist():
            name = Path(item.filename).name.lower()
            if name in ('.env', 'credentials', 'id_rsa', 'id_ed25519') or name.startswith('.env.') and name not in ('.env.example', '.env.sample') or name.endswith(('.pem', '.key', '.p12', '.pfx')):
                raise ValueError('Sensitive filename in approved tree: ' + item.filename)
            body = z.read(item)
            if re.search(rb'-----BEGIN (?:[A-Z]+ )*PRIVATE KEY-----', body):
                raise ValueError('Private key in approved tree: ' + item.filename)
            if body.startswith(b'version https://git-lfs.github.com/spec/v1'):
                raise ValueError('LFS pointer requires a pinned LFS export process')
    target = Path(output).resolve()
    with tempfile.NamedTemporaryFile(dir=target.parent, delete=False) as f:
        try:
            f.write(data)
            os.replace(f.name, target)
        finally:
            if os.path.exists(f.name):
                os.unlink(f.name)


if __name__ == '__main__':
    archive(*sys.argv[1:])
