#!/usr/bin/env python3 """Bind notice repair and fresh-OS delivery evidence to the unchanged v2 build.""" from datetime import datetime, timezone import hashlib import json from pathlib import Path ROOT = Path(__file__).resolve().parents[1] PARENT = ROOT / 'tests/results/pdfium-intent-context/integration-record.json' PARENT_SHA = 'd376de4f28b43c22b9073f07ca06c7e90edf2c9e271c12f6ebcdb364822d7b42' OUTPUT = ROOT / 'tests/results/qpdf-notice-supplement/integration-record.json' def sha(path): with path.open('rb') as stream: return hashlib.file_digest(stream, 'sha256').hexdigest() def ref(path): return {'path': str(path.relative_to(ROOT)), 'sha256': sha(path)} def main(): current = ROOT / 'docs/validation-record.json' assert not OUTPUT.exists(), 'The delivery record is immutable.' assert sha(current) == sha(PARENT) == PARENT_SHA parent = json.loads(PARENT.read_text()) required = { 'qpdfNoticeRepair': ROOT / 'tests/results/qpdf-notice-supplement/report.json', 'ubuntuNoticePackage': ROOT / 'tests/results/qpdf-notice-supplement/ubuntu-package/report.json', 'freshUbuntuInstall': ROOT / 'tests/results/pdfium-context-fresh/report.json', 'currentInteraction': ROOT / 'tests/results/pdfium-context-interaction/report.json', } for key, path in required.items(): assert json.loads(path.read_text())['success'] is True, key source_join = ROOT / 'tests/results/qt-sdk-source-join/report.json' assert json.loads(source_join.read_text())['analysisCompleted'] is True for name, digest in parent['sourceSha256'].items(): if name.startswith(('src/', 'qml/', 'resources/')) or name in ('CMakeLists.txt', 'resources.qrc'): assert sha(ROOT / name) == digest, name for name, digest in parent['executables'].items(): assert sha(ROOT / 'build-context' / name) == digest, name for key in ('selectedLibrary', 'buildInfo', 'reviewedLock'): item = parent['candidateIntegration'][key] assert sha(ROOT / item['path']) == item['sha256'], key anchor = parent['candidateBuildAnchor'] assert sha(ROOT / anchor['path']) == anchor['sha256'] sources = {name: sha(ROOT / name) for name in parent['sourceSha256']} for folder in ('tools', 'tests', 'tests/ubuntu_vm'): for path in sorted((ROOT / folder).glob('*.py')): sources[str(path.relative_to(ROOT))] = sha(path) sources[str(Path(__file__).resolve().relative_to(ROOT))] = sha(Path(__file__).resolve()) evidence = {} for folder in ('qpdf-notice-supplement', 'pdfium-context-fresh', 'pdfium-context-interaction', 'qt-sdk-source-join'): for path in sorted((ROOT / 'tests/results' / folder).rglob('*')): if path.is_file() and path != OUTPUT and '__pycache__' not in path.parts: evidence[str(path.relative_to(ROOT))] = sha(path) documents = {name: sha(ROOT / name) for name in parent['documentationSha256']} documents['docs/DEPENDENCY-PROVENANCE.md'] = sha(ROOT / 'docs/DEPENDENCY-PROVENANCE.md') documents['docs/WINDOWS-BUILD.md'] = sha(ROOT / 'docs/WINDOWS-BUILD.md') record = dict(parent) record.update( schemaVersion=8, recordedAtUtc=datetime.now(timezone.utc).isoformat(), scope='Same v2 application and runtime bytes; repaired qpdf notice correspondence and validation5 packaging, first application install on a fresh Ubuntu cloud-image overlay, and the current T20 interaction workload. The full design acceptance remains incomplete.', goalComplete=False, previousValidation=ref(PARENT), sourceSha256=sources, documentationSha256=documents, evidenceSha256=evidence, changedSincePreviousRecord=[ {'path': name, 'previousSha256': digest, 'currentSha256': sources[name]} for name, digest in parent['sourceSha256'].items() if sources[name] != digest ], deliveryFollowup={key: ref(path) for key, path in required.items()}, qtSdkSourceCorrespondenceInvestigation=ref(source_join), designDocumentsSha256={str(path.relative_to(ROOT)): sha(path) for path in sorted((ROOT / 'docs/design').glob('*.md'))}, archApplicationAndCandidateBytesUnchanged=True, ) record['candidateIntegration'] = dict(parent['candidateIntegration']) record['candidateIntegration']['ubuntuPackageRecord'] = ref(required['ubuntuNoticePackage']) encoded = json.dumps(record, indent=2) + '\n' OUTPUT.write_text(encoded) current.write_text(encoded) print(json.dumps({'schemaVersion': 8, 'sha256': sha(current), 'sourceFiles': len(sources), 'evidenceFiles': len(evidence), 'goalComplete': False})) if __name__ == '__main__': main()