修复运行时凭证与网络出口兼容性

This commit is contained in:
2026-08-27 23:19:13 +08:00
parent 56c618db59
commit ad1df5387e
3 changed files with 59 additions and 14 deletions

View File

@@ -17,13 +17,14 @@
- 仓库根目录包含 `Dockerfile`,监听 `8080`
- `GET /health` 始终返回 HTTP 200并附带扫描器最近状态。
- 从平台注入的 `STRATEGY_ID` 获取自身策略 ID。
- 优先读取 `MODELHUB_XC_TOKEN`,同时兼容官方参考策略使用的 `EXTERNAL_SERVICE_TOKEN`
- 优先读取平台 Secret 挂载路径 `XC_TOKEN_FILE`,同时兼容 `MODELHUB_XC_TOKEN``XC_TOKEN`官方参考策略使用的 `EXTERNAL_SERVICE_TOKEN`
- 保留 Python 默认的 HTTP(S) 代理处理,兼容平台容器的受控网络出口。
- 正确处理 `SIGTERM`,在平台 30 秒窗口内退出。
- 仅使用 Python 标准库,符合 1 CPU / 512 MiB 的平台限制。
## 安全边界
- 令牌只从运行环境读取,不写入仓库、响应或日志。
- 令牌只从运行环境或平台挂载的 Secret 文件读取,不写入仓库、响应或日志。
- stdout 只记录令牌是否存在,不记录令牌值、请求头或完整 API 响应。
- 提交前必须完成精确去重API 返回非成功业务码时不会伪报成功。
- 未获得令牌或策略 ID 时会明确记录 `task_submission_blocked`,不会静默假运行。

55
main.py
View File

@@ -14,13 +14,14 @@ import signal
import threading
from datetime import datetime, timezone
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from typing import Any, Mapping
from pathlib import Path
from typing import Any, Callable, Mapping
from urllib.parse import quote, urlencode, urlsplit
from urllib.request import ProxyHandler, Request, build_opener
from urllib.request import Request, build_opener
AGENT_NAME = "xc-model-auto-adaptation-agent"
AGENT_VERSION = "1.0.0"
AGENT_VERSION = "1.0.1"
TARGET_VENDOR = "天数智芯"
TARGET_CARD = "天垓100"
DEFAULT_TARGET_GPU = "Iluvatar_bi-100"
@@ -103,7 +104,10 @@ CONFIG_PARAMS = os.getenv("MODELHUB_CONFIG_PARAMS", DEFAULT_CONFIG_PARAMS)
SECRET_ASSIGNMENT_RE = re.compile(
r"(?i)(token|secret|password|api[_-]?key)=([^&\s]+)"
)
HTTP_OPENER = build_opener(ProxyHandler({}))
# Keep urllib's standard proxy handling. The hosted runtime may provide its
# outbound route through HTTP(S)_PROXY, so disabling proxies can isolate the
# scanner even though the container itself remains healthy.
HTTP_OPENER = build_opener()
STATE_LOCK = threading.Lock()
STOP = threading.Event()
SCANNER_STATE: dict[str, Any] = {
@@ -125,15 +129,39 @@ class PlatformAPIError(RuntimeError):
"""Raised when ModelHub returns a non-success business response."""
def resolve_runtime_token(environ: Mapping[str, str] | None = None) -> str:
"""Resolve documented/compatible secret names without ever logging values."""
TOKEN_PLACEHOLDERS = {"tmp", "placeholder", "changeme", "change-me", "test"}
def _valid_runtime_token(value: str) -> bool:
value = value.strip()
return bool(value) and value.lower() not in TOKEN_PLACEHOLDERS
def resolve_runtime_token(
environ: Mapping[str, str] | None = None,
read_text: Callable[[str], str] | None = None,
) -> str:
"""Resolve the platform credential without ever logging its value."""
source = environ if environ is not None else os.environ
return (
source.get("MODELHUB_XC_TOKEN", "")
or source.get("EXTERNAL_SERVICE_TOKEN", "")
or source.get("XC_TOKEN", "")
)
token_file = source.get("XC_TOKEN_FILE", "").strip()
if token_file:
file_reader = read_text or (
lambda path: Path(path).read_text(encoding="utf-8")
)
try:
value = file_reader(token_file).strip()
except (OSError, UnicodeError):
return ""
return value if _valid_runtime_token(value) else ""
for name in ("MODELHUB_XC_TOKEN", "XC_TOKEN", "EXTERNAL_SERVICE_TOKEN"):
value = source.get(name, "").strip()
if _valid_runtime_token(value):
return value
if value:
return ""
return ""
XC_TOKEN = resolve_runtime_token()
@@ -187,7 +215,10 @@ def _http_json(
"""Call one JSON endpoint without logging headers, bodies, or credentials."""
body = None
headers = {"Accept": "application/json"}
headers = {
"Accept": "application/json",
"User-Agent": f"{AGENT_NAME}/{AGENT_VERSION}",
}
if payload is not None:
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
headers["Content-Type"] = "application/json"

View File

@@ -42,6 +42,19 @@ class AutoAdaptationTests(unittest.TestCase):
token = resolve_runtime_token({"EXTERNAL_SERVICE_TOKEN": "private-value"})
self.assertEqual(token, "private-value")
def test_runtime_token_file_is_supported(self):
token = resolve_runtime_token(
{"XC_TOKEN_FILE": "/run/secrets/xc-token"},
read_text=lambda path: "mounted-private-value\n"
if path == "/run/secrets/xc-token"
else "",
)
self.assertEqual(token, "mounted-private-value")
def test_placeholder_runtime_token_is_rejected(self):
token = resolve_runtime_token({"EXTERNAL_SERVICE_TOKEN": "tmp"})
self.assertEqual(token, "")
def test_explicit_modelhub_token_takes_precedence(self):
token = resolve_runtime_token(
{