Route delivered HQ tracks to temporary road interception and refresh playtest packages
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Read-only exact current five-addon PAK inspection; optional new /tmp report dir.
|
||||
No extraction, native launch, package modification or qualification upgrade.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import argparse,hashlib,json,sys,zipfile
|
||||
ROOT=Path('/home/jakub/devel/escapistsrereintroduced')
|
||||
SESSION=Path('/tmp/erri-road-interception-packages')
|
||||
sys.path.insert(0,str(ROOT/'tools'))
|
||||
import native_package as package
|
||||
import pak_inventory
|
||||
import packed_external
|
||||
AUTHORED_SHA='acf02e18c1f23e2f68d52393e38c34b9603ce75b895413d270606e043f519a2d'
|
||||
ORIGINAL_SHA='2527b5a9bc4ac22549e7430a99e8598d14c7ad8ff79943c6937cc15c904212b6'
|
||||
|
||||
def require(value,message):
|
||||
if not value:raise ValueError(message)
|
||||
|
||||
def exact_payload(project,entries,authored):
|
||||
actual={'addons/'+project+'/'+entry['path']:entry['sha256'] for entry in entries}
|
||||
require(len(actual)==len(entries),'Duplicate PAK paths')
|
||||
prefix='addons/'+project+'/'
|
||||
expected={name:sha for name,sha in authored.items() if name.startswith(prefix) and not name.endswith('.meta') and name!=prefix+'addon.gproj'}
|
||||
require(bool(expected),'Missing expected addon content: '+project)
|
||||
missing=sorted(set(expected)-set(actual));extra=sorted(set(actual)-set(expected));changed=sorted(name for name in expected.keys()&actual.keys() if actual[name]!=expected[name])
|
||||
require(actual==expected,'PAK/source mismatch '+project+': missing='+repr(missing[:8])+' extra='+repr(extra[:8])+' changed='+repr(changed[:8]))
|
||||
return len(actual)
|
||||
|
||||
def verify(source_zip=None):
|
||||
require(SESSION==SESSION.resolve() and SESSION.is_dir(),'Session redirected')
|
||||
for name in ('authored-before.json','package-report.json'):
|
||||
require((SESSION/name).is_file() and not (SESSION/name).is_symlink(),'Baseline file redirected: '+name)
|
||||
require(package.digest(SESSION/'authored-before.json')==AUTHORED_SHA,'Frozen authored manifest changed')
|
||||
require(package.digest(SESSION/'package-report.json')==ORIGINAL_SHA,'Original failed package report changed')
|
||||
authored=json.loads((SESSION/'authored-before.json').read_text())
|
||||
require(package.inventory(ROOT)==authored and package.copied_authored_snapshot(SESSION/'source',authored)==authored,'Current/captured authored source differs from freeze')
|
||||
artifacts=packed_external.inventory(SESSION/'packages') # exact five directories and fifteen regular runtime files; new AI closure
|
||||
report={'kind':'EXACT DEVELOPMENT FIVE-ADDON PAYLOAD/SOURCE REVIEW','authored_manifest_sha256':AUTHORED_SHA,'original_package_report_sha256':ORIGINAL_SHA,'source_addon_files':len(authored),'projects':{},'artifacts':artifacts,'all_payloads_match':False,'build_qualified':False,'release_qualified':False,'native_consumption_verified':False}
|
||||
inventories={}
|
||||
for project in packed_external.PROJECTS:
|
||||
folder=SESSION/'packages'/project
|
||||
require(artifacts[project+'/addon.gproj']['sha256']==authored['addons/'+project+'/addon.gproj'],'Packed project bytes differ from authored project: '+project)
|
||||
value=pak_inventory.inventory(folder/'data.pak')
|
||||
require(value['archive_sha256']==artifacts[project+'/data.pak']['sha256'],'PAK changed between runtime and content inventory: '+project)
|
||||
count=exact_payload(project,value['entries'],authored)
|
||||
inventories[project]=value;report['projects'][project]={'entries':count,'exact_paths_and_hashes_match':True}
|
||||
if source_zip is not None:
|
||||
require(source_zip.is_file() and not source_zip.is_symlink(),'Source ZIP must be a regular file')
|
||||
zip_sha=package.digest(source_zip)
|
||||
with zipfile.ZipFile(source_zip) as archive:
|
||||
manifest=json.loads(archive.read('BUNDLE-MANIFEST.json'))
|
||||
require(manifest.get('kind')=='DEVELOPMENT SOURCE BUNDLE' and manifest.get('native_build') is False,'Not a development source bundle')
|
||||
require({name:sha for name,sha in manifest['files'].items() if name.startswith('addons/')}==authored,'Source ZIP does not match this frozen package input')
|
||||
require(set(manifest['files'])==set(authored)|{'BUNDLE-README.md','EXTERNAL-ADDONS.json'},'Unexpected development source bundle payload')
|
||||
require(json.loads(archive.read('EXTERNAL-ADDONS.json'))==json.loads((SESSION/'external-addons-policy.json').read_text()),'Source ZIP external policy differs from frozen build')
|
||||
require(len(archive.namelist())==len(set(archive.namelist())) and set(archive.namelist())==set(manifest['files'])|{'BUNDLE-MANIFEST.json'},'Source ZIP has duplicate/unmanifested entries')
|
||||
for name,sha in manifest['files'].items():require(hashlib.sha256(archive.read(name)).hexdigest()==sha,'Source ZIP payload hash mismatch: '+name)
|
||||
require(package.digest(source_zip)==zip_sha,'Source ZIP changed during review')
|
||||
report['matching_source_zip']={'path':str(source_zip),'sha256':zip_sha}
|
||||
require(packed_external.inventory(SESSION/'packages')==artifacts,'Runtime files changed during content review')
|
||||
require(package.inventory(ROOT)==authored and package.copied_authored_snapshot(SESSION/'source',authored)==authored,'Source changed during content review')
|
||||
require(package.digest(SESSION/'authored-before.json')==AUTHORED_SHA and package.digest(SESSION/'package-report.json')==ORIGINAL_SHA,'Original baseline changed during content review')
|
||||
report['all_payloads_match']=True
|
||||
return report,inventories
|
||||
|
||||
def main():
|
||||
parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--output',type=Path,help='Optional new direct /tmp child for JSON inventories/review');parser.add_argument('--source-zip',type=Path);args=parser.parse_args()
|
||||
if args.output is not None:
|
||||
output=args.output
|
||||
require(output.is_absolute() and output.parent==Path('/tmp') and output==output.resolve() and not output.exists() and not output.is_symlink(),'Output must be a new canonical direct /tmp child')
|
||||
report,inventories=verify(args.source_zip)
|
||||
if args.output is not None:
|
||||
args.output.mkdir(exist_ok=False)
|
||||
for project,value in inventories.items():package.save(args.output/(project+'-pak-inventory.json'),value)
|
||||
package.save(args.output/'payload-source-review.json',report)
|
||||
print(json.dumps(report,indent=2))
|
||||
return 0
|
||||
|
||||
if __name__=='__main__':
|
||||
try:raise SystemExit(main())
|
||||
except (OSError,ValueError,pak_inventory.PakError,zipfile.BadZipFile) as error:print('REFUSED: '+str(error),file=sys.stderr);raise SystemExit(1)
|
||||
Reference in New Issue
Block a user