Skip to content

feat(report): visualize snapshot benchmark metrics - #207

Draft
meyer9 wants to merge 10 commits into
mainfrom
meyer9/snapshot-benchmark-visualizer
Draft

feat(report): visualize snapshot benchmark metrics#207
meyer9 wants to merge 10 commits into
mainfrom
meyer9/snapshot-benchmark-visualizer

Conversation

@meyer9

@meyer9 meyer9 commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add a local report API for snapshot benchmark result bundles
  • import relative per-run block numbers and role-specific Prometheus diagnostics
  • add charts for canonical throughput, builder, validator, txpool, and scrape-span metrics
  • preserve compatibility with bundles emitted directly by base/base's snapshot benchmark CLI

Companion to base/base#4180.

Validation

  • yarn prettier --check src/metricDefinitions.ts
  • yarn build
  • imported and rendered matched-duration 2s and 200ms sequential sequencer/validator runs

meyer9 and others added 9 commits July 28, 2026 10:25
Adds server/ — an HTTP server that replaces the per-environment static
metadata.json with a dynamically assembled response fetched directly
from per-run S3 files. This moves the aggregation, retention, and
comparison-synthesis logic into the open-source base/benchmark repo.

There is no central metadata file. The server:
- Lists all <outputDir>/metadata.json objects in S3 (one per run)
- Merges, deduplicates, and applies retention policy
- Appends synthetic [Compare: Time] and [Compare: Versions] groups
  so the existing report UI can compare runs across time windows
  or client versions without any frontend change
- Caches aggressively: per-file by ETag (invalidated when a run is
  rewritten), merged result by object fingerprint + 1h TTL
  (handles time.Now() dependence in retention/comparison)

The server is a straight port of protocols/base-benchmarking's
report-api, updated to use the per-run-directory S3 layout (#66 in
base-benchmarking). The base-benchmarking repo retains its copy
during the transition; a follow-up PR will remove it once this one
is deployed.

14 tests ported from base-benchmarking (comparison synthesizer tests).
All existing runner/ tests unaffected.
Allows the report server to serve directly from the directory written
by 'base-bench run --output-dir <dir>' without any S3 or MinIO setup.
This makes local development a one-command flow:

  report-server --local-dir ./output

The same merge/dedup/retention/comparison-synthesis pipeline runs
against local files as against S3, so reports look identical
regardless of backend.

Changes:
- BackendStorage interface: extracted from S3Service so handlers
  work against either backend
- LocalService: reads <outputDir>/metadata.json + metrics files
  from a local directory tree. Uses file mtime as the ETag
  equivalent for cache invalidation — a newly written metadata.json
  is visible on the next request.
- --local-dir flag (env: BASE_BENCH_API_LOCAL_DIR): mutually
  exclusive with --s3-bucket; both validated at startup
- S3BucketFlag: Required: true removed (validation moved to Validate())
- mergeRuns() + applyRetentionPolicy(): promoted to package-level
  functions so both S3Service and LocalService share the pipeline
- 6 new LocalService unit tests: GetMetadata, cache hit, cache
  invalidation on new file, GetObject, invalid dir, load tests

Verified: server starts with --local-dir, health returns 200,
metadata.json returns runs from local files with comparison groups.
GetObject, ListLoadTests, and GetLoadTest all accepted user-provided
values (HTTP path params) and passed them directly to filepath.Join
without validating that the resolved path stays within the root dir.
This allowed path traversal — e.g. GET /output/../../../etc/passwd.

Fix: safePath() resolves the joined path with filepath.Clean, then
checks it has the root as a prefix. Returns an error for any path
that escapes the root directory.

Also adds TestLocalService_PathTraversalBlocked covering the three
dangerous patterns: ../etc/passwd, ../../secret,
run-a/../../outside.
The previous safePath implementation used strings.HasPrefix against a
manually-constructed base path, which CodeQL did not recognize as a
path sanitizer and continued flagging the call sites.

Switched to filepath.Rel(root, abs): if the relative path from the
root to the resolved target starts with '..', the target is outside
the root. filepath.Rel is the idiomatic Go pattern for this check
and is more likely to be recognized by static analysis tools.
errcheck: defer result.Body.Close() -> defer result.Body.Close() //nolint:errcheck
  The S3 response body Close() is best-effort cleanup; the SDK
  documents the error as always nil.

staticcheck SA1019: add //nolint:staticcheck on aws-sdk-go v1 imports
  aws-sdk-go v1 is deprecated in favour of v2. The migration is a
  larger change tracked separately; the nolint directives keep CI
  green in the meantime.
@cb-heimdall

Copy link
Copy Markdown
Collaborator

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 1
Sum 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants