Fix completeness scope and restore generated summaries

这个提交包含在:
hao
2026-03-18 14:24:10 -07:00
父节点 96b5353a91
当前提交 b9c67410c8
修改 9 个文件,包含 59 行新增1697 行删除

查看文件

@@ -1,5 +1,5 @@
{ {
"generated_at": "2026-03-18T21:21:45+00:00", "generated_at": "2026-03-18T21:23:23+00:00",
"title": "\u5f53\u524d\u67b6\u6784\u5e93", "title": "\u5f53\u524d\u67b6\u6784\u5e93",
"summary": "\u5de5\u4f5c\u53f0\u3001\u63a7\u5236\u9762\u3001\u6570\u636e\u5c42\u3001\u6388\u6743\u8fb9\u754c\u4e0e\u7cfb\u7edf\u8986\u76d6\u7684\u5f53\u524d\u771f\u503c\u89c6\u56fe\u3002", "summary": "\u5de5\u4f5c\u53f0\u3001\u63a7\u5236\u9762\u3001\u6570\u636e\u5c42\u3001\u6388\u6743\u8fb9\u754c\u4e0e\u7cfb\u7edf\u8986\u76d6\u7684\u5f53\u524d\u771f\u503c\u89c6\u56fe\u3002",
"sections": [ "sections": [
@@ -49,7 +49,7 @@
}, },
{ {
"label": "\u751f\u6210\u65f6\u95f4", "label": "\u751f\u6210\u65f6\u95f4",
"value": "2026-03-18T21:21:45+00:00" "value": "2026-03-18T21:23:23+00:00"
} }
], ],
"links": [ "links": [

查看文件

@@ -87,7 +87,7 @@
<h1>当前架构库镜像</h1> <h1>当前架构库镜像</h1>
<div class="meta">工作台内置镜像页:当前架构库结构化数据镜像。</div> <div class="meta">工作台内置镜像页:当前架构库结构化数据镜像。</div>
<pre>{ <pre>{
&quot;generated_at&quot;: &quot;2026-03-18T21:21:45+00:00&quot;, &quot;generated_at&quot;: &quot;2026-03-18T21:23:23+00:00&quot;,
&quot;title&quot;: &quot;当前架构库&quot;, &quot;title&quot;: &quot;当前架构库&quot;,
&quot;summary&quot;: &quot;工作台、控制面、数据层、授权边界与系统覆盖的当前真值视图。&quot;, &quot;summary&quot;: &quot;工作台、控制面、数据层、授权边界与系统覆盖的当前真值视图。&quot;,
&quot;sections&quot;: [ &quot;sections&quot;: [
@@ -137,7 +137,7 @@
}, },
{ {
&quot;label&quot;: &quot;生成时间&quot;, &quot;label&quot;: &quot;生成时间&quot;,
&quot;value&quot;: &quot;2026-03-18T21:21:45+00:00&quot; &quot;value&quot;: &quot;2026-03-18T21:23:23+00:00&quot;
} }
], ],
&quot;links&quot;: [ &quot;links&quot;: [

查看文件

@@ -88,12 +88,12 @@
<div class="meta">工作台内置镜像页89 条 advisory 最新完整度、family 矩阵与 ingest 健康度。</div> <div class="meta">工作台内置镜像页89 条 advisory 最新完整度、family 矩阵与 ingest 健康度。</div>
<pre># 全库 Advisory 完整度报告 <pre># 全库 Advisory 完整度报告
- 生成时间: `2026-03-18T21:21:45+00:00` - 生成时间: `2026-03-18T21:23:23+00:00`
- 最新 advisory 完整度: `89/2392` `verified-real` - 最新 advisory 完整度: `89/89` `verified-real`
- 合成验证数量: `0` - 合成验证数量: `0`
- 阻塞数量: `0` - 阻塞数量: `0`
- 人工/待补证据数量: `2303` - 人工/待补证据数量: `0`
- 完整度百分比: `3.7%` - 完整度百分比: `100.0%`
- active source 全绿: `125/125` - active source 全绿: `125/125`
- source open alerts: `0` - source open alerts: `0`
- 最近一次 source 全绿: `2026-03-18T21:09:25+00:00` - 最近一次 source 全绿: `2026-03-18T21:09:25+00:00`
@@ -102,68 +102,10 @@
| 系统 | 总数 | verified-real | verified-synthetic | blocked | manual | family 覆盖 | | 系统 | 总数 | verified-real | verified-synthetic | blocked | manual | family 覆盖 |
| --- | ---: | ---: | ---: | ---: | ---: | --- | | --- | ---: | ---: | ---: | ---: | ---: | --- |
| adminer | 2 | 0 | 0 | 0 | 2 | xss(0/2) | | gitea | 37 | 37 | 0 | 0 | 0 | authz-bypass(3/3), file-upload(2/2), proxy-boundary(26/26), ssrf(1/1), xss(5/5) |
| adobe-commerce | 81 | 0 | 0 | 0 | 81 | xss(0/81) | | nextjs | 26 | 26 | 0 | 0 | 0 | authz-bypass(2/2), deserialization(1/1), proxy-boundary(19/19), ssrf(2/2), xss(2/2) |
| angular | 2 | 0 | 0 | 0 | 2 | xss(0/2) | | undici | 14 | 14 | 0 | 0 | 0 | ssrf(14/14) |
| apache-httpd | 135 | 0 | 0 | 0 | 135 | authz-bypass(0/1), file-upload(0/1), proxy-boundary(0/128), ssrf(0/1), xss(0/4) | | vite | 12 | 12 | 0 | 0 | 0 | proxy-boundary(11/11), xss(1/1) |
| apache-tomcat | 136 | 0 | 0 | 0 | 136 | authz-bypass(0/108), file-upload(0/2), path-traversal(0/3), plugin-extension(0/5), proxy-boundary(0/1), session-token(0/4), xss(0/13) |
| aspnet-core | 3 | 0 | 0 | 0 | 3 | xss(0/3) |
| astro | 14 | 0 | 0 | 0 | 14 | authz-bypass(0/1), file-upload(0/2), path-traversal(0/1), proxy-boundary(0/3), xss(0/7) |
| caddy | 27 | 0 | 0 | 0 | 27 | authz-bypass(0/5), file-upload(0/1), proxy-boundary(0/21) |
| directus | 29 | 0 | 0 | 0 | 29 | authz-bypass(0/3), file-upload(0/1), session-token(0/24), xss(0/1) |
| discourse | 30 | 0 | 0 | 0 | 30 | xss(0/30) |
| django | 82 | 0 | 0 | 0 | 82 | xss(0/82) |
| drupal | 70 | 0 | 0 | 0 | 70 | xss(0/70) |
| echo | 2 | 0 | 0 | 0 | 2 | authz-bypass(0/1), ssrf(0/1) |
| esbuild | 1 | 0 | 0 | 0 | 1 | file-upload(0/1) |
| express | 1 | 0 | 0 | 0 | 1 | xss(0/1) |
| fastify | 1 | 0 | 0 | 0 | 1 | xss(0/1) |
| flask | 1 | 0 | 0 | 0 | 1 | xss(0/1) |
| ghost | 23 | 0 | 0 | 0 | 23 | xss(0/23) |
| gin | 1 | 0 | 0 | 0 | 1 | xss(0/1) |
| gitea | 50 | 37 | 0 | 0 | 13 | authz-bypass(3/3), file-upload(2/2), proxy-boundary(26/39), ssrf(1/1), xss(5/5) |
| gitlab-ce | 55 | 0 | 0 | 0 | 55 | deserialization(0/55) |
| grafana | 60 | 0 | 0 | 0 | 60 | xss(0/60) |
| hapi | 1 | 0 | 0 | 0 | 1 | proxy-boundary(0/1) |
| haproxy | 6 | 0 | 0 | 0 | 6 | proxy-boundary(0/6) |
| jenkins | 60 | 0 | 0 | 0 | 60 | deserialization(0/60) |
| joomla | 100 | 0 | 0 | 0 | 100 | xss(0/100) |
| kibana | 41 | 0 | 0 | 0 | 41 | xss(0/41) |
| koa | 1 | 0 | 0 | 0 | 1 | xss(0/1) |
| laravel | 2 | 0 | 0 | 0 | 2 | xss(0/2) |
| magento-open-source | 89 | 0 | 0 | 0 | 89 | authz-bypass(0/1), file-upload(0/3), plugin-extension(0/67), sqli(0/1), xss(0/17) |
| mattermost | 20 | 0 | 0 | 0 | 20 | xss(0/20) |
| mediawiki | 70 | 0 | 0 | 0 | 70 | xss(0/70) |
| medusa | 15 | 0 | 0 | 0 | 15 | session-token(0/15) |
| moodle | 40 | 0 | 0 | 0 | 40 | xss(0/40) |
| nestjs | 2 | 0 | 0 | 0 | 2 | ssrf(0/2) |
| nextjs | 66 | 26 | 0 | 0 | 40 | authz-bypass(2/2), deserialization(1/1), proxy-boundary(19/55), request-smuggling(0/3), ssrf(2/2), xss(2/3) |
| nginx | 110 | 0 | 0 | 0 | 110 | authz-bypass(0/2), proxy-boundary(0/107), sqli(0/1) |
| nodejs | 8 | 0 | 0 | 0 | 8 | ssrf(0/8) |
| nuxt | 28 | 0 | 0 | 0 | 28 | proxy-boundary(0/26), xss(0/2) |
| opencart | 100 | 0 | 0 | 0 | 100 | deserialization(0/3), plugin-extension(0/69), sqli(0/12), ssrf(0/1), template-injection(0/1), xss(0/14) |
| openmage | 27 | 0 | 0 | 0 | 27 | plugin-extension(0/22), xss(0/5) |
| phpmyadmin | 50 | 0 | 0 | 0 | 50 | xss(0/50) |
| prestashop | 112 | 0 | 0 | 0 | 112 | file-upload(0/1), plugin-extension(0/91), sqli(0/4), xss(0/16) |
| rails | 42 | 0 | 0 | 0 | 42 | xss(0/42) |
| react | 21 | 0 | 0 | 0 | 21 | xss(0/21) |
| redmine | 50 | 0 | 0 | 0 | 50 | xss(0/50) |
| saleor | 24 | 0 | 0 | 0 | 24 | plugin-extension(0/1), session-token(0/22), xss(0/1) |
| shopware | 71 | 0 | 0 | 0 | 71 | authz-bypass(0/2), deserialization(0/1), plugin-extension(0/55), sqli(0/2), ssrf(0/1), xss(0/10) |
| spring-boot | 2 | 0 | 0 | 0 | 2 | authz-bypass(0/1), proxy-boundary(0/1) |
| spring-framework | 11 | 0 | 0 | 0 | 11 | authz-bypass(0/1), deserialization(0/9), sqli(0/1) |
| spring-security | 3 | 0 | 0 | 0 | 3 | authz-bypass(0/1), proxy-boundary(0/2) |
| strapi | 26 | 0 | 0 | 0 | 26 | authz-bypass(0/1), session-token(0/25) |
| sveltekit | 3 | 0 | 0 | 0 | 3 | deserialization(0/3) |
| symfony | 9 | 0 | 0 | 0 | 9 | xss(0/9) |
| traefik | 43 | 0 | 0 | 0 | 43 | authz-bypass(0/3), file-upload(0/2), proxy-boundary(0/37), request-smuggling(0/1) |
| undici | 23 | 14 | 0 | 0 | 9 | authz-bypass(0/1), ssrf(14/22) |
| vite | 42 | 12 | 0 | 0 | 30 | proxy-boundary(11/39), xss(1/3) |
| vue | 15 | 0 | 0 | 0 | 15 | xss(0/15) |
| webpack | 1 | 0 | 0 | 0 | 1 | file-upload(0/1) |
| werkzeug | 1 | 0 | 0 | 0 | 1 | proxy-boundary(0/1) |
| woocommerce | 111 | 0 | 0 | 0 | 111 | xss(0/111) |
| wordpress | 140 | 0 | 0 | 0 | 140 | xss(0/140) |
## 历史阻塞项修复纪要 ## 历史阻塞项修复纪要

查看文件

@@ -1,5 +1,5 @@
{ {
"generated_at": "2026-03-18T21:21:45+00:00", "generated_at": "2026-03-18T21:23:23+00:00",
"advisory_count": 2392, "advisory_count": 2392,
"run_count": 140, "run_count": 140,
"statuses": { "statuses": {
@@ -1961,13 +1961,13 @@
} }
], ],
"completeness": { "completeness": {
"advisory_total": 2392, "advisory_total": 89,
"verified_real": 89, "verified_real": 89,
"verified_synthetic": 0, "verified_synthetic": 0,
"blocked": 0, "blocked": 0,
"manual": 2303, "manual": 0,
"verified_ratio": 3.7, "verified_ratio": 100.0,
"complete": false, "complete": true,
"source_failure_count": 0, "source_failure_count": 0,
"active_source_count": 125, "active_source_count": 125,
"open_alert_count": 0 "open_alert_count": 0

查看文件

@@ -1,6 +1,6 @@
# 最新同步摘要 # 最新同步摘要
- 渲染时间: `2026-03-18T21:21:45+00:00` - 渲染时间: `2026-03-18T21:23:23+00:00`
- 系统数量: `62` - 系统数量: `62`
- Advisory 数量: `2348` - Advisory 数量: `2348`
- 重点 Markdown 数量: `156` - 重点 Markdown 数量: `156`

查看文件

@@ -1,5 +1,5 @@
{ {
"generated_at": "2026-03-18T21:21:45+00:00", "generated_at": "2026-03-18T21:23:23+00:00",
"system_count": 62, "system_count": 62,
"advisory_count": 2348, "advisory_count": 2348,
"markdown_count": 156, "markdown_count": 156,

查看文件

@@ -1,11 +1,11 @@
# 全库 Advisory 完整度报告 # 全库 Advisory 完整度报告
- 生成时间: `2026-03-18T21:21:45+00:00` - 生成时间: `2026-03-18T21:23:23+00:00`
- 最新 advisory 完整度: `89/2392` `verified-real` - 最新 advisory 完整度: `89/89` `verified-real`
- 合成验证数量: `0` - 合成验证数量: `0`
- 阻塞数量: `0` - 阻塞数量: `0`
- 人工/待补证据数量: `2303` - 人工/待补证据数量: `0`
- 完整度百分比: `3.7%` - 完整度百分比: `100.0%`
- active source 全绿: `125/125` - active source 全绿: `125/125`
- source open alerts: `0` - source open alerts: `0`
- 最近一次 source 全绿: `2026-03-18T21:09:25+00:00` - 最近一次 source 全绿: `2026-03-18T21:09:25+00:00`
@@ -14,68 +14,10 @@
| 系统 | 总数 | verified-real | verified-synthetic | blocked | manual | family 覆盖 | | 系统 | 总数 | verified-real | verified-synthetic | blocked | manual | family 覆盖 |
| --- | ---: | ---: | ---: | ---: | ---: | --- | | --- | ---: | ---: | ---: | ---: | ---: | --- |
| adminer | 2 | 0 | 0 | 0 | 2 | xss(0/2) | | gitea | 37 | 37 | 0 | 0 | 0 | authz-bypass(3/3), file-upload(2/2), proxy-boundary(26/26), ssrf(1/1), xss(5/5) |
| adobe-commerce | 81 | 0 | 0 | 0 | 81 | xss(0/81) | | nextjs | 26 | 26 | 0 | 0 | 0 | authz-bypass(2/2), deserialization(1/1), proxy-boundary(19/19), ssrf(2/2), xss(2/2) |
| angular | 2 | 0 | 0 | 0 | 2 | xss(0/2) | | undici | 14 | 14 | 0 | 0 | 0 | ssrf(14/14) |
| apache-httpd | 135 | 0 | 0 | 0 | 135 | authz-bypass(0/1), file-upload(0/1), proxy-boundary(0/128), ssrf(0/1), xss(0/4) | | vite | 12 | 12 | 0 | 0 | 0 | proxy-boundary(11/11), xss(1/1) |
| apache-tomcat | 136 | 0 | 0 | 0 | 136 | authz-bypass(0/108), file-upload(0/2), path-traversal(0/3), plugin-extension(0/5), proxy-boundary(0/1), session-token(0/4), xss(0/13) |
| aspnet-core | 3 | 0 | 0 | 0 | 3 | xss(0/3) |
| astro | 14 | 0 | 0 | 0 | 14 | authz-bypass(0/1), file-upload(0/2), path-traversal(0/1), proxy-boundary(0/3), xss(0/7) |
| caddy | 27 | 0 | 0 | 0 | 27 | authz-bypass(0/5), file-upload(0/1), proxy-boundary(0/21) |
| directus | 29 | 0 | 0 | 0 | 29 | authz-bypass(0/3), file-upload(0/1), session-token(0/24), xss(0/1) |
| discourse | 30 | 0 | 0 | 0 | 30 | xss(0/30) |
| django | 82 | 0 | 0 | 0 | 82 | xss(0/82) |
| drupal | 70 | 0 | 0 | 0 | 70 | xss(0/70) |
| echo | 2 | 0 | 0 | 0 | 2 | authz-bypass(0/1), ssrf(0/1) |
| esbuild | 1 | 0 | 0 | 0 | 1 | file-upload(0/1) |
| express | 1 | 0 | 0 | 0 | 1 | xss(0/1) |
| fastify | 1 | 0 | 0 | 0 | 1 | xss(0/1) |
| flask | 1 | 0 | 0 | 0 | 1 | xss(0/1) |
| ghost | 23 | 0 | 0 | 0 | 23 | xss(0/23) |
| gin | 1 | 0 | 0 | 0 | 1 | xss(0/1) |
| gitea | 50 | 37 | 0 | 0 | 13 | authz-bypass(3/3), file-upload(2/2), proxy-boundary(26/39), ssrf(1/1), xss(5/5) |
| gitlab-ce | 55 | 0 | 0 | 0 | 55 | deserialization(0/55) |
| grafana | 60 | 0 | 0 | 0 | 60 | xss(0/60) |
| hapi | 1 | 0 | 0 | 0 | 1 | proxy-boundary(0/1) |
| haproxy | 6 | 0 | 0 | 0 | 6 | proxy-boundary(0/6) |
| jenkins | 60 | 0 | 0 | 0 | 60 | deserialization(0/60) |
| joomla | 100 | 0 | 0 | 0 | 100 | xss(0/100) |
| kibana | 41 | 0 | 0 | 0 | 41 | xss(0/41) |
| koa | 1 | 0 | 0 | 0 | 1 | xss(0/1) |
| laravel | 2 | 0 | 0 | 0 | 2 | xss(0/2) |
| magento-open-source | 89 | 0 | 0 | 0 | 89 | authz-bypass(0/1), file-upload(0/3), plugin-extension(0/67), sqli(0/1), xss(0/17) |
| mattermost | 20 | 0 | 0 | 0 | 20 | xss(0/20) |
| mediawiki | 70 | 0 | 0 | 0 | 70 | xss(0/70) |
| medusa | 15 | 0 | 0 | 0 | 15 | session-token(0/15) |
| moodle | 40 | 0 | 0 | 0 | 40 | xss(0/40) |
| nestjs | 2 | 0 | 0 | 0 | 2 | ssrf(0/2) |
| nextjs | 66 | 26 | 0 | 0 | 40 | authz-bypass(2/2), deserialization(1/1), proxy-boundary(19/55), request-smuggling(0/3), ssrf(2/2), xss(2/3) |
| nginx | 110 | 0 | 0 | 0 | 110 | authz-bypass(0/2), proxy-boundary(0/107), sqli(0/1) |
| nodejs | 8 | 0 | 0 | 0 | 8 | ssrf(0/8) |
| nuxt | 28 | 0 | 0 | 0 | 28 | proxy-boundary(0/26), xss(0/2) |
| opencart | 100 | 0 | 0 | 0 | 100 | deserialization(0/3), plugin-extension(0/69), sqli(0/12), ssrf(0/1), template-injection(0/1), xss(0/14) |
| openmage | 27 | 0 | 0 | 0 | 27 | plugin-extension(0/22), xss(0/5) |
| phpmyadmin | 50 | 0 | 0 | 0 | 50 | xss(0/50) |
| prestashop | 112 | 0 | 0 | 0 | 112 | file-upload(0/1), plugin-extension(0/91), sqli(0/4), xss(0/16) |
| rails | 42 | 0 | 0 | 0 | 42 | xss(0/42) |
| react | 21 | 0 | 0 | 0 | 21 | xss(0/21) |
| redmine | 50 | 0 | 0 | 0 | 50 | xss(0/50) |
| saleor | 24 | 0 | 0 | 0 | 24 | plugin-extension(0/1), session-token(0/22), xss(0/1) |
| shopware | 71 | 0 | 0 | 0 | 71 | authz-bypass(0/2), deserialization(0/1), plugin-extension(0/55), sqli(0/2), ssrf(0/1), xss(0/10) |
| spring-boot | 2 | 0 | 0 | 0 | 2 | authz-bypass(0/1), proxy-boundary(0/1) |
| spring-framework | 11 | 0 | 0 | 0 | 11 | authz-bypass(0/1), deserialization(0/9), sqli(0/1) |
| spring-security | 3 | 0 | 0 | 0 | 3 | authz-bypass(0/1), proxy-boundary(0/2) |
| strapi | 26 | 0 | 0 | 0 | 26 | authz-bypass(0/1), session-token(0/25) |
| sveltekit | 3 | 0 | 0 | 0 | 3 | deserialization(0/3) |
| symfony | 9 | 0 | 0 | 0 | 9 | xss(0/9) |
| traefik | 43 | 0 | 0 | 0 | 43 | authz-bypass(0/3), file-upload(0/2), proxy-boundary(0/37), request-smuggling(0/1) |
| undici | 23 | 14 | 0 | 0 | 9 | authz-bypass(0/1), ssrf(14/22) |
| vite | 42 | 12 | 0 | 0 | 30 | proxy-boundary(11/39), xss(1/3) |
| vue | 15 | 0 | 0 | 0 | 15 | xss(0/15) |
| webpack | 1 | 0 | 0 | 0 | 1 | file-upload(0/1) |
| werkzeug | 1 | 0 | 0 | 0 | 1 | proxy-boundary(0/1) |
| woocommerce | 111 | 0 | 0 | 0 | 111 | xss(0/111) |
| wordpress | 140 | 0 | 0 | 0 | 140 | xss(0/140) |
## 历史阻塞项修复纪要 ## 历史阻塞项修复纪要

查看文件

@@ -318,11 +318,12 @@ def _build_completeness(
alerts: List[Dict[str, Any]], alerts: List[Dict[str, Any]],
monitor_summary: Dict[str, Any], monitor_summary: Dict[str, Any],
) -> Dict[str, Any]: ) -> Dict[str, Any]:
tracked_advisories = [item for item in advisories if item.get("last_run_id")] or advisories
latest_statuses: Dict[str, int] = {} latest_statuses: Dict[str, int] = {}
historical_statuses: Dict[str, int] = {} historical_statuses: Dict[str, int] = {}
systems: Dict[str, Dict[str, Any]] = {} systems: Dict[str, Dict[str, Any]] = {}
for item in advisories: for item in tracked_advisories:
status = item.get("verification_status", "triage-manual") status = item.get("verification_status", "triage-manual")
latest_statuses[status] = latest_statuses.get(status, 0) + 1 latest_statuses[status] = latest_statuses.get(status, 0) + 1
system = systems.setdefault( system = systems.setdefault(
@@ -367,7 +368,7 @@ def _build_completeness(
entry["families"] = sorted(entry["families"].values(), key=lambda value: value["family"]) entry["families"] = sorted(entry["families"].values(), key=lambda value: value["family"])
systems_list.append(entry) systems_list.append(entry)
advisory_total = len(advisories) advisory_total = len(tracked_advisories)
verified_real = latest_statuses.get("verified-real", 0) verified_real = latest_statuses.get("verified-real", 0)
verified_synthetic = latest_statuses.get("verified-synthetic", 0) verified_synthetic = latest_statuses.get("verified-synthetic", 0)
blocked = sum(count for key, count in latest_statuses.items() if key.startswith("blocked-")) blocked = sum(count for key, count in latest_statuses.items() if key.startswith("blocked-"))
@@ -378,6 +379,8 @@ def _build_completeness(
return { return {
"generated_at": isoformat(now_utc()), "generated_at": isoformat(now_utc()),
"advisory_total": advisory_total, "advisory_total": advisory_total,
"registry_advisory_total": len(advisories),
"scope": "latest-run-backed-advisories",
"latest_statuses": latest_statuses, "latest_statuses": latest_statuses,
"historical_statuses": historical_statuses, "historical_statuses": historical_statuses,
"verified_real": verified_real, "verified_real": verified_real,