Skip to content

Commit 44489a6

Browse files
committed
feat(auth): migrate from token-based to RAM signature authentication
Migrate authentication mechanism from token-based approach to RAM signature authentication for enhanced security. The changes replace the existing access token system with Alibaba Cloud's Resource Access Management (RAM) signature verification, requiring users to configure access key ID and secret for API calls. Updates include implementation of RAM signature generation, modification of authentication endpoints with '-ram' suffix, and comprehensive updates to all API clients across runtime, sandbox, and toolset modules. This migration affects all API interactions within the SDK, including data API operations, browser automation endpoints, and OpenAI integration points. The new authentication system provides improved security through signature-based verification while maintaining backward compatibility for existing configurations. The changes also include updates to test suites to validate the new authentication flow and ensure proper handling of both authenticated and unauthenticated requests. 将身份验证机制从基于令牌的方式迁移到 RAM 签名身份验证,以提高安全性。更改将现有的访问令牌系统替换为阿里云资源访问管理 (RAM) 签名验证,要求用户为 API 调用配置访问密钥 ID 和密钥。更新包括实现 RAM 签名生成、使用 '-ram' 后缀修改身份验证端点,以及对运行时、沙箱和工具集模块中的所有 API 客户端进行全面更新。 此迁移会影响 SDK 内的所有 API 交互,包括数据 API 操作、浏览器自动化端点和 OpenAI 集成点。新的身份验证系统通过基于签名的验证提供增强的安全性,同时保持现有配置的向后兼容性。 这些更改还包括更新测试套件以验证新的身份验证流程,并确保正确处理经过身份验证和未经身份验证的请求。 Change-Id: I2585151e1acab0f476d9ba9ed909aabd212e5f2c Signed-off-by: OhYee <oyohyee@oyohyee.com>
1 parent 3b8ea78 commit 44489a6

File tree

19 files changed

+1198
-309
lines changed

19 files changed

+1198
-309
lines changed

