fix(findings): 补齐「按资产」视图的 mock,修两处标签重复

demo 模式(NEXT_PUBLIC_MOCK=1)下资产树接口没有实现,点开是空白。

- mock findings 关联到 fixture 里已有的资产:一条挂两个资产(验证父节点不重复
  计数)、一条不挂(演示「未关联资产」桶)
- mock handler 实现 asset-tree,并在平铺/分组两个列表分支接上 asset_scope。
  父子优先级、祖先补齐、去重计数、企业层出现条件都与 db/finding_assets.go
  一致;顺带把三处重复的筛选链抽成 mockFilterFindings
- 没有 URL 的服务(SMB、非 HTTP 端口)标签回退成裸 IP,与宿主那行显示得一模
  一样 —— 后端与 mock 都改为补端口(10.10.10.20:8080)
- 接口挂在 host:port 形式的服务下时没触发简写,仍显示完整 URL。宿主判断统一
  成解析后的 host,现在显示 /script

跑 mock handler 实测:17 个节点逐个对账「树上 total == 该节点子树查出的条数」,
无不一致。
This commit is contained in:
Autumn-27 committed 2026-08-31 11:10:47 -04:00
1 parent 23cfb9ed4e
commit 48e14e8cf2
4 files changed
+352 -33

No files matched your search

@@ -66,6 +66,15 @@ function parseAssetURL(raw: string): URL | null {
}
}
// hostOf 取一个节点代表的宿主:URL 取 hostname,「host:port」取 host,其余就是
// 标签本身(根域名 / 子域名 / IP)。
function hostOf(label: string): string {
const url = parseAssetURL(label);
if (url) return stripBrackets(url.hostname);
const hostPort = label.match(/^(.+):(\d+)$/);
return stripBrackets(hostPort ? hostPort[1] : label);
}
// shortLabel 去掉与父节点重复的前缀。service / endpoint 的 label 是完整 URL,而
// 宿主域名/IP 上一行已经写过了 —— 深层节点本来就窄,再把 host 重复一遍,真正有
// 信息量的端口和路径就全被截断掉了。完整值仍在 title 与面包屑里。
@@ -78,16 +87,17 @@ function shortLabel(node: FindingAssetNode, parent?: FindingAssetNode): string {
}
if (node.kind !== "service" && node.kind !== "endpoint") return node.label;
// 接口挂在服务下:直接砍掉服务那段前缀,剩下的就是路径。
// 父标签正好是自己的前缀(接口挂在同 URL 的服务下、服务挂在同 IP 下):直接砍掉。
if (node.label.startsWith(parent.label)) {
return node.label.slice(parent.label.length) || node.label;
}
// 否则只有父节点确实就是这个 URL 的宿主时才简写,不然会丢掉辨识信息
// (比如服务因为缺子域名资产行而直接挂在根域名下,那就得显示完整 URL)。
if (hostOf(node.label) !== hostOf(parent.label)) return node.label;
const url = parseAssetURL(node.label);
if (!url) return node.label;
// 只有父节点确实就是这个 URL 的宿主时才简写,否则会丢掉辨识信息。
if (stripBrackets(url.hostname) !== parent.label) return node.label;
if (node.kind === "endpoint") return `${url.pathname}${url.search}` || "/";
const scheme = url.protocol.replace(":", "");
const port = url.port || (url.protocol === "https:" ? "443" : "80");