From dc2a60f8fc559f5aba5ab3bf3f57f53db3f7438d Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 10 Nov 2026 14:40:37 -0500 Subject: [PATCH] test: record published HistorianGateway 1.0 package verification --- scripts/validation/historiangw-131/README.md | 12 ++-- scripts/validation/historiangw-131/RESULTS.md | 56 +++++++++++++++++-- .../validation/historiangw-131/validate.py | 29 ++++++++++ 3 files changed, 87 insertions(+), 10 deletions(-) diff --git a/scripts/validation/historiangw-131/README.md b/scripts/validation/historiangw-131/README.md index d308fb7c..d3d84c3f 100644 --- a/scripts/validation/historiangw-131/README.md +++ b/scripts/validation/historiangw-131/README.md @@ -1,8 +1,10 @@ # HistorianGateway consumer TLS migration — issue 131 -`consumer-1.0.0.patch` is a future consumer change, kept separate from the buildable -application while the paired Client/Contracts 1.0.0 packages are being released. -The application in this checkout remains pinned to published 0.4.0. +`consumer-1.0.0.patch` is a reviewable consumer change, kept separate from the +buildable application in this checkout. Real paired Client/Contracts 1.0.0 +packages are now published and the isolated owning-project proof passed (RESULTS.md). +The application in this checkout remains pinned to published 0.4.0 until the patch +is applied by the coordinator. The patch changes both central package pins to 1.0.0 and maps the new option as: @@ -70,4 +72,6 @@ validation does not create or publish any fake package/version. Restore uses an independent copy-on-write/copy cache, isolated HTTP cache and CLI home. Neither user checkout is built or edited. Full owning-suite TRX, required TLS failure classification, command exits and execution guard are retained under the task -output. Never treat source validation as stable published-package verification. +output. Published mode additionally checks package assets/provenance, absence of +source overrides, and exact package-to-test-bin DLL hashes. Never treat source +validation as stable published-package verification. diff --git a/scripts/validation/historiangw-131/RESULTS.md b/scripts/validation/historiangw-131/RESULTS.md index c278c093..e2427d20 100644 --- a/scripts/validation/historiangw-131/RESULTS.md +++ b/scripts/validation/historiangw-131/RESULTS.md @@ -1,4 +1,47 @@ -# HG issue 131 validation evidence +# HG issue 131 — actual published 1.0.0 verification + +Both real stable **Client 1.0.0** and **Contracts 1.0.0** were observed in the live +Gitea indexes at 2026-11-10 19:35:54 UTC and restored into a fresh isolated cache. +The future consumer patch was applied only to a separate SDK 2 consumer archive. +Application files in this working branch remain on 0.4.0, unchanged. + +- Full Gateway owning project: **529 total, 523 passed, 0 failed, 6 existing live skips**. +- Restore, test and repository execution-count guard exits: **0 / 0 / 0**. +- All **3 real TLS/h2c wire cases passed** against the published packages. +- Strict default rejected with AuthenticationException **UntrustedRoot**, before RPC. +- Explicit opt-out and plaintext/stale-TLS-settings cases each completed one RPC. +- Both assets entries are **type=package, version=1.0.0**, from the actual Gitea + source. No source ProjectReference override: the archived Gateway csproj is + byte-identical to the normal consumer csproj. +- The only package folder is the task-isolated cache. Both copied test-bin DLL + hashes equal the package DLL hashes. No package was packed or published here. + +Actual package RepositoryCommit for BOTH packages: +`ea9f21c850fb618767e12690924f9966f1e433ac`. +Consumer archive base: `4ea379fa92e571492ff9f49889a5eb91e3ad1e1a`. +Applied patch SHA-256: `9452ee82b2bace7828a384b9f6048e9c931e8b4ec2078e0ee1baa175d0652fac`. + +| Package | NuGet package SHA-256 | Consumed DLL SHA-256 | +|---|---|---| +| ZB.MOM.WW.HistorianGateway.Client 1.0.0 | `0a3f2836727671c07c0c393e705cc9737d2ed44258213a51fb4acf0d0ab7129e` | `b89a02e0d228ec549c4dfb755694f7f67b573a6077f06ff2781165e884fc5e12` | +| ZB.MOM.WW.HistorianGateway.Contracts 1.0.0 | `83ffd12bcbbf919c973ba522560e10aa93a4cb8c686a3232030a2cfa5f00995e` | `e60d3d4650be5d251982f7847404daf1b666f61d56e2b0ccb844af8677e97743` | + +Proof metadata/source/hash/readback checks: +`/tmp/historiangw-131-published-20261110T193638Z/published-package-proof.json`. +Full run metadata (including typed TLS error and package readback): +`/tmp/historiangw-131-published-20261110T193638Z/metadata.json`. +Fresh actual-package TRX: `/tmp/historiangw-131-published-20261110T193638Z/test-results`. +Restore/test/guard logs: `/tmp/historiangw-131-published-20261110T193638Z`. + +This completes the isolated SDK 2 owning-project proof. The coordinator separately +owns the consumer-master full solution build, Astra review, landing/push and issue +131 comment/closure. No issue action, package publication, or HG user-checkout +mutation was performed by this validation lane. The live AVEVA fixture skips do +not substitute for the three executed local wire tests. + +--- + +# Earlier archived-source validation Future consumer patch validated against exact archived HG source commit `e4321915ebc5e0704a68ecad21b85c1cc1c80d6b`. Consumer archive base: @@ -8,8 +51,9 @@ Future consumer patch validated against exact archived HG source commit ## Scope and isolation Mode: **unreleased source project references**, not published-package verification. -Both live package feed indexes still listed only 0.4.0, 0.3.0, 0.2.0, 0.1.0 after -validation. Stable Client/Contracts 1.0.0 verification remains pending. +At that earlier source-validation time, both feed indexes still listed only +0.4.0, 0.3.0, 0.2.0, 0.1.0. The published-package run below supersedes that pending +release-availability status. The user's HG checkout was only read by git archive. Only the disposable archived consumer Gateway csproj had its two package references replaced by project @@ -49,6 +93,6 @@ Archived-source Client DLL SHA-256: Archived-source Contracts DLL SHA-256: `ebaaa43ffc485288054eb864a59ec59264d8d9c4ea6871319fd7995192370751`. -No stable release was consumed by this run. The real paired 1.0.0 packages must be -restored, the full owning suite/solution built and reviewed, and the consumer change -landed before issue 131 is closed. No issue comment/close was performed here. +That earlier run consumed source only. Actual stable-package proof is recorded +above. Consumer-master solution build/review/landing and issue handling are owned +by the coordinator; no issue comment/close was performed here. diff --git a/scripts/validation/historiangw-131/validate.py b/scripts/validation/historiangw-131/validate.py index 51cfc291..73a747e4 100644 --- a/scripts/validation/historiangw-131/validate.py +++ b/scripts/validation/historiangw-131/validate.py @@ -4,6 +4,33 @@ import argparse, datetime, hashlib, io, json, os, shutil, subprocess, tarfile, u import xml.etree.ElementTree as ET from pathlib import Path +def verify_published_packages(root, consumer, cache, project): + relative = Path('src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.csproj') + assert (consumer/relative).read_bytes() == (root/relative).read_bytes(), 'Unexpected source-project override' + assets = json.loads((consumer/project.parent/'obj/project.assets.json').read_text()) + assert all(Path(p).resolve() == cache.resolve() for p in assets['packageFolders']) + proof = {'no_source_project_reference_override': True, 'packages': {}} + for name in ['Client', 'Contracts']: + ident = 'ZB.MOM.WW.HistorianGateway.' + name + library = assets['libraries'][ident + '/1.0.0'] + assert library['type'] == 'package' + package = cache/ident.lower()/'1.0.0' + provenance = json.loads((package/'.nupkg.metadata').read_text()) + assert provenance['source'].startswith('https://gitea.dohertylan.com/api/packages/dohertj2/nuget') + dll = package/'lib/net10.0'/(ident + '.dll') + copied = consumer/project.parent/'bin/Release/net10.0'/(ident + '.dll') + digest = hashlib.sha256(dll.read_bytes()).hexdigest() + assert digest == hashlib.sha256(copied.read_bytes()).hexdigest() + nuspec = ET.parse(package/(ident.lower() + '.nuspec')) + assert nuspec.findtext('.//{*}version') == '1.0.0' + repository = nuspec.find('.//{*}repository') + proof['packages'][ident] = {'version': '1.0.0', 'asset_type': 'package', + 'source': provenance['source'], 'dll_sha256': digest, + 'nupkg_sha256': hashlib.sha256((package/(ident.lower() + '.1.0.0.nupkg')).read_bytes()).hexdigest(), + 'repository': repository.attrib if repository is not None else None, + 'test_bin_dll_matches_package': True} + return proof + parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--consumer-root', type=Path, required=True) parser.add_argument('--hg-root', type=Path, required=True) @@ -93,5 +120,7 @@ for trx in results.glob('*.trx'): xml=ET.parse(trx);metadata['results'].append(xml.find('.//t:Counters',ns).attrib) metadata['tls_cases']=[{'name':r.get('testName'),'outcome':r.get('outcome'),'output':'\n'.join(p.text or '' for p in r.findall('.//t:StdOut',ns)), 'error':r.findtext('.//t:Message','',ns)} for r in xml.findall('.//t:UnitTestResult',ns) if 'HistorianGatewayTlsPolicyWireTests' in r.get('testName','')] +if published: + metadata['package_proof'] = verify_published_packages(root, consumer, cache, project) (out/'metadata.json').write_text(json.dumps(metadata,indent=2));print(json.dumps(metadata,indent=2),flush=True) raise SystemExit(test if test else guard.returncode)