diff --git a/wwwroot/api/cockpit_context_update.dspy b/wwwroot/api/cockpit_context_update.dspy index 6e285c7..039f30a 100644 --- a/wwwroot/api/cockpit_context_update.dspy +++ b/wwwroot/api/cockpit_context_update.dspy @@ -17,6 +17,28 @@ if not pid and not iid: dbname = get_module_dbname('pipeline-sdlc') +# 归属门禁(2026-09-18 银联事故实锤):旧版无校验,任何登录用户可把**他机构** +# 项目 id 写进自己的会话指针(cockpit 上下文栏直传),随后工作空间列表/读文件 +# 端点按指针解析目录 → 看到他机构项目文件。校验对齐 agent_project_popup 切换 +# 门禁:同机构 + 本人创建(owner.superuser 放行,与 _check_confirm_operator 同口径)。 +if pid: + async with DBPools().sqlorContext(dbname) as _gsor: + _pr = await _gsor.sqlExe( + "SELECT org_id, created_by FROM sd_projects WHERE id=${p}$ LIMIT 1", {"p": pid}) + await _gsor.sqlExe("COMMIT", {}) + if not _pr: + return json.dumps({"success": False, "error": "项目不存在"}, ensure_ascii=False) + _porg = getattr(_pr[0], 'org_id', '') or '' + _pby = getattr(_pr[0], 'created_by', '') or '' + _uorg = await get_userorgid() or '' + if _pby != uid: + from pipeline_service.human_task_capability import _get_user_roles + _roles = await _get_user_roles(_gsor, uid) + if "owner.superuser" not in _roles or (_porg and _uorg != _porg): + return json.dumps({"success": False, + "error": "无权切换到该项目(仅限本人创建的项目)"}, + ensure_ascii=False) + async with DBPools().sqlorContext(dbname) as sor: # Upsert agent_settings existing = await sor.sqlExe( diff --git a/wwwroot/api/cockpit_project_picker.dspy b/wwwroot/api/cockpit_project_picker.dspy index c82fe99..c6e44b6 100644 --- a/wwwroot/api/cockpit_project_picker.dspy +++ b/wwwroot/api/cockpit_project_picker.dspy @@ -1,12 +1,23 @@ -# cockpit_project_picker.dspy - Returns all projects as {value, text} for dropdown +# cockpit_project_picker.dspy - Returns projects as {value, text} for dropdown # Used by cockpit context bar project picker +# +# 跨租户修复(2026-09-18 银联事故实锤):旧版全表无过滤,任何登录用户能枚举 +# 全部机构的全部项目(含他机构标书项目),配合 cockpit_context_update 无归属 +# 校验可把他机构项目写进自己的会话指针 → 工作空间/读文件端点随之越权看到他 +# 机构文件。可见范围对齐 agent_project_popup 切换门禁(用户 2026-09-11 拍板): +# 本产线 + 本人创建。 dbname = get_module_dbname('pipeline-sdlc') +uid = await get_user() +if not uid: + return [] + async with DBPools().sqlorContext(dbname) as sor: recs = await sor.sqlExe( - "SELECT id, name FROM sd_projects WHERE pipeline_id='sdlc_general' ORDER BY name", - {} + "SELECT id, name FROM sd_projects WHERE pipeline_id='sdlc_general' " + "AND created_by=${u}$ ORDER BY name", + {"u": uid} ) rows = []