From 84c036e53ab9dd6d28c5ef0c6267f890341785d6 Mon Sep 17 00:00:00 2001 From: ModelHub XC Automation Date: Mon, 26 Oct 2026 23:56:16 +0800 Subject: [PATCH] Check dependency installation and credential presence without exposing values --- Dockerfile | 1 + app.py | 5 ++++- network_probe.py | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 network_probe.py diff --git a/Dockerfile b/Dockerfile index 0aa7755..2326913 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,5 +6,6 @@ COPY requirements.lock /app/requirements.lock COPY wheels /wheels RUN pip install --no-cache-dir --no-index --find-links=/wheels --require-hashes -r /app/requirements.lock COPY app.py /app/app.py +COPY network_probe.py /app/network_probe.py EXPOSE 8080 CMD ["python", "/app/app.py"] diff --git a/app.py b/app.py index 0b6a21c..de6ea4d 100644 --- a/app.py +++ b/app.py @@ -2,9 +2,11 @@ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer import json import os +from threading import Thread +from network_probe import run external_token = os.environ.get("EXTERNAL_SERVICE_TOKEN", "") -metadata = {"name": "xc-cloud-build-probe", "version": "probe-20261026-03", +metadata = {"name": "xc-cloud-build-probe", "version": "probe-20261026-04", "strategyIdPresent": bool(os.environ.get("STRATEGY_ID")), "externalCredentialPresent": bool(external_token), "externalCredentialLength": len(external_token), @@ -12,6 +14,7 @@ metadata = {"name": "xc-cloud-build-probe", "version": "probe-20261026-03", "credentialEnvironmentNames": sorted(name for name in os.environ if any(marker in name for marker in ("TOKEN", "AUTH", "CREDENTIAL", "SECRET", "API_KEY")))} print(json.dumps(metadata), flush=True) +Thread(target=run, daemon=True).start() class Handler(BaseHTTPRequestHandler): diff --git a/network_probe.py b/network_probe.py new file mode 100644 index 0000000..fb42bc1 --- /dev/null +++ b/network_probe.py @@ -0,0 +1,34 @@ +"""Time public model metadata endpoints; no account credential is sent.""" +from concurrent.futures import ThreadPoolExecutor +import json +import time +from urllib.error import HTTPError, URLError +from urllib.request import urlopen + + +def run(): + urls = { + "hf_mirror_api": "https://hf-mirror.com/api/models/Qwen/Qwen2.5-0.5B-Instruct", + "hf_mirror_config": "https://hf-mirror.com/Qwen/Qwen2.5-0.5B-Instruct/resolve/main/config.json", + "hf_official_api": "https://huggingface.co/api/models/Qwen/Qwen2.5-0.5B-Instruct", + "modelscope_config": "https://modelscope.cn/models/Qwen/Qwen2.5-0.5B-Instruct/resolve/master/config.json", + } + + def check(item): + name, url = item + started = time.monotonic() + value = {"endpoint": name} + try: + with urlopen(url, timeout=8) as response: + body = response.read(262144) + value.update(httpStatus=response.status, jsonValid=isinstance(json.loads(body), dict)) + except HTTPError as error: + value.update(httpStatus=error.code, errorType=type(error).__name__) + except (URLError, TimeoutError, ValueError, OSError) as error: + value["errorType"] = type(error).__name__ + value["seconds"] = round(time.monotonic() - started, 2) + return value + + with ThreadPoolExecutor(max_workers=4) as executor: + results = list(executor.map(check, urls.items())) + print(json.dumps({"name": "xc-cloud-network-probe", "version": "probe-20261026-04", "results": results}), flush=True)