Spaces:
Running
Running
Commit ·
651cbf7
1
Parent(s): 2c16be5
feat(contracts): add typed Forge runtime probes (#8)
Browse files- feat(contracts): add typed Forge runtime probes (d89267a3c4bac6bce619e74b3b280a1b0623524a)
- docs(provenance): bound provider build timestamp semantics (813cf06b4255cca3f4e649d24e96e6e2f5e7f615)
- README.md +8 -1
- app.py +19 -11
- forge_runtime_contract.py +256 -0
- tests/test_managed_gradio_contract.py +86 -0
- tests/test_runtime_contract.py +122 -0
README.md
CHANGED
|
@@ -4,6 +4,7 @@ emoji: "⚒️"
|
|
| 4 |
colorFrom: green
|
| 5 |
colorTo: gray
|
| 6 |
sdk: gradio
|
|
|
|
| 7 |
app_file: app.py
|
| 8 |
pinned: false
|
| 9 |
short_description: Evidence console for SZL Forge models and formulas.
|
|
@@ -34,6 +35,12 @@ The Gradio API exposes `/status`, `/integrity`, `/evaluation`, `/receipt`,
|
|
| 34 |
`/curriculum-stage`. Exact inputs and outputs are visible in the Space's
|
| 35 |
**Use via API** panel and its **Callable API** tab.
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
```python
|
| 38 |
from gradio_client import Client
|
| 39 |
|
|
@@ -46,5 +53,5 @@ formulas = client.predict("lambda", "ALL", 10, api_name="/formulas")
|
|
| 46 |
|
| 47 |
```bash
|
| 48 |
python -m unittest discover -s tests -v
|
| 49 |
-
python -m py_compile forge_lab.py app.py
|
| 50 |
```
|
|
|
|
| 4 |
colorFrom: green
|
| 5 |
colorTo: gray
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 6.20.0
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
short_description: Evidence console for SZL Forge models and formulas.
|
|
|
|
| 35 |
`/curriculum-stage`. Exact inputs and outputs are visible in the Space's
|
| 36 |
**Use via API** panel and its **Callable API** tab.
|
| 37 |
|
| 38 |
+
Operational probes that require ordinary HTTP GET JSON use three separate,
|
| 39 |
+
typed compatibility routes: `/.well-known/szl-source.json`, `/healthz`, and
|
| 40 |
+
`/api/status`. They report transport, evidence, revision measurement, source
|
| 41 |
+
alignment, and authority independently. In particular,
|
| 42 |
+
`PENDING_GITHUB_SYNC` never implies GitHub/Hugging Face byte parity.
|
| 43 |
+
|
| 44 |
```python
|
| 45 |
from gradio_client import Client
|
| 46 |
|
|
|
|
| 53 |
|
| 54 |
```bash
|
| 55 |
python -m unittest discover -s tests -v
|
| 56 |
+
python -m py_compile forge_lab.py forge_runtime_contract.py app.py
|
| 57 |
```
|
app.py
CHANGED
|
@@ -27,6 +27,7 @@ from forge_lab import (
|
|
| 27 |
metrics,
|
| 28 |
source_rows,
|
| 29 |
)
|
|
|
|
| 30 |
|
| 31 |
|
| 32 |
CSS = """
|
|
@@ -396,14 +397,21 @@ with gr.Blocks(title="SZL Forge Lab") as demo:
|
|
| 396 |
|
| 397 |
|
| 398 |
if __name__ == "__main__":
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
metrics,
|
| 28 |
source_rows,
|
| 29 |
)
|
| 30 |
+
from forge_runtime_contract import register_contract_routes
|
| 31 |
|
| 32 |
|
| 33 |
CSS = """
|
|
|
|
| 397 |
|
| 398 |
|
| 399 |
if __name__ == "__main__":
|
| 400 |
+
try:
|
| 401 |
+
server_app, _, _ = demo.launch(
|
| 402 |
+
server_name="0.0.0.0",
|
| 403 |
+
server_port=int(os.environ.get("PORT", "7860")),
|
| 404 |
+
show_error=False,
|
| 405 |
+
prevent_thread_lock=True,
|
| 406 |
+
# The managed SSR shell only packages Brotli variants for its /_app CSS.
|
| 407 |
+
# Use Gradio's client shell so assets remain reachable without relying on
|
| 408 |
+
# proxy content-encoding negotiation.
|
| 409 |
+
ssr_mode=False,
|
| 410 |
+
css=CSS,
|
| 411 |
+
theme=gr.themes.Base(),
|
| 412 |
+
)
|
| 413 |
+
register_contract_routes(server_app, get_status)
|
| 414 |
+
except Exception:
|
| 415 |
+
demo.close()
|
| 416 |
+
raise
|
| 417 |
+
demo.block_thread()
|
forge_runtime_contract.py
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Typed, read-only HTTP compatibility contracts for the managed Forge Space.
|
| 2 |
+
|
| 3 |
+
The Gradio event API remains the product API. These routes are deliberately
|
| 4 |
+
small operational contracts for probes that require ordinary HTTP GET JSON.
|
| 5 |
+
They do not claim GitHub/Hugging Face byte parity or a reproducible build.
|
| 6 |
+
"""
|
| 7 |
+
from __future__ import annotations
|
| 8 |
+
|
| 9 |
+
import json
|
| 10 |
+
import os
|
| 11 |
+
import re
|
| 12 |
+
import threading
|
| 13 |
+
import time
|
| 14 |
+
import urllib.request
|
| 15 |
+
from collections.abc import Callable
|
| 16 |
+
from datetime import datetime, timezone
|
| 17 |
+
from typing import Any
|
| 18 |
+
|
| 19 |
+
from fastapi.responses import JSONResponse
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
SPACE_ID = "SZLHOLDINGS/szl-forge-lab"
|
| 23 |
+
SOURCE_REPOSITORY = "szl-holdings/szl-forge"
|
| 24 |
+
SOURCE_COMMIT = "43e0aedb176fbc8868557e56e30501d8de24578e"
|
| 25 |
+
SOURCE_PATH = ""
|
| 26 |
+
ALIGNMENT_STATE = "PENDING_GITHUB_SYNC"
|
| 27 |
+
_SHA = re.compile(r"^[0-9a-f]{40}$")
|
| 28 |
+
_CACHE_LOCK = threading.Lock()
|
| 29 |
+
_CACHE: dict[str, Any] = {"stored_at": 0.0, "measurement": None}
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def _now_iso() -> str:
|
| 33 |
+
return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def _valid_sha(value: object) -> str | None:
|
| 37 |
+
candidate = str(value or "").strip().lower()
|
| 38 |
+
return candidate if _SHA.fullmatch(candidate) else None
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def measure_hf_repository_head(force: bool = False) -> dict[str, Any]:
|
| 42 |
+
"""Measure Hub repository-head evidence without calling it process identity."""
|
| 43 |
+
|
| 44 |
+
now = time.monotonic()
|
| 45 |
+
with _CACHE_LOCK:
|
| 46 |
+
cached = _CACHE.get("measurement")
|
| 47 |
+
if not force and cached and now - float(_CACHE["stored_at"]) < 60:
|
| 48 |
+
return dict(cached)
|
| 49 |
+
|
| 50 |
+
space_id = os.environ.get("SPACE_ID") or SPACE_ID
|
| 51 |
+
observed_at = _now_iso()
|
| 52 |
+
resolver = f"https://huggingface.co/api/spaces/{space_id}?expand[]=sha&expand[]=lastModified"
|
| 53 |
+
revision = None
|
| 54 |
+
last_modified = None
|
| 55 |
+
error = None
|
| 56 |
+
request = urllib.request.Request(
|
| 57 |
+
resolver,
|
| 58 |
+
headers={"Accept": "application/json", "User-Agent": "szl-forge-runtime-contract/1.0"},
|
| 59 |
+
)
|
| 60 |
+
try:
|
| 61 |
+
with urllib.request.urlopen(request, timeout=4) as response:
|
| 62 |
+
payload = json.load(response)
|
| 63 |
+
revision = _valid_sha(payload.get("sha"))
|
| 64 |
+
last_modified = payload.get("lastModified")
|
| 65 |
+
except Exception as exc: # Network evidence is optional and reported honestly.
|
| 66 |
+
error = type(exc).__name__
|
| 67 |
+
|
| 68 |
+
measurement: dict[str, Any] = {
|
| 69 |
+
"hf_revision": revision,
|
| 70 |
+
"revision_state": "MEASURED_REPOSITORY_HEAD" if revision else "UNAVAILABLE",
|
| 71 |
+
"running_process_revision_state": "NOT_EXPOSED_IN_PROCESS",
|
| 72 |
+
"measurement_method": "HUGGINGFACE_HUB_API" if revision else "UNAVAILABLE",
|
| 73 |
+
"resolver": resolver,
|
| 74 |
+
"observed_at": observed_at,
|
| 75 |
+
"provider_last_modified": last_modified,
|
| 76 |
+
}
|
| 77 |
+
if error:
|
| 78 |
+
measurement["measurement_error"] = error
|
| 79 |
+
with _CACHE_LOCK:
|
| 80 |
+
_CACHE.update(stored_at=time.monotonic(), measurement=dict(measurement))
|
| 81 |
+
return measurement
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def build_source_attestation(force: bool = False) -> tuple[dict[str, Any], int]:
|
| 85 |
+
measurement = measure_hf_repository_head(force=force)
|
| 86 |
+
revision = measurement["hf_revision"]
|
| 87 |
+
if revision is None:
|
| 88 |
+
return (
|
| 89 |
+
{
|
| 90 |
+
"schema": "szl.deployment-source-unavailable/v1",
|
| 91 |
+
"observed_at": measurement["observed_at"],
|
| 92 |
+
"transport_state": "REACHABLE",
|
| 93 |
+
"evidence_state": "UNAVAILABLE",
|
| 94 |
+
"authority_state": "READ_ONLY",
|
| 95 |
+
"deployment": {"hf_space": SPACE_ID, **measurement},
|
| 96 |
+
"limits": [
|
| 97 |
+
"Repository-head evidence was unavailable, so no deployment-source document was fabricated.",
|
| 98 |
+
"Retry this GET with ?refresh=1 after Hub API reachability recovers.",
|
| 99 |
+
],
|
| 100 |
+
},
|
| 101 |
+
503,
|
| 102 |
+
)
|
| 103 |
+
|
| 104 |
+
built_at = measurement.get("provider_last_modified") or measurement["observed_at"]
|
| 105 |
+
return (
|
| 106 |
+
{
|
| 107 |
+
"schema": "szl.deployment-source/v1",
|
| 108 |
+
"source": {
|
| 109 |
+
"repository": SOURCE_REPOSITORY,
|
| 110 |
+
"commit": SOURCE_COMMIT,
|
| 111 |
+
"path": SOURCE_PATH,
|
| 112 |
+
},
|
| 113 |
+
"deployment": {"hf_space": SPACE_ID, "hf_revision": revision},
|
| 114 |
+
"built_at": built_at,
|
| 115 |
+
"alignment_state": ALIGNMENT_STATE,
|
| 116 |
+
"extensions": {
|
| 117 |
+
"schema": "szl.forge.deployment-source-extension/v1",
|
| 118 |
+
"deployment_revision_evidence": measurement,
|
| 119 |
+
"source_observation": {
|
| 120 |
+
"state": "VERIFIED_REFERENCE",
|
| 121 |
+
"relation": "showcase-derived-from-source",
|
| 122 |
+
"immutable_evidence": (
|
| 123 |
+
"https://api.github.com/repos/szl-holdings/szl-forge/commits/"
|
| 124 |
+
+ SOURCE_COMMIT
|
| 125 |
+
),
|
| 126 |
+
},
|
| 127 |
+
"build_metadata": {
|
| 128 |
+
"built_at_semantics": (
|
| 129 |
+
"Provider-reported lastModified for deployment.hf_revision; "
|
| 130 |
+
"not a verified process start time or reproducible-build attestation."
|
| 131 |
+
)
|
| 132 |
+
},
|
| 133 |
+
"claims": {
|
| 134 |
+
"github_parity": "NOT_CLAIMED",
|
| 135 |
+
"reproducible_build": "NOT_CLAIMED",
|
| 136 |
+
"build_provenance": "NOT_CLAIMED",
|
| 137 |
+
},
|
| 138 |
+
},
|
| 139 |
+
"limits": [
|
| 140 |
+
"PENDING_GITHUB_SYNC means GitHub/Hugging Face content parity is not claimed.",
|
| 141 |
+
"deployment.hf_revision is repository-head evidence, not exact serving-process identity.",
|
| 142 |
+
"source.commit is a verified immutable reference, not proof of deployed byte equivalence.",
|
| 143 |
+
"This unsigned document does not establish SLSA provenance or binary reproducibility.",
|
| 144 |
+
],
|
| 145 |
+
},
|
| 146 |
+
200,
|
| 147 |
+
)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def build_health(status_provider: Callable[[], dict[str, Any]]) -> dict[str, Any]:
|
| 151 |
+
observed_at = _now_iso()
|
| 152 |
+
try:
|
| 153 |
+
packaged_status = status_provider()
|
| 154 |
+
packaged_contract = "PASS"
|
| 155 |
+
evidence_state = str(packaged_status.get("evidence_state", "UNKNOWN"))
|
| 156 |
+
except Exception as exc:
|
| 157 |
+
packaged_contract = "FAIL"
|
| 158 |
+
evidence_state = "UNAVAILABLE"
|
| 159 |
+
packaged_status = {"error": type(exc).__name__}
|
| 160 |
+
return {
|
| 161 |
+
"schema": "szl.forge.health/v1",
|
| 162 |
+
"observed_at": observed_at,
|
| 163 |
+
"status": "OK" if packaged_contract == "PASS" else "DEGRADED",
|
| 164 |
+
"transport_state": "REACHABLE",
|
| 165 |
+
"evidence_state": evidence_state,
|
| 166 |
+
"authority_state": "READ_ONLY",
|
| 167 |
+
"checks": {
|
| 168 |
+
"packaged_status_contract": packaged_contract,
|
| 169 |
+
"external_dependencies": "NOT_REQUIRED_FOR_TRANSPORT_HEALTH",
|
| 170 |
+
"model_quality": "NOT_MEASURED",
|
| 171 |
+
"source_parity": ALIGNMENT_STATE,
|
| 172 |
+
},
|
| 173 |
+
"limits": [
|
| 174 |
+
"HTTP health proves this process can answer a bounded read-only contract only.",
|
| 175 |
+
"It does not prove training quality, freshness, source parity, or promotion approval.",
|
| 176 |
+
],
|
| 177 |
+
"packaged_status_schema": packaged_status.get("schema"),
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
def build_runtime_status(
|
| 182 |
+
status_provider: Callable[[], dict[str, Any]], force: bool = False
|
| 183 |
+
) -> dict[str, Any]:
|
| 184 |
+
packaged = status_provider()
|
| 185 |
+
measurement = measure_hf_repository_head(force=force)
|
| 186 |
+
return {
|
| 187 |
+
"schema": "szl.forge.runtime-status/v1",
|
| 188 |
+
"observed_at": _now_iso(),
|
| 189 |
+
"transport_state": "REACHABLE",
|
| 190 |
+
"evidence_state": packaged.get("evidence_state", "UNKNOWN"),
|
| 191 |
+
"authority_state": "READ_ONLY",
|
| 192 |
+
"interface_mode": packaged.get("interface_mode", "READ_ONLY"),
|
| 193 |
+
"deployment": {"hf_space": SPACE_ID, **measurement},
|
| 194 |
+
"source": {
|
| 195 |
+
"repository": SOURCE_REPOSITORY,
|
| 196 |
+
"commit": SOURCE_COMMIT,
|
| 197 |
+
"alignment_state": ALIGNMENT_STATE,
|
| 198 |
+
"github_parity": "NOT_CLAIMED",
|
| 199 |
+
},
|
| 200 |
+
"application": packaged,
|
| 201 |
+
"limits": [
|
| 202 |
+
"Runtime reachability, repository-head evidence, training state, and model quality are independent.",
|
| 203 |
+
"The nested application object is packaged snapshot evidence, not a live benchmark.",
|
| 204 |
+
],
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
def _json_response(payload: dict[str, Any], status_code: int = 200) -> JSONResponse:
|
| 209 |
+
return JSONResponse(
|
| 210 |
+
payload,
|
| 211 |
+
status_code=status_code,
|
| 212 |
+
headers={
|
| 213 |
+
"Cache-Control": "no-store",
|
| 214 |
+
"X-SZL-Transport-State": str(payload.get("transport_state", "REACHABLE")),
|
| 215 |
+
"X-SZL-Evidence-State": str(payload.get("evidence_state", "SNAPSHOT")),
|
| 216 |
+
"X-SZL-Authority-State": str(payload.get("authority_state", "READ_ONLY")),
|
| 217 |
+
},
|
| 218 |
+
)
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
def register_contract_routes(
|
| 222 |
+
app: Any, status_provider: Callable[[], dict[str, Any]]
|
| 223 |
+
) -> dict[str, Any]:
|
| 224 |
+
"""Add exact GET routes ahead of Gradio's fallback after launch."""
|
| 225 |
+
|
| 226 |
+
async def source_attestation(refresh: int = 0): # noqa: ANN202
|
| 227 |
+
payload, status_code = build_source_attestation(force=refresh == 1)
|
| 228 |
+
return _json_response(payload, status_code=status_code)
|
| 229 |
+
|
| 230 |
+
async def health(): # noqa: ANN202
|
| 231 |
+
return _json_response(build_health(status_provider))
|
| 232 |
+
|
| 233 |
+
async def runtime_status(refresh: int = 0): # noqa: ANN202
|
| 234 |
+
return _json_response(build_runtime_status(status_provider, force=refresh == 1))
|
| 235 |
+
|
| 236 |
+
contracts = (
|
| 237 |
+
("/.well-known/szl-source.json", source_attestation),
|
| 238 |
+
("/healthz", health),
|
| 239 |
+
("/api/status", runtime_status),
|
| 240 |
+
)
|
| 241 |
+
existing_paths = {getattr(route, "path", None) for route in app.router.routes}
|
| 242 |
+
collisions = [path for path, _ in contracts if path in existing_paths]
|
| 243 |
+
if collisions:
|
| 244 |
+
raise RuntimeError(f"Refusing to shadow existing routes: {collisions}")
|
| 245 |
+
|
| 246 |
+
before = list(app.router.routes)
|
| 247 |
+
for path, endpoint in contracts:
|
| 248 |
+
app.add_api_route(path, endpoint, methods=["GET"], include_in_schema=True)
|
| 249 |
+
added = list(app.router.routes[len(before) :])
|
| 250 |
+
app.router.routes[:] = added + before
|
| 251 |
+
app.openapi_schema = None
|
| 252 |
+
return {
|
| 253 |
+
"ok": True,
|
| 254 |
+
"routes": [path for path, _ in contracts],
|
| 255 |
+
"position": "BEFORE_GRADIO_FALLBACK",
|
| 256 |
+
}
|
tests/test_managed_gradio_contract.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import socket
|
| 3 |
+
import time
|
| 4 |
+
import unittest
|
| 5 |
+
import urllib.request
|
| 6 |
+
import warnings
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
from unittest.mock import patch
|
| 9 |
+
|
| 10 |
+
import app as forge_app
|
| 11 |
+
import forge_runtime_contract as contract
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
warnings.filterwarnings("ignore", category=ResourceWarning)
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
MEASUREMENT = {
|
| 18 |
+
"hf_revision": "d" * 40,
|
| 19 |
+
"revision_state": "MEASURED_REPOSITORY_HEAD",
|
| 20 |
+
"running_process_revision_state": "NOT_EXPOSED_IN_PROCESS",
|
| 21 |
+
"measurement_method": "HUGGINGFACE_HUB_API",
|
| 22 |
+
"resolver": "https://huggingface.co/api/spaces/SZLHOLDINGS/szl-forge-lab",
|
| 23 |
+
"observed_at": "2026-07-12T00:00:00Z",
|
| 24 |
+
"provider_last_modified": "2026-07-12T00:00:00Z",
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def _free_port() -> int:
|
| 29 |
+
with socket.socket() as sock:
|
| 30 |
+
sock.bind(("127.0.0.1", 0))
|
| 31 |
+
return int(sock.getsockname()[1])
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class ManagedGradioCompatibilityTests(unittest.TestCase):
|
| 35 |
+
def test_space_pins_the_locally_verified_managed_gradio_version(self):
|
| 36 |
+
readme = (Path(__file__).resolve().parents[1] / "README.md").read_text(encoding="utf-8")
|
| 37 |
+
self.assertIn("sdk: gradio\n", readme)
|
| 38 |
+
self.assertIn("sdk_version: 6.20.0\n", readme)
|
| 39 |
+
|
| 40 |
+
def test_public_launch_lifecycle_preserves_ui_config_and_exact_get_routes(self):
|
| 41 |
+
port = _free_port()
|
| 42 |
+
server_app, local_url, _ = forge_app.demo.launch(
|
| 43 |
+
server_name="127.0.0.1",
|
| 44 |
+
server_port=port,
|
| 45 |
+
prevent_thread_lock=True,
|
| 46 |
+
show_error=False,
|
| 47 |
+
ssr_mode=False,
|
| 48 |
+
css=forge_app.CSS,
|
| 49 |
+
theme=forge_app.gr.themes.Base(),
|
| 50 |
+
quiet=True,
|
| 51 |
+
)
|
| 52 |
+
try:
|
| 53 |
+
result = contract.register_contract_routes(server_app, forge_app.get_status)
|
| 54 |
+
self.assertTrue(result["ok"])
|
| 55 |
+
with patch.object(contract, "measure_hf_repository_head", return_value=MEASUREMENT):
|
| 56 |
+
expected = {
|
| 57 |
+
"/": "text/html",
|
| 58 |
+
"/config": "application/json",
|
| 59 |
+
"/.well-known/szl-source.json": "application/json",
|
| 60 |
+
"/healthz": "application/json",
|
| 61 |
+
"/api/status": "application/json",
|
| 62 |
+
"/gradio_api/openapi.json": "application/json",
|
| 63 |
+
}
|
| 64 |
+
for path, content_type in expected.items():
|
| 65 |
+
response = None
|
| 66 |
+
for _ in range(20):
|
| 67 |
+
try:
|
| 68 |
+
response = urllib.request.urlopen(
|
| 69 |
+
local_url.rstrip("/") + path, timeout=3
|
| 70 |
+
)
|
| 71 |
+
break
|
| 72 |
+
except OSError:
|
| 73 |
+
time.sleep(0.05)
|
| 74 |
+
self.assertIsNotNone(response, path)
|
| 75 |
+
with response:
|
| 76 |
+
self.assertEqual(200, response.status, path)
|
| 77 |
+
self.assertTrue(response.headers["content-type"].startswith(content_type), path)
|
| 78 |
+
body = response.read()
|
| 79 |
+
if path in result["routes"]:
|
| 80 |
+
self.assertIn("schema", json.loads(body))
|
| 81 |
+
finally:
|
| 82 |
+
forge_app.demo.close()
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
if __name__ == "__main__":
|
| 86 |
+
unittest.main()
|
tests/test_runtime_contract.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import unittest
|
| 3 |
+
from unittest.mock import patch
|
| 4 |
+
|
| 5 |
+
from fastapi import FastAPI
|
| 6 |
+
from fastapi.responses import HTMLResponse
|
| 7 |
+
from fastapi.testclient import TestClient
|
| 8 |
+
|
| 9 |
+
import forge_runtime_contract as contract
|
| 10 |
+
from forge_lab import get_status
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
MEASUREMENT = {
|
| 14 |
+
"hf_revision": "b" * 40,
|
| 15 |
+
"revision_state": "MEASURED_REPOSITORY_HEAD",
|
| 16 |
+
"running_process_revision_state": "NOT_EXPOSED_IN_PROCESS",
|
| 17 |
+
"measurement_method": "HUGGINGFACE_HUB_API",
|
| 18 |
+
"resolver": "https://huggingface.co/api/spaces/SZLHOLDINGS/szl-forge-lab",
|
| 19 |
+
"observed_at": "2026-07-12T00:00:00Z",
|
| 20 |
+
"provider_last_modified": "2026-07-12T00:00:00Z",
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class RuntimeContractTests(unittest.TestCase):
|
| 25 |
+
def test_source_attestation_separates_head_evidence_from_process_identity(self):
|
| 26 |
+
with patch.object(contract, "measure_hf_repository_head", return_value=MEASUREMENT):
|
| 27 |
+
payload, status_code = contract.build_source_attestation()
|
| 28 |
+
self.assertEqual(200, status_code)
|
| 29 |
+
self.assertEqual("szl.deployment-source/v1", payload["schema"])
|
| 30 |
+
self.assertEqual("b" * 40, payload["deployment"]["hf_revision"])
|
| 31 |
+
self.assertEqual("PENDING_GITHUB_SYNC", payload["alignment_state"])
|
| 32 |
+
evidence = payload["extensions"]["deployment_revision_evidence"]
|
| 33 |
+
self.assertEqual("NOT_EXPOSED_IN_PROCESS", evidence["running_process_revision_state"])
|
| 34 |
+
self.assertIn(
|
| 35 |
+
"Provider-reported lastModified",
|
| 36 |
+
payload["extensions"]["build_metadata"]["built_at_semantics"],
|
| 37 |
+
)
|
| 38 |
+
self.assertEqual("NOT_CLAIMED", payload["extensions"]["claims"]["github_parity"])
|
| 39 |
+
|
| 40 |
+
def test_source_attestation_fails_closed_when_hub_measurement_is_unavailable(self):
|
| 41 |
+
unavailable = dict(MEASUREMENT, hf_revision=None, revision_state="UNAVAILABLE")
|
| 42 |
+
with patch.object(contract, "measure_hf_repository_head", return_value=unavailable):
|
| 43 |
+
payload, status_code = contract.build_source_attestation()
|
| 44 |
+
self.assertEqual(503, status_code)
|
| 45 |
+
self.assertEqual("szl.deployment-source-unavailable/v1", payload["schema"])
|
| 46 |
+
self.assertEqual("UNAVAILABLE", payload["evidence_state"])
|
| 47 |
+
|
| 48 |
+
def test_health_does_not_conflate_reachability_with_quality_or_parity(self):
|
| 49 |
+
payload = contract.build_health(get_status)
|
| 50 |
+
self.assertEqual("OK", payload["status"])
|
| 51 |
+
self.assertEqual("REACHABLE", payload["transport_state"])
|
| 52 |
+
self.assertEqual("NOT_MEASURED", payload["checks"]["model_quality"])
|
| 53 |
+
self.assertEqual("PENDING_GITHUB_SYNC", payload["checks"]["source_parity"])
|
| 54 |
+
|
| 55 |
+
def test_runtime_status_wraps_existing_packaged_contract(self):
|
| 56 |
+
with patch.object(contract, "measure_hf_repository_head", return_value=MEASUREMENT):
|
| 57 |
+
payload = contract.build_runtime_status(get_status)
|
| 58 |
+
self.assertEqual("szl.forge.runtime-status/v1", payload["schema"])
|
| 59 |
+
self.assertEqual("szl.forge.lab-status/v1", payload["application"]["schema"])
|
| 60 |
+
self.assertEqual("READ_ONLY", payload["authority_state"])
|
| 61 |
+
self.assertEqual("NOT_CLAIMED", payload["source"]["github_parity"])
|
| 62 |
+
|
| 63 |
+
def test_exact_routes_precede_html_fallback_and_return_json(self):
|
| 64 |
+
app = FastAPI()
|
| 65 |
+
|
| 66 |
+
@app.get("/{full_path:path}")
|
| 67 |
+
async def fallback(full_path: str): # noqa: ARG001
|
| 68 |
+
return HTMLResponse("<html>fallback</html>")
|
| 69 |
+
|
| 70 |
+
result = contract.register_contract_routes(app, get_status)
|
| 71 |
+
self.assertTrue(result["ok"])
|
| 72 |
+
paths = [getattr(route, "path", None) for route in app.router.routes]
|
| 73 |
+
for path in result["routes"]:
|
| 74 |
+
self.assertLess(paths.index(path), paths.index("/{full_path:path}"))
|
| 75 |
+
|
| 76 |
+
with patch.object(contract, "measure_hf_repository_head", return_value=MEASUREMENT):
|
| 77 |
+
client = TestClient(app)
|
| 78 |
+
for path, schema in (
|
| 79 |
+
("/.well-known/szl-source.json", "szl.deployment-source/v1"),
|
| 80 |
+
("/healthz", "szl.forge.health/v1"),
|
| 81 |
+
("/api/status", "szl.forge.runtime-status/v1"),
|
| 82 |
+
):
|
| 83 |
+
response = client.get(path)
|
| 84 |
+
self.assertEqual(200, response.status_code)
|
| 85 |
+
self.assertTrue(response.headers["content-type"].startswith("application/json"))
|
| 86 |
+
self.assertEqual("no-store", response.headers["cache-control"])
|
| 87 |
+
self.assertEqual(schema, response.json()["schema"])
|
| 88 |
+
|
| 89 |
+
def test_registration_refuses_route_collisions(self):
|
| 90 |
+
app = FastAPI()
|
| 91 |
+
|
| 92 |
+
@app.get("/healthz")
|
| 93 |
+
async def existing_health():
|
| 94 |
+
return {"status": "existing"}
|
| 95 |
+
|
| 96 |
+
with self.assertRaisesRegex(RuntimeError, "Refusing to shadow"):
|
| 97 |
+
contract.register_contract_routes(app, get_status)
|
| 98 |
+
|
| 99 |
+
def test_space_id_is_built_from_documented_environment_variable(self):
|
| 100 |
+
class Response:
|
| 101 |
+
def __enter__(self):
|
| 102 |
+
return self
|
| 103 |
+
|
| 104 |
+
def __exit__(self, *_args):
|
| 105 |
+
return False
|
| 106 |
+
|
| 107 |
+
def read(self, *_args):
|
| 108 |
+
return (
|
| 109 |
+
b'{"sha":"cccccccccccccccccccccccccccccccccccccccc",'
|
| 110 |
+
b'"lastModified":"2026-07-12T00:00:00Z"}'
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
with patch.dict(os.environ, {"SPACE_ID": "SZLHOLDINGS/szl-forge-lab"}):
|
| 114 |
+
with patch("urllib.request.urlopen", return_value=Response()) as mocked:
|
| 115 |
+
measurement = contract.measure_hf_repository_head(force=True)
|
| 116 |
+
request = mocked.call_args.args[0]
|
| 117 |
+
self.assertIn("SZLHOLDINGS/szl-forge-lab", request.full_url)
|
| 118 |
+
self.assertEqual("c" * 40, measurement["hf_revision"])
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
if __name__ == "__main__":
|
| 122 |
+
unittest.main()
|