tigrcorn-certification 0.3.16.dev12__tar.gz → 0.3.17.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/PKG-INFO +3 -3
  2. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/pyproject.toml +3 -3
  3. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/__init__.py +203 -0
  4. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/aioquic_preflight/__init__.py +9 -0
  5. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/aioquic_preflight/bundle.py +80 -0
  6. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/aioquic_preflight/core.py +115 -0
  7. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/aioquic_preflight/helpers.py +87 -0
  8. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/aioquic_preflight/imports.py +24 -0
  9. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/aioquic_preflight/records.py +54 -0
  10. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/aioquic_preflight/status_docs.py +109 -0
  11. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/artifacts.py +337 -0
  12. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/src/tigrcorn_certification/certification_env.py +4 -52
  13. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/__init__.py +17 -0
  14. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/adapters.py +259 -0
  15. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/assertions.py +61 -0
  16. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/core.py +23 -0
  17. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/environment.py +211 -0
  18. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/helpers.py +179 -0
  19. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/imports.py +57 -0
  20. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/matrix.py +148 -0
  21. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/models.py +144 -0
  22. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/ports.py +69 -0
  23. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/process.py +46 -0
  24. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/proxies.py +211 -0
  25. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/qlog.py +142 -0
  26. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/runner.py +116 -0
  27. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/interop_runner/scenario.py +395 -0
  28. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/perf_runner/__init__.py +12 -0
  29. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/perf_runner/artifacts.py +158 -0
  30. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/perf_runner/environment.py +45 -0
  31. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/perf_runner/imports.py +16 -0
  32. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/perf_runner/matrix.py +38 -0
  33. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/perf_runner/metrics.py +231 -0
  34. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/perf_runner/models.py +62 -0
  35. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/perf_runner/runner.py +126 -0
  36. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/perf_runner/stats.py +43 -0
  37. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/perf_runner/validation.py +56 -0
  38. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/release_gates/__init__.py +14 -0
  39. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/release_gates/artifact_gate.py +40 -0
  40. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/release_gates/contract_registry.py +340 -0
  41. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/release_gates/core.py +161 -0
  42. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/release_gates/docs.py +139 -0
  43. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/release_gates/imports.py +27 -0
  44. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/release_gates/independent.py +302 -0
  45. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/release_gates/loaders.py +55 -0
  46. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/release_gates/models.py +65 -0
  47. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/release_gates/promotion.py +111 -0
  48. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/release_gates/promotion_sections.py +373 -0
  49. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/release_gates/supply_chain_gate.py +47 -0
  50. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification/supply_chain.py +373 -0
  51. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/src/tigrcorn_certification.egg-info/PKG-INFO +3 -3
  52. tigrcorn_certification-0.3.17.dev1/src/tigrcorn_certification.egg-info/SOURCES.txt +59 -0
  53. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/src/tigrcorn_certification.egg-info/requires.txt +2 -2
  54. tigrcorn_certification-0.3.16.dev12/src/tigrcorn_certification/__init__.py +0 -55
  55. tigrcorn_certification-0.3.16.dev12/src/tigrcorn_certification/aioquic_preflight.py +0 -449
  56. tigrcorn_certification-0.3.16.dev12/src/tigrcorn_certification/interop_runner.py +0 -2017
  57. tigrcorn_certification-0.3.16.dev12/src/tigrcorn_certification/perf_runner.py +0 -725
  58. tigrcorn_certification-0.3.16.dev12/src/tigrcorn_certification/release_gates.py +0 -1351
  59. tigrcorn_certification-0.3.16.dev12/src/tigrcorn_certification.egg-info/SOURCES.txt +0 -17
  60. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/LICENSE +0 -0
  61. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/README.md +0 -0
  62. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/setup.cfg +0 -0
  63. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/src/tigrcorn_certification/conformance.py +0 -0
  64. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/src/tigrcorn_certification/explicit_surfaces.py +0 -0
  65. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/src/tigrcorn_certification/py.typed +0 -0
  66. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/src/tigrcorn_certification.egg-info/dependency_links.txt +0 -0
  67. {tigrcorn_certification-0.3.16.dev12 → tigrcorn_certification-0.3.17.dev1}/src/tigrcorn_certification.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tigrcorn-certification
