Skip to content

chore: merge develop branch into main#19

Merged
cbermudez97 merged 48 commits into
mainfrom
chore/app-refactor
Jun 18, 2026
Merged

chore: merge develop branch into main#19
cbermudez97 merged 48 commits into
mainfrom
chore/app-refactor

Conversation

@cbermudez97

Copy link
Copy Markdown
Contributor

Merges chore/app-refactor into main. The branch carries six
implementation stages, each landed as its own commit so the history
stays bisectable.

What changed

  • Stage 1 - Ported runner/api/inputvalidation.go + tests verbatim
    from main, wired ~32 validator/sanitizer call sites across the API
    handlers, disabled the XSS-prone HTML branch in HandleGetReport,
    added artifact-metadata: write to the docker workflow, and bumped
    dashboard deps.
  • Stage 2 - Replaced the flag-modal runner entry point with
    explicit Cobra subcommands (benchmark, api, historic). runner
    with no arguments prints usage and exits 2.
  • Stage 3 - Added the compare subcommand for one-shot cross-client
    JSON-RPC response comparison; swept out the dead
    Config.ValidateResponses field, the validate_responses: YAML keys,
    the orphan runner/validator/ package, and
    runner/comparator/utils.go.
  • Stage 4 - Added the compare-openrpc subcommand with
    --variations, variant-aware --filter, and the --curl debug aid.
  • Stage 5 - Made benchmark metrics resilient to Prometheus data
    loss by gap-filling from the k6 --summary-export JSON on a
    per-(client, method) basis, with a per-pair Warn log.
  • Stage 6 - Gated the benchmark HTML report behind --html-report
    (default off), trimmed the dead comparator-render branch from the
    generators, dropped the broken jsonrpc-benchmark.json Grafana
    dashboard, and stripped non-ASCII characters from Go source.

Follow-up work is tracked in
POST_MERGE_FOLLOWUPS.md.

Breaking changes

  • No implicit default subcommand. runner -api, runner -historic-mode
    and other pre-refactor flag-modal invocations no longer parse; the
    mapping is documented under "Migrating from the pre-refactor CLI" in
    README.md.
  • runner benchmark no longer writes outputs/report.html by default.
    Pass --html-report to restore it. JSON and CSV exports remain on.
  • The pre-refactor endpoints + frequency YAML schema is no longer
    accepted; configs must be migrated by hand to the calls: schema.
  • metrics/dashboards/jsonrpc-benchmark.json has been removed; its
    queries targeted custom counters the current k6 driver no longer
    emits.

Test plan

  • CI green.
  • runner benchmark --config config/mixed.yaml --clients config/clients.yaml --html-report against a live docker stack produces outputs/results.{json,csv} and outputs/report.html.
  • Same command without --html-report produces outputs/results.{json,csv} and no report.html.
  • runner compare and runner compare-openrpc against local clients each produce both comparison-results.json and comparison-report.html.
  • runner api --storage-config config/storage-example.yaml boots and serves /api/health.
  • runner historic --storage-config config/storage-example.yaml --config config/mixed.yaml runs to completion against a populated database.

cbermudez97 and others added 14 commits November 12, 2025 11:30
* fix: Grafana Startup and Warnings

* fix: Copy configs into final stage docker container

* fix: Use a mount for runner configs

* fix: Update README and prometheusRWEndpoint

* fix: Restore endpoint configs

* fix: formatting

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Brings develop to security parity with main (commits 53997ff, a9bd670,
c860d7f):

- Add runner/api/inputvalidation.go with ValidateID, ValidateSeverity,
  ValidateComparisonMode, SanitizeLogValue (+ tests, verbatim from main).
- Wire 34 validation/sanitization call sites across handlers.go,
  grafana_api.go, websocket.go.
- Disable HTML branch in HandleGetReport (return JSON for any format
  query) to close CodeQL go/reflected-xss.