agentrun/agent_runtime/__runtime_async_template.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class AgentRuntime(
4343
delete, update, query, and endpoint/version management.
4444
"""
4545

46+
_data_api: Dict[str, AgentRuntimeDataAPI] = {}
47+
4648
@classmethod
4749
def __get_client(cls):
4850
"""获取客户端实例 / Get client instance
@@ -462,16 +464,19 @@ async def invoke_openai_async(
462464
cfg = Config.with_configs(self._config, kwargs.get("config"))
463465
kwargs["config"] = cfg
464466

465-
if not self.__data_api:
466-
self.__data_api: Dict[str, AgentRuntimeDataAPI] = {}
467+
if not self._data_api:
468+
self._data_api: Dict[str, AgentRuntimeDataAPI] = {}
467469

468-
if self.__data_api[agent_runtime_endpoint_name] is None:
469-
self.__data_api[agent_runtime_endpoint_name] = AgentRuntimeDataAPI(
470+
if (
471+
agent_runtime_endpoint_name not in self._data_api
472+
or self._data_api[agent_runtime_endpoint_name] is None
473+
):
474+
self._data_api[agent_runtime_endpoint_name] = AgentRuntimeDataAPI(
470475
agent_runtime_name=self.agent_runtime_name or "",
471476
agent_runtime_endpoint_name=agent_runtime_endpoint_name or "",
472477
config=cfg,
473478
)
474479

475-
return await self.__data_api[
480+
return await self._data_api[
476481
agent_runtime_endpoint_name
477482
].invoke_openai_async(**kwargs)

agentrun/agent_runtime/api/__data_async_template.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,15 @@ async def invoke_openai_async(
3737
config = kwargs.get("config", None)
3838

3939
cfg = Config.with_configs(self.config, config)
40-
api_base = self.with_path("openai/v1")
41-
_, headers, _ = self.auth(headers=cfg.get_headers())
40+
api_base = self.with_path("openai/v1", config=cfg)
41+
# Sign the actual request URL (OpenAI client will POST to base + /chat/completions)
42+
chat_completions_url = api_base.rstrip("/") + "/chat/completions"
43+
_, headers, _ = self.auth(
44+
url=chat_completions_url,
45+
headers=cfg.get_headers(),
46+
config=cfg,
47+
method="POST",
48+
)
4249

4350
from httpx import AsyncClient
4451
from openai import AsyncOpenAI

agentrun/agent_runtime/api/data.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,15 @@ async def invoke_openai_async(
4848
config = kwargs.get("config", None)
4949

5050
cfg = Config.with_configs(self.config, config)
51-
api_base = self.with_path("openai/v1")
52-
_, headers, _ = self.auth(headers=cfg.get_headers())
51+
api_base = self.with_path("openai/v1", config=cfg)
52+
# Sign the actual request URL (OpenAI client will POST to base + /chat/completions)
53+
chat_completions_url = api_base.rstrip("/") + "/chat/completions"
54+
_, headers, _ = self.auth(
55+
url=chat_completions_url,
56+
headers=cfg.get_headers(),
57+
config=cfg,
58+
method="POST",
59+
)
5360

5461
from httpx import AsyncClient
5562
from openai import AsyncOpenAI
@@ -77,8 +84,15 @@ def invoke_openai(
7784
config = kwargs.get("config", None)
7885

7986
cfg = Config.with_configs(self.config, config)
80-
api_base = self.with_path("openai/v1")
81-
_, headers, _ = self.auth(headers=cfg.get_headers())
87+
api_base = self.with_path("openai/v1", config=cfg)
88+
# Sign the actual request URL (OpenAI client will POST to base + /chat/completions)
89+
chat_completions_url = api_base.rstrip("/") + "/chat/completions"
90+
_, headers, _ = self.auth(
91+
url=chat_completions_url,
92+
headers=cfg.get_headers(),
93+
config=cfg,
94+
method="POST",
95+
)
8296

8397
from httpx import Client
8498
from openai import OpenAI

agentrun/agent_runtime/runtime.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class AgentRuntime(
5353
delete, update, query, and endpoint/version management.
5454
"""
5555

56+
_data_api: Dict[str, AgentRuntimeDataAPI] = {}
57+
5658
@classmethod
5759
def __get_client(cls):
5860
"""获取客户端实例 / Get client instance
@@ -867,17 +869,20 @@ async def invoke_openai_async(
867869
cfg = Config.with_configs(self._config, kwargs.get("config"))
868870
kwargs["config"] = cfg
869871

870-
if not self.__data_api:
871-
self.__data_api: Dict[str, AgentRuntimeDataAPI] = {}
872+
if not self._data_api:
873+
self._data_api: Dict[str, AgentRuntimeDataAPI] = {}
872874

873-
if self.__data_api[agent_runtime_endpoint_name] is None:
874-
self.__data_api[agent_runtime_endpoint_name] = AgentRuntimeDataAPI(
875+
if (
876+
agent_runtime_endpoint_name in self._data_api
877+
and self._data_api[agent_runtime_endpoint_name] is None
878+
):
879+
self._data_api[agent_runtime_endpoint_name] = AgentRuntimeDataAPI(
875880
agent_runtime_name=self.agent_runtime_name or "",
876881
agent_runtime_endpoint_name=agent_runtime_endpoint_name or "",
877882
config=cfg,
878883
)
879884

880-
return await self.__data_api[
885+
return await self._data_api[
881886
agent_runtime_endpoint_name
882887
].invoke_openai_async(**kwargs)
883888

@@ -889,16 +894,19 @@ def invoke_openai(
889894
cfg = Config.with_configs(self._config, kwargs.get("config"))
890895
kwargs["config"] = cfg
891896

892-
if not self.__data_api:
893-
self.__data_api: Dict[str, AgentRuntimeDataAPI] = {}
897+
if not self._data_api:
898+
self._data_api: Dict[str, AgentRuntimeDataAPI] = {}
894899

895-
if self.__data_api[agent_runtime_endpoint_name] is None:
896-
self.__data_api[agent_runtime_endpoint_name] = AgentRuntimeDataAPI(
900+
if (
901+
agent_runtime_endpoint_name not in self._data_api
902+
or self._data_api[agent_runtime_endpoint_name] is None
903+
):
904+
self._data_api[agent_runtime_endpoint_name] = AgentRuntimeDataAPI(
897905
agent_runtime_name=self.agent_runtime_name or "",
898906
agent_runtime_endpoint_name=agent_runtime_endpoint_name or "",
899907
config=cfg,
900908
)
901909

902-
return self.__data_api[agent_runtime_endpoint_name].invoke_openai(
910+
return self._data_api[agent_runtime_endpoint_name].invoke_openai(
903911
**kwargs
904912
)

agentrun/sandbox/api/__aio_data_async_template.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,13 @@ def sync_playwright(
103103
from .playwright_sync import BrowserPlaywrightSync
104104

105105
cfg = Config.with_configs(self.config, config)
106-
_, headers, _ = self.auth(headers=cfg.get_headers(), config=cfg)
106+
107+
url = self.get_cdp_url(record=record)
108+
url, headers, _ = self.auth(
109+
url=url, headers=cfg.get_headers(), config=cfg
110+
)
107111
return BrowserPlaywrightSync(
108-
self.get_cdp_url(record=record),
112+
url,
109113
browser_type=browser_type,
110114
headers=headers,
111115
)
@@ -119,9 +123,13 @@ def async_playwright(
119123
from .playwright_async import BrowserPlaywrightAsync
120124

121125
cfg = Config.with_configs(self.config, config)
122-
_, headers, _ = self.auth(headers=cfg.get_headers(), config=cfg)
126+
127+
url = self.get_cdp_url(record=record)
128+
url, headers, _ = self.auth(
129+
url=url, headers=cfg.get_headers(), config=cfg
130+
)
123131
return BrowserPlaywrightAsync(
124-
self.get_cdp_url(record=record),
132+
url,
125133
browser_type=browser_type,
126134
headers=headers,
127135
)

agentrun/sandbox/api/__browser_data_async_template.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,13 @@ def sync_playwright(
9292
from .playwright_sync import BrowserPlaywrightSync
9393

9494
cfg = Config.with_configs(self.config, config)
95-
_, headers, _ = self.auth(headers=cfg.get_headers(), config=cfg)
95+
96+
url = self.get_cdp_url(record=record)
97+
url, headers, _ = self.auth(
98+
url=url, headers=cfg.get_headers(), config=cfg
99+
)
96100
return BrowserPlaywrightSync(
97-
self.get_cdp_url(record=record),
101+
url,
98102
browser_type=browser_type,
99103
headers=headers,
100104
)
@@ -108,9 +112,13 @@ def async_playwright(
108112
from .playwright_async import BrowserPlaywrightAsync
109113

110114
cfg = Config.with_configs(self.config, config)
111-
_, headers, _ = self.auth(headers=cfg.get_headers(), config=cfg)
115+
116+
url = self.get_cdp_url(record=record)
117+
url, headers, _ = self.auth(
118+
url=url, headers=cfg.get_headers(), config=cfg
119+
)
112120
return BrowserPlaywrightAsync(
113-
self.get_cdp_url(record=record),
121+
url,
114122
browser_type=browser_type,
115123
headers=headers,
116124
)

agentrun/sandbox/api/aio_data.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,13 @@ def sync_playwright(
113113
from .playwright_sync import BrowserPlaywrightSync
114114

115115
cfg = Config.with_configs(self.config, config)
116-
_, headers, _ = self.auth(headers=cfg.get_headers(), config=cfg)
116+
117+
url = self.get_cdp_url(record=record)
118+
url, headers, _ = self.auth(
119+
url=url, headers=cfg.get_headers(), config=cfg
120+
)
117121
return BrowserPlaywrightSync(
118-
self.get_cdp_url(record=record),
122+
url,
119123
browser_type=browser_type,
120124
headers=headers,
121125
)
@@ -129,9 +133,13 @@ def async_playwright(
129133
from .playwright_async import BrowserPlaywrightAsync
130134

131135
cfg = Config.with_configs(self.config, config)
132-
_, headers, _ = self.auth(headers=cfg.get_headers(), config=cfg)
136+
137+
url = self.get_cdp_url(record=record)
138+
url, headers, _ = self.auth(
139+
url=url, headers=cfg.get_headers(), config=cfg
140+
)
133141
return BrowserPlaywrightAsync(
134-
self.get_cdp_url(record=record),
142+
url,
135143
browser_type=browser_type,
136144
headers=headers,
137145
)

agentrun/sandbox/api/browser_data.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,13 @@ def sync_playwright(
102102
from .playwright_sync import BrowserPlaywrightSync
103103

104104
cfg = Config.with_configs(self.config, config)
105-
_, headers, _ = self.auth(headers=cfg.get_headers(), config=cfg)
105+
106+
url = self.get_cdp_url(record=record)
107+
url, headers, _ = self.auth(
108+
url=url, headers=cfg.get_headers(), config=cfg
109+
)
106110
return BrowserPlaywrightSync(
107-
self.get_cdp_url(record=record),
111+
url,
108112
browser_type=browser_type,
109113
headers=headers,
110114
)
@@ -118,9 +122,13 @@ def async_playwright(
118122
from .playwright_async import BrowserPlaywrightAsync
119123

120124
cfg = Config.with_configs(self.config, config)
121-
_, headers, _ = self.auth(headers=cfg.get_headers(), config=cfg)
125+
126+
url = self.get_cdp_url(record=record)
127+
url, headers, _ = self.auth(
128+
url=url, headers=cfg.get_headers(), config=cfg
129+
)
122130
return BrowserPlaywrightAsync(
123-
self.get_cdp_url(record=record),
131+
url,
124132
browser_type=browser_type,
125133
headers=headers,
126134
)

agentrun/toolset/__toolset_async_template.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,18 @@ def _get_openapi_auth_defaults(
9494
return headers, query
9595

9696
def _get_openapi_base_url(self) -> Optional[str]:
97-
return pydash.get(
98-
self,
99-
"status.outputs.urls.intranet_url",
100-
None,
101-
) or pydash.get(self, "status.outputs.urls.internet_url", None)
97+
import os
98+
99+
fc_region = os.getenv("FC_REGION")
100+
arn = pydash.get(self, "status.outputs.function_arn", "")
101+
102+
if fc_region and arn and pydash.get(arn.split(":"), "[2]"):
103+
# 在同一个 region,则使用内网地址
104+
return pydash.get(
105+
self,
106+
"status.outputs.urls.intranet_url",
107+
None,
108+
)
102109

103110
async def get_async(self, config: Optional[Config] = None):
104111
if self.name is None:

agentrun/toolset/api/openapi.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,8 @@ def invoke_tool(
829829
request_kwargs, timeout, raise_for_status = self._prepare_request(
830830
name, arguments, config
831831
)
832+
833+
print(request_kwargs)
832834
with httpx.Client(timeout=timeout) as client:
833835
response = client.request(**request_kwargs)
834836
if raise_for_status:
@@ -943,6 +945,7 @@ def _walk(node: Any):
943945

944946
def _extract_base_url(self, schema: Dict[str, Any]) -> Optional[str]:
945947
servers = schema.get("servers") or []
948+
print("======", servers)
946949
return self._pick_server_url(servers)
947950

948951
def _convert_to_native(self, value: Any) -> Any:

0 commit comments

Comments
 (0)