split: handler mixins for oauth/identity/project/automation/fullauto (94 methods) on integration base 02835f6

- CloudControlPlaneHandler mixes in OAuthMixin, IdentityMemoryMixin,
  ProjectMixin, AutomationMixin, FullAutoMixin; shared helpers move to
  cloud/handler_support.py with server.py re-exports (old import paths
  keep working, incl. _validate_env_branch for tests).
- Method bodies moved verbatim; routers, base plumbing, task/lifecycle,
  webhooks stay in server.py. No >100-line method body split.
- test_handler_split_conformance.py (6 tests) pins resolution, layer
  bans and method accounting (238 total, 144 + 94, no duplicates).
- test_p1_security_server.py: monkeypatch targets follow the defining
  module (handler_project MAX_PROJECTS_PER_USER, handler_identity
  relay helpers); assertions unchanged.

(cherry picked from commit 92165a2b097126470e4827327d96d592a253adf1)
This commit is contained in:
host committed 2026-11-03 02:49:26 +00:00
1 parent c900a0f78d
commit 935b530f84
9 files changed
+3439 -3119

No files matched your search

+23 -14
View File
@@ -24,6 +24,11 @@ try:
from cloud.push import create_subscription
from cloud.server import create_server
from cloud import server as server_mod
# 拆分后补丁目标跟随方法定义模块:项目上限在 handler_project,
# relay 模型查询在 handler_identity(方法查本模块全局变量,
# 补丁 cloud.server 已不再生效,见 code-to10-v2-split 摘要)。
from cloud import handler_identity as handler_identity_mod
from cloud import handler_project as handler_project_mod
from cloud.sub2api import Sub2apiError
from cloud.sub2api import ensure_gateway_keys_table
from cloud.sub2api import get_user_gateway_key
@@ -36,6 +41,8 @@ except ImportError:
from cloud.push import create_subscription
from cloud.server import create_server
from cloud import server as server_mod
from cloud import handler_identity as handler_identity_mod
from cloud import handler_project as handler_project_mod
from cloud.sub2api import Sub2apiError
from cloud.sub2api import ensure_gateway_keys_table
from cloud.sub2api import get_user_gateway_key
@@ -265,7 +272,7 @@ class ServerP1TestCase(unittest.TestCase):
os.environ.pop("CLOUD_GATEWAY", None)
os.environ.pop("CLOUD_BACKUP_ROOT", None)
os.environ.pop("CLOUD_BACKUP_DIR", None)
self._old_max_projects = server_mod.MAX_PROJECTS_PER_USER
self._old_max_projects = handler_project_mod.MAX_PROJECTS_PER_USER
self.server = create_server(self.db_path, "127.0.0.1", 0)
self.port = self.server.server_address[1]
self.thread = threading.Thread(
@@ -287,7 +294,7 @@ class ServerP1TestCase(unittest.TestCase):
except Exception:
pass
self.tmp.cleanup()
server_mod.MAX_PROJECTS_PER_USER = self._old_max_projects
handler_project_mod.MAX_PROJECTS_PER_USER = self._old_max_projects
if self._old_admins is None:
os.environ.pop("CODEX_GLOBAL_ADMINS", None)
else:
@@ -304,11 +311,13 @@ class ServerP1TestCase(unittest.TestCase):
os.environ.pop("CLOUD_BACKUP_DIR", None)
else:
os.environ["CLOUD_BACKUP_DIR"] = self._old_backup_dir
# 恢复猴子补丁过的 server 模块函数(relay/rotate 相关测试用)。
for name in ("_validate_sub2api_key", "_list_sub2api_models",
"_rotate_sub2api_key"):
# 恢复猴子补丁过的模块函数(relay 在 handler_identity,
# rotate 仍在 server;补丁目标跟随方法定义模块)。
for mod, name in ((handler_identity_mod, "_validate_sub2api_key"),
(handler_identity_mod, "_list_sub2api_models"),
(server_mod, "_rotate_sub2api_key")):
try:
mock.patch.object(server_mod, name).stop()
mock.patch.object(mod, name).stop()
except Exception:
pass
@@ -437,7 +446,7 @@ class ServerP1TestCase(unittest.TestCase):
{"name": "ok", "id": "y" * 65}, self.owner_key)
self.assertEqual(s, 400, body)
self.assertIn("64", body["error"])
server_mod.MAX_PROJECTS_PER_USER = 1
handler_project_mod.MAX_PROJECTS_PER_USER = 1
# setUp 已建 1 个 owner 项目,限额 1 时再建即超限。
s, body = _req(self.port, "POST", "/projects",
{"name": "second"}, self.owner_key)
@@ -488,27 +497,27 @@ class ServerP1TestCase(unittest.TestCase):
# -- sub2api 懒开通 / 轮换端点 --------------------------------------
def test_relay_models_lazy_provision_not_just_pending(self):
os.environ["CLOUD_GATEWAY"] = "sub2api"
orig_validate = server_mod._validate_sub2api_key
orig_list = server_mod._list_sub2api_models
orig_validate = handler_identity_mod._validate_sub2api_key
orig_list = handler_identity_mod._list_sub2api_models
try:
server_mod._validate_sub2api_key = (
handler_identity_mod._validate_sub2api_key = (
lambda conn, uid: ("provisioned", "fake-key", 7, 9))
server_mod._list_sub2api_models = (
handler_identity_mod._list_sub2api_models = (
lambda origin, key: ["model-a"])
s, body = _req(self.port, "GET", "/relay/models",
key=self.owner_key)
self.assertEqual(s, 200, body)
self.assertEqual(body["models"], ["model-a"])
self.assertEqual(body["provisioning"], "provisioned")
server_mod._validate_sub2api_key = (
handler_identity_mod._validate_sub2api_key = (
lambda conn, uid: (_ for _ in ()).throw(
Sub2apiError("网关暂不可用")))
s, body = _req(self.port, "GET", "/relay/models",
key=self.owner_key)
self.assertEqual(s, 502, body)
finally:
server_mod._validate_sub2api_key = orig_validate
server_mod._list_sub2api_models = orig_list
handler_identity_mod._validate_sub2api_key = orig_validate
handler_identity_mod._list_sub2api_models = orig_list
def test_gateway_rotate_endpoint(self):
s, body = _req(self.port, "POST", "/users/me/gateway/rotate",