From d31b851fd59da3ae93bea5ce19ed42d77e8128c8 Mon Sep 17 00:00:00 2001 From: hannahwestra25 Date: Wed, 16 Sep 2026 15:36:02 -0400 Subject: [PATCH] FEAT: Add metrics dashboard (scorer quality + benchmark leaderboard) to adversarial dataset branch Transplants the dashboard-only work from PR #2667 (hannahwestra25-metrics-dashboard) onto this branch's already-integrated benchmark-store/cache-reuse/pipeline-automation work from PR #2551, producing a single hackathon-demo branch with the full data -> pipeline -> committed store -> dashboard loop. Brings over, unchanged from #2667: - doc/dashboard/ (0_dashboard.md, 1_scorer_quality.md, 2_benchmark_leaderboard.md, and the committed _generated/*.html fragments) - build_scripts/generate_dashboard_html.py (renders the committed JSONL/scorer_evals data into the static HTML fragments the docs pages include) - build_scripts/import_adversarial_benchmark_snapshot.py + its test (manual fallback to upsert a technique-metrics.json snapshot, e.g. downloaded from an ADO pipeline artifact, when the scenario result isn't in local memory) - pyrit/datasets/benchmark_results/adversarial_benchmark_metrics.jsonl seeded with real ADO-ingested demo data - doc/myst.yml (nav entry) and pyrit/common/path.py (BENCHMARK_RESULTS_PATH constant) Deliberately NOT brought over: the exporter identity-fields/cache-reuse logic and scenario/pipeline changes from #2667's f973f5e69, since this branch already has its own, more advanced version of that same logic (55bece4a1, cherry-picked earlier from f973f5e69 and reconciled against this branch's dynamic BenchmarkTechnique registry). Re-applying #2667's version here would conflict with and regress that integration. Also updates 0_dashboard.md's "Refreshing the data" section: it previously said there was no CI automation for the benchmark store; this branch's pipeline now has an opt-in publishBenchmarkStore parameter that runs the exporter and opens a PR automatically, so the doc now describes that path alongside the fully-manual one. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- build_scripts/generate_dashboard_html.py | 287 ++++++++++++++++++ .../import_adversarial_benchmark_snapshot.py | 171 +++++++++++ doc/dashboard/0_dashboard.md | 116 +++++++ doc/dashboard/1_scorer_quality.md | 39 +++ doc/dashboard/2_benchmark_leaderboard.md | 41 +++ .../_generated/benchmark_leaderboard.html | 50 +++ .../_generated/harm_scorer_leaderboard.html | 50 +++ .../objective_scorer_leaderboard.html | 50 +++ doc/myst.yml | 4 + pyrit/common/path.py | 4 + .../adversarial_benchmark_metrics.jsonl | 9 + ...t_import_adversarial_benchmark_snapshot.py | 232 ++++++++++++++ 12 files changed, 1053 insertions(+) create mode 100644 build_scripts/generate_dashboard_html.py create mode 100644 build_scripts/import_adversarial_benchmark_snapshot.py create mode 100644 doc/dashboard/0_dashboard.md create mode 100644 doc/dashboard/1_scorer_quality.md create mode 100644 doc/dashboard/2_benchmark_leaderboard.md create mode 100644 doc/dashboard/_generated/benchmark_leaderboard.html create mode 100644 doc/dashboard/_generated/harm_scorer_leaderboard.html create mode 100644 doc/dashboard/_generated/objective_scorer_leaderboard.html create mode 100644 pyrit/datasets/benchmark_results/adversarial_benchmark_metrics.jsonl create mode 100644 tests/unit/build_scripts/test_import_adversarial_benchmark_snapshot.py diff --git a/build_scripts/generate_dashboard_html.py b/build_scripts/generate_dashboard_html.py new file mode 100644 index 0000000000..a294132a52 --- /dev/null +++ b/build_scripts/generate_dashboard_html.py @@ -0,0 +1,287 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT license. + +""" +Generate the static HTML leaderboard fragments used by the metrics dashboard docs pages. + +The dashboard pages under `doc/dashboard/` are plain MyST Markdown files that `{include}` +pre-rendered HTML fragments rather than notebooks, so no Python source is shown to readers. +This script renders those fragments from the committed scorer/benchmark evaluation data and +writes them to `doc/dashboard/_generated/`. Re-run it and commit the output whenever the +underlying `pyrit/datasets/scorer_evals/` or `pyrit/datasets/benchmark_results/` data changes. + +Usage: + python -m build_scripts.generate_dashboard_html +""" + +import asyncio +import html +import sys +from typing import TYPE_CHECKING + +from pyrit.common.path import DOCS_PATH + +if TYPE_CHECKING: + import pandas as pd + +_OUTPUT_DIR = DOCS_PATH / "dashboard" / "_generated" + +# Static (non-interactive) dark leaderboard-card styling shared by every card this script +# renders. MyST includes each fragment's raw HTML directly into the page DOM (no