main
John Lauer Add repeatable GLB binding and asset integrity verification 00cf997 12d ago
"""Check the published motion asset and provenance without a graphics runtime."""
from pathlib import Path
import hashlib,json,struct
root=Path(__file__).resolve().parents[1]
manifest=json.loads((root/'states.json').read_text()); motion=manifest['motion']
blob=(root/motion['model']).read_bytes()
assert hashlib.sha256(blob).hexdigest()==motion['sha256']
magic,version,length=struct.unpack_from('<4sII',blob)
assert (magic,version,length)==(b'glTF',2,len(blob))
n,kind=struct.unpack_from('<II',blob,12);assert kind==0x4e4f534a
model=json.loads(blob[20:20+n]);nodes=model['nodes']
def unique(name):
 found=[i for i,node in enumerate(nodes) if node.get('name')==name]
 assert len(found)==1,(name,found)
 return found[0]
rotor=unique(motion['nodes']['rotor']);housing=unique(motion['nodes']['stationary'])
rootnode=unique(motion['nodes']['assembly'])
assert rotor in nodes[rootnode]['children'] and housing in nodes[rootnode]['children']
assert len(nodes[rotor]['children'])==8
for binding in motion['bindings']:
 animations=[a for a in model['animations'] if a.get('name')==binding['animation']]
 assert len(animations)==1
 assert all(c['target']['node']==rotor and c['target']['path']=='rotation' for c in animations[0]['channels'])
for asset in json.loads((root/'provenance/assets.json').read_text())['assets']:
 assert hashlib.sha256((root/asset['file']).read_bytes()).hexdigest()==asset['sha256'],asset['file']
print('PASS: GLB structure, unique bindings, rotor-only animation, asset hashes')