initial commit
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Repackage the fixed Ubuntu v2 install with pinned qpdf notices, without rebuilding."""
|
||||
from pathlib import Path
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import time
|
||||
|
||||
HOME = Path('/home/docview')
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
OUTPUT = HOME / 'validation/qpdf-notice-package'
|
||||
PRIOR_SOURCE = HOME / 'docview-context-source'
|
||||
INSTALL = HOME / 'docview-context-install'
|
||||
VERSION = '0.1.0~validation5'
|
||||
|
||||
|
||||
def sha(path):
|
||||
with path.open('rb') as stream:
|
||||
return hashlib.file_digest(stream, 'sha256').hexdigest()
|
||||
|
||||
|
||||
def main():
|
||||
assert Path.home() == HOME and os.getuid() == 1000
|
||||
assert ROOT == HOME / 'validation/qpdf-notice-tools'
|
||||
OUTPUT.mkdir(parents=True, exist_ok=False)
|
||||
sys.path.insert(0, str(ROOT / 'tools'))
|
||||
from verify_ubuntu_package import inspect, verify, MANIFEST
|
||||
from collect_ubuntu_validation_runtime import QPDF_NOTICE_PIN
|
||||
env = {**os.environ, 'PATH': '/opt/docview-deps/bin:/opt/docview-qt/6.11.2/gcc_64/bin:' + os.environ['PATH'],
|
||||
'LD_LIBRARY_PATH': '/opt/docview-deps/lib:/opt/docview-qt/6.11.2/gcc_64/lib'}
|
||||
for key in ('LD_PRELOAD', 'LD_AUDIT', 'QTWEBENGINE_DISABLE_SANDBOX'):
|
||||
env.pop(key, None)
|
||||
preserved = [INSTALL/'bin'/name for name in ('docview','docview-pdf-worker','docview-archive-worker')]
|
||||
preserved += [INSTALL/'lib/libpdfium.so', HOME/'validation/pdfium-context-prefix/BUILDINFO.json',
|
||||
Path('/opt/docview-deps/lib/libqpdf.so.30')]
|
||||
before = {str(p):sha(p) for p in preserved}
|
||||
report = {'success': False, 'version': VERSION, 'scope': 'Notice collection and packaging only; no C++ rebuild or repeated full CTest',
|
||||
'runtimeBefore': before, 'runnerSha256': sha(Path(__file__)), 'commands': []}
|
||||
def run(name, command):
|
||||
start = time.monotonic()
|
||||
with (OUTPUT/(name+'.log')).open('w') as log:
|
||||
result = subprocess.run(command, env=env, stdout=log, stderr=subprocess.STDOUT, timeout=900)
|
||||
report['commands'].append({'name':name, 'command':command, 'exitCode':result.returncode,
|
||||
'seconds':time.monotonic()-start, 'logSha256':sha(OUTPUT/(name+'.log'))})
|
||||
assert result.returncode == 0, name
|
||||
try:
|
||||
for name in ('test_ubuntu_validation_runtime','test_qpdf_notice_package','test_pdfium_candidate_integration'):
|
||||
run(name,[sys.executable,str(ROOT/'tests'/(name+'.py')),'-v'])
|
||||
command = [sys.executable,str(ROOT/'tools/package_ubuntu.py'),'--prefix',str(INSTALL),
|
||||
'--qtpaths','/opt/docview-qt/6.11.2/gcc_64/bin/qtpaths','--dependency-prefix','/opt/docview-deps',
|
||||
'--source-root',str(HOME/'dependency-sources/qpdf-12.4.1'),
|
||||
'--source-root',str(HOME/'dependency-sources/libzip-1.11.4'),
|
||||
'--qpdf-source-archive',str(HOME/'incoming/qpdf-12.4.1.tar.gz'),
|
||||
'--input-manifest',str(HOME/'incoming/sdk-downloads.json'),
|
||||
'--sdk-notices',str(PRIOR_SOURCE/'tests/results/source-archives/qt-sdk-notices-final'),
|
||||
'--sdk-supplement',str(PRIOR_SOURCE/'tests/results/qt-notice-supplement/collection'),
|
||||
'--qt-licenses',str(PRIOR_SOURCE/'tests/results/ubuntu-package/inputs/qt-licenses'), '--version',VERSION]
|
||||
archives = []
|
||||
for name in ('package','repeat'):
|
||||
run(name,[*command,'--output',str(OUTPUT/name)])
|
||||
archive = OUTPUT/name/('docview_'+VERSION+'_amd64.deb'); archives.append(archive)
|
||||
run(name+'-verify',[sys.executable,str(ROOT/'tools/verify_ubuntu_package.py'),'--archive',str(archive),
|
||||
'--output',str(OUTPUT/name/'verification.json')])
|
||||
assert sha(archives[0]) == sha(archives[1])
|
||||
prior = HOME/'validation/pdfium-context-package/package/package/docview_0.1.0~validation4_amd64.deb'
|
||||
assert sha(prior) == 'bd4f00912078d406cb466cd6910ed01c0c9fdd32b76cb2f47b74cfb9719f1bd9'
|
||||
def inventory(path):
|
||||
data, _, _ = inspect(path, '--fsys-tarfile')
|
||||
control, _, _ = inspect(path, '--ctrl-tarfile')
|
||||
return {**data, **{'DEBIAN/'+name:dict(row,path='DEBIAN/'+name) for name,row in control.items()}}
|
||||
old, new = inventory(prior), inventory(archives[0])
|
||||
differences = {'added':[new[k] for k in sorted(new.keys()-old.keys())],
|
||||
'removed':[old[k] for k in sorted(old.keys()-new.keys())],
|
||||
'changed':[{'path':k,'before':old[k],'after':new[k]} for k in sorted(old.keys()&new.keys()) if old[k]!=new[k]]}
|
||||
protected = lambda k: not k.startswith(('DEBIAN/','opt/docview/share/doc/docview/'))
|
||||
protected_paths = {k for k in old.keys()|new.keys() if protected(k)}
|
||||
unchanged = all(old.get(k)==new.get(k) for k in protected_paths)
|
||||
assert unchanged, 'Runtime or application payload changed'
|
||||
diff = {'success': True, 'method':'Bounded raw data/control inventory; old validation4 is not accepted by the current notice verifier',
|
||||
'oldArchiveSha256':sha(prior),'newArchiveSha256':sha(archives[0]),'oldFiles':len(old),'newFiles':len(new),
|
||||
'allRuntimeAndApplicationFilesUnchanged':unchanged,'protectedFileCount':len(protected_paths),**differences}
|
||||
(OUTPUT/'payload-difference.json').write_text(json.dumps(diff,indent=2)+'\n')
|
||||
result = verify(archives[0])
|
||||
notice = next(row for row in result['qpdfNoticeCorrespondence']['notices'] if row['source']=='NOTICE.md')
|
||||
wanted = './opt/docview/share/doc/docview/third-party/runtime/'+notice['copiedPath']
|
||||
process = subprocess.Popen(['dpkg-deb','--fsys-tarfile',str(archives[0])],stdout=subprocess.PIPE)
|
||||
found = None
|
||||
with tarfile.open(fileobj=process.stdout,mode='r|') as tar:
|
||||
for member in tar:
|
||||
if member.name == wanted:
|
||||
assert member.isfile() and member.size==QPDF_NOTICE_PIN['notices']['NOTICE.md']['size']
|
||||
found = tar.extractfile(member).read()
|
||||
process.stdout.close(); assert process.wait(timeout=15)==0
|
||||
assert found is not None and hashlib.sha256(found).hexdigest()==QPDF_NOTICE_PIN['notices']['NOTICE.md']['sha256']
|
||||
assert found==(HOME/'dependency-sources/qpdf-12.4.1/NOTICE.md').read_bytes()
|
||||
(OUTPUT/'NOTICE.from-deb.md').write_bytes(found)
|
||||
report.update(success=True, archive=str(archives[0]),archiveSha256=sha(archives[0]),
|
||||
repeatSha256=sha(archives[1]),archiveBytes=archives[0].stat().st_size,
|
||||
qpdfNoticeCorrespondence=result['qpdfNoticeCorrespondence'],pdfiumCorrespondence=result['pdfiumCorrespondence'],
|
||||
actualNoticeBytesMatchSelectedSource=True, actualPayloadCompared=True)
|
||||
finally:
|
||||
report['runtimeAfter']={str(p):sha(p) for p in preserved}
|
||||
report['runtimeUnchanged']=report['runtimeBefore']==report['runtimeAfter']
|
||||
report['success']=report['success'] and report['runtimeUnchanged']
|
||||
(OUTPUT/'report.json').write_text(json.dumps(report,indent=2)+'\n')
|
||||
print(json.dumps({k:report[k] for k in ('success','archiveSha256','archiveBytes','runtimeUnchanged')}))
|
||||
|
||||
|
||||
if __name__=='__main__': main()
|
||||
Reference in New Issue
Block a user