91 lines
6.4 KiB
Python
91 lines
6.4 KiB
Python
"""Synthetic OOXML originals through the guarded QA web server; no secrets in proof."""
|
|
import hashlib
|
|
import io
|
|
import json
|
|
import uuid
|
|
import zipfile
|
|
import xml.etree.ElementTree as ET
|
|
from datetime import datetime, timezone
|
|
from portal_profiles_http_session import Session, PRIVATE, EXPECTED, REASON, events
|
|
|
|
source = json.loads((PRIVATE / 'opportunity-semantic-http-qa.json').read_text(encoding='utf-8-sig'))
|
|
assert source['result'] == 'passed' and source['target'] == EXPECTED
|
|
record = next(c['id'] for c in source['cases'] if c['category'] == 'concession')
|
|
base = f'/minhas-oportunidades/{record}'
|
|
proof = {'target': EXPECTED, 'id': record, 'started_at': datetime.now(timezone.utc).isoformat(), 'active_writes': 0, 'interface_observed': False, 'types': []}
|
|
|
|
def file_bytes(kind):
|
|
mime = 'application/vnd.openxmlformats-officedocument.' + ('wordprocessingml.document' if kind == 'docx' else 'spreadsheetml.sheet')
|
|
part = 'word/document.xml' if kind == 'docx' else 'xl/workbook.xml'
|
|
content = ('<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:body><w:p><w:r><w:t>Synthetic QA no official value</w:t></w:r></w:p></w:body></w:document>' if kind == 'docx' else '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheets><sheet name="Synthetic QA" sheetId="1" r:id="rId1"/></sheets></workbook>')
|
|
files = {
|
|
'[Content_Types].xml': f'<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/{part}" ContentType="{mime}.main+xml"/>' + ('<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>' if kind == 'xlsx' else '') + '</Types>',
|
|
'_rels/.rels': f'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="{part}"/></Relationships>',
|
|
part: content,
|
|
}
|
|
if kind == 'xlsx':
|
|
files['xl/_rels/workbook.xml.rels'] = '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/></Relationships>'
|
|
files['xl/worksheets/sheet1.xml'] = '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData><row r="1"><c r="A1" t="inlineStr"><is><t>Synthetic QA no official value</t></is></c></row></sheetData></worksheet>'
|
|
buffer = io.BytesIO()
|
|
with zipfile.ZipFile(buffer, 'w', zipfile.ZIP_DEFLATED) as z:
|
|
for name, text in files.items():
|
|
ET.fromstring(text)
|
|
z.writestr(name, text)
|
|
with zipfile.ZipFile(io.BytesIO(buffer.getvalue())) as z:
|
|
assert z.testzip() is None and z.read(part).decode() == content
|
|
return mime, buffer.getvalue()
|
|
|
|
def page(s):
|
|
return s.call('GET', base + '/edit', inertia=True)['props']
|
|
|
|
def resources(s):
|
|
return s.call('GET', base + '/resources', inertia=True)['props']['resources']['documents']
|
|
|
|
try:
|
|
owner = Session('promoter').login()
|
|
reviewer = Session('validator').login()
|
|
publisher = Session('publisher').login()
|
|
outsider = Session('outsider').login()
|
|
for kind in ['docx', 'xlsx']:
|
|
mime, data = file_bytes(kind)
|
|
title = 'Original sintético QA OOXML ' + kind
|
|
old = next((r for r in resources(owner) if r['payload'].get('title') == title), None)
|
|
if old:
|
|
assert old['deleted_at'] is None
|
|
resource_id = old['id']
|
|
data = owner.call('GET', base + f'/resources/documents/{resource_id}/download', binary=True)
|
|
with zipfile.ZipFile(io.BytesIO(data)) as z:
|
|
assert z.testzip() is None
|
|
for name in z.namelist():
|
|
ET.fromstring(z.read(name))
|
|
else:
|
|
resource_id = owner.call('POST', base + '/resources/documents', {'etag': page(owner)['etag'], 'creation_key': str(uuid.uuid4()), 'reason': REASON,
|
|
'payload': json.dumps({'title': title, 'category': 'qa-synthetic', 'classification': 'restricted', 'visibility': 'internal'})},
|
|
multipart=('synthetic-qa.' + kind, mime, data), status=201)['id']
|
|
row = next(r for r in resources(owner) if r['id'] == resource_id)
|
|
digest = hashlib.sha256(data).hexdigest()
|
|
assert row['file']['media_type'] == mime and row['file']['malware_scan_status'] == 'clean' and row['file']['sha256'].strip() == digest
|
|
url = base + f'/resources/documents/{resource_id}/download'
|
|
for actor in [owner, reviewer, publisher]:
|
|
assert actor.call('GET', url, binary=True) == data
|
|
outsider.call('GET', url, status=403, binary=True)
|
|
for action in ['delete', 'restore']:
|
|
current = next(r for r in resources(owner) if r['id'] == resource_id)
|
|
owner.call('POST', base + f'/resources/documents/{resource_id}/lifecycle', {'etag': page(owner)['etag'], 'version': current['version'], 'action': action, 'reason': REASON, 'confirm': True})
|
|
if action == 'delete':
|
|
owner.call('GET', url, status=404, binary=True)
|
|
assert resource_id not in [d['id'] for d in page(owner)['canonicalOptions']['resources']['documents']]
|
|
fresh = Session('promoter').login()
|
|
assert fresh.call('GET', url, binary=True) == data
|
|
proof['types'].append({'type': kind, 'resource_id': resource_id, 'sha256': digest, 'package_xml_crc_valid': True, 'clamd_real_clean': True,
|
|
'allowed': [21, 24, 25], 'foreign_organization': 403, 'deleted_download': 404, 'original_restored_identical_new_session': True})
|
|
proof['result'] = 'passed'
|
|
except Exception as error:
|
|
proof.update({'result': 'failed', 'failure': str(error)})
|
|
raise
|
|
finally:
|
|
proof['events'] = events
|
|
proof['completed_at'] = datetime.now(timezone.utc).isoformat()
|
|
(PRIVATE / 'opportunity-office-documents-http-qa.json').write_text(json.dumps(proof, ensure_ascii=False, indent=2), encoding='utf-8')
|
|
print(json.dumps({'result': proof['result'], 'target': EXPECTED, 'types': [r['type'] for r in proof['types']], 'events': len(events), 'active_writes': 0}))
|