tigrcorn-certification 0.3.16.dev5__py3-none-any.whl
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.
- tigrcorn_certification/__init__.py +55 -0
- tigrcorn_certification/aioquic_preflight.py +449 -0
- tigrcorn_certification/certification_env.py +419 -0
- tigrcorn_certification/conformance.py +42 -0
- tigrcorn_certification/explicit_surfaces.py +130 -0
- tigrcorn_certification/interop_runner.py +2017 -0
- tigrcorn_certification/perf_runner.py +725 -0
- tigrcorn_certification/py.typed +1 -0
- tigrcorn_certification/release_gates.py +1354 -0
- tigrcorn_certification-0.3.16.dev5.dist-info/METADATA +242 -0
- tigrcorn_certification-0.3.16.dev5.dist-info/RECORD +14 -0
- tigrcorn_certification-0.3.16.dev5.dist-info/WHEEL +5 -0
- tigrcorn_certification-0.3.16.dev5.dist-info/licenses/LICENSE +163 -0
- tigrcorn_certification-0.3.16.dev5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib.metadata
|
|
4
|
+
import importlib.util
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import platform
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
import tomllib
|
|
11
|
+
from datetime import datetime, timezone
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any, Iterable, Mapping, Sequence
|
|
14
|
+
|
|
15
|
+
SUPPORTED_PYTHON_VERSIONS: tuple[str, ...] = ('3.11', '3.12')
|
|
16
|
+
REQUIRED_IMPORTS: tuple[str, ...] = ('aioquic', 'h2', 'websockets', 'wsproto')
|
|
17
|
+
REQUIRED_EXTRAS: tuple[str, ...] = ('certification', 'dev')
|
|
18
|
+
SAFE_ENV_KEYS: tuple[str, ...] = (
|
|
19
|
+
'PYTHONPATH',
|
|
20
|
+
'VIRTUAL_ENV',
|
|
21
|
+
'PIP_CONSTRAINT',
|
|
22
|
+
'PIP_REQUIRE_VIRTUALENV',
|
|
23
|
+
)
|
|
24
|
+
DEFAULT_BUNDLE_NAME = 'tigrcorn-certification-environment-bundle'
|
|
25
|
+
DEFAULT_STATUS_DOC = 'docs/review/conformance/CERTIFICATION_ENVIRONMENT_FREEZE.md'
|
|
26
|
+
DEFAULT_STATUS_JSON = 'docs/review/conformance/certification_environment_freeze.current.json'
|
|
27
|
+
DEFAULT_DELIVERY_NOTES = 'docs/review/conformance/delivery/DELIVERY_NOTES_CERTIFICATION_ENVIRONMENT_FREEZE.md'
|
|
28
|
+
DEFAULT_RELEASE_WORKFLOW = '.github/workflows/phase9-certification-release.yml'
|
|
29
|
+
DEFAULT_WRAPPER = 'tools/run_phase9_release_workflow.py'
|
|
30
|
+
DEFAULT_INSTALL_COMMAND = 'python -m pip install -e ".[certification,dev]"'
|
|
31
|
+
DEFAULT_VERIFY_COMMAND = "python - <<'PY'\nimport aioquic, h2, websockets, wsproto\nprint('certification deps OK')\nPY"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class CertificationEnvironmentError(RuntimeError):
|
|
35
|
+
"""Raised when the release certification environment contract is not satisfied."""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _now() -> str:
|
|
39
|
+
return datetime.now(timezone.utc).isoformat()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _read_pyproject(root: Path) -> dict[str, Any]:
|
|
43
|
+
return tomllib.loads((root / 'pyproject.toml').read_text(encoding='utf-8'))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _load_optional_dependencies(root: Path) -> dict[str, list[str]]:
|
|
47
|
+
payload = _read_pyproject(root)
|
|
48
|
+
project = payload.get('project', {})
|
|
49
|
+
optional = project.get('optional-dependencies', {})
|
|
50
|
+
return {str(name): [str(item) for item in values] for name, values in optional.items()}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _safe_env_snapshot(env: Mapping[str, str] | None = None) -> dict[str, str]:
|
|
54
|
+
source = os.environ if env is None else env
|
|
55
|
+
return {key: str(source[key]) for key in SAFE_ENV_KEYS if key in source}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _module_status(module_name: str) -> dict[str, Any]:
|
|
59
|
+
spec = importlib.util.find_spec(module_name)
|
|
60
|
+
importable = spec is not None
|
|
61
|
+
try:
|
|
62
|
+
version = importlib.metadata.version(module_name)
|
|
63
|
+
installed = True
|
|
64
|
+
except importlib.metadata.PackageNotFoundError:
|
|
65
|
+
version = None
|
|
66
|
+
installed = False
|
|
67
|
+
return {
|
|
68
|
+
'module': module_name,
|
|
69
|
+
'importable': importable,
|
|
70
|
+
'installed': installed,
|
|
71
|
+
'version': version,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _current_python_version() -> str:
|
|
76
|
+
return f'{sys.version_info.major}.{sys.version_info.minor}'
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _python_ready() -> bool:
|
|
80
|
+
return _current_python_version() in SUPPORTED_PYTHON_VERSIONS
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _capture_command(command: Sequence[str] | None) -> list[str]:
|
|
84
|
+
if command is None:
|
|
85
|
+
return [sys.executable, *sys.argv]
|
|
86
|
+
return [str(item) for item in command]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _resolve_git_commit(root: Path) -> str | None:
|
|
90
|
+
try:
|
|
91
|
+
result = subprocess.run(
|
|
92
|
+
['git', 'rev-parse', 'HEAD'],
|
|
93
|
+
cwd=root,
|
|
94
|
+
check=True,
|
|
95
|
+
capture_output=True,
|
|
96
|
+
text=True,
|
|
97
|
+
)
|
|
98
|
+
except (FileNotFoundError, subprocess.CalledProcessError):
|
|
99
|
+
return None
|
|
100
|
+
commit = result.stdout.strip()
|
|
101
|
+
return commit or None
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def build_certification_environment_snapshot(
|
|
105
|
+
root: str | Path,
|
|
106
|
+
*,
|
|
107
|
+
command: Sequence[str] | None = None,
|
|
108
|
+
workflow_path: str = DEFAULT_RELEASE_WORKFLOW,
|
|
109
|
+
wrapper_path: str = DEFAULT_WRAPPER,
|
|
110
|
+
) -> dict[str, Any]:
|
|
111
|
+
repo_root = Path(root)
|
|
112
|
+
optional = _load_optional_dependencies(repo_root)
|
|
113
|
+
current_python = _current_python_version()
|
|
114
|
+
dependency_state = {name: _module_status(name) for name in REQUIRED_IMPORTS}
|
|
115
|
+
missing_imports = [name for name, state in dependency_state.items() if not state['importable']]
|
|
116
|
+
required_imports_ready = not missing_imports
|
|
117
|
+
python_version_ready = current_python in SUPPORTED_PYTHON_VERSIONS
|
|
118
|
+
|
|
119
|
+
extras = {
|
|
120
|
+
name: optional.get(name, []) for name in REQUIRED_EXTRAS
|
|
121
|
+
}
|
|
122
|
+
frozen_dependencies = {
|
|
123
|
+
name: {
|
|
124
|
+
**dependency_state[name],
|
|
125
|
+
'declared_in_extras': [extra for extra, requirements in extras.items() if any(requirement.split('>=', 1)[0].split('==', 1)[0] == name for requirement in requirements)],
|
|
126
|
+
}
|
|
127
|
+
for name in REQUIRED_IMPORTS
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
snapshot: dict[str, Any] = {
|
|
131
|
+
'schema_version': 1,
|
|
132
|
+
'captured_at': _now(),
|
|
133
|
+
'repository_root': '.',
|
|
134
|
+
'git_commit': _resolve_git_commit(repo_root),
|
|
135
|
+
'python': {
|
|
136
|
+
'executable': sys.executable,
|
|
137
|
+
'version': sys.version,
|
|
138
|
+
'minor_version': current_python,
|
|
139
|
+
'supported_release_workflow_versions': list(SUPPORTED_PYTHON_VERSIONS),
|
|
140
|
+
'version_ready': python_version_ready,
|
|
141
|
+
'implementation': platform.python_implementation(),
|
|
142
|
+
'platform': platform.platform(),
|
|
143
|
+
'machine': platform.machine(),
|
|
144
|
+
},
|
|
145
|
+
'installation_contract': {
|
|
146
|
+
'required_extras': list(REQUIRED_EXTRAS),
|
|
147
|
+
'optional_dependencies': extras,
|
|
148
|
+
'install_command': DEFAULT_INSTALL_COMMAND,
|
|
149
|
+
'verify_command': DEFAULT_VERIFY_COMMAND,
|
|
150
|
+
'bootstrap_commands': [
|
|
151
|
+
'python -m venv .venv',
|
|
152
|
+
'source .venv/bin/activate',
|
|
153
|
+
'python -m pip install -U pip',
|
|
154
|
+
DEFAULT_INSTALL_COMMAND,
|
|
155
|
+
DEFAULT_VERIFY_COMMAND,
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
'dependencies': frozen_dependencies,
|
|
159
|
+
'environment': {
|
|
160
|
+
'selected_variables': _safe_env_snapshot(),
|
|
161
|
+
'command': _capture_command(command),
|
|
162
|
+
},
|
|
163
|
+
'release_workflow': {
|
|
164
|
+
'workflow_path': workflow_path,
|
|
165
|
+
'wrapper_path': wrapper_path,
|
|
166
|
+
},
|
|
167
|
+
'validation': {
|
|
168
|
+
'required_imports': list(REQUIRED_IMPORTS),
|
|
169
|
+
'required_imports_ready': required_imports_ready,
|
|
170
|
+
'missing_imports': missing_imports,
|
|
171
|
+
'python_version_ready': python_version_ready,
|
|
172
|
+
'environment_ready_for_release_workflow': python_version_ready and required_imports_ready,
|
|
173
|
+
},
|
|
174
|
+
}
|
|
175
|
+
return snapshot
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _bundle_manifest(bundle_root: Path, artifact_root: str, snapshot: Mapping[str, Any], *, workflow_path: str, wrapper_path: str) -> dict[str, Any]:
|
|
179
|
+
return {
|
|
180
|
+
'bundle_kind': 'certification_environment_bundle',
|
|
181
|
+
'generated_at': snapshot['captured_at'],
|
|
182
|
+
'release_gate_eligible': False,
|
|
183
|
+
'artifact_root': artifact_root,
|
|
184
|
+
'install_command': snapshot['installation_contract']['install_command'],
|
|
185
|
+
'verify_command': snapshot['installation_contract']['verify_command'],
|
|
186
|
+
'workflow_path': workflow_path,
|
|
187
|
+
'wrapper_path': wrapper_path,
|
|
188
|
+
'note': 'This bundle freezes the certification-environment installation contract and the observed execution environment for the strict-promotion workflow.',
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _bundle_index(bundle_root: Path, artifact_root: str, snapshot: Mapping[str, Any], *, workflow_path: str, wrapper_path: str, environment_file: str) -> dict[str, Any]:
|
|
193
|
+
validation = dict(snapshot['validation'])
|
|
194
|
+
return {
|
|
195
|
+
'artifact_root': artifact_root,
|
|
196
|
+
'bundle_kind': 'certification_environment_bundle',
|
|
197
|
+
'generated_at': snapshot['captured_at'],
|
|
198
|
+
'status': 'certification_environment_ready' if validation['environment_ready_for_release_workflow'] else 'certification_environment_frozen_but_not_ready',
|
|
199
|
+
'required_extras': list(snapshot['installation_contract']['required_extras']),
|
|
200
|
+
'required_imports': list(validation['required_imports']),
|
|
201
|
+
'required_imports_ready': validation['required_imports_ready'],
|
|
202
|
+
'missing_imports': list(validation['missing_imports']),
|
|
203
|
+
'python_minor_version': snapshot['python']['minor_version'],
|
|
204
|
+
'python_version_ready': validation['python_version_ready'],
|
|
205
|
+
'environment_ready_for_release_workflow': validation['environment_ready_for_release_workflow'],
|
|
206
|
+
'install_command': snapshot['installation_contract']['install_command'],
|
|
207
|
+
'verify_command': snapshot['installation_contract']['verify_command'],
|
|
208
|
+
'environment_snapshot': environment_file,
|
|
209
|
+
'workflow_path': workflow_path,
|
|
210
|
+
'wrapper_path': wrapper_path,
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _bundle_summary(index: Mapping[str, Any]) -> dict[str, Any]:
|
|
215
|
+
return {
|
|
216
|
+
'bundle_kind': index['bundle_kind'],
|
|
217
|
+
'generated_at': index['generated_at'],
|
|
218
|
+
'status': index['status'],
|
|
219
|
+
'python_minor_version': index['python_minor_version'],
|
|
220
|
+
'python_version_ready': index['python_version_ready'],
|
|
221
|
+
'required_imports_ready': index['required_imports_ready'],
|
|
222
|
+
'missing_imports': index['missing_imports'],
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _bundle_readme(snapshot: Mapping[str, Any], *, workflow_path: str, wrapper_path: str) -> str:
|
|
227
|
+
validation = snapshot['validation']
|
|
228
|
+
missing_imports = ', '.join(validation['missing_imports']) if validation['missing_imports'] else 'none'
|
|
229
|
+
return (
|
|
230
|
+
'# Certification environment bundle\n\n'
|
|
231
|
+
'This bundle freezes the release-workflow installation contract for the strict-promotion certification path.\n\n'
|
|
232
|
+
'Required bootstrap commands:\n\n'
|
|
233
|
+
'```bash\n'
|
|
234
|
+
'python -m venv .venv\n'
|
|
235
|
+
'source .venv/bin/activate\n'
|
|
236
|
+
'python -m pip install -U pip\n'
|
|
237
|
+
f"{snapshot['installation_contract']['install_command']}\n"
|
|
238
|
+
f"{snapshot['installation_contract']['verify_command']}\n"
|
|
239
|
+
'```\n\n'
|
|
240
|
+
f"Observed Python minor version: `{snapshot['python']['minor_version']}`\n\n"
|
|
241
|
+
f"Observed required-import readiness: `{validation['required_imports_ready']}`\n\n"
|
|
242
|
+
f"Observed missing imports: `{missing_imports}`\n\n"
|
|
243
|
+
f"Release workflow path: `{workflow_path}`\n\n"
|
|
244
|
+
f"Checkpoint wrapper path: `{wrapper_path}`\n"
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _bootstrap_script(snapshot: Mapping[str, Any]) -> str:
|
|
249
|
+
commands = '\n'.join(snapshot['installation_contract']['bootstrap_commands'])
|
|
250
|
+
return '#!/usr/bin/env bash\nset -euo pipefail\n' + commands + '\n'
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def write_certification_environment_bundle(
|
|
254
|
+
root: str | Path,
|
|
255
|
+
*,
|
|
256
|
+
bundle_root: str | Path | None = None,
|
|
257
|
+
release_root: str | Path | None = None,
|
|
258
|
+
bundle_name: str = DEFAULT_BUNDLE_NAME,
|
|
259
|
+
workflow_path: str = DEFAULT_RELEASE_WORKFLOW,
|
|
260
|
+
wrapper_path: str = DEFAULT_WRAPPER,
|
|
261
|
+
command: Sequence[str] | None = None,
|
|
262
|
+
require_ready: bool = False,
|
|
263
|
+
) -> dict[str, Any]:
|
|
264
|
+
repo_root = Path(root)
|
|
265
|
+
if bundle_root is None:
|
|
266
|
+
if release_root is None:
|
|
267
|
+
raise ValueError('bundle_root or release_root must be provided')
|
|
268
|
+
bundle_path = Path(release_root) / bundle_name
|
|
269
|
+
else:
|
|
270
|
+
bundle_path = Path(bundle_root)
|
|
271
|
+
bundle_path.mkdir(parents=True, exist_ok=True)
|
|
272
|
+
|
|
273
|
+
snapshot = build_certification_environment_snapshot(
|
|
274
|
+
repo_root,
|
|
275
|
+
command=command,
|
|
276
|
+
workflow_path=workflow_path,
|
|
277
|
+
wrapper_path=wrapper_path,
|
|
278
|
+
)
|
|
279
|
+
try:
|
|
280
|
+
artifact_root = str(bundle_path.relative_to(repo_root)).replace('\\', '/')
|
|
281
|
+
except ValueError:
|
|
282
|
+
artifact_root = str(bundle_path).replace('\\', '/')
|
|
283
|
+
environment_file = 'environment.json'
|
|
284
|
+
manifest = _bundle_manifest(bundle_path, artifact_root, snapshot, workflow_path=workflow_path, wrapper_path=wrapper_path)
|
|
285
|
+
index = _bundle_index(
|
|
286
|
+
bundle_path,
|
|
287
|
+
artifact_root,
|
|
288
|
+
snapshot,
|
|
289
|
+
workflow_path=workflow_path,
|
|
290
|
+
wrapper_path=wrapper_path,
|
|
291
|
+
environment_file=environment_file,
|
|
292
|
+
)
|
|
293
|
+
summary = _bundle_summary(index)
|
|
294
|
+
|
|
295
|
+
(bundle_path / 'environment.json').write_text(json.dumps(snapshot, indent=2) + '\n', encoding='utf-8')
|
|
296
|
+
(bundle_path / 'manifest.json').write_text(json.dumps(manifest, indent=2) + '\n', encoding='utf-8')
|
|
297
|
+
(bundle_path / 'index.json').write_text(json.dumps(index, indent=2) + '\n', encoding='utf-8')
|
|
298
|
+
(bundle_path / 'summary.json').write_text(json.dumps(summary, indent=2) + '\n', encoding='utf-8')
|
|
299
|
+
(bundle_path / 'README.md').write_text(_bundle_readme(snapshot, workflow_path=workflow_path, wrapper_path=wrapper_path), encoding='utf-8')
|
|
300
|
+
bootstrap = bundle_path / 'bootstrap.sh'
|
|
301
|
+
bootstrap.write_text(_bootstrap_script(snapshot), encoding='utf-8')
|
|
302
|
+
bootstrap.chmod(0o755)
|
|
303
|
+
|
|
304
|
+
if require_ready and not snapshot['validation']['environment_ready_for_release_workflow']:
|
|
305
|
+
missing = ', '.join(snapshot['validation']['missing_imports']) or 'python version mismatch'
|
|
306
|
+
raise CertificationEnvironmentError(
|
|
307
|
+
'certification environment is not ready: '
|
|
308
|
+
f"python_ready={snapshot['validation']['python_version_ready']} "
|
|
309
|
+
f"required_imports_ready={snapshot['validation']['required_imports_ready']} "
|
|
310
|
+
f"missing={missing}"
|
|
311
|
+
)
|
|
312
|
+
return snapshot
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def build_status_payload(
|
|
316
|
+
snapshot: Mapping[str, Any],
|
|
317
|
+
*,
|
|
318
|
+
release_root: str,
|
|
319
|
+
bundle_root: str,
|
|
320
|
+
workflow_path: str = DEFAULT_RELEASE_WORKFLOW,
|
|
321
|
+
wrapper_path: str = DEFAULT_WRAPPER,
|
|
322
|
+
) -> dict[str, Any]:
|
|
323
|
+
validation = snapshot['validation']
|
|
324
|
+
return {
|
|
325
|
+
'checkpoint': 'certification_environment_freeze',
|
|
326
|
+
'phase': 'step1_execution_environment_freeze',
|
|
327
|
+
'status': 'environment_ready' if validation['environment_ready_for_release_workflow'] else 'environment_contract_frozen_but_not_ready',
|
|
328
|
+
'current_state': {
|
|
329
|
+
'required_install_command': snapshot['installation_contract']['install_command'],
|
|
330
|
+
'required_verify_command': snapshot['installation_contract']['verify_command'],
|
|
331
|
+
'required_extras': list(snapshot['installation_contract']['required_extras']),
|
|
332
|
+
'required_imports': list(validation['required_imports']),
|
|
333
|
+
'required_imports_ready': validation['required_imports_ready'],
|
|
334
|
+
'missing_imports': list(validation['missing_imports']),
|
|
335
|
+
'python_minor_version': snapshot['python']['minor_version'],
|
|
336
|
+
'python_version_ready': validation['python_version_ready'],
|
|
337
|
+
'environment_ready_for_release_workflow': validation['environment_ready_for_release_workflow'],
|
|
338
|
+
'release_root': release_root,
|
|
339
|
+
'bundle_root': bundle_root,
|
|
340
|
+
'workflow_path': workflow_path,
|
|
341
|
+
'wrapper_path': wrapper_path,
|
|
342
|
+
},
|
|
343
|
+
'validation': {
|
|
344
|
+
'python_version_ready': validation['python_version_ready'],
|
|
345
|
+
'required_imports_ready': validation['required_imports_ready'],
|
|
346
|
+
'missing_imports': list(validation['missing_imports']),
|
|
347
|
+
'supported_release_workflow_versions': list(snapshot['python']['supported_release_workflow_versions']),
|
|
348
|
+
},
|
|
349
|
+
'notes': [
|
|
350
|
+
'The release workflow must install the package with both the certification and dev extras before any Phase 9 checkpoint script is executed.',
|
|
351
|
+
'The local/offline checkpoint environment may still be non-ready even when the installation contract has been frozen; current readiness is recorded, not assumed.',
|
|
352
|
+
'This checkpoint closes the operational ambiguity around how the strict-promotion environment is provisioned, but it does not by itself turn the strict RFC target green.',
|
|
353
|
+
],
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def build_status_markdown(payload: Mapping[str, Any]) -> str:
|
|
358
|
+
state = payload['current_state']
|
|
359
|
+
missing = ', '.join(state['missing_imports']) if state['missing_imports'] else 'none'
|
|
360
|
+
return (
|
|
361
|
+
'# Certification environment freeze\n\n'
|
|
362
|
+
'This checkpoint freezes the certification-environment installation contract for the strict-promotion workflow.\n\n'
|
|
363
|
+
'## Required bootstrap\n\n'
|
|
364
|
+
'```bash\n'
|
|
365
|
+
'python -m venv .venv\n'
|
|
366
|
+
'source .venv/bin/activate\n'
|
|
367
|
+
'python -m pip install -U pip\n'
|
|
368
|
+
f"{state['required_install_command']}\n"
|
|
369
|
+
f"{state['required_verify_command']}\n"
|
|
370
|
+
'```\n\n'
|
|
371
|
+
'## Current recorded state\n\n'
|
|
372
|
+
f"- python minor version: `{state['python_minor_version']}`\n"
|
|
373
|
+
f"- python version ready for the release workflow: `{state['python_version_ready']}`\n"
|
|
374
|
+
f"- required imports ready: `{state['required_imports_ready']}`\n"
|
|
375
|
+
f"- missing imports: `{missing}`\n"
|
|
376
|
+
f"- environment ready for the release workflow: `{state['environment_ready_for_release_workflow']}`\n"
|
|
377
|
+
f"- release workflow path: `{state['workflow_path']}`\n"
|
|
378
|
+
f"- wrapper path: `{state['wrapper_path']}`\n"
|
|
379
|
+
f"- preserved bundle root: `{state['bundle_root']}`\n\n"
|
|
380
|
+
'## What this checkpoint changes\n\n'
|
|
381
|
+
'- makes the strict-promotion installation contract explicit\n'
|
|
382
|
+
'- records the observed environment snapshot in a preserved certification bundle\n'
|
|
383
|
+
'- adds a release-workflow guard that fails when the required imports are missing\n'
|
|
384
|
+
'- adds a local wrapper that freezes the environment before invoking Phase 9 checkpoint scripts\n\n'
|
|
385
|
+
'## Honest current result\n\n'
|
|
386
|
+
'This update improves the package operationally, but it does **not** by itself make the package certifiably fully featured or strict-target fully RFC compliant. The remaining strict-target HTTP/3 evidence blockers still need to be closed separately.\n'
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def write_status_documents(
|
|
391
|
+
root: str | Path,
|
|
392
|
+
snapshot: Mapping[str, Any],
|
|
393
|
+
*,
|
|
394
|
+
release_root: str,
|
|
395
|
+
bundle_root: str,
|
|
396
|
+
workflow_path: str = DEFAULT_RELEASE_WORKFLOW,
|
|
397
|
+
wrapper_path: str = DEFAULT_WRAPPER,
|
|
398
|
+
status_doc: str = DEFAULT_STATUS_DOC,
|
|
399
|
+
status_json: str = DEFAULT_STATUS_JSON,
|
|
400
|
+
delivery_notes: str = DEFAULT_DELIVERY_NOTES,
|
|
401
|
+
) -> dict[str, Any]:
|
|
402
|
+
repo_root = Path(root)
|
|
403
|
+
payload = build_status_payload(
|
|
404
|
+
snapshot,
|
|
405
|
+
release_root=release_root,
|
|
406
|
+
bundle_root=bundle_root,
|
|
407
|
+
workflow_path=workflow_path,
|
|
408
|
+
wrapper_path=wrapper_path,
|
|
409
|
+
)
|
|
410
|
+
markdown = build_status_markdown(payload)
|
|
411
|
+
(repo_root / status_doc).write_text(markdown, encoding='utf-8')
|
|
412
|
+
(repo_root / status_json).write_text(json.dumps(payload, indent=2) + '\n', encoding='utf-8')
|
|
413
|
+
(repo_root / delivery_notes).write_text(
|
|
414
|
+
'# Delivery notes — certification environment freeze\n\n'
|
|
415
|
+
'This checkpoint freezes the strict-promotion installation contract, adds a certification-environment bundle, and wires the requirement into a release-workflow guard and a local checkpoint wrapper.\n\n'
|
|
416
|
+
'It does **not** claim that the package is already strict-target green; it only closes the environment-provisioning ambiguity that previously allowed the remaining HTTP/3 third-party scenarios to run without the required extras installed.\n',
|
|
417
|
+
encoding='utf-8',
|
|
418
|
+
)
|
|
419
|
+
return payload
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(slots=True)
|
|
8
|
+
class TraceDiff:
|
|
9
|
+
missing_left: list[str] = field(default_factory=list)
|
|
10
|
+
missing_right: list[str] = field(default_factory=list)
|
|
11
|
+
mismatches: list[str] = field(default_factory=list)
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def ok(self) -> bool:
|
|
15
|
+
return not (self.missing_left or self.missing_right or self.mismatches)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def normalize_scope(scope: dict[str, Any]) -> dict[str, Any]:
|
|
19
|
+
scope = dict(scope)
|
|
20
|
+
scope.pop('state', None)
|
|
21
|
+
return scope
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def normalize_message(message: dict[str, Any]) -> dict[str, Any]:
|
|
25
|
+
message = dict(message)
|
|
26
|
+
if 'headers' in message:
|
|
27
|
+
message['headers'] = list(message['headers'])
|
|
28
|
+
return message
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def compare_sequence(left: list[dict[str, Any]], right: list[dict[str, Any]]) -> TraceDiff:
|
|
32
|
+
diff = TraceDiff()
|
|
33
|
+
for idx in range(max(len(left), len(right))):
|
|
34
|
+
if idx >= len(left):
|
|
35
|
+
diff.missing_left.append(f'left missing event[{idx}]')
|
|
36
|
+
continue
|
|
37
|
+
if idx >= len(right):
|
|
38
|
+
diff.missing_right.append(f'right missing event[{idx}]')
|
|
39
|
+
continue
|
|
40
|
+
if normalize_message(left[idx]) != normalize_message(right[idx]):
|
|
41
|
+
diff.mismatches.append(f'event[{idx}] {normalize_message(left[idx])!r} != {normalize_message(right[idx])!r}')
|
|
42
|
+
return diff
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class ExplicitCertificationSurface:
|
|
9
|
+
feature_id: str
|
|
10
|
+
title: str
|
|
11
|
+
category: str
|
|
12
|
+
evidence_tier: str
|
|
13
|
+
|
|
14
|
+
def as_dict(self) -> dict[str, str]:
|
|
15
|
+
return {
|
|
16
|
+
"feature_id": self.feature_id,
|
|
17
|
+
"title": self.title,
|
|
18
|
+
"category": self.category,
|
|
19
|
+
"evidence_tier": self.evidence_tier,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
EXPLICIT_CERTIFICATION_SURFACES: tuple[ExplicitCertificationSurface, ...] = (
|
|
24
|
+
ExplicitCertificationSurface("feat:surface-http2-tls-posture", "HTTP/2 TLS posture", "certification", "T4"),
|
|
25
|
+
ExplicitCertificationSurface("feat:surface-https-http11", "HTTPS HTTP/1.1", "certification", "T4"),
|
|
26
|
+
ExplicitCertificationSurface("feat:surface-https-service-identity", "HTTPS service identity", "certification", "T4"),
|
|
27
|
+
ExplicitCertificationSurface(
|
|
28
|
+
"feat:surface-tcp-tls13-external-peer-interop",
|
|
29
|
+
"TCP TLS 1.3 external peer interop",
|
|
30
|
+
"certification",
|
|
31
|
+
"T4",
|
|
32
|
+
),
|
|
33
|
+
ExplicitCertificationSurface(
|
|
34
|
+
"feat:surface-tls13-handshake-messages",
|
|
35
|
+
"TLS 1.3 handshake messages",
|
|
36
|
+
"certification",
|
|
37
|
+
"T4",
|
|
38
|
+
),
|
|
39
|
+
ExplicitCertificationSurface("feat:surface-tls13-record-layer", "TLS 1.3 record layer", "certification", "T4"),
|
|
40
|
+
ExplicitCertificationSurface(
|
|
41
|
+
"feat:surface-tls13-shutdown-behavior",
|
|
42
|
+
"TLS 1.3 shutdown behavior",
|
|
43
|
+
"certification",
|
|
44
|
+
"T4",
|
|
45
|
+
),
|
|
46
|
+
ExplicitCertificationSurface(
|
|
47
|
+
"feat:surface-tls13-state-transition",
|
|
48
|
+
"TLS 1.3 state transition",
|
|
49
|
+
"certification",
|
|
50
|
+
"T4",
|
|
51
|
+
),
|
|
52
|
+
ExplicitCertificationSurface(
|
|
53
|
+
"feat:surface-tls-server-name-indication",
|
|
54
|
+
"TLS server name indication",
|
|
55
|
+
"certification",
|
|
56
|
+
"T4",
|
|
57
|
+
),
|
|
58
|
+
ExplicitCertificationSurface(
|
|
59
|
+
"feat:surface-x509-certificate-profiles",
|
|
60
|
+
"X.509 certificate profiles",
|
|
61
|
+
"certification",
|
|
62
|
+
"T4",
|
|
63
|
+
),
|
|
64
|
+
ExplicitCertificationSurface("feat:surface-x509-path-validation", "X.509 path validation", "certification", "T4"),
|
|
65
|
+
ExplicitCertificationSurface(
|
|
66
|
+
"feat:surface-http3-control-plane",
|
|
67
|
+
"HTTP/3 control plane",
|
|
68
|
+
"certification_support",
|
|
69
|
+
"T4",
|
|
70
|
+
),
|
|
71
|
+
ExplicitCertificationSurface("feat:surface-ocsp-policy", "OCSP policy", "certification_support", "T2"),
|
|
72
|
+
ExplicitCertificationSurface("feat:surface-qpack-error-handling", "QPACK error handling", "certification_support", "T4"),
|
|
73
|
+
ExplicitCertificationSurface(
|
|
74
|
+
"feat:surface-quic-retry-token-integrity",
|
|
75
|
+
"QUIC Retry token integrity",
|
|
76
|
+
"certification_support",
|
|
77
|
+
"T4",
|
|
78
|
+
),
|
|
79
|
+
ExplicitCertificationSurface("feat:surface-quic-tls-mapping", "QUIC TLS mapping", "certification_support", "T4"),
|
|
80
|
+
ExplicitCertificationSurface(
|
|
81
|
+
"feat:surface-tls-status-request-policy",
|
|
82
|
+
"TLS status_request policy",
|
|
83
|
+
"certification_support",
|
|
84
|
+
"T2",
|
|
85
|
+
),
|
|
86
|
+
ExplicitCertificationSurface(
|
|
87
|
+
"feat:surface-tcp-tls13-backend-control",
|
|
88
|
+
"TCP TLS 1.3 backend control",
|
|
89
|
+
"governance_support",
|
|
90
|
+
"T2",
|
|
91
|
+
),
|
|
92
|
+
ExplicitCertificationSurface(
|
|
93
|
+
"feat:surface-package-owned-http-fields",
|
|
94
|
+
"Package-owned HTTP fields",
|
|
95
|
+
"operator_surface",
|
|
96
|
+
"T2",
|
|
97
|
+
),
|
|
98
|
+
ExplicitCertificationSurface("feat:fail-state-registry", "Fail-state registry", "roadmap_feature", "T2"),
|
|
99
|
+
ExplicitCertificationSurface(
|
|
100
|
+
"feat:observability-export-surfaces",
|
|
101
|
+
"Observability export surfaces",
|
|
102
|
+
"roadmap_feature",
|
|
103
|
+
"T2",
|
|
104
|
+
),
|
|
105
|
+
ExplicitCertificationSurface("feat:origin-negative-corpora", "Origin negative corpora", "roadmap_feature", "T2"),
|
|
106
|
+
ExplicitCertificationSurface("feat:qlog-stance", "qlog stance", "roadmap_feature", "T2"),
|
|
107
|
+
ExplicitCertificationSurface("feat:quic-h3-counters", "QUIC/H3 counters", "roadmap_feature", "T2"),
|
|
108
|
+
ExplicitCertificationSurface("feat:quic-negative-corpora", "QUIC negative corpora", "roadmap_feature", "T2"),
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def certification_explicit_surface_catalog() -> tuple[dict[str, str], ...]:
|
|
113
|
+
return tuple(surface.as_dict() for surface in EXPLICIT_CERTIFICATION_SURFACES)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def certification_explicit_surface_ids() -> tuple[str, ...]:
|
|
117
|
+
return tuple(surface.feature_id for surface in EXPLICIT_CERTIFICATION_SURFACES)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def validate_explicit_surface_manifest(manifest: dict[str, Any]) -> list[str]:
|
|
121
|
+
failures: list[str] = []
|
|
122
|
+
expected = set(certification_explicit_surface_ids())
|
|
123
|
+
actual = set(manifest.get("feature_ids", []))
|
|
124
|
+
if actual != expected:
|
|
125
|
+
failures.append(f"feature_ids mismatch: missing={sorted(expected - actual)} extra={sorted(actual - expected)}")
|
|
126
|
+
if manifest.get("boundary_id") != "bnd:certification-explicit-surfaces":
|
|
127
|
+
failures.append("boundary_id must be bnd:certification-explicit-surfaces")
|
|
128
|
+
if manifest.get("status") != "closed":
|
|
129
|
+
failures.append("status must be closed")
|
|
130
|
+
return failures
|