security: 权限门禁收紧为owner组织角色

- _require_admin→_require_owner: 持有任一orgtypeid='owner'角色(含通配)放行
- 不再仅限superuser/admin; 其他组织(含ownerx前缀伪造)一律拒绝
- 工具描述/文案同步更新
This commit is contained in:
yumoqing 2026-09-02 16:14:18 +08:00
parent b947d3456e
commit e95e618372
3 changed files with 29 additions and 26 deletions

View File

@ -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 组织的角色。返回 ''=通过,否则错误信息。
判定userrolerole 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/

View File

@ -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",