AFFECTOR / source /macos /sign_release.py
will-taggart's picture
Stage standalone documentation, technical paper, and source for signed release
f592f80 verified
Raw History Blame Contribute Delete
1.74 kB
"""Sign an existing, prepared AFFECTOR release copy from the inside out."""
from pathlib import Path
import argparse,subprocess
p=argparse.ArgumentParser(description=__doc__);p.add_argument('--app',type=Path,required=True);p.add_argument('--identity',required=True);a=p.parse_args();app=a.app.resolve()
if not (app/'Contents/Info.plist').is_file():raise SystemExit('Expected an existing .app bundle')
framework=app/'Contents/Resources/Python.framework'
for name,target in {'Versions/Current':'3.14','Python':'Versions/Current/Python','Resources':'Versions/Current/Resources','Headers':'Versions/Current/Headers'}.items():
link=framework/name
if not link.exists() and not link.is_symlink():link.symlink_to(target)
magic={bytes.fromhex(s) for s in ('cffaedfe','cefaedfe','feedfacf','feedface','cafebabe','cafebabf','bebafeca','bfbafeca')}
def macho(path):
if path.is_symlink() or not path.is_file():return False
with path.open('rb') as f:return f.read(4) in magic
def sign(path):
r=subprocess.run(['codesign','--force','--sign',a.identity,'--timestamp','--options','runtime',str(path)],capture_output=True,text=True)
if r.returncode:raise RuntimeError(str(path)+'\n'+r.stderr)
binaries=sorted((x for x in app.rglob('*') if macho(x)),key=lambda x:len(x.parts),reverse=True)
print('Signing',len(binaries),'native binaries',flush=True)
for i,b in enumerate(binaries):
sign(b)
if (i+1)%25==0:print(i+1,'signed',flush=True)
for b in sorted((x for x in app.rglob('*') if x.is_dir() and not x.is_symlink() and x.suffix in ('.app','.framework','.xpc','.appex')),key=lambda x:len(x.parts),reverse=True):sign(b)
sign(app);subprocess.run(['codesign','--verify','--deep','--strict',str(app)],check=True)
print('Signed and verified',app,flush=True)