From 40ffbbd9cd55a6502a841e6540850674b97ce6c6 Mon Sep 17 00:00:00 2001 From: hao Date: Tue, 17 Mar 2026 00:37:18 -0700 Subject: [PATCH] Add dashboard docs and richer lab UI --- 07-framework-security/cms/directus/INDEX.md | 2 +- 07-framework-security/cms/discourse/INDEX.md | 2 +- 07-framework-security/cms/drupal/INDEX.md | 2 +- 07-framework-security/cms/ghost/INDEX.md | 2 +- 07-framework-security/cms/joomla/INDEX.md | 2 +- 07-framework-security/cms/mediawiki/INDEX.md | 2 +- 07-framework-security/cms/moodle/INDEX.md | 2 +- 07-framework-security/cms/strapi/INDEX.md | 2 +- 07-framework-security/cms/wordpress/INDEX.md | 2 +- .../ecommerce/adobe-commerce/INDEX.md | 2 +- .../ecommerce/magento-open-source/INDEX.md | 2 +- .../ecommerce/medusa/INDEX.md | 2 +- .../ecommerce/opencart/INDEX.md | 2 +- .../ecommerce/openmage/INDEX.md | 2 +- .../ecommerce/prestashop/INDEX.md | 2 +- .../ecommerce/saleor/INDEX.md | 2 +- .../ecommerce/shopware/INDEX.md | 2 +- .../ecommerce/woocommerce/INDEX.md | 2 +- .../frameworks/angular/INDEX.md | 2 +- .../frameworks/aspnet-core/INDEX.md | 2 +- .../frameworks/astro/INDEX.md | 2 +- .../frameworks/django/INDEX.md | 2 +- .../frameworks/echo/INDEX.md | 2 +- .../frameworks/esbuild/INDEX.md | 2 +- .../frameworks/express/INDEX.md | 2 +- .../frameworks/fastify/INDEX.md | 2 +- .../frameworks/flask/INDEX.md | 2 +- 07-framework-security/frameworks/gin/INDEX.md | 2 +- .../frameworks/hapi/INDEX.md | 2 +- 07-framework-security/frameworks/koa/INDEX.md | 2 +- .../frameworks/laravel/INDEX.md | 2 +- .../frameworks/nestjs/INDEX.md | 2 +- .../frameworks/nextjs/INDEX.md | 2 +- .../frameworks/nodejs/INDEX.md | 2 +- .../frameworks/nuxt/INDEX.md | 2 +- .../frameworks/rails/INDEX.md | 2 +- .../frameworks/react/INDEX.md | 2 +- .../frameworks/spring-boot/INDEX.md | 2 +- .../frameworks/spring-framework/INDEX.md | 2 +- .../frameworks/spring-security/INDEX.md | 2 +- .../frameworks/sveltekit/INDEX.md | 2 +- .../frameworks/symfony/INDEX.md | 2 +- .../frameworks/undici/INDEX.md | 2 +- .../frameworks/vite/INDEX.md | 2 +- 07-framework-security/frameworks/vue/INDEX.md | 2 +- .../frameworks/webpack/INDEX.md | 2 +- .../frameworks/werkzeug/INDEX.md | 2 +- .../platforms/adminer/INDEX.md | 2 +- .../platforms/gitea/INDEX.md | 2 +- .../platforms/gitlab-ce/INDEX.md | 2 +- .../platforms/grafana/INDEX.md | 2 +- .../platforms/jenkins/INDEX.md | 2 +- .../platforms/kibana/INDEX.md | 2 +- .../platforms/mattermost/INDEX.md | 2 +- .../platforms/phpmyadmin/INDEX.md | 2 +- .../platforms/redmine/INDEX.md | 2 +- .../servers/apache-httpd/INDEX.md | 2 +- .../servers/apache-tomcat/INDEX.md | 2 +- 07-framework-security/servers/caddy/INDEX.md | 2 +- .../servers/haproxy/INDEX.md | 2 +- 07-framework-security/servers/nginx/INDEX.md | 2 +- .../servers/traefik/INDEX.md | 2 +- .../generated/dashboard/assets/app.js | 86 +++- .../generated/dashboard/assets/styles.css | 64 +++ .../docs/frontend-dashboard-design.html | 402 ++++++++++++++++++ .../dashboard/docs/project-features.html | 255 +++++++++++ .../dashboard/docs/secure-code-index.html | 108 +++++ .../generated/dashboard/index.html | 1 + 08-threat-intel/generated/dashboard/runs.json | 29 +- .../generated/dashboard/summary.json | 2 +- 08-threat-intel/generated/latest-ingest.md | 2 +- 08-threat-intel/generated/run-summary.json | 2 +- scripts/intel/validators.py | 3 + scripts/lab/render.py | 300 ++++++++++++- 74 files changed, 1285 insertions(+), 93 deletions(-) create mode 100644 08-threat-intel/generated/dashboard/docs/frontend-dashboard-design.html create mode 100644 08-threat-intel/generated/dashboard/docs/project-features.html create mode 100644 08-threat-intel/generated/dashboard/docs/secure-code-index.html diff --git a/07-framework-security/cms/directus/INDEX.md b/07-framework-security/cms/directus/INDEX.md index 67797f16..1e94e0b3 100644 --- a/07-framework-security/cms/directus/INDEX.md +++ b/07-framework-security/cms/directus/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/cms/discourse/INDEX.md b/07-framework-security/cms/discourse/INDEX.md index e786fed2..54893fa6 100644 --- a/07-framework-security/cms/discourse/INDEX.md +++ b/07-framework-security/cms/discourse/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/cms/drupal/INDEX.md b/07-framework-security/cms/drupal/INDEX.md index f6dc0f6d..9f0e2a67 100644 --- a/07-framework-security/cms/drupal/INDEX.md +++ b/07-framework-security/cms/drupal/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/cms/ghost/INDEX.md b/07-framework-security/cms/ghost/INDEX.md index 5724cc7d..1f2e365f 100644 --- a/07-framework-security/cms/ghost/INDEX.md +++ b/07-framework-security/cms/ghost/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/cms/joomla/INDEX.md b/07-framework-security/cms/joomla/INDEX.md index 5fdc29c8..2a6fcf7b 100644 --- a/07-framework-security/cms/joomla/INDEX.md +++ b/07-framework-security/cms/joomla/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/cms/mediawiki/INDEX.md b/07-framework-security/cms/mediawiki/INDEX.md index ac92df6a..d48489f3 100644 --- a/07-framework-security/cms/mediawiki/INDEX.md +++ b/07-framework-security/cms/mediawiki/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/cms/moodle/INDEX.md b/07-framework-security/cms/moodle/INDEX.md index 0b696b17..435c512d 100644 --- a/07-framework-security/cms/moodle/INDEX.md +++ b/07-framework-security/cms/moodle/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/cms/strapi/INDEX.md b/07-framework-security/cms/strapi/INDEX.md index 50d170b6..6c3826bf 100644 --- a/07-framework-security/cms/strapi/INDEX.md +++ b/07-framework-security/cms/strapi/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/cms/wordpress/INDEX.md b/07-framework-security/cms/wordpress/INDEX.md index c0850125..a2d1bfec 100644 --- a/07-framework-security/cms/wordpress/INDEX.md +++ b/07-framework-security/cms/wordpress/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/ecommerce/adobe-commerce/INDEX.md b/07-framework-security/ecommerce/adobe-commerce/INDEX.md index 4a269281..ad036c19 100644 --- a/07-framework-security/ecommerce/adobe-commerce/INDEX.md +++ b/07-framework-security/ecommerce/adobe-commerce/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/ecommerce/magento-open-source/INDEX.md b/07-framework-security/ecommerce/magento-open-source/INDEX.md index 5a1a4c94..515d3d0e 100644 --- a/07-framework-security/ecommerce/magento-open-source/INDEX.md +++ b/07-framework-security/ecommerce/magento-open-source/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/ecommerce/medusa/INDEX.md b/07-framework-security/ecommerce/medusa/INDEX.md index 30cc55b6..38e85c8f 100644 --- a/07-framework-security/ecommerce/medusa/INDEX.md +++ b/07-framework-security/ecommerce/medusa/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/ecommerce/opencart/INDEX.md b/07-framework-security/ecommerce/opencart/INDEX.md index 19ccaa36..a51fa75c 100644 --- a/07-framework-security/ecommerce/opencart/INDEX.md +++ b/07-framework-security/ecommerce/opencart/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/ecommerce/openmage/INDEX.md b/07-framework-security/ecommerce/openmage/INDEX.md index d107a165..26db064f 100644 --- a/07-framework-security/ecommerce/openmage/INDEX.md +++ b/07-framework-security/ecommerce/openmage/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/ecommerce/prestashop/INDEX.md b/07-framework-security/ecommerce/prestashop/INDEX.md index 89e8a378..cebb88e2 100644 --- a/07-framework-security/ecommerce/prestashop/INDEX.md +++ b/07-framework-security/ecommerce/prestashop/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/ecommerce/saleor/INDEX.md b/07-framework-security/ecommerce/saleor/INDEX.md index 8fee89b3..651a17a0 100644 --- a/07-framework-security/ecommerce/saleor/INDEX.md +++ b/07-framework-security/ecommerce/saleor/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/ecommerce/shopware/INDEX.md b/07-framework-security/ecommerce/shopware/INDEX.md index 888acb84..c172c541 100644 --- a/07-framework-security/ecommerce/shopware/INDEX.md +++ b/07-framework-security/ecommerce/shopware/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/ecommerce/woocommerce/INDEX.md b/07-framework-security/ecommerce/woocommerce/INDEX.md index 53ffc810..2ced713a 100644 --- a/07-framework-security/ecommerce/woocommerce/INDEX.md +++ b/07-framework-security/ecommerce/woocommerce/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/angular/INDEX.md b/07-framework-security/frameworks/angular/INDEX.md index 66a1eeeb..dcf7c4a5 100644 --- a/07-framework-security/frameworks/angular/INDEX.md +++ b/07-framework-security/frameworks/angular/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:58+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/aspnet-core/INDEX.md b/07-framework-security/frameworks/aspnet-core/INDEX.md index b11983c1..c9a73a04 100644 --- a/07-framework-security/frameworks/aspnet-core/INDEX.md +++ b/07-framework-security/frameworks/aspnet-core/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/astro/INDEX.md b/07-framework-security/frameworks/astro/INDEX.md index 764bf4e1..7dc5a5af 100644 --- a/07-framework-security/frameworks/astro/INDEX.md +++ b/07-framework-security/frameworks/astro/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:58+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/django/INDEX.md b/07-framework-security/frameworks/django/INDEX.md index 772601de..b6f83ad6 100644 --- a/07-framework-security/frameworks/django/INDEX.md +++ b/07-framework-security/frameworks/django/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/echo/INDEX.md b/07-framework-security/frameworks/echo/INDEX.md index 945bdc3b..9eba3112 100644 --- a/07-framework-security/frameworks/echo/INDEX.md +++ b/07-framework-security/frameworks/echo/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/esbuild/INDEX.md b/07-framework-security/frameworks/esbuild/INDEX.md index daa0b3d8..4d9280ce 100644 --- a/07-framework-security/frameworks/esbuild/INDEX.md +++ b/07-framework-security/frameworks/esbuild/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/express/INDEX.md b/07-framework-security/frameworks/express/INDEX.md index 209eacc6..60463d4a 100644 --- a/07-framework-security/frameworks/express/INDEX.md +++ b/07-framework-security/frameworks/express/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:58+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/fastify/INDEX.md b/07-framework-security/frameworks/fastify/INDEX.md index 7d60c8b6..60c2bcf7 100644 --- a/07-framework-security/frameworks/fastify/INDEX.md +++ b/07-framework-security/frameworks/fastify/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:58+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/flask/INDEX.md b/07-framework-security/frameworks/flask/INDEX.md index 14e5f92b..f60106bc 100644 --- a/07-framework-security/frameworks/flask/INDEX.md +++ b/07-framework-security/frameworks/flask/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/gin/INDEX.md b/07-framework-security/frameworks/gin/INDEX.md index bec788dd..ae870af9 100644 --- a/07-framework-security/frameworks/gin/INDEX.md +++ b/07-framework-security/frameworks/gin/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/hapi/INDEX.md b/07-framework-security/frameworks/hapi/INDEX.md index c77dee6e..9df23faf 100644 --- a/07-framework-security/frameworks/hapi/INDEX.md +++ b/07-framework-security/frameworks/hapi/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:58+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/koa/INDEX.md b/07-framework-security/frameworks/koa/INDEX.md index f22a5cc4..090bc378 100644 --- a/07-framework-security/frameworks/koa/INDEX.md +++ b/07-framework-security/frameworks/koa/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:58+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/laravel/INDEX.md b/07-framework-security/frameworks/laravel/INDEX.md index 7ece308e..e53702f1 100644 --- a/07-framework-security/frameworks/laravel/INDEX.md +++ b/07-framework-security/frameworks/laravel/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/nestjs/INDEX.md b/07-framework-security/frameworks/nestjs/INDEX.md index 52875476..bc1b3d9e 100644 --- a/07-framework-security/frameworks/nestjs/INDEX.md +++ b/07-framework-security/frameworks/nestjs/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:58+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/nextjs/INDEX.md b/07-framework-security/frameworks/nextjs/INDEX.md index effbe677..9248601f 100644 --- a/07-framework-security/frameworks/nextjs/INDEX.md +++ b/07-framework-security/frameworks/nextjs/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `26` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:57+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/nodejs/INDEX.md b/07-framework-security/frameworks/nodejs/INDEX.md index 92e5e274..0efe2fb9 100644 --- a/07-framework-security/frameworks/nodejs/INDEX.md +++ b/07-framework-security/frameworks/nodejs/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:58+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/nuxt/INDEX.md b/07-framework-security/frameworks/nuxt/INDEX.md index 83d653f7..0eefd22d 100644 --- a/07-framework-security/frameworks/nuxt/INDEX.md +++ b/07-framework-security/frameworks/nuxt/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:57+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/rails/INDEX.md b/07-framework-security/frameworks/rails/INDEX.md index bd205c00..97603448 100644 --- a/07-framework-security/frameworks/rails/INDEX.md +++ b/07-framework-security/frameworks/rails/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/react/INDEX.md b/07-framework-security/frameworks/react/INDEX.md index 2c7e0ae4..5318c4bf 100644 --- a/07-framework-security/frameworks/react/INDEX.md +++ b/07-framework-security/frameworks/react/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:10+00:00` +- 最近渲染时间: `2026-03-17T07:35:56+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/spring-boot/INDEX.md b/07-framework-security/frameworks/spring-boot/INDEX.md index 914c1138..75fb2b64 100644 --- a/07-framework-security/frameworks/spring-boot/INDEX.md +++ b/07-framework-security/frameworks/spring-boot/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/spring-framework/INDEX.md b/07-framework-security/frameworks/spring-framework/INDEX.md index 01f71324..2d7e1c79 100644 --- a/07-framework-security/frameworks/spring-framework/INDEX.md +++ b/07-framework-security/frameworks/spring-framework/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/spring-security/INDEX.md b/07-framework-security/frameworks/spring-security/INDEX.md index bd032cc9..d74516df 100644 --- a/07-framework-security/frameworks/spring-security/INDEX.md +++ b/07-framework-security/frameworks/spring-security/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/sveltekit/INDEX.md b/07-framework-security/frameworks/sveltekit/INDEX.md index bb93dc07..3f5ea9f8 100644 --- a/07-framework-security/frameworks/sveltekit/INDEX.md +++ b/07-framework-security/frameworks/sveltekit/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:58+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/symfony/INDEX.md b/07-framework-security/frameworks/symfony/INDEX.md index bdd30328..25b37929 100644 --- a/07-framework-security/frameworks/symfony/INDEX.md +++ b/07-framework-security/frameworks/symfony/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/undici/INDEX.md b/07-framework-security/frameworks/undici/INDEX.md index bd9a762d..585f95c1 100644 --- a/07-framework-security/frameworks/undici/INDEX.md +++ b/07-framework-security/frameworks/undici/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `14` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/vite/INDEX.md b/07-framework-security/frameworks/vite/INDEX.md index edc08fec..d646d968 100644 --- a/07-framework-security/frameworks/vite/INDEX.md +++ b/07-framework-security/frameworks/vite/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `12` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:58+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/vue/INDEX.md b/07-framework-security/frameworks/vue/INDEX.md index 77df6373..de7a2fc3 100644 --- a/07-framework-security/frameworks/vue/INDEX.md +++ b/07-framework-security/frameworks/vue/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:12+00:00` +- 最近渲染时间: `2026-03-17T07:35:57+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/webpack/INDEX.md b/07-framework-security/frameworks/webpack/INDEX.md index 7e19b849..b96f9d27 100644 --- a/07-framework-security/frameworks/webpack/INDEX.md +++ b/07-framework-security/frameworks/webpack/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/frameworks/werkzeug/INDEX.md b/07-framework-security/frameworks/werkzeug/INDEX.md index 6538e15d..6418c943 100644 --- a/07-framework-security/frameworks/werkzeug/INDEX.md +++ b/07-framework-security/frameworks/werkzeug/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/platforms/adminer/INDEX.md b/07-framework-security/platforms/adminer/INDEX.md index 81374b40..8b5c44f8 100644 --- a/07-framework-security/platforms/adminer/INDEX.md +++ b/07-framework-security/platforms/adminer/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/platforms/gitea/INDEX.md b/07-framework-security/platforms/gitea/INDEX.md index 11858683..13622319 100644 --- a/07-framework-security/platforms/gitea/INDEX.md +++ b/07-framework-security/platforms/gitea/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `1` - 待人工/缺浏览器证据: `36` -- 最近渲染时间: `2026-03-17T07:27:15+00:00` +- 最近渲染时间: `2026-03-17T07:36:01+00:00` ## 目标约束 diff --git a/07-framework-security/platforms/gitlab-ce/INDEX.md b/07-framework-security/platforms/gitlab-ce/INDEX.md index e45c2e49..db11d20b 100644 --- a/07-framework-security/platforms/gitlab-ce/INDEX.md +++ b/07-framework-security/platforms/gitlab-ce/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:15+00:00` +- 最近渲染时间: `2026-03-17T07:36:01+00:00` ## 目标约束 diff --git a/07-framework-security/platforms/grafana/INDEX.md b/07-framework-security/platforms/grafana/INDEX.md index 4dbab379..16e9e90f 100644 --- a/07-framework-security/platforms/grafana/INDEX.md +++ b/07-framework-security/platforms/grafana/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:15+00:00` +- 最近渲染时间: `2026-03-17T07:36:01+00:00` ## 目标约束 diff --git a/07-framework-security/platforms/jenkins/INDEX.md b/07-framework-security/platforms/jenkins/INDEX.md index 597da6fe..95c7955c 100644 --- a/07-framework-security/platforms/jenkins/INDEX.md +++ b/07-framework-security/platforms/jenkins/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:15+00:00` +- 最近渲染时间: `2026-03-17T07:36:01+00:00` ## 目标约束 diff --git a/07-framework-security/platforms/kibana/INDEX.md b/07-framework-security/platforms/kibana/INDEX.md index e686ac84..8c1afc03 100644 --- a/07-framework-security/platforms/kibana/INDEX.md +++ b/07-framework-security/platforms/kibana/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:15+00:00` +- 最近渲染时间: `2026-03-17T07:36:01+00:00` ## 目标约束 diff --git a/07-framework-security/platforms/mattermost/INDEX.md b/07-framework-security/platforms/mattermost/INDEX.md index 2f2b05fa..5c59da45 100644 --- a/07-framework-security/platforms/mattermost/INDEX.md +++ b/07-framework-security/platforms/mattermost/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:15+00:00` +- 最近渲染时间: `2026-03-17T07:36:01+00:00` ## 目标约束 diff --git a/07-framework-security/platforms/phpmyadmin/INDEX.md b/07-framework-security/platforms/phpmyadmin/INDEX.md index 490c3103..981a9c86 100644 --- a/07-framework-security/platforms/phpmyadmin/INDEX.md +++ b/07-framework-security/platforms/phpmyadmin/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/platforms/redmine/INDEX.md b/07-framework-security/platforms/redmine/INDEX.md index 4e215142..6530ea33 100644 --- a/07-framework-security/platforms/redmine/INDEX.md +++ b/07-framework-security/platforms/redmine/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:15+00:00` +- 最近渲染时间: `2026-03-17T07:36:01+00:00` ## 目标约束 diff --git a/07-framework-security/servers/apache-httpd/INDEX.md b/07-framework-security/servers/apache-httpd/INDEX.md index ff6d9f98..433eee24 100644 --- a/07-framework-security/servers/apache-httpd/INDEX.md +++ b/07-framework-security/servers/apache-httpd/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/servers/apache-tomcat/INDEX.md b/07-framework-security/servers/apache-tomcat/INDEX.md index 89d6e826..4ef48c71 100644 --- a/07-framework-security/servers/apache-tomcat/INDEX.md +++ b/07-framework-security/servers/apache-tomcat/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/servers/caddy/INDEX.md b/07-framework-security/servers/caddy/INDEX.md index 48ad1fef..781b6d53 100644 --- a/07-framework-security/servers/caddy/INDEX.md +++ b/07-framework-security/servers/caddy/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/servers/haproxy/INDEX.md b/07-framework-security/servers/haproxy/INDEX.md index 038f217a..f0a19002 100644 --- a/07-framework-security/servers/haproxy/INDEX.md +++ b/07-framework-security/servers/haproxy/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/servers/nginx/INDEX.md b/07-framework-security/servers/nginx/INDEX.md index 7c3a3b12..3c8e2570 100644 --- a/07-framework-security/servers/nginx/INDEX.md +++ b/07-framework-security/servers/nginx/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/07-framework-security/servers/traefik/INDEX.md b/07-framework-security/servers/traefik/INDEX.md index 6efe75e8..0564dcb8 100644 --- a/07-framework-security/servers/traefik/INDEX.md +++ b/07-framework-security/servers/traefik/INDEX.md @@ -12,7 +12,7 @@ - 已实证(synthetic): `0` - 阻塞数: `0` - 待人工/缺浏览器证据: `0` -- 最近渲染时间: `2026-03-17T07:27:13+00:00` +- 最近渲染时间: `2026-03-17T07:35:59+00:00` ## 目标约束 diff --git a/08-threat-intel/generated/dashboard/assets/app.js b/08-threat-intel/generated/dashboard/assets/app.js index d7ec6b0e..7710b047 100644 --- a/08-threat-intel/generated/dashboard/assets/app.js +++ b/08-threat-intel/generated/dashboard/assets/app.js @@ -169,6 +169,7 @@ function renderRunList() { const active = item.run_id === state.selectedRunId ? "is-active" : ""; const title = item.advisory_meta?.title || item.advisory_id; const reasoning = item.reasoning_lines?.[0] || item.blocked_reason || ""; + const browserLabel = item.browser_evidence?.present ? "ready" : (item.browser_evidence?.required ? "required" : "n/a"); return ` @@ -234,7 +235,7 @@ function hydrateFilterOptions() { } function defaultArtifact(run) { - const preference = ["requests", "container", "browser", "compose", "reports"]; + const preference = ["attack", "requests", "container", "browser", "baseline", "compose", "reports"]; for (const key of preference) { const group = (run.artifact_groups || []).find((item) => item.key === key && item.items?.length); if (!group) continue; @@ -244,6 +245,73 @@ function defaultArtifact(run) { return null; } +function totalProgress(progress) { + const values = Object.values(progress || {}).map((value) => Number(value || 0)); + return values.reduce((sum, value) => sum + value, 0); +} + +function renderProgressStrip(progress) { + const total = totalProgress(progress); + if (!total) { + return ` +
+
+
No timeline progress recorded.
+
+ `; + } + const order = [ + ["completed", "Completed", "progress-completed"], + ["blocked", "Blocked", "progress-blocked"], + ["failed", "Failed", "progress-failed"], + ["skipped", "Skipped", "progress-skipped"], + ["planned", "Planned", "progress-planned"], + ["other", "Other", "progress-other"], + ]; + const segments = order + .filter(([key]) => Number(progress?.[key] || 0) > 0) + .map(([key, _label, klass]) => { + const count = Number(progress?.[key] || 0); + const pct = Math.max((count / total) * 100, 4); + return `
`; + }) + .join(""); + const legend = order + .filter(([key]) => Number(progress?.[key] || 0) > 0) + .map(([key, label, klass]) => ` + + + ${escapeHtml(label)} ${escapeHtml(progress?.[key] || 0)} + + `) + .join(""); + return ` +
+
${segments}
+
${legend}
+
+ `; +} + +function renderStageCards(run) { + const timeline = run.timeline || []; + if (!timeline.length) { + return `
No stage records available.
`; + } + return ` +
+ ${timeline.map((item) => ` +
+ ${escapeHtml(item.step || "-")} +
${escapeHtml(item.status || "unknown")}
+
${escapeHtml(item.detail || "-")}
+
${escapeHtml(item.at || "-")}
+
+ `).join("")} +
+ `; +} + async function openArtifact(href, label, kind) { state.selectedArtifact = { href, label, kind }; document.querySelectorAll(".artifact-button").forEach((button) => { @@ -300,6 +368,7 @@ function renderDetail() { ${escapeHtml(run.repro_profile_id)} ${escapeHtml(run.artifact_mode)} ${escapeHtml(run.verification_mode)} + ${escapeHtml(run.target_env || "local-docker")}

${escapeHtml(advisory.title || run.advisory_id)}

@@ -308,11 +377,12 @@ function renderDetail() { Open HTML report Open Markdown Open run JSON + Open UI spec
Timeline Steps${escapeHtml(run.timeline?.length || 0)}
Artifacts${escapeHtml((run.artifact_groups || []).reduce((sum, group) => sum + group.count, 0))}
-
Browser${run.browser_evidence?.present ? "Ready" : "Missing"}
+
Browser${run.browser_evidence?.present ? "Ready" : (run.browser_evidence?.required ? "Required" : "Optional")}
Finished${escapeHtml(timeAgo(run.finished_at))}
@@ -322,12 +392,8 @@ function renderDetail() {
Progress Timeline${escapeHtml(run.timeline?.length || 0)} steps
-
- completed ${escapeHtml(run.progress?.completed || 0)} - blocked ${escapeHtml(run.progress?.blocked || 0)} - skipped ${escapeHtml(run.progress?.skipped || 0)} - failed ${escapeHtml(run.progress?.failed || 0)} -
+ ${renderProgressStrip(run.progress)} + ${renderStageCards(run)}
${(run.timeline || []).map((item) => `
@@ -424,7 +490,7 @@ function renderDetail() { ${(advisory.secondary_source_urls || []).map((ref) => `${escapeHtml(ref)}`).join("")}
- ${(advisory.secure_code_topics || []).map((topic) => `${escapeHtml(topic)}`).join("")} + ${(advisory.secure_code_topics || []).map((topic) => `${escapeHtml(topic)}`).join("")}
diff --git a/08-threat-intel/generated/dashboard/assets/styles.css b/08-threat-intel/generated/dashboard/assets/styles.css index ad2ac571..61c46ff2 100644 --- a/08-threat-intel/generated/dashboard/assets/styles.css +++ b/08-threat-intel/generated/dashboard/assets/styles.css @@ -400,6 +400,70 @@ button, input, select { gap: 18px; } +.progress-strip { + display: grid; + gap: 12px; + margin-bottom: 16px; +} + +.progress-bar { + display: flex; + width: 100%; + min-height: 12px; + overflow: hidden; + border-radius: 999px; + background: rgba(255,255,255,0.08); + border: 1px solid rgba(159, 179, 202, 0.14); +} + +.progress-segment { + min-width: 10px; + transition: width 180ms ease; +} + +.progress-completed { background: linear-gradient(90deg, rgba(110, 231, 165, 0.9), rgba(94, 234, 212, 0.9)); } +.progress-blocked { background: linear-gradient(90deg, rgba(255, 123, 123, 0.95), rgba(255, 160, 122, 0.9)); } +.progress-failed { background: linear-gradient(90deg, rgba(255, 123, 123, 0.92), rgba(255, 209, 102, 0.88)); } +.progress-skipped { background: linear-gradient(90deg, rgba(255,255,255,0.22), rgba(159, 179, 202, 0.3)); } +.progress-planned { background: linear-gradient(90deg, rgba(144, 205, 244, 0.82), rgba(94, 234, 212, 0.72)); } +.progress-other { background: linear-gradient(90deg, rgba(255,255,255,0.18), rgba(255,255,255,0.1)); } + +.progress-legend { + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.progress-legend .tag { + gap: 7px; +} + +.progress-legend .swatch { + width: 10px; + height: 10px; + border-radius: 999px; + display: inline-block; +} + +.stage-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 12px; + margin-bottom: 18px; +} + +.stage-card { + padding: 14px; + border-radius: 16px; + background: rgba(255,255,255,0.04); + border: 1px solid rgba(159, 179, 202, 0.16); +} + +.stage-card strong { + display: block; + margin-bottom: 10px; +} + .accordion { overflow: hidden; } diff --git a/08-threat-intel/generated/dashboard/docs/frontend-dashboard-design.html b/08-threat-intel/generated/dashboard/docs/frontend-dashboard-design.html new file mode 100644 index 00000000..68f975cf --- /dev/null +++ b/08-threat-intel/generated/dashboard/docs/frontend-dashboard-design.html @@ -0,0 +1,402 @@ + + + + + + 本地前端工作台设计文档 + + + +
+
+ +

本地前端工作台设计文档

+
Dashboard-local mirror of the UI and interaction specification. | source: docs/frontend-dashboard-design.md
+
# 本地前端工作台设计文档
+
+> `LAB ONLY` | `AUTHORIZED TARGETS ONLY`
+
+## 1. 设计目标
+
+本地 dashboard 要从“简单索引页”升级成“完整的授权攻防实证工作台”。它需要同时满足三类使用场景:
+
+1. 运行中观察
+   - 看当前 run 进度
+   - 看失败原因和阻塞点
+   - 实时打开日志和证据
+2. 复盘分析
+   - 查看 timeline、思路、利用路径、来源与修复主题
+   - 对比真实版本与 synthetic 复现差异
+3. 审阅归档
+   - 从一个前端入口点进 `report.md`, `report.html`, `run.json`, 原始日志和截图
+
+## 2. 页面定位
+
+### 2.1 页面名称
+
+- 页面名称:`Authorized Lab Dashboard`
+- 页面语境:本地静态前端 + 本地文件 JSON 数据源
+- 非目标:在线 SaaS、多用户后端、生产管理台
+
+### 2.2 核心原则
+
+- 所有展示都围绕授权目标
+- 失败信息不能被隐藏在深层页面里
+- 信息密度高,但必须可折叠、可筛选、可逐层展开
+- 日志与原始 JSON 必须能直接预览
+- 页面视觉应更生动,但不能牺牲扫描效率
+
+## 3. 信息架构
+
+```mermaid
+flowchart LR
+  A["Hero + Global Status"] --> B["Sidebar Filters"]
+  A --> C["Run Queue List"]
+  C --> D["Run Detail Hero"]
+  D --> E["Progress Timeline"]
+  D --> F["Attack Plan & Reasoning"]
+  D --> G["Evidence Explorer"]
+  D --> H["Live Log Viewer"]
+  D --> I["Sources & Fix Topics"]
+  D --> J["Raw JSON Panels"]
+```
+
+## 4. 页面布局
+
+### 4.1 顶部 Hero
+
+必须展示:
+
+- 页面名称
+- 授权实验语境说明
+- 刷新按钮
+- 自动刷新开关
+- 当前同步状态
+- 核心 metric cards
+
+视觉要求:
+
+- 不能是纯白表格页
+- 需要有分层背景、渐变光晕、轻微动态氛围
+- 顶栏 sticky,滚动时仍可看到刷新和状态
+
+### 4.2 左侧侧栏
+
+包含四块:
+
+- Filters
+  - 搜索
+  - system filter
+  - status filter
+  - profile filter
+- Systems
+  - 系统覆盖度
+  - browser evidence 覆盖
+  - latest update
+- Recent Failures
+  - 最近 blocker
+  - status
+  - 原因摘要
+- Run Queue View
+  - 最近 run 卡片列表
+  - 可选中并切换到 detail panel
+
+### 4.3 右侧 Detail Workspace
+
+必须包含:
+
+- Run Hero
+  - advisory 标题
+  - system / profile / artifact / verification 状态
+  - report / bundle / markdown 入口
+- Progress Timeline
+  - 每一步的时间、状态、说明
+- Attack Plan & Reasoning
+  - success criteria
+  - seed / attack notes
+  - failure reason
+  - 当前 blocker
+- Evidence Explorer
+  - reports
+  - compose
+  - browser evidence
+  - request logs
+  - container logs
+- Live Log Viewer
+  - 预览 text/json/html/image
+  - refresh preview
+  - open artifact
+- Sources & Fix Topics
+  - official source
+  - secondary sources
+  - aliases
+  - secure code topics
+- Raw JSON
+  - run JSON
+  - advisory JSON
+  - profile JSON
+
+## 5. 交互要求
+
+### 5.1 折叠 / 展开
+
+所有 detail 分区都应支持折叠:
+
+- Progress Timeline
+- Attack Plan & Reasoning
+- Evidence Explorer
+- Live Log Viewer
+- Sources & Fix Topics
+- Raw JSON sections
+
+折叠要求:
+
+- 默认展开常用分区
+- 次级原始数据可以默认收起
+- 折叠状态视觉要清晰,不靠小箭头弱提示
+
+### 5.2 Run 切换
+
+- 点击左侧 run card 后,右侧 detail panel 即时刷新
+- 当前选中项要有强视觉区别
+- URL hash 应保留 `#run=<id>`,方便直接打开特定 run
+
+### 5.3 Artifact 预览
+
+点击 artifact button 后:
+
+- JSON 自动格式化
+- 日志文件以 `<pre>` 方式显示
+- 图片以内联方式展示
+- HTML 报告可 iframe 预览或新窗口打开
+
+### 5.4 自动刷新
+
+- 默认每 5 秒刷新一次 dashboard JSON
+- 用户可以关闭自动刷新
+- 当前正在查看的 artifact 在自动刷新开启时应支持重新抓取
+
+### 5.5 失败原因高亮
+
+对于 `blocked-*` 和 `triage-manual`:
+
+- 顶部 hero 要显示状态 pill
+- reasoning 面板要显示 failure callout
+- 左侧 Recent Failures 要保留最近失败摘要
+
+## 6. 展示字段清单
+
+### 6.1 Hero 区
+
+- run_id
+- advisory_id
+- advisory title
+- verification_status
+- verification_mode
+- artifact_mode
+- system_id
+- repro_profile_id
+- finished_at
+
+### 6.2 Timeline 区
+
+- `timeline[].at`
+- `timeline[].step`
+- `timeline[].status`
+- `timeline[].detail`
+
+### 6.3 Reasoning 区
+
+- advisory summary
+- profile seed messages
+- profile attack messages
+- profile success criteria
+- blocked reason
+
+### 6.4 Sources 区
+
+- official_source_url
+- secondary_source_urls
+- aliases
+- secure_code_topics
+
+### 6.5 Evidence 区
+
+- report.html
+- report.md
+- timeline.mmd
+- bundle json
+- compose.yaml
+- browser screenshots / DOM / console / network
+- request logs
+- container logs
+
+## 7. 动效与视觉要求
+
+### 7.1 必须有的视觉增强
+
+- 顶部背景渐变和环境光
+- status pill 发光色彩区分
+- 卡片 hover 浮起
+- sticky hero
+- 折叠面板开合层次
+- gallery 缩略图点击查看
+
+### 7.2 推荐但必须受控
+
+- 状态小圆点 pulse
+- 背景网格或轻微数据面纹理
+- 面板玻璃感和浅透视阴影
+
+### 7.3 不允许
+
+- 花哨但影响可读性的动画
+- 大面积纯装饰 3D 效果
+- 自动播放噪音式动效
+- 让日志区难以复制文本的视觉处理
+
+## 8. 实时日志与细节查看要求
+
+### 8.1 日志查看器
+
+日志查看器必须支持:
+
+- 选中文件后即刻预览
+- JSON 格式化
+- text/json/html/image 四类预览
+- 打开原文件
+- 在自动刷新开启时重新抓取当前文件
+
+### 8.2 重点要看的日志
+
+- compose / environment 文件
+- baseline / attack / browser json
+- container logs
+- request logs
+- timeline / bundle
+
+### 8.3 失败排查导向
+
+失败时应优先展示:
+
+- `blocked_reason`
+- 当前 step
+- 上一个完成 step
+- 当前可打开的日志 / 报告 / run bundle
+- 对应 advisory 来源与 profile success criteria
+
+## 9. 数据源契约
+
+前端依赖的本地 JSON/文件源:
+
+- `summary.json`
+- `runs.json`
+- `systems.json`
+- `advisories.json`
+- `profiles.json`
+- `runs/<run-id>/report.html`
+- `runs/<run-id>/report.md`
+- `runs/<run-id>/run.json`
+- `runs/<run-id>/logs/*`
+- `runs/<run-id>/assets/*`
+
+前端不直接写这些数据,只读取并展示。
+
+## 10. 落地约束
+
+- 保持静态前端,不引入长期运行后端
+- 本地 `serve-dashboard` 即可查看
+- 对于正在跑的 case,前端通过轮询读取新 JSON 实现“近实时”
+- 不依赖第三方 CDN UI 库
+- 优先使用原生 HTML/CSS/JS,可长期维护
+
+## 11. 验收标准
+
+页面完成后,应满足:
+
+- 能从 run list 切换到 detail panel
+- 能折叠与展开各信息区
+- 能打开并预览 JSON / text / image / html artifact
+- 能看到失败原因、思路、来源、修复主题
+- 能筛选 system / status / profile
+- 能在自动刷新开启时重新载入 dashboard 数据
+- 页面视觉比“普通表格页”更生动,但仍适合高密度阅读
+
+
+
+ + diff --git a/08-threat-intel/generated/dashboard/docs/project-features.html b/08-threat-intel/generated/dashboard/docs/project-features.html new file mode 100644 index 00000000..59bca206 --- /dev/null +++ b/08-threat-intel/generated/dashboard/docs/project-features.html @@ -0,0 +1,255 @@ + + + + + + 项目功能与特性总览 + + + +
+
+ +

项目功能与特性总览

+
Dashboard-local mirror of the repo feature guide. | source: docs/project-features.md
+
# 项目功能与特性总览
+
+> `LAB ONLY` | `AUTHORIZED TARGETS ONLY`
+
+## 1. 项目定位
+
+`websafe` 是一套“授权攻防实验与研究知识库 + 本地实证系统”。它不是生产安全基线库,也不是面向任意第三方站点的扫描平台。
+
+项目覆盖:
+
+- 本地靶场、Docker 集群、内网实验节点
+- 自建且可公网访问的测试网站、服务器、设备
+- 已明确授权的验证性测试目标
+
+项目不覆盖:
+
+- 无归属证明、无授权的公网资产
+- 公共知名网站
+- 泛互联网画像、枚举、对外大规模探测
+
+## 2. 功能版图
+
+### 2.1 情报与入库
+
+- `08-threat-intel/source-map.yaml`
+  - 定义系统范围、来源、覆盖策略、输出目录、secure-code 主题
+- `08-threat-intel/repro-map.yaml`
+  - 定义系统到 repro family、浏览器要求、日志策略和报告模板的映射
+- `08-threat-intel/repro-profiles/`
+  - family 级和 advisory 级复现说明
+- `08-threat-intel/registry/`
+  - advisory、system、run、triage 的唯一真值层
+- `08-threat-intel/generated/`
+  - coverage matrix、latest ingest、dashboard 等人类可读产物
+
+### 2.2 本地实证与编排
+
+- `00-environments/catalog/`
+  - 记录系统、镜像、源码、依赖和健康检查的 catalog
+- `00-environments/profiles/`
+  - 记录具体版本或 current profile 的 compose / baseline / seed 参数
+- `scripts/lab/main.py`
+  - 唯一 lab CLI 入口
+- `scripts/lab/`
+  - `catalog`, `provision`, `compose`, `seed`, `baseline`, `attack`, `browser`, `evidence`, `render`, `queue`, `validators`
+
+### 2.3 攻击验证工具
+
+- `01-sql-injection/`
+  - `sqli-scanner.py`, `blind-sqli.py`, `sqli-exploit.go`
+- `02-xss/`
+  - `xss-fuzzer.py`, `xss-scanner.go`
+- `03-authentication/`
+  - `web-brute.py`, `jwt-cracker.py`, `session-lab.py`
+- `04-server-security/`
+  - `port-scanner.py`, `tls-scanner.py`, `site-scope-mapper.py`, `misconfig-lab.py`
+
+### 2.4 结果展示
+
+- `06-case-studies/generated-runs/<run-id>/`
+  - `report.md`, `report.html`, `timeline.mmd`, `assets/`, `logs/`
+- `08-threat-intel/generated/dashboard/`
+  - 静态前端工作台
+- `07-framework-security/`
+  - 系统级 README、INDEX、案例页,自动显示本地实证状态
+
+## 3. 数据流与自动化链路
+
+```mermaid
+flowchart LR
+  A["Threat Intel Sources"] --> B["registry/advisories"]
+  B --> C["repro-map + repro-profiles"]
+  C --> D["00-environments catalog/profiles"]
+  D --> E["scripts/lab run-case / run-batch"]
+  E --> F["generated-runs/<run-id>"]
+  F --> G["registry/runs"]
+  G --> H["case pages / system INDEX"]
+  G --> I["dashboard JSON + local UI"]
+  H --> J["README / docs / PR"]
+  I --> J
+```
+
+## 4. 关键特性
+
+### 4.1 完整覆盖语义
+
+- 每条 advisory 至少进入 `registry/advisories`
+- 每条 advisory 必须有明确的实证状态
+- 状态只允许:
+  - `verified-real`
+  - `verified-synthetic`
+  - `blocked-artifact`
+  - `blocked-destructive`
+  - `triage-manual`
+
+### 4.2 浏览器证据强制
+
+- XSS、DOM XSS、Token 存储、前端路由绕过、前端配置暴露等浏览器类 case
+  - 必须生成截图
+  - 必须生成 DOM 快照
+  - 必须生成 console / network 证据
+  - 没有浏览器证据不得升级为 `verified-*`
+
+### 4.3 受控攻击语义
+
+- 默认模式是 `minimal-proof`
+- 只读探测、最小化注入、可审计回显、可回滚验证
+- 破坏性利用、越权下载真实数据、不可回滚行为默认禁用
+
+### 4.4 双展示面
+
+- 静态归档报告
+  - 适合证据留存、归档、PR 审阅
+- 本地前端工作台
+  - 适合实时查看进度、日志、失败原因、来源、思路、截图和原始 JSON
+
+### 4.5 自动化提交
+
+- `scripts/intel/run-hourly.sh`
+  - hotlane ingest + hotlane repro
+- `scripts/intel/run-nightly.sh`
+  - 常规 ingest + batch repro + render + validate + PR
+- `scripts/intel/run-weekly-reconcile.sh`
+  - reconcile + retry failures + rerender + validate + PR
+
+## 5. CLI 能力
+
+### 5.1 Intel CLI
+
+```bash
+python3 /Users/x/websafe/scripts/intel/main.py hotlane
+python3 /Users/x/websafe/scripts/intel/main.py ingest --since last-success
+python3 /Users/x/websafe/scripts/intel/main.py reconcile
+python3 /Users/x/websafe/scripts/intel/main.py render
+python3 /Users/x/websafe/scripts/intel/main.py validate
+python3 /Users/x/websafe/scripts/intel/main.py open-pr --dry-run
+```
+
+### 5.2 Lab CLI
+
+```bash
+python3 /Users/x/websafe/scripts/lab/main.py catalog sync
+python3 /Users/x/websafe/scripts/lab/main.py validate
+python3 /Users/x/websafe/scripts/lab/main.py run-case --case gitea--CVE-2025-68939
+python3 /Users/x/websafe/scripts/lab/main.py run-case --case nextjs--CVE-2025-29927 --dry-run
+python3 /Users/x/websafe/scripts/lab/main.py run-batch --limit 10
+python3 /Users/x/websafe/scripts/lab/main.py serve-dashboard --port 8734
+```
+
+## 6. 前端工作台当前目标
+
+前端不只是“一个结果页”,而是本地实验控制台与证据阅读器。它需要:
+
+- 快速定位系统 / advisory / repro profile
+- 折叠与展开 timeline、evidence、sources、raw JSON
+- 直接查看 compose、JSON、日志、截图、报告
+- 高亮失败原因、当前 blocker、利用思路、成功判据
+- 自动刷新生成数据,适配正在进行中的本地 run
+
+详细设计见:
+
+- [本地前端工作台设计文档](/Users/x/websafe/docs/frontend-dashboard-design.md)
+
+
+
+ + diff --git a/08-threat-intel/generated/dashboard/docs/secure-code-index.html b/08-threat-intel/generated/dashboard/docs/secure-code-index.html new file mode 100644 index 00000000..c33a4148 --- /dev/null +++ b/08-threat-intel/generated/dashboard/docs/secure-code-index.html @@ -0,0 +1,108 @@ + + + + + + 安全编码修复库索引 + + + +
+
+ +

安全编码修复库索引

+
Dashboard-local mirror of the secure-code library index. | source: 05-defense/secure-code/INDEX.md
+
# 安全编码修复库
+
+> `LAB ONLY` | 修复主题用于把实验发现映射回代码整改,不代表默认生产基线。
+
+- 语言范围: `javascript-typescript`, `nodejs`, `java`, `php`, `python`, `ruby`, `csharp`, `go`
+- 主题范围: 输出编码、DOM sink、CSP / Trusted Types、令牌存储、鉴权复核、SSRF、走私边界、路径穿越、文件上传、插件信任、依赖升级、代理信任、反序列化、模板注入。
+
+- [javascript-typescript](/Users/x/websafe/05-defense/secure-code/javascript-typescript/README.md)
+- [nodejs](/Users/x/websafe/05-defense/secure-code/nodejs/README.md)
+- [java](/Users/x/websafe/05-defense/secure-code/java/README.md)
+- [php](/Users/x/websafe/05-defense/secure-code/php/README.md)
+- [python](/Users/x/websafe/05-defense/secure-code/python/README.md)
+- [ruby](/Users/x/websafe/05-defense/secure-code/ruby/README.md)
+- [csharp](/Users/x/websafe/05-defense/secure-code/csharp/README.md)
+- [go](/Users/x/websafe/05-defense/secure-code/go/README.md)
+
+
+
+ + diff --git a/08-threat-intel/generated/dashboard/index.html b/08-threat-intel/generated/dashboard/index.html index 8cdf32bd..3bbf6390 100644 --- a/08-threat-intel/generated/dashboard/index.html +++ b/08-threat-intel/generated/dashboard/index.html @@ -19,6 +19,7 @@ Open Summary JSON + Open Feature Docs
diff --git a/08-threat-intel/generated/dashboard/runs.json b/08-threat-intel/generated/dashboard/runs.json index 9820e0a9..fd5826b6 100644 --- a/08-threat-intel/generated/dashboard/runs.json +++ b/08-threat-intel/generated/dashboard/runs.json @@ -272,6 +272,11 @@ "timeline": "./runs/gitea-gitea--CVE-2025-68939-20260317063330/timeline.mmd", "bundle": "./runs/gitea-gitea--CVE-2025-68939-20260317063330/run.json" }, + "browser_evidence": { + "required": false, + "present": false, + "refs": [] + }, "browser_links": [], "container_links": [], "request_links": [ @@ -462,6 +467,11 @@ "timeline": "./runs/nextjs-nextjs--CVE-2025-29927-20260317063047/timeline.mmd", "bundle": "./runs/nextjs-nextjs--CVE-2025-29927-20260317063047/run.json" }, + "browser_evidence": { + "required": false, + "present": false, + "refs": [] + }, "browser_links": [], "container_links": [], "request_links": [ @@ -591,20 +601,27 @@ } ] }, + { + "key": "baseline", + "label": "Baseline Snapshots", + "count": 1, + "items": [ + { + "href": "./runs/nextjs-nextjs--CVE-2025-29927-20260317063047/logs/baseline.json", + "label": "baseline.json", + "kind": "text" + } + ] + }, { "key": "requests", "label": "Request Logs", - "count": 2, + "count": 1, "items": [ { "href": "./runs/nextjs-nextjs--CVE-2025-29927-20260317063047/logs/attack.json", "label": "attack.json", "kind": "text" - }, - { - "href": "./runs/nextjs-nextjs--CVE-2025-29927-20260317063047/logs/baseline.json", - "label": "baseline.json", - "kind": "text" } ] } diff --git a/08-threat-intel/generated/dashboard/summary.json b/08-threat-intel/generated/dashboard/summary.json index 0deefa04..a2eccfaa 100644 --- a/08-threat-intel/generated/dashboard/summary.json +++ b/08-threat-intel/generated/dashboard/summary.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-03-17T07:27:25+00:00", + "generated_at": "2026-03-17T07:36:43+00:00", "advisory_count": 89, "run_count": 3, "statuses": { diff --git a/08-threat-intel/generated/latest-ingest.md b/08-threat-intel/generated/latest-ingest.md index e5be00b1..7747faf4 100644 --- a/08-threat-intel/generated/latest-ingest.md +++ b/08-threat-intel/generated/latest-ingest.md @@ -1,6 +1,6 @@ # 最新同步摘要 -- 渲染时间: `2026-03-17T07:27:25+00:00` +- 渲染时间: `2026-03-17T07:36:11+00:00` - 系统数量: `62` - Advisory 数量: `89` - 重点 Markdown 数量: `89` diff --git a/08-threat-intel/generated/run-summary.json b/08-threat-intel/generated/run-summary.json index 9d59a02d..677f2cd9 100644 --- a/08-threat-intel/generated/run-summary.json +++ b/08-threat-intel/generated/run-summary.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-03-17T07:27:25+00:00", + "generated_at": "2026-03-17T07:36:11+00:00", "system_count": 62, "advisory_count": 89, "markdown_count": 89, diff --git a/scripts/intel/validators.py b/scripts/intel/validators.py index 4b082eda..2dff384f 100644 --- a/scripts/intel/validators.py +++ b/scripts/intel/validators.py @@ -89,6 +89,9 @@ def validate(source_map: Dict[str, Any]) -> List[str]: GENERATED_DIR / "dashboard" / "profiles.json", GENERATED_DIR / "dashboard" / "assets" / "app.js", GENERATED_DIR / "dashboard" / "assets" / "styles.css", + GENERATED_DIR / "dashboard" / "docs" / "project-features.html", + GENERATED_DIR / "dashboard" / "docs" / "frontend-dashboard-design.html", + GENERATED_DIR / "dashboard" / "docs" / "secure-code-index.html", ROOT / "08-threat-intel" / "registry" / "source-confidence.md", ]: if not path.exists(): diff --git a/scripts/lab/render.py b/scripts/lab/render.py index d07cd9cf..206296b1 100644 --- a/scripts/lab/render.py +++ b/scripts/lab/render.py @@ -5,7 +5,7 @@ import os from pathlib import Path from typing import Any, Dict, List -from lab.config import ADVISORIES_DIR, CASE_RUNS_DIR, DASHBOARD_DIR, RUNS_DIR +from lab.config import ADVISORIES_DIR, CASE_RUNS_DIR, DASHBOARD_DIR, ROOT, RUNS_DIR from lab.repro import load_profiles from lab.utils import ensure_dir, isoformat, load_json_dir, now_utc, unique, write_json, write_text @@ -72,6 +72,15 @@ def _artifact_group(run: Dict[str, Any], key: str, label: str, refs: List[str], } +def _attack_result_refs(run: Dict[str, Any]) -> List[str]: + refs: List[str] = [] + for step in run.get("attack_steps", []): + result_path = step.get("result_path") + if result_path: + refs.append(str(result_path)) + return unique(refs) + + def _progress_counts(run: Dict[str, Any]) -> Dict[str, int]: counts = {"completed": 0, "skipped": 0, "failed": 0, "blocked": 0, "planned": 0, "other": 0} for item in run.get("timeline", []): @@ -148,6 +157,132 @@ def _reasoning_lines(advisory: Dict[str, Any], profile: Dict[str, Any]) -> List[ return unique(notes) +def _dashboard_doc_page(title: str, source_path: Path, description: str) -> str: + source_label = source_path.relative_to(ROOT) if source_path.is_relative_to(ROOT) else source_path + body = source_path.read_text(encoding="utf-8") if source_path.exists() else f"missing source: {source_path}" + return f""" + + + + + {html.escape(title)} + + + +
+
+ +

{html.escape(title)}

+
{html.escape(description)} | source: {html.escape(str(source_label))}
+
{html.escape(body)}
+
+
+ + +""" + + +def _write_dashboard_docs() -> None: + docs_dir = DASHBOARD_DIR / "docs" + ensure_dir(docs_dir) + docs = [ + ( + "project-features.html", + "项目功能与特性总览", + ROOT / "docs" / "project-features.md", + "Dashboard-local mirror of the repo feature guide.", + ), + ( + "frontend-dashboard-design.html", + "本地前端工作台设计文档", + ROOT / "docs" / "frontend-dashboard-design.md", + "Dashboard-local mirror of the UI and interaction specification.", + ), + ( + "secure-code-index.html", + "安全编码修复库索引", + ROOT / "05-defense" / "secure-code" / "INDEX.md", + "Dashboard-local mirror of the secure-code library index.", + ), + ] + for filename, title, source_path, description in docs: + write_text(docs_dir / filename, _dashboard_doc_page(title, source_path, description)) + + def render_run(run: Dict[str, Any]) -> Dict[str, str]: run_dir = CASE_RUNS_DIR / run["run_id"] ensure_dir(run_dir / "assets") @@ -310,6 +445,7 @@ def render_run(run: Dict[str, Any]) -> Dict[str, str]: def render_dashboard() -> Dict[str, str]: ensure_dir(DASHBOARD_DIR) + _write_dashboard_docs() advisory_records = load_json_dir(ADVISORIES_DIR) runs = load_json_dir(RUNS_DIR) advisory_map = {item["canonical_id"]: item for item in advisory_records if item.get("canonical_id")} @@ -378,12 +514,19 @@ def render_dashboard() -> Dict[str, str]: cloned = dict(item) advisory = advisory_map.get(item["advisory_id"], {}) profile = profile_map.get(item["repro_profile_id"], {}) + browser_evidence = item.get("browser_evidence") or advisory.get("browser_evidence") or { + "required": bool(profile.get("browser_assertions", {}).get("required")), + "present": False, + "refs": [], + } + request_only_refs = [ref for ref in item.get("request_log_refs", []) if ref not in item.get("baseline_refs", [])] cloned["dashboard_refs"] = { "report_html": f"./runs/{item['run_id']}/report.html", "report_md": f"./runs/{item['run_id']}/report.md", "timeline": f"./runs/{item['run_id']}/timeline.mmd", "bundle": f"./runs/{item['run_id']}/run.json", } + cloned["browser_evidence"] = browser_evidence cloned["browser_links"] = [_dashboard_ref(item, ref) for ref in item.get("browser_refs", [])] cloned["container_links"] = [_dashboard_ref(item, ref) for ref in item.get("container_log_refs", [])] cloned["request_links"] = [_dashboard_ref(item, ref) for ref in item.get("request_log_refs", [])] @@ -405,9 +548,11 @@ def render_dashboard() -> Dict[str, str]: use_dashboard_refs=True, ), _artifact_group(item, "compose", "Compose", item.get("compose_refs", [])), + _artifact_group(item, "baseline", "Baseline Snapshots", item.get("baseline_refs", [])), + _artifact_group(item, "attack", "Attack Outputs", _attack_result_refs(item)), _artifact_group(item, "browser", "Browser Evidence", item.get("browser_refs", [])), _artifact_group(item, "container", "Container Logs", item.get("container_log_refs", [])), - _artifact_group(item, "requests", "Request Logs", item.get("request_log_refs", [])), + _artifact_group(item, "requests", "Request Logs", request_only_refs), ] cloned["artifact_groups"] = [group for group in cloned["artifact_groups"] if group["count"]] decorated_runs.append(cloned) @@ -842,6 +987,70 @@ button, input, select { gap: 18px; } +.progress-strip { + display: grid; + gap: 12px; + margin-bottom: 16px; +} + +.progress-bar { + display: flex; + width: 100%; + min-height: 12px; + overflow: hidden; + border-radius: 999px; + background: rgba(255,255,255,0.08); + border: 1px solid rgba(159, 179, 202, 0.14); +} + +.progress-segment { + min-width: 10px; + transition: width 180ms ease; +} + +.progress-completed { background: linear-gradient(90deg, rgba(110, 231, 165, 0.9), rgba(94, 234, 212, 0.9)); } +.progress-blocked { background: linear-gradient(90deg, rgba(255, 123, 123, 0.95), rgba(255, 160, 122, 0.9)); } +.progress-failed { background: linear-gradient(90deg, rgba(255, 123, 123, 0.92), rgba(255, 209, 102, 0.88)); } +.progress-skipped { background: linear-gradient(90deg, rgba(255,255,255,0.22), rgba(159, 179, 202, 0.3)); } +.progress-planned { background: linear-gradient(90deg, rgba(144, 205, 244, 0.82), rgba(94, 234, 212, 0.72)); } +.progress-other { background: linear-gradient(90deg, rgba(255,255,255,0.18), rgba(255,255,255,0.1)); } + +.progress-legend { + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.progress-legend .tag { + gap: 7px; +} + +.progress-legend .swatch { + width: 10px; + height: 10px; + border-radius: 999px; + display: inline-block; +} + +.stage-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 12px; + margin-bottom: 18px; +} + +.stage-card { + padding: 14px; + border-radius: 16px; + background: rgba(255,255,255,0.04); + border: 1px solid rgba(159, 179, 202, 0.16); +} + +.stage-card strong { + display: block; + margin-bottom: 10px; +} + .accordion { overflow: hidden; } @@ -1278,6 +1487,7 @@ function renderRunList() { const active = item.run_id === state.selectedRunId ? "is-active" : ""; const title = item.advisory_meta?.title || item.advisory_id; const reasoning = item.reasoning_lines?.[0] || item.blocked_reason || ""; + const browserLabel = item.browser_evidence?.present ? "ready" : (item.browser_evidence?.required ? "required" : "n/a"); return ` @@ -1343,7 +1553,7 @@ function hydrateFilterOptions() { } function defaultArtifact(run) { - const preference = ["requests", "container", "browser", "compose", "reports"]; + const preference = ["attack", "requests", "container", "browser", "baseline", "compose", "reports"]; for (const key of preference) { const group = (run.artifact_groups || []).find((item) => item.key === key && item.items?.length); if (!group) continue; @@ -1353,6 +1563,73 @@ function defaultArtifact(run) { return null; } +function totalProgress(progress) { + const values = Object.values(progress || {}).map((value) => Number(value || 0)); + return values.reduce((sum, value) => sum + value, 0); +} + +function renderProgressStrip(progress) { + const total = totalProgress(progress); + if (!total) { + return ` +
+
+
No timeline progress recorded.
+
+ `; + } + const order = [ + ["completed", "Completed", "progress-completed"], + ["blocked", "Blocked", "progress-blocked"], + ["failed", "Failed", "progress-failed"], + ["skipped", "Skipped", "progress-skipped"], + ["planned", "Planned", "progress-planned"], + ["other", "Other", "progress-other"], + ]; + const segments = order + .filter(([key]) => Number(progress?.[key] || 0) > 0) + .map(([key, _label, klass]) => { + const count = Number(progress?.[key] || 0); + const pct = Math.max((count / total) * 100, 4); + return `
`; + }) + .join(""); + const legend = order + .filter(([key]) => Number(progress?.[key] || 0) > 0) + .map(([key, label, klass]) => ` + + + ${escapeHtml(label)} ${escapeHtml(progress?.[key] || 0)} + + `) + .join(""); + return ` +
+
${segments}
+
${legend}
+
+ `; +} + +function renderStageCards(run) { + const timeline = run.timeline || []; + if (!timeline.length) { + return `
No stage records available.
`; + } + return ` +
+ ${timeline.map((item) => ` +
+ ${escapeHtml(item.step || "-")} +
${escapeHtml(item.status || "unknown")}
+
${escapeHtml(item.detail || "-")}
+
${escapeHtml(item.at || "-")}
+
+ `).join("")} +
+ `; +} + async function openArtifact(href, label, kind) { state.selectedArtifact = { href, label, kind }; document.querySelectorAll(".artifact-button").forEach((button) => { @@ -1409,6 +1686,7 @@ function renderDetail() { ${escapeHtml(run.repro_profile_id)} ${escapeHtml(run.artifact_mode)} ${escapeHtml(run.verification_mode)} + ${escapeHtml(run.target_env || "local-docker")}

${escapeHtml(advisory.title || run.advisory_id)}

@@ -1417,11 +1695,12 @@ function renderDetail() { Open HTML report Open Markdown Open run JSON + Open UI spec
Timeline Steps${escapeHtml(run.timeline?.length || 0)}
Artifacts${escapeHtml((run.artifact_groups || []).reduce((sum, group) => sum + group.count, 0))}
-
Browser${run.browser_evidence?.present ? "Ready" : "Missing"}
+
Browser${run.browser_evidence?.present ? "Ready" : (run.browser_evidence?.required ? "Required" : "Optional")}
Finished${escapeHtml(timeAgo(run.finished_at))}
@@ -1431,12 +1710,8 @@ function renderDetail() {
Progress Timeline${escapeHtml(run.timeline?.length || 0)} steps
-
- completed ${escapeHtml(run.progress?.completed || 0)} - blocked ${escapeHtml(run.progress?.blocked || 0)} - skipped ${escapeHtml(run.progress?.skipped || 0)} - failed ${escapeHtml(run.progress?.failed || 0)} -
+ ${renderProgressStrip(run.progress)} + ${renderStageCards(run)}
${(run.timeline || []).map((item) => `
@@ -1533,7 +1808,7 @@ function renderDetail() { ${(advisory.secondary_source_urls || []).map((ref) => `${escapeHtml(ref)}`).join("")}
- ${(advisory.secure_code_topics || []).map((topic) => `${escapeHtml(topic)}`).join("")} + ${(advisory.secure_code_topics || []).map((topic) => `${escapeHtml(topic)}`).join("")}
@@ -1638,6 +1913,7 @@ document.addEventListener("DOMContentLoaded", init); Open Summary JSON + Open Feature Docs