From 3de93c86bc4aba1c1318180a99286154e8d6e926 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 25 Jul 2026 20:58:18 +0000 Subject: [PATCH] =?UTF-8?q?fix(portal-data):=20=E5=9C=96=E8=AD=9C=20neighb?= =?UTF-8?q?ors/overview=20=E6=8C=89=E5=BA=AB=E9=81=8E=E6=BF=BE=EF=BC=88?= =?UTF-8?q?=E5=BA=AB=E7=B4=9A=E6=AC=8A=E9=99=90=E7=B4=85=E7=B7=9A=EF=BC=89?= =?UTF-8?q?[cloud-worker]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /portal/data/graph/neighbors:executeWebhookGraph input 加 libraries ('*' 或逗號清單),由 tenant workflow 的 code node 濾。 /portal/data/graph/overview:直讀 records 迴圈內按 library 濾(server-side, 隨 cypher 部署即生效,不需重推 workflow)。語意鏡像已部署的 keyword 面 ('*'=不濾/NULL→general);hasGraphAccess 對空庫集合 fail-closed(403)。 配套產品包 workflow 濾在 arcrun-rag work/b5-graph-library-filter-0726。 未部署、未 e2e(雲端做到產物就緒)。 portal-auth(active SDD)tasks.md「graph 逐節點/逐邊細粒度過濾」庫級粒度。 --- cypher-executor/src/routes/portal-data.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cypher-executor/src/routes/portal-data.ts b/cypher-executor/src/routes/portal-data.ts index c17a5b5..f55080c 100644 --- a/cypher-executor/src/routes/portal-data.ts +++ b/cypher-executor/src/routes/portal-data.ts @@ -214,7 +214,7 @@ portalDataRouter.get('/portal/data/graph/neighbors/:name', (c) => const result = await executeWebhookGraph( c.env, wfGraph, - { node: c.req.param('name'), depth, namespace: tenant, owner: tenant }, + { node: c.req.param('name'), depth, namespace: tenant, owner: tenant, libraries: libraries.includes('*') ? '*' : libraries.join(',') }, 'graph_neighbors', tenant, c.executionCtx, @@ -252,6 +252,7 @@ portalDataRouter.get('/portal/data/graph/overview', (c) => if (!(await hasGraphAccess(c.env, libraries))) { return c.json({ error: '無知識圖譜檢視權限' }, 403); } + const allowAll = libraries.includes('*'); const tenant = portalTenant(c.env); const res = await kbdbFetch(c.env, `/records/by-template/triplet?owner_id=${encodeURIComponent(tenant)}`); if (!res.ok) { @@ -270,6 +271,10 @@ portalDataRouter.get('/portal/data/graph/overview', (c) => const v = r && typeof r.values === 'object' && r.values ? r.values : null; if (!v) continue; if (v.status === 'deprecated') continue; + if (!allowAll) { + const lib = typeof v.library === 'string' && v.library.trim() ? v.library.trim() : 'general'; + if (!libraries.includes(lib)) continue; + } const s = typeof v.subject === 'string' ? v.subject.trim() : ''; const o = typeof v.object === 'string' ? v.object.trim() : ''; if (!s || !o) continue;