security: 权限门禁收紧为owner组织角色
- _require_admin→_require_owner: 持有任一orgtypeid='owner'角色(含通配)放行 - 不再仅限superuser/admin; 其他组织(含ownerx前缀伪造)一律拒绝 - 工具描述/文案同步更新
This commit is contained in:
parent
b947d3456e
commit
e95e618372
Binary file not shown.
@ -5,8 +5,8 @@ pipeline-service: platform_ability — 平台内部 agent 能力包(pipeline_i
|
||||
核心能力是「通读模型 API 文档 → 自动生成模型治理配置(供应商/适配模板/模型/定价)」。
|
||||
|
||||
权限模型(代码层硬门禁,不依赖 prompt):
|
||||
所有工具 handler 入口校验调用者的 RBAC 角色 ∈ {owner.superuser, owner.admin}。
|
||||
内部 agent 只服务管理员——普通用户即使打开页面也调不动任何工具。
|
||||
所有工具 handler 入口校验调用者持有 owner 组织的角色(orgtypeid='owner',含通配 'owner.*')。
|
||||
内部 agent 只服务 owner 组织的角色——其他组织的用户即使打开页面也调不动任何工具。
|
||||
|
||||
配置生成链路(用户给定 API 文档 → 完成配置):
|
||||
① fetch_model_doc:抓取文档页面(SSRF 防护:仅 http(s) 公网域名)
|
||||
@ -29,8 +29,8 @@ logger = logging.getLogger("pipeline.platform_ability")
|
||||
|
||||
PLATFORM_PIPELINE_ID = "platform_general"
|
||||
|
||||
# 管理角色:内部 agent 仅管理员可用
|
||||
ADMIN_ROLES = ("owner.superuser", "owner.admin")
|
||||
# 组织门禁:内部 agent 仅 owner 组织的角色可操作(任一 owner.* 角色,含通配)
|
||||
OWNER_ORG = "owner"
|
||||
|
||||
# 当前运行时调用链支持的协议(llm_bridge 固定 OpenAI 兼容路径)。
|
||||
# 其他协议的适配模板会存入 llm_api_profile 备查,但运行时暂不渲染。
|
||||
@ -39,25 +39,28 @@ RUNTIME_PROTOCOLS = ("openai_compat",)
|
||||
|
||||
# ────────────────────── 权限门禁(代码层) ──────────────────────
|
||||
|
||||
async def _require_admin(sor, ctx) -> str:
|
||||
"""校验当前用户是管理员。返回 ''=通过,否则错误信息。"""
|
||||
async def _require_owner(sor, ctx) -> str:
|
||||
"""校验当前用户持有 owner 组织的角色。返回 ''=通过,否则错误信息。
|
||||
|
||||
判定:userrole→role JOIN 后,存在任一 orgtypeid='owner' 的角色(含通配 'owner.*')。
|
||||
"""
|
||||
uid = ctx.get("user_id", "") or ""
|
||||
if not uid:
|
||||
return "无法识别当前用户身份(未登录),内部 agent 仅管理员可用"
|
||||
return "无法识别当前用户身份(未登录),内部 agent 仅 owner 组织角色可用"
|
||||
recs = await sor.sqlExe(
|
||||
"SELECT r.orgtypeid, r.name FROM userrole ur JOIN role r ON ur.roleid=r.id "
|
||||
"WHERE ur.userid=${u}$", {"u": uid})
|
||||
await sor.sqlExe("COMMIT", {})
|
||||
roles = set()
|
||||
roles = []
|
||||
for r in (recs or []):
|
||||
o = getattr(r, "orgtypeid", "") or ""
|
||||
n = getattr(r, "name", "") or ""
|
||||
if o and n:
|
||||
roles.add("%s.%s" % (o, n))
|
||||
if roles & set(ADMIN_ROLES):
|
||||
roles.append("%s.%s" % (o, n))
|
||||
if any(fn.split(".", 1)[0] == OWNER_ORG for fn in roles):
|
||||
return ""
|
||||
return "权限不足:内部 agent 工具仅管理员(%s)可用,当前角色 %s" % (
|
||||
"/".join(ADMIN_ROLES), sorted(roles) or "无")
|
||||
return "权限不足:内部 agent 工具仅 %s 组织的角色可操作,当前角色 %s" % (
|
||||
OWNER_ORG, sorted(set(roles)) or "无")
|
||||
|
||||
|
||||
def _row(r):
|
||||
@ -70,8 +73,8 @@ def _row(r):
|
||||
# ────────────────────── 工具 1:模型治理状态 ──────────────────────
|
||||
|
||||
async def _h_platform_llm_status(sor, params, ctx):
|
||||
"""供应商/账号/模型/用量概览(管理员诊断配置用)。"""
|
||||
err = await _require_admin(sor, ctx)
|
||||
"""供应商/账号/模型/用量概览(owner 组织诊断配置用)。"""
|
||||
err = await _require_owner(sor, ctx)
|
||||
if err:
|
||||
return err
|
||||
out = {}
|
||||
@ -132,7 +135,7 @@ def _html_to_text(html: str) -> str:
|
||||
|
||||
async def _h_fetch_model_doc(sor, params, ctx):
|
||||
"""抓取模型 API 文档页面 → 纯文本(供 LLM 提取配置规格)。"""
|
||||
err = await _require_admin(sor, ctx)
|
||||
err = await _require_owner(sor, ctx)
|
||||
if err:
|
||||
return err
|
||||
url = (params.get("url") or "").strip()
|
||||
@ -192,7 +195,7 @@ _EXTRACT_PROMPT = """你是大模型 API 配置专家。通读下面这份模型
|
||||
|
||||
async def _h_extract_llm_api_spec(sor, params, ctx):
|
||||
"""LLM 通读文档文本 → 结构化配置规格(JSON)。"""
|
||||
err = await _require_admin(sor, ctx)
|
||||
err = await _require_owner(sor, ctx)
|
||||
if err:
|
||||
return err
|
||||
doc_text = (params.get("doc_text") or "").strip()
|
||||
@ -238,7 +241,7 @@ async def _h_apply_llm_config(sor, params, ctx):
|
||||
幂等:供应商按名称复用;模型按 (vendor, vendor_model_id) 复用——
|
||||
已存在则更新定价,不重复创建。
|
||||
"""
|
||||
err = await _require_admin(sor, ctx)
|
||||
err = await _require_owner(sor, ctx)
|
||||
if err:
|
||||
return err
|
||||
try:
|
||||
@ -410,7 +413,7 @@ def _default_templates(protocol: str, capability: str, spec: dict) -> tuple:
|
||||
|
||||
async def _h_platform_modules(sor, params, ctx):
|
||||
"""列出平台已装载的业务模块(内部 agent 了解平台构成用)。"""
|
||||
err = await _require_admin(sor, ctx)
|
||||
err = await _require_owner(sor, ctx)
|
||||
if err:
|
||||
return err
|
||||
mods = []
|
||||
@ -439,39 +442,39 @@ async def _h_platform_modules(sor, params, ctx):
|
||||
PLATFORM_TOOLS = [
|
||||
ToolDefinition(
|
||||
name="platform_llm_status",
|
||||
description="查看模型治理状态:供应商/账号余额/模型定价/各状态分布。用户问「模型配置状态/账号余额」时调用。仅管理员可用。",
|
||||
description="查看模型治理状态:供应商/账号余额/模型定价/各状态分布。用户问「模型配置状态/账号余额」时调用。仅owner组织角色可用。",
|
||||
parameters={},
|
||||
category="platform",
|
||||
),
|
||||
ToolDefinition(
|
||||
name="fetch_model_doc",
|
||||
description="抓取大模型供应商的 API 文档页面(返回纯文本)。配置新模型前先用此抓取官方文档。仅管理员可用。",
|
||||
description="抓取大模型供应商的 API 文档页面(返回纯文本)。配置新模型前先用此抓取官方文档。仅owner组织角色可用。",
|
||||
parameters={"url": "文档页面 URL(必须是公网 http/https)"},
|
||||
category="platform",
|
||||
),
|
||||
ToolDefinition(
|
||||
name="extract_llm_api_spec",
|
||||
description="通读文档文本,LLM 提取 API 配置规格(端点/协议/请求响应格式/定价)。配合 fetch_model_doc 使用。仅管理员可用。",
|
||||
description="通读文档文本,LLM 提取 API 配置规格(端点/协议/请求响应格式/定价)。配合 fetch_model_doc 使用。仅owner组织角色可用。",
|
||||
parameters={"doc_text": "fetch_model_doc 返回的文档文本"},
|
||||
category="platform",
|
||||
),
|
||||
ToolDefinition(
|
||||
name="apply_llm_config",
|
||||
description="按提取的规格写入模型治理配置:供应商/端点/适配模板/模型(含定价)。幂等——已有模型只更新定价。仅管理员可用。",
|
||||
description="按提取的规格写入模型治理配置:供应商/端点/适配模板/模型(含定价)。幂等——已有模型只更新定价。仅owner组织角色可用。",
|
||||
parameters={"spec": "extract_llm_api_spec 返回的 JSON 规格"},
|
||||
category="platform",
|
||||
requires_confirmation=True,
|
||||
),
|
||||
ToolDefinition(
|
||||
name="platform_modules",
|
||||
description="列出平台已装载的业务模块清单。用户问「平台有哪些模块」时调用。仅管理员可用。",
|
||||
description="列出平台已装载的业务模块清单。用户问「平台有哪些模块」时调用。仅owner组织角色可用。",
|
||||
parameters={},
|
||||
category="platform",
|
||||
),
|
||||
]
|
||||
|
||||
PLATFORM_PROMPT = """
|
||||
你是产线平台的内部运维 agent,服务对象是平台管理员。
|
||||
你是产线平台的内部运维 agent,服务对象是 owner 组织的角色。
|
||||
|
||||
## 模型自动配置工作流(用户给你文档 URL 要求配置模型时)
|
||||
1. `fetch_model_doc` 抓取官方文档页面
|
||||
@ -484,7 +487,7 @@ PLATFORM_PROMPT = """
|
||||
- cost_*(供应商成本)未知时与 price_* 相同
|
||||
- 非 openai_compat 协议的模型:模板会存档但运行时暂不可调用,必须如实告知
|
||||
- 文档抓取失败/内容不足时如实说明,不要凭记忆编造 API 格式
|
||||
- 所有工具仅管理员可用,权限报错时如实转告用户
|
||||
- 所有工具仅 owner 组织角色可用,权限报错时如实转告用户
|
||||
|
||||
## 平台知识
|
||||
平台模块清单用 `platform_modules` 查询;技能库中「平台」相关技能(skills_library/all/ 与
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
"options": {"width": "100%", "alignItems": "center", "padding": "16px 24px 8px 24px", "cheight": 6, "gap": "12px"},
|
||||
"subwidgets": [
|
||||
{"widgettype": "Title2", "options": {"text": "平台内部助手"}},
|
||||
{"widgettype": "Text", "options": {"text": "平台运维/管理 agent · 模型自动配置 · 仅管理员可用", "cfontsize": 0.9, "color": "#94a3b8"}},
|
||||
{"widgettype": "Text", "options": {"text": "平台运维/管理 agent · 模型自动配置 · 仅owner组织角色可用", "cfontsize": 0.9, "color": "#94a3b8"}},
|
||||
{"widgettype": "Filler"},
|
||||
{
|
||||
"widgettype": "Button",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user