File size: 2,433 Bytes
a0a9254
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
"""Verify or export the exact public files listed in MANIFEST.json."""
import argparse,gzip,hashlib,json,tarfile
from pathlib import Path
ROOT=Path(__file__).resolve().parents[1]
FORBIDDEN={'.local','.runtime','.venv','node_modules','__pycache__','.git','runs','bench'}
def digest(path):
    h=hashlib.sha256()
    with path.open('rb') as f:
        for block in iter(lambda:f.read(8*1024*1024),b''):h.update(block)
    return h.hexdigest()
def verify():
    manifest=json.loads((ROOT/'MANIFEST.json').read_text())
    for name,info in manifest['files'].items():
        p=Path(name)
        if name=='bench.command' or p.is_absolute() or '..' in p.parts or set(p.parts)&FORBIDDEN or any(x.startswith('.env') for x in p.parts):raise ValueError('Forbidden manifest path')
        file=ROOT/p
        if file.is_symlink() or not file.is_file() or ROOT not in file.resolve().parents:raise ValueError('Release file missing or not a regular contained file')
        if file.stat().st_size!=info['bytes'] or digest(file)!=info['sha256']:raise ValueError('Release checksum mismatch: '+name)
    return manifest

def export(path,manifest):
    path=path.resolve()
    if path==ROOT or ROOT in path.parents:raise ValueError('Export outside the release directory')
    path.parent.mkdir(parents=True,exist_ok=True)
    if path.exists():raise ValueError('Output already exists; choose a new filename')
    with path.open('xb') as raw,gzip.GzipFile(filename='',fileobj=raw,mode='wb',mtime=0,compresslevel=6) as gz,tarfile.open(fileobj=gz,mode='w') as archive:
        for name in sorted([*manifest['files'],'MANIFEST.json']):
            file=ROOT/name;info=tarfile.TarInfo('NanoJev-Web/'+name)
            info.size=file.stat().st_size;info.mode=0o755 if name.endswith('.command') or name.endswith('.sh') else 0o644
            info.uid=info.gid=0;info.uname=info.gname='';info.mtime=0
            with file.open('rb') as src:archive.addfile(info,src)
    checksum=digest(path);path.with_suffix(path.suffix+'.sha256').write_text(checksum+'  '+path.name+'\n')
    print(json.dumps({'archive':path.name,'bytes':path.stat().st_size,'sha256':checksum}))
if __name__=='__main__':
    p=argparse.ArgumentParser(description=__doc__);p.add_argument('--export',type=Path);a=p.parse_args();m=verify()
    print(json.dumps({'verified':True,'files':len(m['files']),'bytes':sum(i['bytes'] for i in m['files'].values())}))
    if a.export:export(a.export,m)