"""Synthetic ZIP fixity controls: Python 3 standard library, entirely in memory.
Usage: python reproducibility-controls.py > reproducibility-controls.json
Creates four tiny archives from original XML written for this experiment. It reads
no client files, extracts nothing, executes no archive content, and uses no network.
Fixed names, timestamps, ordering and compression settings make repeated runs
deterministic within the same ZIP/DEFLATE implementation. Member SHA-256 values
remain comparable even if a different compressor produces different ZIP bytes.
"""
import hashlib
from io import BytesIO
import json
import zipfile
BASE_MEMBERS = {
'interface/window.xml': b'\n',
'interface/theme.xml': b'#17352b8\n',
}
CHANGED_MEMBER = 'interface/window.xml'
CHANGED_CONTENT = b'\n'
MISSING_MEMBER = 'interface/theme.xml'
BASE_DATE = (2025, 9, 11, 12, 0, 0)
REPACKED_DATE = (2026, 10, 15, 14, 30, 0)
def sha256(content):
return hashlib.sha256(content).hexdigest()
def make_archive(members, timestamp=BASE_DATE, compression=zipfile.ZIP_STORED):
"""Create authored controls with explicit metadata and sorted member order."""
output = BytesIO()
with zipfile.ZipFile(output, 'w') as archive:
for name, content in sorted(members.items()):
entry = zipfile.ZipInfo(name, date_time=timestamp)
entry.create_system = 3
entry.external_attr = 0o100644 << 16
entry.compress_type = compression
archive.writestr(entry, content, compresslevel=9)
return output.getvalue()
def inspect_archive(content):
"""Measure container bytes and decoded member bytes separately."""
members = {}
with zipfile.ZipFile(BytesIO(content), 'r') as archive:
for entry in archive.infolist():
payload = archive.read(entry)
members[entry.filename] = {
'bytes': len(payload), 'sha256': sha256(payload),
'zipCompressionMethod': entry.compress_type,
'zipTimestamp': list(entry.date_time),
}
return {'bytes': len(content), 'sha256': sha256(content), 'members': members}
def compare_members(reference, candidate):
reference_members = reference['members']
candidate_members = candidate['members']
reference_names = set(reference_members)
candidate_names = set(candidate_members)
changed = sorted(name for name in reference_names & candidate_names
if reference_members[name]['sha256'] != candidate_members[name]['sha256'])
missing = sorted(reference_names - candidate_names)
added = sorted(candidate_names - reference_names)
return {
'containerDigestChanged': reference['sha256'] != candidate['sha256'],
'memberNamesEqual': reference_names == candidate_names,
'memberBytesIdentical': not changed and not missing and not added,
'changedMembers': changed, 'missingMembers': missing, 'addedMembers': added,
}
def run_controls():
changed = dict(BASE_MEMBERS, **{CHANGED_MEMBER: CHANGED_CONTENT})
missing = {name: content for name, content in BASE_MEMBERS.items()
if name != MISSING_MEMBER}
fixtures = {
'baseline': inspect_archive(make_archive(BASE_MEMBERS)),
'repackaged': inspect_archive(make_archive(BASE_MEMBERS, REPACKED_DATE, zipfile.ZIP_DEFLATED)),
'changedPayload': inspect_archive(make_archive(changed)),
'missingMember': inspect_archive(make_archive(missing)),
}
expectations = {
'repackaged': {'containerDigestChanged': True, 'memberNamesEqual': True,
'memberBytesIdentical': True, 'changedMembers': [],
'missingMembers': [], 'addedMembers': []},
'changedPayload': {'containerDigestChanged': True, 'memberNamesEqual': True,
'memberBytesIdentical': False, 'changedMembers': [CHANGED_MEMBER],
'missingMembers': [], 'addedMembers': []},
'missingMember': {'containerDigestChanged': True, 'memberNamesEqual': False,
'memberBytesIdentical': False, 'changedMembers': [],
'missingMembers': [MISSING_MEMBER], 'addedMembers': []},
}
controls = []
for name, expected in expectations.items():
observed = compare_members(fixtures['baseline'], fixtures[name])
controls.append({'id': name, 'expected': expected, 'observed': observed,
'passed': observed == expected})
return {
'schemaVersion': 1,
'study': 'Synthetic ZIP fixity and member-identity controls',
'scope': 'Original authored XML fixtures; no EverQuest client files or behavior were examined.',
'method': {'inMemory': True, 'clientFilesRead': False, 'filesExtracted': False,
'archiveContentExecuted': False, 'networkConnections': False,
'fixedMetadata': True,
'reproducibility': 'Repeated runs with the same ZIP/DEFLATE implementation; member digests do not depend on compression.'},
'expectedMemberSHA256': {
'baseline': {name: sha256(content) for name, content in sorted(BASE_MEMBERS.items())},
'changedPayload': {CHANGED_MEMBER: sha256(CHANGED_CONTENT)},
},
'fixtures': fixtures,
'controls': controls,
'allControlsPassed': all(control['passed'] for control in controls),
}
if __name__ == '__main__':
print(json.dumps(run_controls(), indent=2, ensure_ascii=True))