3
- Version: 0.3.16.dev12
3
+ Version: 0.3.17.dev1
4
4
  Summary: Certification and release-gate tooling for Tigrcorn HTTP/3, QUIC, WebSocket, WebTransport, and ASGI conformance evidence.
5
5
  Author-email: Jacob Stewart <jacob@swarmauri.com>
6
6
  License: Apache License
@@ -187,8 +187,8 @@ Classifier: Typing :: Typed
187
187
  Requires-Python: <3.15,>=3.10
188
188
  Description-Content-Type: text/markdown
189
189
  License-File: LICENSE
190
- Requires-Dist: tigrcorn-compat==0.3.16.dev12
191
- Requires-Dist: tigrcorn-runtime==0.3.16.dev12
190
+ Requires-Dist: tigrcorn-compat==0.3.17.dev1
191
+ Requires-Dist: tigrcorn-runtime==0.3.17.dev1
192
192
  Requires-Dist: tomli>=2.0.0; python_version < "3.11"
193
193
  Requires-Dist: cryptography>=46.0.0
194
194
  Requires-Dist: aioquic>=1.3.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tigrcorn-certification"
7
- version = "0.3.16.dev12"
7
+ version = "0.3.17.dev1"
8
8
  description = "Certification and release-gate tooling for Tigrcorn HTTP/3, QUIC, WebSocket, WebTransport, and ASGI conformance evidence."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10,<3.15"
@@ -30,8 +30,8 @@ classifiers = [
30
30
  "Typing :: Typed",
31
31
  ]
