tigrcorn-certification 0.3.18.dev1__tar.gz → 0.3.18.dev3__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 (65) hide show
  1. {tigrcorn_certification-0.3.18.dev1/src/tigrcorn_certification.egg-info → tigrcorn_certification-0.3.18.dev3}/PKG-INFO +5 -4
  2. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/README.md +1 -1
  3. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/pyproject.toml +4 -3
  4. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/__init__.py +26 -0
  5. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/certification_env.py +1 -1
  6. tigrcorn_certification-0.3.18.dev3/src/tigrcorn_certification/certify/__init__.py +5 -0
  7. tigrcorn_certification-0.3.18.dev3/src/tigrcorn_certification/certify/static.py +118 -0
  8. tigrcorn_certification-0.3.18.dev3/src/tigrcorn_certification/hardening_suites.py +103 -0
  9. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/__init__.py +1 -0
  10. tigrcorn_certification-0.3.18.dev3/src/tigrcorn_certification/interop_runner/impairment.py +55 -0
  11. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/proxies.py +20 -9
  12. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3/src/tigrcorn_certification.egg-info}/PKG-INFO +5 -4
  13. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification.egg-info/SOURCES.txt +4 -0
  14. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification.egg-info/requires.txt +3 -2
  15. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/LICENSE +0 -0
  16. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/setup.cfg +0 -0
  17. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/aioquic_preflight/__init__.py +0 -0
  18. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/aioquic_preflight/bundle.py +0 -0
  19. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/aioquic_preflight/core.py +0 -0
  20. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/aioquic_preflight/helpers.py +0 -0
  21. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/aioquic_preflight/imports.py +0 -0
  22. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/aioquic_preflight/records.py +0 -0
  23. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/aioquic_preflight/status_docs.py +0 -0
  24. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/artifacts.py +0 -0
  25. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/conformance.py +0 -0
  26. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/explicit_surfaces.py +0 -0
  27. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/adapters.py +0 -0
  28. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/assertions.py +0 -0
  29. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/core.py +0 -0
  30. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/environment.py +0 -0
  31. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/helpers.py +0 -0
  32. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/imports.py +0 -0
  33. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/matrix.py +0 -0
  34. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/models.py +0 -0
  35. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/ports.py +0 -0
  36. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/process.py +0 -0
  37. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/qlog.py +0 -0
  38. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/runner.py +0 -0
  39. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/interop_runner/scenario.py +0 -0
  40. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/perf_runner/__init__.py +0 -0
  41. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/perf_runner/artifacts.py +0 -0
  42. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/perf_runner/environment.py +0 -0
  43. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/perf_runner/imports.py +0 -0
  44. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/perf_runner/matrix.py +0 -0
  45. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/perf_runner/metrics.py +0 -0
  46. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/perf_runner/models.py +0 -0
  47. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/perf_runner/runner.py +0 -0
  48. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/perf_runner/stats.py +0 -0
  49. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/perf_runner/validation.py +0 -0
  50. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/py.typed +0 -0
  51. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/release_gates/__init__.py +0 -0
  52. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/release_gates/artifact_gate.py +0 -0
  53. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/release_gates/contract_registry.py +0 -0
  54. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/release_gates/core.py +0 -0
  55. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/release_gates/docs.py +0 -0
  56. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/release_gates/imports.py +0 -0
  57. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/release_gates/independent.py +0 -0
  58. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/release_gates/loaders.py +0 -0
  59. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/release_gates/models.py +0 -0
  60. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/release_gates/promotion.py +0 -0
  61. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/release_gates/promotion_sections.py +0 -0
  62. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/release_gates/supply_chain_gate.py +0 -0
  63. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification/supply_chain.py +0 -0
  64. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/src/tigrcorn_certification.egg-info/dependency_links.txt +0 -0
  65. {tigrcorn_certification-0.3.18.dev1 → tigrcorn_certification-0.3.18.dev3}/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.18.dev1
