63 lines
3.9 KiB
Python
63 lines
3.9 KiB
Python
"""Preserve four sanitized publication records; never read credentials or upload."""
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
|
|
destination = Path(__file__).resolve().parent
|
|
repository = destination.parents[2]
|
|
source = repository / '.local/cli-packaging-20260911'
|
|
names = ['upload-binaries-verified.json', 'upload-validation-verified.json',
|
|
'published-verified.json', 'RELEASE-NOTES.md']
|
|
records = []
|
|
for name in names:
|
|
data = (source / name).read_bytes()
|
|
target = destination / name
|
|
if not target.exists():
|
|
with target.open('xb') as output:
|
|
output.write(data)
|
|
assert target.read_bytes() == data
|
|
records.append({'path': name, 'source': '.local/cli-packaging-20260911/' + name,
|
|
'bytes': len(data), 'sha256': hashlib.sha256(data).hexdigest(),
|
|
'crlf_sequences': data.count(b'\r\n'),
|
|
'bare_lf_sequences': data.count(b'\n') - data.count(b'\r\n'),
|
|
'method': 'exact byte copy; source and destination reread equal'})
|
|
def read(name):
|
|
return json.loads((destination / name).read_text(encoding='utf-8-sig'))
|
|
publication = read('published-verified.json')
|
|
release = read('mcp-release-readback.json')
|
|
tag = read('mcp-tag-readback.json')
|
|
assert publication['id'] == release['id'] == 2
|
|
assert publication['tag'] == release['tag_name'] == tag['name'] == 'cli-v0.2.0-preview.authoring.20260911'
|
|
assert publication['draft'] is release['draft'] is False
|
|
assert publication['prerelease'] is release['prerelease'] is True
|
|
assert release['target'] == tag['commit_sha'] == '27df4a3945ebc97cd7cbde61f6aeea7a91c680d3'
|
|
assert publication['published_at'] == release['published_at'] == '2026-09-11T12:50:39Z'
|
|
notes = (destination / 'RELEASE-NOTES.md').read_bytes()
|
|
# The publisher's recorded hash binds the LF public body, not the local CRLF
|
|
# file. Keep both exact identities and prove the sole normalization explicitly.
|
|
normalized_notes = notes.decode('utf-8-sig').replace('\r\n', '\n')
|
|
assert hashlib.sha256(normalized_notes.encode('utf-8')).hexdigest() == publication['notes_sha256']
|
|
assert normalized_notes == release['body']
|
|
assets = read('upload-binaries-verified.json') + read('upload-validation-verified.json')
|
|
assert len(assets) == publication['asset_count'] == 3
|
|
assert all(item['readback'] == 'PASS' for item in assets)
|
|
assert assets[0]['sha256'] == '2b051f8ce1ea4f59ee7e233e1fbd516d423aadbfbca5d549755cbe78fcde1af6'
|
|
assert assets[0]['bytes'] == 5091267
|
|
for name in ['mcp-release-readback.json', 'mcp-tag-readback.json']:
|
|
data = (destination / name).read_bytes()
|
|
records.append({'path': name, 'bytes': len(data), 'sha256': hashlib.sha256(data).hexdigest(),
|
|
'method': 'MCP read-only parsed response, locally serialized as UTF-8 JSON; not original HTTP wire bytes'})
|
|
result = {'scope': 'Publication evidence preservation and read-only MCP release/tag comparison; no runtime tests or asset re-download.',
|
|
'release_id': 2, 'tag': tag['name'], 'publication_url': release['html_url'],
|
|
'published_at': release['published_at'], 'source_roles': {
|
|
'semantic_source': '01b76a1e89e93b7992f39e63560aa8b2ca2f69e0',
|
|
'packaging_assembly': 'a0a48e82bd43be181caca1fe2c1514c21f2bc405',
|
|
'release_integration': release['target']},
|
|
'assets': assets, 'files': records,
|
|
'checks': {'four_exact_copies': True, 'release_and_tag_match': True,
|
|
'published_flags_and_time_match': True, 'normalized_notes_hash_matches_publisher_record': True,
|
|
'notes_match_public_body_after_CRLF_to_LF_only': True,
|
|
'asset_records_are_original_publisher_readbacks': True}}
|
|
(destination / 'manifest.json').write_text(json.dumps(result, indent=2) + '\n', encoding='utf-8', newline='\n')
|
|
print(json.dumps({'result': 'PASS', 'copied_files': records[:4], 'release_target': release['target']}, indent=2))
|