65 lines
4.5 KiB
Python
65 lines
4.5 KiB
Python
"""Archive closed GUI receipts and read package bytes; never executes application code."""
|
|
from pathlib import Path, PurePosixPath
|
|
import datetime,hashlib,json,shutil
|
|
OUT=Path(__file__).resolve().parent
|
|
SOURCE=Path('C:/Users/User/Documents/Git/ARCADIA-Studio/.local/native-865483b')
|
|
def sha(path):return hashlib.sha256(path.read_bytes()).hexdigest().upper()
|
|
def save(name,obj):(OUT/name).write_text(json.dumps(obj,indent=2)+'\n',encoding='utf-8')
|
|
assert not (OUT/'manifest.json').exists()
|
|
baseline=json.loads((SOURCE/'extraction-readback.json').read_bytes())
|
|
package=Path(baseline['package_directory'])
|
|
assert baseline['exit']==0 and len(baseline['files'])==559
|
|
expected={}
|
|
for item in baseline['files']:
|
|
parts=PurePosixPath(item['path']).parts
|
|
assert parts[0]==package.name
|
|
relative=PurePosixPath(*parts[1:]).as_posix()
|
|
assert relative not in expected
|
|
expected[relative]=item
|
|
actual={p.relative_to(package).as_posix():p for p in package.rglob('*') if p.is_file()}
|
|
assert set(actual)==set(expected),'Package inventory differs from original extraction'
|
|
checked=[]
|
|
for relative,path in sorted(actual.items()):
|
|
observed={'bytes':path.stat().st_size,'sha256':sha(path)}
|
|
old=expected[relative]
|
|
assert observed['bytes']==old['bytes'] and observed['sha256']==old['sha256'].upper(),relative
|
|
checked.append({'path':relative,**observed})
|
|
sums={}
|
|
for line in (package/'SHA256SUMS.txt').read_text(encoding='utf-8').splitlines():
|
|
digest,relative=line.split(' ',1)
|
|
assert relative not in sums
|
|
sums[relative]=digest.upper()
|
|
assert set(sums)==set(actual)-{'SHA256SUMS.txt'}
|
|
for relative,digest in sums.items():assert sha(actual[relative])==digest,relative
|
|
completion=json.loads((SOURCE/'packaged-home-guide-close-complete.json').read_bytes())
|
|
assert completion['pid']==8680 and completion['remaining_target_windows']==[]
|
|
assert 'do not infer0' in completion['exit_code']
|
|
assert (SOURCE/'logs/studio-packaged.stdout.log').stat().st_size==0
|
|
assert (SOURCE/'logs/studio-packaged.stderr.log').stat().st_size==0
|
|
launch=json.loads((SOURCE/'launch-packaged.json').read_bytes())
|
|
assert sha(package/'package.json')==launch['package_json']['sha256']
|
|
copy_map=[]
|
|
for number in range(96,101):
|
|
matches=list((SOURCE/'screenshots').glob(f'{number}-*.jpg'))
|
|
assert len(matches)==1,(number,matches)
|
|
copy_map.append((matches[0],Path('screenshots')/matches[0].name))
|
|
for name in ['normal-close-observation.json','packaged-home-guide-close-complete.json','launch-packaged.json','extraction-readback.json']:
|
|
copy_map.append((SOURCE/name,Path(name)))
|
|
for name in ['studio-packaged.stdout.log','studio-packaged.stderr.log']:
|
|
copy_map.append((SOURCE/'logs'/name,Path('logs')/name))
|
|
for name in ['package.json','SHA256SUMS.txt']:
|
|
copy_map.append((package/name,Path('package-baseline')/name))
|
|
records=[]
|
|
for original,relative in copy_map:
|
|
target=OUT/relative
|
|
assert not target.exists(),target
|
|
before={'bytes':original.stat().st_size,'sha256':sha(original)}
|
|
target.parent.mkdir(parents=True,exist_ok=True)
|
|
shutil.copyfile(original,target)
|
|
after={'bytes':target.stat().st_size,'sha256':sha(target)}
|
|
assert before==after and sha(original)==before['sha256']
|
|
records.append({'original':str(original),'archive':relative.as_posix(),'bytes':after['bytes'],'original_sha256':before['sha256'],'copy_sha256':after['sha256']})
|
|
save('manifest.json',{'result':'passed','source':'865483b4c66361a01fe0d9e731859220bafb4136','gui_sha256':completion['gui_sha256'],'payload_files':len(records),'payload_bytes':sum(r['bytes'] for r in records),'files':records})
|
|
save('package-readback.json',{'result':'passed','readback_utc':datetime.datetime.now(datetime.timezone.utc).isoformat(),'method':'Read-only full package inventory and SHA256/size comparison to original extraction receipt; every SHA256SUMS entry also independently rehashed','package_directory':str(package),'baseline_receipt':'extraction-readback.json','baseline_receipt_sha256':sha(SOURCE/'extraction-readback.json'),'original_archive_sha256':baseline['archive_sha256'],'package_files':len(checked),'package_bytes':sum(r['bytes'] for r in checked),'checksum_entries':len(sums),'checksum_file_covered_by_original_extraction':True,'package_json_matches_original_launch_receipt':True,'mismatches':[],'files':checked})
|
|
print(json.dumps({'payload_files':len(records),'payload_bytes':sum(r['bytes'] for r in records),'package_files':len(checked),'checksum_entries':len(sums),'manifest_sha256':sha(OUT/'manifest.json'),'package_readback_sha256':sha(OUT/'package-readback.json')},indent=2))
|