32
32
  dependencies = [
33
- "tigrcorn-compat==0.3.16.dev12",
34
- "tigrcorn-runtime==0.3.16.dev12",
33
+ "tigrcorn-compat==0.3.17.dev1",
34
+ "tigrcorn-runtime==0.3.17.dev1",
35
35
  "tomli>=2.0.0; python_version < '3.11'",
36
36
  "cryptography>=46.0.0",
37
37
  "aioquic>=1.3.0",
@@ -0,0 +1,203 @@
1
+ from __future__ import annotations
2
+
3
+ PACKAGE_BOUNDARY = "certification"
4
+
5
+ __all__ = [
6
+ "PACKAGE_BOUNDARY",
7
+ "evaluate_release_gates",
8
+ "assert_release_ready",
9
+ "ReleaseGateError",
10
+ "ReleaseGateReport",
11
+ "certification_explicit_surface_catalog",
12
+ "certification_explicit_surface_ids",
13
+ "validate_explicit_surface_manifest",
14
+ "evaluate_contract_registry_release_gate",
15
+ "evaluate_certification_artifact_release_gate",
16
+ "evaluate_supply_chain_release_gate",
17
+ "CertificationArtifact",
18
+ "CertificationArtifactError",
19
+ "CertificationBundle",
20
+ "build_artifact",
21
+ "build_bundle",
22
+ "build_manifest",
23
+ "canonical_json",
24
+ "output_directory_contract",
25
+ "reject_nondeterministic_fields",
26
+ "replay_diff",
27
+ "sign_manifest",
28
+ "verify_release_evidence",
29
+ "verify_output_tree",
30
+ "write_bundle",
31
+ "write_certification_artifacts",
32
+ "PackageRecord",
33
+ "SupplyChainEvidenceError",
34
+ "dependency_drift_report",
35
+ "generated_certification_artifact_links",
36
+ "has_slsa_provenance",
37
+ "has_spdx_or_cyclonedx",
38
+ "package_list",
39
+ "package_record",
40
+ "release_train_evidence",
41
+ "supply_chain_manifest",
42
+ "validate_release_bundle",
43
+ "validate_certification_artifact_linkage",
44
+ "validate_package_manifest_integrity",
45
+ "validate_release_evidence",
46
+ "write_supply_chain_release_bundle",
47
+ ]
48
+
49
+
50
+ def __getattr__(name: str):
51
+ if name in {
52
+ "evaluate_release_gates",
53
+ "assert_release_ready",
54
+ "ReleaseGateError",
55
+ "ReleaseGateReport",
56
+ "evaluate_contract_registry_release_gate",
57
+ "evaluate_certification_artifact_release_gate",
58
+ "evaluate_supply_chain_release_gate",
59
+ }:
60
+ from .release_gates import (
61
+ ReleaseGateError,
62
+ ReleaseGateReport,
63
+ assert_release_ready,
64
+ evaluate_certification_artifact_release_gate,
65
+ evaluate_contract_registry_release_gate,
66
+ evaluate_release_gates,
67
+ evaluate_supply_chain_release_gate,
68
+ )
69
+
70
+ mapping = {
71
+ "evaluate_release_gates": evaluate_release_gates,
72
+ "evaluate_certification_artifact_release_gate": evaluate_certification_artifact_release_gate,
73
+ "evaluate_contract_registry_release_gate": evaluate_contract_registry_release_gate,
74
+ "evaluate_supply_chain_release_gate": evaluate_supply_chain_release_gate,
75
+ "assert_release_ready": assert_release_ready,
76
+ "ReleaseGateError": ReleaseGateError,
77
+ "ReleaseGateReport": ReleaseGateReport,
78
+ }
79
+ return mapping[name]
80
+ if name in {
81
+ "certification_explicit_surface_catalog",
82
+ "certification_explicit_surface_ids",
83
+ "validate_explicit_surface_manifest",
84
+ }:
85
+ from .explicit_surfaces import (
86
+ certification_explicit_surface_catalog,
87
+ certification_explicit_surface_ids,
88
+ validate_explicit_surface_manifest,
89
+ )
90
+
91
+ mapping = {
92
+ "certification_explicit_surface_catalog": certification_explicit_surface_catalog,
93
+ "certification_explicit_surface_ids": certification_explicit_surface_ids,
94
+ "validate_explicit_surface_manifest": validate_explicit_surface_manifest,
95
+ }
96
+ return mapping[name]
97
+ if name in {
98
+ "CertificationArtifact",
99
+ "CertificationArtifactError",
100
+ "CertificationBundle",
101
+ "build_artifact",
102
+ "build_bundle",
103
+ "build_manifest",
104
+ "canonical_json",
105
+ "output_directory_contract",
106
+ "reject_nondeterministic_fields",
107
+ "replay_diff",
108
+ "sign_manifest",
109
+ "verify_release_evidence",
110
+ "verify_output_tree",
111
+ "write_bundle",
112
+ "write_certification_artifacts",
113
+ }:
114
+ from .artifacts import (
115
+ CertificationArtifact,
116
+ CertificationArtifactError,
117
+ CertificationBundle,
118
+ build_artifact,
119
+ build_bundle,
120
+ build_manifest,
121
+ canonical_json,
122
+ output_directory_contract,
123
+ reject_nondeterministic_fields,
124
+ replay_diff,
125
+ sign_manifest,
126
+ verify_release_evidence,
127
+ verify_output_tree,
128
+ write_bundle,
129
+ write_certification_artifacts,
130
+ )
131
+
132
+ mapping = {
133
+ "CertificationArtifact": CertificationArtifact,
134
+ "CertificationArtifactError": CertificationArtifactError,
135
+ "CertificationBundle": CertificationBundle,
136
+ "build_artifact": build_artifact,
137
+ "build_bundle": build_bundle,
138
+ "build_manifest": build_manifest,
139
+ "canonical_json": canonical_json,
140
+ "output_directory_contract": output_directory_contract,
141
+ "reject_nondeterministic_fields": reject_nondeterministic_fields,
142
+ "replay_diff": replay_diff,
143
+ "sign_manifest": sign_manifest,
144
+ "verify_release_evidence": verify_release_evidence,
145
+ "verify_output_tree": verify_output_tree,
146
+ "write_bundle": write_bundle,
147
+ "write_certification_artifacts": write_certification_artifacts,
148
+ }
149
+ return mapping[name]
150
+ if name in {
151
+ "PackageRecord",
152
+ "SupplyChainEvidenceError",
153
+ "dependency_drift_report",
154
+ "generated_certification_artifact_links",
155
+ "has_slsa_provenance",
156
+ "has_spdx_or_cyclonedx",
157
+ "package_list",
158
+ "package_record",
159
+ "release_train_evidence",
160
+ "supply_chain_manifest",
161
+ "validate_certification_artifact_linkage",
162
+ "validate_package_manifest_integrity",
163
+ "validate_release_bundle",
164
+ "validate_release_evidence",
165
+ "write_supply_chain_release_bundle",
166
+ }:
167
+ from .supply_chain import (
168
+ PackageRecord,
169
+ SupplyChainEvidenceError,
170
+ dependency_drift_report,
171
+ generated_certification_artifact_links,
172
+ has_slsa_provenance,
173
+ has_spdx_or_cyclonedx,
174
+ package_list,
175
+ package_record,
176
+ release_train_evidence,
177
+ supply_chain_manifest,
178
+ validate_certification_artifact_linkage,
179
+ validate_package_manifest_integrity,
180
+ validate_release_bundle,
181
+ validate_release_evidence,
182
+ write_supply_chain_release_bundle,
183
+ )
184
+
185
+ mapping = {
186
+ "PackageRecord": PackageRecord,
187
+ "SupplyChainEvidenceError": SupplyChainEvidenceError,
188
+ "dependency_drift_report": dependency_drift_report,
189
+ "generated_certification_artifact_links": generated_certification_artifact_links,
190
+ "has_slsa_provenance": has_slsa_provenance,
191
+ "has_spdx_or_cyclonedx": has_spdx_or_cyclonedx,
192
+ "package_list": package_list,
193
+ "package_record": package_record,
194
+ "release_train_evidence": release_train_evidence,
195
+ "supply_chain_manifest": supply_chain_manifest,
196
+ "validate_certification_artifact_linkage": validate_certification_artifact_linkage,
197
+ "validate_package_manifest_integrity": validate_package_manifest_integrity,
198
+ "validate_release_bundle": validate_release_bundle,
199
+ "validate_release_evidence": validate_release_evidence,
200
+ "write_supply_chain_release_bundle": write_supply_chain_release_bundle,
201
+ }
202
+ return mapping[name]
203
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+
3
+ from .helpers import *
4
+ from .records import *
5
+ from .bundle import *
6
+ from .status_docs import *
7
+ from .core import *
8
+
9
+ __all__ = [name for name in globals() if not name.startswith('_')]
@@ -0,0 +1,80 @@
1
+ from __future__ import annotations
2
+
3
+ from .imports import *
4
+ from .helpers import *
5
+ from .helpers import _now
6
+
7
+ def _bundle_manifest(*, artifact_root: str, matrix_path: str, scenario_ids: Sequence[str]) -> dict[str, Any]:
8
+ return {
9
+ 'bundle_kind': 'aioquic_adapter_preflight_bundle',
10
+ 'generated_at': _now(),
11
+ 'release_gate_eligible': False,
12
+ 'artifact_root': artifact_root,
13
+ 'matrix_path': matrix_path,
14
+ 'scenario_ids': list(scenario_ids),
15
+ 'note': 'This bundle proves the third-party aioquic HTTP/3 adapters can execute cleanly before strict-target checkpoint promotion work continues.',
16
+ }
17
+
18
+
19
+ def _bundle_index(*, artifact_root: str, matrix_path: str, scenario_records: Sequence[Mapping[str, Any]], environment: Mapping[str, Any], gate_status: Mapping[str, Any]) -> dict[str, Any]:
20
+ return {
21
+ 'artifact_root': artifact_root,
22
+ 'bundle_kind': 'aioquic_adapter_preflight_bundle',
23
+ 'generated_at': _now(),
24
+ 'matrix_path': matrix_path,
25
+ 'scenario_count': len(scenario_records),
26
+ 'scenario_ids': [str(item['scenario_id']) for item in scenario_records],
27
+ 'all_adapters_passed': all(bool(item['passed']) for item in scenario_records),
28
+ 'no_peer_exit_code_2': all(int(item['peer_exit_code']) != 2 for item in scenario_records),
29
+ 'negotiation_metadata_emitted': all(bool(item['negotiation_metadata_emitted']) for item in scenario_records),
30
+ 'transcript_metadata_emitted': all(bool(item['transcript_emitted']) for item in scenario_records),
31
+ 'all_protocols_h3': all(item.get('protocol') == 'h3' for item in scenario_records),
32
+ 'all_handshakes_complete': all(bool(item['handshake_complete']) for item in scenario_records),
33
+ 'certificate_inputs_ready': all(bool(item['certificate_inputs_ready']) for item in scenario_records),
34
+ 'packet_traces_emitted': all(bool(item['packet_trace_exists']) for item in scenario_records),
35
+ 'qlogs_emitted': all(bool(item['qlog_exists']) for item in scenario_records),
36
+ 'environment': dict(environment),
37
+ 'gate_status_after_preflight': dict(gate_status),
38
+ 'release_gate_eligible': False,
39
+ }
40
+
41
+
42
+ def _bundle_summary(index: Mapping[str, Any]) -> dict[str, Any]:
43
+ return {
44
+ 'artifact_root': index['artifact_root'],
45
+ 'bundle_kind': index['bundle_kind'],
46
+ 'generated_at': index['generated_at'],
47
+ 'scenario_count': index['scenario_count'],
48
+ 'all_adapters_passed': index['all_adapters_passed'],
49
+ 'no_peer_exit_code_2': index['no_peer_exit_code_2'],
50
+ 'all_protocols_h3': index['all_protocols_h3'],
51
+ 'all_handshakes_complete': index['all_handshakes_complete'],
52
+ 'certificate_inputs_ready': index['certificate_inputs_ready'],
53
+ }
54
+
55
+
56
+ def _bundle_readme(index: Mapping[str, Any], scenario_records: Sequence[Mapping[str, Any]]) -> str:
57
+ lines = [
58
+ '# aioquic adapter preflight bundle',
59
+ '',
60
+ 'This bundle preserves the direct third-party aioquic HTTP/3 adapter preflight runs used before strict-target certification checkpoints.',
61
+ '',
62
+ '## Exit-criteria status',
63
+ '',
64
+ f"- all adapters passed: `{index['all_adapters_passed']}`",
65
+ f"- no peer exit code 2: `{index['no_peer_exit_code_2']}`",
66
+ f"- negotiation metadata emitted: `{index['negotiation_metadata_emitted']}`",
67
+ f"- transcript metadata emitted: `{index['transcript_metadata_emitted']}`",
68
+ f"- ALPN h3 observed for every run: `{index['all_protocols_h3']}`",
69
+ f"- QUIC handshakes complete: `{index['all_handshakes_complete']}`",
70
+ f"- certificate inputs ready: `{index['certificate_inputs_ready']}`",
71
+ '',
72
+ '## Scenarios',
73
+ '',
74
+ ]
75
+ for item in scenario_records:
76
+ lines.extend([
77
+ f"- `{item['scenario_id']}` → passed=`{item['passed']}`, peer_exit=`{item['peer_exit_code']}`, protocol=`{item['protocol']}`, handshake_complete=`{item['handshake_complete']}`",
78
+ ])
79
+ lines.append('')
80
+ return '\n'.join(lines) + '\n'
@@ -0,0 +1,115 @@
1
+ from __future__ import annotations
2
+
3
+ from .imports import *
4
+ from .helpers import *
5
+ from .helpers import _dump_json, _module_version, _now
6
+ from .records import *
7
+ from .records import _extract_scenario_record
8
+ from .bundle import *
9
+ from .bundle import _bundle_index, _bundle_manifest, _bundle_readme, _bundle_summary
10
+ from .status_docs import *
11
+
12
+ def run_aioquic_adapter_preflight(
13
+ root: str | Path,
14
+ *,
15
+ release_root: str = DEFAULT_RELEASE_ROOT,
16
+ bundle_name: str = DEFAULT_BUNDLE_NAME,
17
+ matrix_path: str = DEFAULT_MATRIX_PATH,
18
+ scenario_ids: Sequence[str] = DEFAULT_PRELIGHT_SCENARIOS,
19
+ bundle_root: str | Path | None = None,
20
+ require_pass: bool = False,
21
+ ) -> dict[str, Any]:
22
+ repo_root = Path(root)
23
+ resolved_release_root = repo_root / release_root
24
+ target_bundle_root = Path(bundle_root) if bundle_root is not None else resolved_release_root / bundle_name
25
+ if target_bundle_root.exists():
26
+ shutil.rmtree(target_bundle_root)
27
+ target_bundle_root.mkdir(parents=True, exist_ok=True)
28
+
29
+ with tempfile.TemporaryDirectory(prefix='aioquic-preflight-') as tmpdir:
30
+ summary = run_external_matrix(
31
+ repo_root / matrix_path,
32
+ artifact_root=tmpdir,
33
+ source_root=repo_root,
34
+ scenario_ids=list(scenario_ids),
35
+ strict=False,
36
+ )
37
+ generated_root = Path(summary.artifact_root)
38
+ for source_name, target_name in (
39
+ ('manifest.json', 'generated_matrix_manifest.json'),
40
+ ('index.json', 'generated_matrix_index.json'),
41
+ ('summary.json', 'generated_matrix_summary.json'),
42
+ ):
43
+ shutil.copy2(generated_root / source_name, target_bundle_root / target_name)
44
+ for scenario_id in scenario_ids:
45
+ shutil.copytree(generated_root / scenario_id, target_bundle_root / scenario_id)
46
+
47
+ environment = {
48
+ 'python_version': sys.version,
49
+ 'python_minor_version': f'{sys.version_info.major}.{sys.version_info.minor}',
50
+ 'aioquic_version': _module_version('aioquic'),
51
+ 'wsproto_version': _module_version('wsproto'),
52
+ 'h2_version': _module_version('h2'),
53
+ 'websockets_version': _module_version('websockets'),
54
+ }
55
+ gate_status = {
56
+ 'authoritative_boundary_passed': evaluate_release_gates(repo_root).passed,
57
+ 'strict_target_boundary_passed': evaluate_release_gates(repo_root, boundary_path='docs/review/conformance/certification_boundary.strict_target.json').passed,
58
+ 'promotion_target_passed': evaluate_promotion_target(repo_root).passed,
59
+ }
60
+ scenario_records = [_extract_scenario_record(repo_root, target_bundle_root, scenario_id) for scenario_id in scenario_ids]
61
+ index = _bundle_index(
62
+ artifact_root=str(target_bundle_root.relative_to(repo_root)) if target_bundle_root.is_relative_to(repo_root) else str(target_bundle_root),
63
+ matrix_path=matrix_path,
64
+ scenario_records=scenario_records,
65
+ environment=environment,
66
+ gate_status=gate_status,
67
+ )
68
+ manifest = _bundle_manifest(
69
+ artifact_root=index['artifact_root'],
70
+ matrix_path=matrix_path,
71
+ scenario_ids=scenario_ids,
72
+ )
73
+ summary = _bundle_summary(index)
74
+ _dump_json(target_bundle_root / 'manifest.json', manifest)
75
+ _dump_json(target_bundle_root / 'index.json', index)
76
+ _dump_json(target_bundle_root / 'summary.json', summary)
77
+ _dump_json(target_bundle_root / 'preflight.json', {
78
+ 'generated_at': _now(),
79
+ 'environment': environment,
80
+ 'gate_status_after_preflight': gate_status,
81
+ 'scenario_records': scenario_records,
82
+ })
83
+ (target_bundle_root / 'README.md').write_text(_bundle_readme(index, scenario_records), encoding='utf-8')
84
+
85
+ snapshot = {
86
+ 'checkpoint': 'aioquic_adapter_preflight',
87
+ 'status': 'aioquic_adapter_preflight_passed' if summary['all_adapters_passed'] else 'aioquic_adapter_preflight_failed',
88
+ 'current_state': {
89
+ 'release_root': release_root,
90
+ 'bundle_root': index['artifact_root'],
91
+ 'matrix_path': matrix_path,
92
+ 'scenario_ids': list(scenario_ids),
93
+ 'scenario_records': scenario_records,
94
+ 'environment': environment,
95
+ 'all_adapters_passed': index['all_adapters_passed'],
96
+ 'no_peer_exit_code_2': index['no_peer_exit_code_2'],
97
+ 'negotiation_metadata_emitted': index['negotiation_metadata_emitted'],
98
+ 'transcript_metadata_emitted': index['transcript_metadata_emitted'],
99
+ 'all_protocols_h3': index['all_protocols_h3'],
100
+ 'all_handshakes_complete': index['all_handshakes_complete'],
101
+ 'certificate_inputs_ready': index['certificate_inputs_ready'],
102
+ 'packet_traces_emitted': index['packet_traces_emitted'],
103
+ 'qlogs_emitted': index['qlogs_emitted'],
104
+ 'gate_status_after_preflight': gate_status,
105
+ },
106
+ 'remaining_strict_target_blockers': [
107
+ 'websocket-http3-server-aioquic-client-permessage-deflate',
108
+ 'http3-connect-relay-aioquic-client',
109
+ 'http3-trailer-fields-aioquic-client',
110
+ 'http3-content-coding-aioquic-client',
111
+ ],
112
+ }
113
+ if require_pass and not summary['all_adapters_passed']:
114
+ raise AioquicAdapterPreflightError('one or more aioquic adapter preflight scenarios failed')
115
+ return snapshot
@@ -0,0 +1,87 @@
1
+ from __future__ import annotations
2
+
3
+ from .imports import *
4
+
5
+ class AioquicAdapterPreflightError(RuntimeError):
6
+ """Raised when the aioquic adapter preflight fails and strict pass mode is enabled."""
7
+
8
+
9
+ def _now() -> str:
10
+ return datetime.now(timezone.utc).isoformat()
11
+
12
+
13
+ def _load_json(path: Path) -> dict[str, Any]:
14
+ return json.loads(path.read_text(encoding='utf-8'))
15
+
16
+
17
+ def _dump_json(path: Path, payload: Any) -> None:
18
+ path.parent.mkdir(parents=True, exist_ok=True)
19
+ path.write_text(json.dumps(payload, indent=2, sort_keys=True) + '\n', encoding='utf-8')
20
+
21
+
22
+ def _module_version(name: str) -> str | None:
23
+ try:
24
+ return importlib.metadata.version(name)
25
+ except importlib.metadata.PackageNotFoundError:
26
+ return None
27
+
28
+
29
+ def _command_option(command: Sequence[str], option: str) -> str | None:
30
+ try:
31
+ index = list(command).index(option)
32
+ except ValueError:
33
+ return None
34
+ next_index = index + 1
35
+ if next_index >= len(command):
36
+ return None
37
+ return str(command[next_index])
38
+
39
+
40
+ def _module_name(command: Sequence[str]) -> str | None:
41
+ try:
42
+ index = list(command).index('-m')
43
+ except ValueError:
44
+ return None
45
+ next_index = index + 1
46
+ if next_index >= len(command):
47
+ return None
48
+ return str(command[next_index])
49
+
50
+
51
+ def _path_ready(entry: Mapping[str, Any] | None) -> bool:
52
+ if not isinstance(entry, Mapping):
53
+ return False
54
+ return bool(entry.get('exists')) and bool(entry.get('is_file'))
55
+
56
+
57
+ def _default_certificate_inputs(repo_root: Path, peer_command: Sequence[str]) -> dict[str, Any]:
58
+ def _entry(option: str) -> dict[str, Any]:
59
+ value = _command_option(peer_command, option)
60
+ if value is None:
61
+ return {'path': None, 'exists': False, 'is_file': False}
62
+ candidate = repo_root / value
63
+ return {
64
+ 'path': value,
65
+ 'exists': candidate.exists(),
66
+ 'is_file': candidate.is_file(),
67
+ }
68
+
69
+ ca = _entry('--cacert')
70
+ cert = _entry('--client-cert')
71
+ key = _entry('--client-key')
72
+ client_material_requested = bool(cert['path'] or key['path'])
73
+ client_material_ready = (not client_material_requested) or (bool(cert['exists']) and bool(key['exists']))
74
+ return {
75
+ 'ca_cert': ca,
76
+ 'client_cert': cert,
77
+ 'client_key': key,
78
+ 'client_material_requested': client_material_requested,
79
+ 'client_material_ready': client_material_ready,
80
+ 'ready': bool(ca['exists']) and client_material_ready,
81
+ }
82
+
83
+
84
+ def _scenario_kind(scenario_id: str) -> str:
85
+ if 'websocket' in scenario_id:
86
+ return 'http3_websocket_adapter'
87
+ return 'http3_client_adapter'
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib.metadata
4
+ import json
5
+ import shutil
6
+ import sys
7
+ import tempfile
8
+ from datetime import datetime, timezone
9
+ from pathlib import Path
10
+ from typing import Any, Iterable, Mapping, Sequence
11
+
12
+ from ..interop_runner import run_external_matrix
13
+ from ..release_gates import evaluate_promotion_target, evaluate_release_gates
14
+
15
+ DEFAULT_PRELIGHT_SCENARIOS: tuple[str, ...] = (
16
+ 'http3-server-aioquic-client-post',
17
+ 'websocket-http3-server-aioquic-client',
18
+ )
19
+ DEFAULT_BUNDLE_NAME = 'tigrcorn-aioquic-adapter-preflight-bundle'
20
+ DEFAULT_STATUS_DOC = 'docs/review/conformance/AIOQUIC_ADAPTER_PREFLIGHT.md'
21
+ DEFAULT_STATUS_JSON = 'docs/review/conformance/aioquic_adapter_preflight.current.json'
22
+ DEFAULT_DELIVERY_NOTES = 'docs/review/conformance/delivery/DELIVERY_NOTES_AIOQUIC_ADAPTER_PREFLIGHT.md'
23
+ DEFAULT_MATRIX_PATH = 'docs/review/conformance/external_matrix.release.json'
24
+ DEFAULT_RELEASE_ROOT = 'docs/review/conformance/releases/0.3.9/release-0.3.9'
@@ -0,0 +1,54 @@
1
+ from __future__ import annotations
2
+
3
+ from .imports import *
4
+ from .helpers import *
5
+ from .helpers import _default_certificate_inputs, _load_json, _module_name, _path_ready, _scenario_kind
6
+
7
+ def _extract_scenario_record(repo_root: Path, bundle_root: Path, scenario_id: str) -> dict[str, Any]:
8
+ scenario_root = bundle_root / scenario_id
9
+ result = _load_json(scenario_root / 'result.json')
10
+ commands = _load_json(scenario_root / 'command.json')
11
+ versions = _load_json(scenario_root / 'versions.json')
12
+ peer_command = [str(item) for item in commands['peer']['command']]
13
+ negotiation = dict((result.get('negotiation') or {}).get('peer') or {})
14
+ transcript = dict((result.get('transcript') or {}).get('peer') or {})
15
+ transcript_quic = dict(transcript.get('quic') or {})
16
+ certificate_inputs = dict(negotiation.get('certificate_inputs') or _default_certificate_inputs(repo_root, peer_command))
17
+ handshake_complete = bool(
18
+ negotiation.get('handshake_complete')
19
+ or transcript_quic.get('handshake_complete')
20
+ or (result.get('passed') and (result.get('peer') or {}).get('exit_code') == 0 and negotiation.get('protocol') == 'h3')
21
+ )
22
+ artifacts = result.get('artifacts') or {}
23
+ response = dict(transcript.get('response') or {})
24
+
25
+ return {
26
+ 'scenario_id': scenario_id,
27
+ 'kind': _scenario_kind(scenario_id),
28
+ 'passed': bool(result.get('passed')),
29
+ 'peer_exit_code': int((result.get('peer') or {}).get('exit_code') or 0),
30
+ 'peer_module': _module_name(peer_command),
31
+ 'peer_command': peer_command,
32
+ 'peer_version': (versions.get('peer') or {}).get('implementation_version'),
33
+ 'protocol': negotiation.get('protocol'),
34
+ 'tls_version': negotiation.get('tls_version'),
35
+ 'server_name': negotiation.get('server_name'),
36
+ 'handshake_complete': handshake_complete,
37
+ 'retry_observed': bool(negotiation.get('retry_observed')),
38
+ 'negotiation_metadata_emitted': bool((artifacts.get('peer_negotiation') or {}).get('exists')),
39
+ 'transcript_emitted': bool((artifacts.get('peer_transcript') or {}).get('exists')),
40
+ 'packet_trace_exists': bool((artifacts.get('packet_trace') or {}).get('exists')),
41
+ 'qlog_exists': bool((artifacts.get('qlog') or {}).get('exists')),
42
+ 'certificate_inputs': certificate_inputs,
43
+ 'certificate_inputs_ready': bool(negotiation.get('certificate_inputs_ready', certificate_inputs.get('ready'))),
44
+ 'ca_cert_path': (certificate_inputs.get('ca_cert') or {}).get('path'),
45
+ 'ca_cert_exists': _path_ready(certificate_inputs.get('ca_cert') or {}),
46
+ 'client_material_requested': bool(certificate_inputs.get('client_material_requested')),
47
+ 'response_status': response.get('status'),
48
+ 'websocket_connect_protocol_enabled': negotiation.get('connect_protocol_enabled'),
49
+ 'websocket_negotiated_extensions': list(negotiation.get('negotiated_extensions') or []),
50
+ 'artifact_dir': str(scenario_root.relative_to(bundle_root)),
51
+ 'result_path': str((scenario_root / 'result.json').relative_to(bundle_root)),
52
+ 'peer_negotiation_path': str((scenario_root / 'peer_negotiation.json').relative_to(bundle_root)),
53
+ 'peer_transcript_path': str((scenario_root / 'peer_transcript.json').relative_to(bundle_root)),
54
+ }