128 lines
7.8 KiB
Python
128 lines
7.8 KiB
Python
"""Collect reviewed package evidence only after the parent's explicit confirmation."""
|
|
from pathlib import Path
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
|
|
ROOT = Path('C:/ar-save-01a0d717')
|
|
QA = ROOT / '.local/package46'
|
|
DEST = ROOT / 'harness/experiments/save-diagnostics-package-20261001/raw'
|
|
ARCHIVE_SHA = '8b4e353e075f22350a07794ee47a02cf85725501223299cf367134aa1f5b63b7'
|
|
|
|
|
|
def identity(path):
|
|
data = path.read_bytes()
|
|
return {'bytes': len(data), 'sha256': hashlib.sha256(data).hexdigest()}
|
|
|
|
|
|
def read(path):
|
|
return json.loads(path.read_text(encoding='utf-8-sig'))
|
|
|
|
|
|
def require(value, why):
|
|
if not value:
|
|
raise RuntimeError(why)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--confirmed', action='store_true', help='Parent confirmed collection after final evidence readiness review')
|
|
args = parser.parse_args()
|
|
require(args.confirmed, 'Do not collect before parent confirmation')
|
|
require(not DEST.exists(), 'Fresh raw evidence directory required; never merge/overwrite a previous packet')
|
|
extraction = read(QA / 'extraction-check.json')
|
|
require(extraction['status'] == 'PASS' and extraction['archive_sha256'] == ARCHIVE_SHA, 'Extraction identity mismatch')
|
|
for folder in ['native46', 'reopen46']:
|
|
result = read(QA / 'qa' / folder / 'finished.json')
|
|
require(result['exit_code'] == 0 and result['stdout_bytes'] == result['stderr_bytes'] == 0
|
|
and result['package_files_unchanged'] and result['archive_sha256'] == ARCHIVE_SHA,
|
|
'Native process has not completed cleanly: ' + folder)
|
|
require(read(QA / 'server-smoke/result.json')['status'] == 'PASS', 'Server smoke incomplete')
|
|
require(len(read(QA / 'server-smoke/result.json')['checks']) == 23, 'Server check count changed; review')
|
|
require(read(QA / 'native-model-oracle/result.json')['status'] == 'PASS', 'Model oracle incomplete')
|
|
reopened = read(QA / 'qa/reopen46/bytes-oracle.json')
|
|
require(reopened['status'] == 'PASS' and len(reopened['files']) == 37
|
|
and reopened['files'] == read(QA / 'qa/native46/saved-c-oracle.json')['files'], 'Reopen byte oracle mismatch')
|
|
require(len(list((QA / 'qa/native46/captures').glob('*.jpg'))) == 19, 'Expected 19 native captures')
|
|
require('Status: interim' not in (QA / 'independent-review.md').read_text(encoding='utf-8'),
|
|
'Independent review remains interim; wait for completed critic report')
|
|
warning_result = read(QA / 'model-warnings/result.json')
|
|
require(warning_result['exit'] == 1, 'Warnings process receipt mismatch')
|
|
warnings = {r['label']: r['response'] for r in warning_result['records']}
|
|
require(set(warnings) == {'pristine', 'saved'}, 'Warning response labels mismatch')
|
|
for label, response in warnings.items():
|
|
require(response == read(QA / 'model-warnings' / (label + '.json')) and response['valid'], 'Raw validation response mismatch')
|
|
prior = warnings['pristine']['issues']
|
|
drift = [i for i in warnings['saved']['issues'] if i['code'] == 'trace_drift']
|
|
require(len(prior) == 1 and prior[0]['code'] == 'work_without_behavior_context'
|
|
and len(drift) == 1 and 'OaChanged' in drift[0]['message']
|
|
and [i for i in warnings['saved']['issues'] if i['code'] != 'trace_drift'] == prior,
|
|
'Validation warning delta differs from expected trace drift')
|
|
phases = ['collision', 'saved-a', 'saved-c', 'external-before', 'inject', 'external-refused', 'restore', 'external-recovered']
|
|
for phase in phases:
|
|
require(read(QA / 'qa/native46' / (phase + '-oracle.json'))['status'] == 'PASS', 'Phase incomplete: ' + phase)
|
|
bundle = Path(extraction['bundle'])
|
|
require({p.relative_to(bundle).as_posix(): identity(p)['sha256'] for p in bundle.rglob('*') if p.is_file()}
|
|
== extraction['sha256'], 'Extracted package changed')
|
|
sources = {}
|
|
|
|
def add(path, name):
|
|
require(path.is_file(), 'Missing required evidence: ' + str(path))
|
|
require(not path.is_symlink(), 'Symlink evidence refused')
|
|
require(name not in sources, 'Duplicate destination: ' + name)
|
|
require(path.suffix.lower() not in ['.exe', '.dll', '.zip'], 'Excluded binary/archive')
|
|
sources[name] = path
|
|
|
|
for name in ['artifact-precheck.md', 'build-evidence.json', 'extraction-check.json', 'packaging.log',
|
|
'preparation-receipt.json', 'source-inputs.json', 'check-native-bytes.py',
|
|
'native-model-oracle.py', 'evidence-plan.md', 'collect-evidence.py']:
|
|
add(QA / name, name)
|
|
for name in ['native-observation.md', 'read-model-warnings.py', 'check-reopened-bytes.py', 'independent-review.md', 'executed-commands.json']:
|
|
add(QA / name, name)
|
|
for name in ['prepare-package46.py', 'extract-package46.py', 'setup-package46-native.py',
|
|
'launch-package46-native.py', 'prepare-package46-reopen.py', 'launch-package46-reopen.py',
|
|
'prepare-package46-model-oracle.py', 'prepare-package46-warnings.py', 'package46-helper-review.md']:
|
|
add(ROOT / '.local' / name, 'scripts/' + name)
|
|
for folder in ['provenance', 'qa/native46', 'qa/reopen46', 'server-smoke', 'native-model-oracle', 'model-warnings']:
|
|
require((QA / folder).is_dir(), 'Missing required evidence directory: ' + folder)
|
|
for path in sorted((QA / folder).rglob('*')):
|
|
if path.is_file() and 'store' not in path.relative_to(QA / folder).parts:
|
|
add(path, path.relative_to(QA).as_posix())
|
|
for name in ['package.json', 'dependency-notices.json', 'documentation-check.json',
|
|
'SHA256SUMS.txt', 'START-HERE.txt', 'THIRD-PARTY-NOTICES.txt']:
|
|
add(bundle / name, 'package/' + name)
|
|
add(QA / 'dist' / (extraction['archive'] + '.sha256'), 'package/' + extraction['archive'] + '.sha256')
|
|
add(ROOT / '.local/package46-donor-recovery/recover.py', 'scripts/recover-donor.py')
|
|
add(QA / 'verify-evidence.py', 'verify.py')
|
|
baseline = read(QA / 'qa/native46/baseline.json')
|
|
companions = [name for name in baseline['baseline'] if not name.endswith('.arcadia')]
|
|
require(len(companions) == 7, 'Companion set changed')
|
|
for name in companions:
|
|
add(bundle / 'examples/release1' / name, 'reference-companions/' + name)
|
|
before = {name: identity(path) for name, path in sources.items()}
|
|
require(sum(x['bytes'] for x in before.values()) < 40000000, 'Unexpected packet expansion')
|
|
DEST.mkdir(parents=True, exist_ok=False)
|
|
for name, source in sources.items():
|
|
target = DEST / name
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
shutil.copyfile(source, target)
|
|
require(identity(target) == before[name] == identity(source), 'Evidence changed during capture: ' + name)
|
|
(DEST / '.gitattributes').write_text('* -text\n**/* -text\n', encoding='utf-8')
|
|
(DEST / 'collection-receipt.json').write_text(json.dumps({
|
|
'source': 'ef28f1784efe6717b0ca72c0eb3c97bc30ebfe47',
|
|
'observed_head': subprocess.check_output(['git', 'rev-parse', 'HEAD'], cwd=ROOT, text=True).strip(),
|
|
'archive_sha256': ARCHIVE_SHA,
|
|
'copies': {name: {'historical_local_path': str(sources[name]), **value} for name, value in before.items()},
|
|
'excluded': ['ZIPs', 'EXEs/DLLs', 'full extracted/staged bundle', 'stores', 'working fixture directories'],
|
|
'scope': 'Byte capture of completed receipts; historical scripts retain original paths and are not portable replay commands.'
|
|
}, indent=2) + '\n', encoding='utf-8')
|
|
inventory = {p.relative_to(DEST).as_posix(): identity(p) for p in sorted(DEST.rglob('*')) if p.is_file()}
|
|
(DEST / 'evidence-files.json').write_text(json.dumps(inventory, indent=2) + '\n', encoding='utf-8')
|
|
print(json.dumps({'packet': str(DEST), 'files': len(inventory), 'bytes': sum(x['bytes'] for x in inventory.values())}))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|