- Add artifact-metadata: write to build_docker_image.yml.
- Bump dashboard deps: vitest ^4.1.0, @typescript-eslint/* ^8.60.0,
  axios ^1.16.1. Regenerate package-lock.json.
Replaces the flag-modal `runner` entry point with explicit subcommands:

- `runner benchmark` — run a benchmark (k6 → Prometheus → reports)
- `runner api` — start the HTTP API server
- `runner historic` — generate a historic-analysis report from PostgreSQL

`runner` with no subcommand prints usage and exits 2. Global `--output`
and `--log-level` flags live on the root command. The old single-dash
flag-modal invocations (`runner -api`, `runner -historic-mode`,
`-config`, ...) are no longer recognised and will fail at flag-parse
time with a clear error — preferable to silently doing nothing.

- Add `github.com/spf13/cobra` as a direct dependency.
- Extract the existing flows from `runner/main.go` into a new
  `runner/cmd/` package (root, benchmark, api, historic, common).
- Shrink `runner/main.go` to a thin `cmd.Execute()` entry point.
- Update `runner/Dockerfile` to build the full package (`./runner`
  instead of `./runner/main.go`).
- Update `docker-compose.yml`'s runner service to invoke
  `runner api --storage-config=...`.
- Update README invocations + add a "Migrating from the pre-refactor
  CLI" table.
…rison

Adds the `compare` Cobra subcommand for one-shot cross-client JSON-RPC
response comparison. Flags-only, no YAML — uses the existing
`clients.yaml` registry for client definitions:

  runner compare \
    --clients ./config/clients.yaml \
    --client-refs geth,nethermind \
    --methods eth_blockNumber,eth_chainId,eth_gasPrice \
    --output ./out

Always writes both `comparison-results.json` and `comparison-report.html`
to `--output`. Filesystem-only; does not touch the historic-runs DB.

Cleans up the dead `ValidateResponses` field from the benchmark config
(removed from `config.Config`, the backward-compat loader struct, and
the four YAML files under `config/` that still set it). Also drops the
orphaned `runner/validator/` package and the dead
`runner/comparator/utils.go` bridge — neither had any importers after
the Cobra refactor.
Adds OpenRPC-spec-driven cross-client response comparison as the fifth
Cobra subcommand. Flags-only, reuses the `clients.yaml` registry from
the `compare` subcommand, and produces the same filesystem artefacts
(`comparison-results.json` and `comparison-report.html` under
`--output`).

  runner compare-openrpc \
    --spec ./openrpc.json \
    --variations ./config/param_variations.yaml \
    --clients ./config/clients.yaml \
    --client-refs geth,nethermind \
    --filter eth_blockNumber,eth_getBlockByNumber \
    --output ./openrpc-results

Implements the historical debug aids from main's old
`cmd/compare-openrpc/main.go`:
- `--filter` accepts both base method names and their full variant
  names; matching on the base name keeps every `_variantN` sibling
  generated from the variations file.
- `--curl` enables the comparator's verbose mode, which logs a
  curl-equivalent command for each JSON-RPC request.

Filesystem-only; does not touch the historic-runs DB, matching the
behaviour of `compare`.
Make benchmark metrics resilient when Prometheus loses data for a
subset of (client, method) pairs by gap-filling from the k6
--summary-export JSON. Per-pair, not all-or-nothing: a pair with even
one Prometheus sample stays on Prometheus.

- Add runner/metrics/summary_fallback.go with the k6 summary parser,
  per-(client,method) extractor, and per-pair walker. The summary file
  is loaded lazily, once per CollectClientsMetrics call, and the load
  error (if any) is cached so we don't re-attempt per pair.
- Modify metrics.CollectClientsMetrics to accept a *logrus.Logger and
  emit one Warn per (client, method) pair where Prometheus returned
  zero samples:
    "Prometheus had no data for %s.%s, falling back to summary.json"
- Add TODO(post-merge) markers on ClientMetrics.ErrorTypes and
  ClientMetrics.StatusCodes — they stay declared and empty pending the
  follow-up that wires them from k6 Prometheus labels.

Lifts the field-population logic from main's runner/generator/
metrics_parser.go but explicitly drops ValidatePercentiles,
extractClientNames, the percentile-ordering sanity checks, the
"p99=0 for traffic" per-method warn, and the p99-coverage logging:
user-defined k6 thresholds per Call are the replacement for static
percentile checks.

Tests cover the happy path, the fallback path against a synthetic
summary fixture, and the no-summary-file path (Warn + leave-at-zero,
no panic).
Final pass before the develop->main merge.

- Add --html-report flag to `runner benchmark` (default false). JSON
  and CSV exports remain on by default; the cascading HTML report
  block is now opt-in. `compare` and `compare-openrpc` are unaffected
  and continue to always generate their HTML report.
- Trim the dead `runner/comparator` rendering branch from
  runner/generator/html_report.go and delete
  runner/generator/response_utils.go, both of which had no callers
  after the Stage 2 cmd/ split.
- Drop metrics/dashboards/jsonrpc-benchmark.json. Its Prometheus
  queries target custom counters (method_calls_*, rpc_errors_*,
  rpc_calls_*) that develop's k6 driver no longer emits. The three
  remaining dashboards stay in place.
- Strip non-ASCII characters from all Go source under runner/: arrows
  and em-dashes in comments and Cobra `Short:` descriptions, plus
  emoji glyphs in HTML report titles, recommendation strings, and a
  handful of debug-binary `fmt.Println` calls.
- README: document --html-report, refresh the migration callout, and
  swap em-dashes for plain ASCII.
Brings the three commits from main (53997ff, a9bd670, c860d7f) into
this branch's ancestry. Their content was already ported verbatim in
4074525 (Stage 1); this merge resolves conflicts in favour of the
current branch so no functional change lands. Clears the
"branch out-of-date" warning on PR #19.
…ment GetHistoricSummary

Three pre-existing bugs surfaced during the live pre-merge smoke. All
of them blocked end-to-end runs of subcommands the refactor stream
otherwise wired up correctly.

- benchmark could not query Prometheus after the run because
  --prometheus-rw http://localhost:9090/api/v1/write was used both as
  k6's remote-write target and as the Prometheus query client's base
  address. The query client then issued GET <base>/api/v1/query, which
  resolved to http://localhost:9090/api/v1/write/api/v1/query and
  404ed. Split the single flag into a base URL plus a path-only
  override:
  * --prometheus (default http://localhost:9090): base URL. Used
    directly by the query client; --prometheus-rw-path is appended
    to form the remote-write target.
  * --prometheus-rw-path (default /api/v1/write): path appended for
    remote-write. Override only when your deployment uses a
    non-standard path.
  * --prometheus-rw (the old full-URL flag) is removed. Old
    invocations migrate by passing --prometheus http://host:port and
    optionally --prometheus-rw-path <path>.

- runner historic required a resolvable client registry even though
  it only consumes cfg.TestName from the loaded config. Add a
  --clients flag mirroring runner benchmark so configs using
  clients: [name, name] references resolve correctly. Also guard
  against an empty GetHistoricSummary result so the report generator
  is never called with a nil BestRun.

- storage.HistoricStorage.GetHistoricSummary was a "not implemented"
  stub. Implement it by aggregating over ListHistoricRuns: TotalRuns,
  FirstRun/LastRun timestamps, BestRun and WorstRun by lowest/highest
  avg_latency, and a RecentRuns slice (top 10). Also drop the error
  from GetHistoricTrends so the warn-log path doesn't fire while real
  trend aggregation remains a post-merge follow-up.
@cbermudez97 cbermudez97 changed the title chore: develop -> main, six-stage refactor chore: merge develop branch into main Jun 18, 2026
CI's Trivy scan reports 19 vulnerabilities (HIGH: 17, CRITICAL: 2) in
the grafana/k6:1.4.0 base image, all in libcrypto3 / libssl3
(OpenSSL 3.5.4-r0). Fixed versions exist in Alpine 3.22's update
channel; the base image pin just hasn't picked them up. Add an
`apk --no-cache upgrade` step before the package install so the
runtime stage refreshes against Alpine 3.22's current security
patches without changing the pinned k6 release.
CI's Trivy scan was flagging 15 stdlib CVEs (CRITICAL: 1, HIGH: 14)
in the runner binary built against Go 1.25.4, plus 19 stdlib CVEs in
the k6 binary embedded in grafana/k6:1.4.0 (Go 1.25.3). Bump both:

- builder: golang:1.25.4-alpine -> golang:1.25.11-alpine (matches
  main; covers all listed crypto/tls, crypto/x509, net/http,
  net/url, encoding/asn1 CVE fixes for our binary).
- runtime: grafana/k6:1.4.0 -> grafana/k6:1.8.0 (latest published
  k6 release; brings the embedded Go runtime forward).
Switch the build_docker_image workflow from the Nethermind-shared
docker-build-push-dockerhub workflow to a self-contained GHCR
pipeline. The shared workflows repo doesn't ship a GHCR equivalent.

- Registry: docker.io -> ghcr.io.
- Image name: nethermindeth/jsonrpc-bench-runner -> ghcr.io/<repo>,
  which resolves to ghcr.io/nethermindeth/json-bench to match the
  repository name.
- Auth: drop the DOCKER_HUB_USERNAME / DOCKER_HUB_PASSWORD secrets;
  use the built-in GITHUB_TOKEN with `packages: write` instead.
- Trivy: keep the CRITICAL/HIGH gate inline. Add
  `ignore-unfixed: true` so upstream CVEs without a published fix
  do not block CI (they still appear in the report).
- Build provenance: attest the pushed image via
  actions/attest-build-provenance@v2.
`${{ github.repository }}` resolves to `NethermindEth/json-bench`
with the org's camelcase. Docker reference grammar requires repo
paths to be lowercase, so Trivy was aborting at parse time with
"could not parse reference: NethermindEth/json-bench:scan-...".
The push tags coming from docker/metadata-action are already
lowercased, so only the locally-loaded scan tag is affected.
Decouple that local-only handle from the registry image name by
tagging it `local/runner:scan-<sha>`.
@cbermudez97 cbermudez97 merged commit 0ad625e into main Jun 18, 2026
1 check passed
@cbermudez97 cbermudez97 deleted the chore/app-refactor branch June 18, 2026 16:08
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