3
+ Version: 0.3.18.dev3
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,9 @@ 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.18.dev1
191
- Requires-Dist: tigrcorn-runtime==0.3.18.dev1
190
+ Requires-Dist: tigrcorn-compat==0.3.18.dev3
191
+ Requires-Dist: tigrcorn-runtime==0.3.18.dev3
192
+ Requires-Dist: tigrcorn-static==0.3.18.dev3
192
193
  Requires-Dist: tomli>=2.0.0; python_version < "3.11"
193
194
  Requires-Dist: cryptography>=46.0.0
194
195
  Requires-Dist: aioquic>=1.3.0
@@ -286,7 +287,7 @@ The package exposes its supported public surface through the <code>tigrcorn_cert
286
287
 
287
288
  ## Package Graph
288
289
 
289
- [tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
290
+ [tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-quic-cc](https://pypi.org/project/tigrcorn-quic-cc/) | [tigrcorn-quic-cc-reno](https://pypi.org/project/tigrcorn-quic-cc-reno/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
290
291
 
291
292
  ## Best Practices
292
293
 
@@ -87,7 +87,7 @@ The package exposes its supported public surface through the <code>tigrcorn_cert
87
87
 
88
88
  ## Package Graph
89
89
 
90
- [tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
90
+ [tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-quic-cc](https://pypi.org/project/tigrcorn-quic-cc/) | [tigrcorn-quic-cc-reno](https://pypi.org/project/tigrcorn-quic-cc-reno/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
91
91
 
92
92
  ## Best Practices
93
93
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tigrcorn-certification"
7
- version = "0.3.18.dev1"
7
+ version = "0.3.18.dev3"
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,9 @@ classifiers = [
30
30
  "Typing :: Typed",
31
31
  ]
32
32
  dependencies = [
33
- "tigrcorn-compat==0.3.18.dev1",
34
- "tigrcorn-runtime==0.3.18.dev1",
33
+ "tigrcorn-compat==0.3.18.dev3",
34
+ "tigrcorn-runtime==0.3.18.dev3",
35
+ "tigrcorn-static==0.3.18.dev3",
35
36
  "tomli>=2.0.0; python_version < '3.11'",
36
37
  "cryptography>=46.0.0",
37
38
  "aioquic>=1.3.0",
@@ -44,10 +44,36 @@ __all__ = [
44
44
  "validate_package_manifest_integrity",
45
45
  "validate_release_evidence",
46
46
  "write_supply_chain_release_bundle",
47
+ "certify_static",
48
+ "certify_static_main",
49
+ "export_hardening_suite_catalog",
50
+ "validate_hardening_suite_catalog",
47
51
  ]
48
52
 
49
53
 
50
54
  def __getattr__(name: str):
55
+ if name in {
56
+ "certify_static",
57
+ "certify_static_main",
58
+ }:
59
+ from .certify.static import certify_static, certify_static_main
60
+
61
+ mapping = {
62
+ "certify_static": certify_static,
63
+ "certify_static_main": certify_static_main,
64
+ }
65
+ return mapping[name]
66
+ if name in {
67
+ "export_hardening_suite_catalog",
68
+ "validate_hardening_suite_catalog",
69
+ }:
70
+ from .hardening_suites import export_hardening_suite_catalog, validate_hardening_suite_catalog
71
+
72
+ mapping = {
73
+ "export_hardening_suite_catalog": export_hardening_suite_catalog,
74
+ "validate_hardening_suite_catalog": validate_hardening_suite_catalog,
75
+ }
76
+ return mapping[name]
51
77
  if name in {
52
78
  "evaluate_release_gates",
53
79
  "assert_release_ready",
@@ -13,7 +13,7 @@ try:
13
13
  import tomllib
14
14
  except ModuleNotFoundError: # pragma: no cover - Python 3.10 fallback
15
15
  import tomli as tomllib
16
- SUPPORTED_PYTHON_VERSIONS: tuple[str, ...] = ('3.11', '3.12')
16
+ SUPPORTED_PYTHON_VERSIONS: tuple[str, ...] = ('3.10', '3.11', '3.12', '3.13', '3.14')
17
17
  REQUIRED_IMPORTS: tuple[str, ...] = ('aioquic', 'h2', 'websockets', 'wsproto')
18
18
  REQUIRED_EXTRAS: tuple[str, ...] = ('certification', 'dev')
19
19
  SAFE_ENV_KEYS: tuple[str, ...] = (
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+
3
+ from .static import certify_static, certify_static_main
4
+
5
+ __all__ = ["certify_static", "certify_static_main"]
@@ -0,0 +1,118 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ from pathlib import Path
7
+ from typing import Callable, Iterable
8
+
9
+ from tigrcorn_static.static import (
10
+ StaticSecurityCertificationError,
11
+ build_static_certification_evidence,
12
+ certify_static_delivery_security,
13
+ static_delivery_certification_artifact,
14
+ )
15
+
16
+ from ..artifacts import canonical_json
17
+
18
+
19
+ class StaticCertificationCommandError(ValueError):
20
+ """Raised when static certification cannot be completed."""
21
+
22
+
23
+ def build_static_certification_parser() -> argparse.ArgumentParser:
24
+ parser = argparse.ArgumentParser(prog="tigrcorn certify static")
25
+ parser.add_argument("--mount", required=True, help="Static mount directory to certify")
26
+ parser.add_argument("--profile", default="default", help="Blessed deployment profile")
27
+ parser.add_argument("--output", required=True, help="Directory where certification artifacts are written")
28
+ return parser
29
+
30
+
31
+ def certify_static(
32
+ *,
33
+ mount: str | Path,
34
+ profile: str = "default",
35
+ output: str | Path,
36
+ require_supported: Callable[[Iterable[str]], None] | None = None,
37
+ ) -> dict[str, object]:
38
+ mount_path = Path(mount)
39
+ if not mount_path.exists() or not mount_path.is_dir():
40
+ raise StaticCertificationCommandError(f"static mount does not exist or is not a directory: {mount_path}")
41
+
42
+ if require_supported is not None:
43
+ require_supported(["delivery.static"])
44
+
45
+ evidence = build_static_certification_evidence(mount_path, profile=profile)
46
+ certification = certify_static_delivery_security(evidence)
47
+ static_artifact = {
48
+ "artifact": static_delivery_certification_artifact(),
49
+ "certification": certification,
50
+ "evidence": evidence,
51
+ "mount_name": mount_path.name,
52
+ "profile": profile,
53
+ "schema_version": 1,
54
+ }
55
+ manifest = {
56
+ "artifacts": [
57
+ {
58
+ "digest": _digest(static_artifact),
59
+ "name": "static.json",
60
+ }
61
+ ],
62
+ "certification": "static",
63
+ "digest_algorithm": "sha256",
64
+ "manifest_version": 1,
65
+ "profile": profile,
66
+ }
67
+ output_path = Path(output)
68
+ output_path.mkdir(parents=True, exist_ok=True)
69
+ static_path = output_path / "static.json"
70
+ manifest_path = output_path / "manifest.json"
71
+ static_path.write_text(canonical_json(static_artifact), encoding="utf-8", newline="\n")
72
+ manifest_path.write_text(canonical_json(manifest), encoding="utf-8", newline="\n")
73
+ return {
74
+ "artifact_paths": [str(static_path), str(manifest_path)],
75
+ "mount": str(mount_path),
76
+ "output": str(output_path),
77
+ "passed": True,
78
+ "profile": profile,
79
+ }
80
+
81
+
82
+ def certify_static_main(
83
+ argv: list[str] | None = None,
84
+ *,
85
+ require_supported: Callable[[Iterable[str]], None] | None = None,
86
+ ) -> int:
87
+ parser = build_static_certification_parser()
88
+ ns = parser.parse_args(list(argv or ()))
89
+
90
+ capability_gate = None
91
+ if require_supported is not None:
92
+ capability_gate = lambda ids: require_supported(ids, profile=ns.profile) # noqa: E731
93
+ try:
94
+ result = certify_static(
95
+ mount=ns.mount,
96
+ profile=ns.profile,
97
+ output=ns.output,
98
+ require_supported=capability_gate,
99
+ )
100
+ except (StaticCertificationCommandError, StaticSecurityCertificationError, ValueError) as exc:
101
+ print(str(exc), file=sys.stderr)
102
+ return 2
103
+ print(json.dumps(result, sort_keys=True, separators=(",", ":")))
104
+ return 0
105
+
106
+
107
+ def _digest(payload: dict[str, object]) -> str:
108
+ import hashlib
109
+
110
+ return hashlib.sha256(canonical_json(payload).encode("utf-8")).hexdigest()
111
+
112
+
113
+ __all__ = [
114
+ "StaticCertificationCommandError",
115
+ "build_static_certification_parser",
116
+ "certify_static",
117
+ "certify_static_main",
118
+ ]
@@ -0,0 +1,103 @@
1
+ from __future__ import annotations
2
+
3
+ from copy import deepcopy
4
+ from typing import Any
5
+
6
+
7
+ HARDENING_SUITE_CATALOG: dict[str, dict[str, Any]] = {
8
+ "http1": {
9
+ "owner_package": "tigrcorn-protocols",
10
+ "package_tests": ["tests/test_http1_hardening_pass.py"],
11
+ "cross_cutting_tests": ["tests/test_adversarial_protocol_hardening_suites.py"],
12
+ "feature_ids": ["feat:adversarial-protocol-hardening-suites"],
13
+ "spec_ids": ["spc:2080"],
14
+ "cases": ["slowloris", "malformed_chunking", "request_smuggling", "oversized_headers", "premature_eof"],
15
+ },
16
+ "http2": {
17
+ "owner_package": "tigrcorn-protocols",
18
+ "package_tests": ["tests/test_http2_state_machine_completion.py"],
19
+ "cross_cutting_tests": ["tests/test_adversarial_protocol_hardening_suites.py"],
20
+ "feature_ids": ["feat:adversarial-protocol-hardening-suites"],
21
+ "spec_ids": ["spc:2080"],
22
+ "cases": ["rapid_reset", "continuation_flood", "stream_exhaustion", "settings_churn", "flow_control_deadlock"],
23
+ },
24
+ "http3_quic": {
25
+ "owner_package": "tigrcorn-transports",
26
+ "package_tests": ["tests/test_quic_operational_security_certification.py", "tests/test_quic_impairment_policy.py"],
27
+ "cross_cutting_tests": ["tests/test_quic_operational_security_integration.py", "tests/test_quic_recovery_live_runtime_integration.py"],
28
+ "feature_ids": ["feat:quic-operational-security-certification", "feat:adversarial-protocol-hardening-suites"],
29
+ "spec_ids": ["spc:2060", "spc:2080"],
30
+ "cases": ["packet_loss", "packet_reordering", "packet_duplication", "controlled_delay", "reliable_stream_recovery", "datagram_abandonment", "amplification_limit", "connection_migration", "cid_rotation"],
31
+ },
32
+ "websocket": {
33
+ "owner_package": "tigrcorn-protocols",
34
+ "package_tests": ["tests/test_server_websocket.py"],
35
+ "cross_cutting_tests": ["tests/test_adversarial_protocol_hardening_suites.py"],
36
+ "feature_ids": ["feat:adversarial-protocol-hardening-suites"],
37
+ "spec_ids": ["spc:2080"],
38
+ "cases": ["fragmented_control_frames", "masking_rules", "close_races", "compression_bombs"],
39
+ },
40
+ "webtransport": {
41
+ "owner_package": "tigrcorn-protocols",
42
+ "package_tests": ["tests/test_webtransport_resource_governance.py"],
43
+ "cross_cutting_tests": ["tests/test_webtransport_resource_governance_integration.py"],
44
+ "feature_ids": ["feat:webtransport-resource-governance", "feat:adversarial-protocol-hardening-suites"],
45
+ "spec_ids": ["spc:2061", "spc:2080"],
46
+ "cases": ["session_budget", "stream_budget", "datagram_budget", "drain", "reset_stop_sending"],
47
+ },
48
+ "static": {
49
+ "owner_package": "tigrcorn-static",
50
+ "package_tests": ["tests/test_static_delivery_security_certification.py"],
51
+ "cross_cutting_tests": ["tests/test_certification_command_namespace.py"],
52
+ "feature_ids": ["feat:static-delivery-security-certification", "feat:adversarial-protocol-hardening-suites"],
53
+ "spec_ids": ["spc:2062", "spc:2080"],
54
+ "cases": ["traversal", "sidecar_mismatch", "range_amplification", "content_type_ambiguity"],
55
+ },
56
+ "observability": {
57
+ "owner_package": "tigrcorn-observability",
58
+ "package_tests": ["tests/test_protocol_aware_observability.py"],
59
+ "cross_cutting_tests": ["tests/test_protocol_aware_observability_integration.py"],
60
+ "feature_ids": ["feat:protocol-aware-observability"],
61
+ "spec_ids": ["spc:2064"],
62
+ "cases": ["metric_names", "event_names", "cardinality_limits"],
63
+ },
64
+ "certification": {
65
+ "owner_package": "tigrcorn-certification",
66
+ "package_tests": ["tests/test_certification_command_namespace.py"],
67
+ "cross_cutting_tests": ["tests/test_adversarial_protocol_hardening_suites.py"],
68
+ "feature_ids": ["feat:certification-command-namespace"],
69
+ "spec_ids": ["spc:2079"],
70
+ "cases": ["command_dispatch", "artifact_shape", "leaf_import_boundary", "fail_closed"],
71
+ },
72
+ }
73
+
74
+
75
+ def export_hardening_suite_catalog() -> dict[str, Any]:
76
+ return {
77
+ "catalog": deepcopy(HARDENING_SUITE_CATALOG),
78
+ "schema_version": 1,
79
+ }
80
+
81
+
82
+ def validate_hardening_suite_catalog(catalog: dict[str, dict[str, Any]] | None = None) -> dict[str, Any]:
83
+ selected = catalog or HARDENING_SUITE_CATALOG
84
+ failures: list[str] = []
85
+ for suite_id, suite in sorted(selected.items()):
86
+ owner = suite.get("owner_package")
87
+ if not isinstance(owner, str) or not owner.startswith("tigrcorn-"):
88
+ failures.append(f"{suite_id}: owner_package must be a tigrcorn distribution")
89
+ for field in ("package_tests", "cross_cutting_tests", "feature_ids", "spec_ids", "cases"):
90
+ values = suite.get(field)
91
+ if not isinstance(values, list) or not values:
92
+ failures.append(f"{suite_id}: {field} must be a non-empty list")
93
+ for test_path in suite.get("package_tests", []) + suite.get("cross_cutting_tests", []):
94
+ if not isinstance(test_path, str) or not test_path.startswith("tests/"):
95
+ failures.append(f"{suite_id}: test path must be under tests/: {test_path!r}")
96
+ return {"failures": failures, "passed": not failures, "suite_count": len(selected)}
97
+
98
+
99
+ __all__ = [
100
+ "HARDENING_SUITE_CATALOG",
101
+ "export_hardening_suite_catalog",
102
+ "validate_hardening_suite_catalog",
103
+ ]
@@ -5,6 +5,7 @@ from .process import *
5
5
  from .helpers import *
6
6
  from .adapters import *
7
7
  from .proxies import *
8
+ from .impairment import *
8
9
  from .ports import *
9
10
  from .environment import *
10
11
  from .assertions import *
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+
5
+
6
+ @dataclass(frozen=True, slots=True)
7
+ class UDPImpairmentProfile:
8
+ """Deterministic UDP impairment settings for repeatable QUIC proofs."""
9
+
10
+ drop_every: int = 0
11
+ duplicate_every: int = 0
12
+ reorder_every: int = 0
13
+ delay_seconds: float = 0.0
14
+
15
+ def __post_init__(self) -> None:
16
+ for name in ("drop_every", "duplicate_every", "reorder_every"):
17
+ if int(getattr(self, name)) < 0:
18
+ raise ValueError(f"{name} must be non-negative")
19
+ if self.delay_seconds < 0:
20
+ raise ValueError("delay_seconds must be non-negative")
21
+
22
+
23
+ @dataclass(slots=True)
24
+ class UDPImpairmentPolicy:
25
+ profile: UDPImpairmentProfile
26
+ _counts: dict[str, int] = field(default_factory=dict)
27
+ _held: dict[str, bytes] = field(default_factory=dict)
28
+
29
+ def apply(self, direction: str, payload: bytes) -> tuple[bytes, ...]:
30
+ count = self._counts.get(direction, 0) + 1
31
+ self._counts[direction] = count
32
+ if self.profile.drop_every and count % self.profile.drop_every == 0:
33
+ return ()
34
+
35
+ emitted: list[bytes] = []
36
+ held = self._held.pop(direction, None)
37
+ if self.profile.reorder_every and count % self.profile.reorder_every == 0:
38
+ self._held[direction] = bytes(payload)
39
+ if held is not None:
40
+ emitted.append(held)
41
+ return tuple(emitted)
42
+
43
+ emitted.append(bytes(payload))
44
+ if held is not None:
45
+ emitted.append(held)
46
+ if self.profile.duplicate_every and count % self.profile.duplicate_every == 0:
47
+ emitted.append(bytes(payload))
48
+ return tuple(emitted)
49
+
50
+ def flush(self, direction: str) -> tuple[bytes, ...]:
51
+ held = self._held.pop(direction, None)
52
+ return () if held is None else (held,)
53
+
54
+
55
+ __all__ = ["UDPImpairmentPolicy", "UDPImpairmentProfile"]
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from .imports import *
4
4
  from .helpers import *
5
5
  from .ports import _normalize_sockaddr
6
+ from .impairment import UDPImpairmentPolicy
6
7
 
7
8
  class _PacketTraceWriter:
8
9
  def __init__(self, path: Path) -> None:
@@ -124,7 +125,7 @@ class TCPRecordProxy:
124
125
 
125
126
 
126
127
  class UDPRecordProxy:
127
- def __init__(self, *, listen_host: str, listen_port: int, target_host: str, target_port: int, packet_trace_path: Path, ip_family: str = 'ipv4') -> None:
128
+ def __init__(self, *, listen_host: str, listen_port: int, target_host: str, target_port: int, packet_trace_path: Path, ip_family: str = 'ipv4', impairment: UDPImpairmentPolicy | None = None) -> None:
128
129
  family = socket.AF_INET6 if ip_family == 'ipv6' else socket.AF_INET
129
130
  self.listen_host = listen_host
130
131
  self.listen_port = listen_port
@@ -144,6 +145,14 @@ class UDPRecordProxy:
144
145
  self._stop = threading.Event()
145
146
  self._thread = threading.Thread(target=self._loop, daemon=True)
146
147
  self._last_client: tuple[str, int] | None = None
148
+ self._impairment = impairment
149
+
150
+ def _forward_payloads(self, direction: str, payload: bytes) -> tuple[bytes, ...]:
151
+ if self._impairment is None:
152
+ return (payload,)
153
+ if self._impairment.profile.delay_seconds:
154
+ time.sleep(self._impairment.profile.delay_seconds)
155
+ return self._impairment.apply(direction, payload)
147
156
 
148
157
  def start(self) -> None:
149
158
  self._thread.start()
@@ -170,10 +179,11 @@ class UDPRecordProxy:
170
179
  remote=(self.target_host, self.target_port),
171
180
  payload=payload,
172
181
  )
173
- try:
174
- self._upstream.sendto(payload, target)
175
- except OSError:
176
- continue
182
+ for forwarded in self._forward_payloads('client_to_server', payload):
183
+ try:
184
+ self._upstream.sendto(forwarded, target)
185
+ except OSError:
186
+ continue
177
187
  elif key.fileobj is self._upstream:
178
188
  try:
179
189
  payload, _addr = self._upstream.recvfrom(65535)
@@ -188,10 +198,11 @@ class UDPRecordProxy:
188
198
  remote=self._last_client,
189
199
  payload=payload,
190
200
  )
191
- try:
192
- self._downstream.sendto(payload, self._last_client)
193
- except OSError:
194
- continue
201
+ for forwarded in self._forward_payloads('server_to_client', payload):
202
+ try:
203
+ self._downstream.sendto(forwarded, self._last_client)
204
+ except OSError:
205
+ continue
195
206
  finally:
196
207
  selector.close()
197
208
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tigrcorn-certification
3
- Version: 0.3.18.dev1
3
+ Version: 0.3.18.dev3
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,9 @@ 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.18.dev1
191
- Requires-Dist: tigrcorn-runtime==0.3.18.dev1
190
+ Requires-Dist: tigrcorn-compat==0.3.18.dev3
191
+ Requires-Dist: tigrcorn-runtime==0.3.18.dev3
192
+ Requires-Dist: tigrcorn-static==0.3.18.dev3
192
193
  Requires-Dist: tomli>=2.0.0; python_version < "3.11"
193
194
  Requires-Dist: cryptography>=46.0.0
194
195
  Requires-Dist: aioquic>=1.3.0
@@ -286,7 +287,7 @@ The package exposes its supported public surface through the <code>tigrcorn_cert
286
287
 
287
288
  ## Package Graph
288
289
 
289
- [tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
290
+ [tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-quic-cc](https://pypi.org/project/tigrcorn-quic-cc/) | [tigrcorn-quic-cc-reno](https://pypi.org/project/tigrcorn-quic-cc-reno/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
290
291
 
291
292
  ## Best Practices
292
293
 
@@ -6,6 +6,7 @@ src/tigrcorn_certification/artifacts.py
6
6
  src/tigrcorn_certification/certification_env.py
7
7
  src/tigrcorn_certification/conformance.py
8
8
  src/tigrcorn_certification/explicit_surfaces.py
9
+ src/tigrcorn_certification/hardening_suites.py
9
10
  src/tigrcorn_certification/py.typed
10
11
  src/tigrcorn_certification/supply_chain.py
11
12
  src/tigrcorn_certification.egg-info/PKG-INFO
@@ -20,12 +21,15 @@ src/tigrcorn_certification/aioquic_preflight/helpers.py
20
21
  src/tigrcorn_certification/aioquic_preflight/imports.py
21
22
  src/tigrcorn_certification/aioquic_preflight/records.py
22
23
  src/tigrcorn_certification/aioquic_preflight/status_docs.py
24
+ src/tigrcorn_certification/certify/__init__.py
25
+ src/tigrcorn_certification/certify/static.py
23
26
  src/tigrcorn_certification/interop_runner/__init__.py
24
27
  src/tigrcorn_certification/interop_runner/adapters.py
25
28
  src/tigrcorn_certification/interop_runner/assertions.py
26
29
  src/tigrcorn_certification/interop_runner/core.py
27
30
  src/tigrcorn_certification/interop_runner/environment.py
28
31
  src/tigrcorn_certification/interop_runner/helpers.py
32
+ src/tigrcorn_certification/interop_runner/impairment.py
29
33
  src/tigrcorn_certification/interop_runner/imports.py
30
34
  src/tigrcorn_certification/interop_runner/matrix.py
31
35
  src/tigrcorn_certification/interop_runner/models.py
@@ -1,5 +1,6 @@
1
- tigrcorn-compat==0.3.18.dev1
2
- tigrcorn-runtime==0.3.18.dev1
1
+ tigrcorn-compat==0.3.18.dev3
2
+ tigrcorn-runtime==0.3.18.dev3
3
+ tigrcorn-static==0.3.18.dev3
3
4
  cryptography>=46.0.0
4
5
  aioquic>=1.3.0
5
6
  h2>=4.1.0