Skip to content

SEC-359: Replace compare app with embedded Grafana dashboard#9

Draft
smypmsa wants to merge 3 commits into
mainfrom
feature/SEC-359-grafana-iframe
Draft

SEC-359: Replace compare app with embedded Grafana dashboard#9
smypmsa wants to merge 3 commits into
mainfrom
feature/SEC-359-grafana-iframe

Conversation

@smypmsa
Copy link
Copy Markdown
Member

@smypmsa smypmsa commented May 22, 2026

Description

Replaces the in-app comparison flow on compare.chainstack.com with an iframe-embedded view of the existing Grafana Cloud public dashboards at chainstack.grafana.net. This is the frontend half of the SEC-359 deprecation — paired with the backend PR in chainstack/performance-tool-backend#feature/SEC-359-deprecate-prod-backend, which scales the vulnerable /scenarios API to 0 replicas.

Diff: 44 files, +68 / -2,125 (mostly dead-code deletion from the now-removed pages).

Related Issue

SEC-359 — https://chainstack.myjetbrains.com/youtrack/issue/SEC-359

What changed

  • src/app/page.js: rewritten as a thin shell with <Header />, an iframe pointing at the Ethereum global dashboard (?orgId=1&theme=dark&kiosk=1), and a fallback "open in new tab" link. The 31 public dashboards (8 chains × ~4 regions, audited from the dashboard JSON) all use target="_self" on their nav links, so chain/region switching happens inside the iframe.
  • Route deletions: src/app/compare-single/, compare-double/, injection-start/, injection-result-double/. All previously hit the backend's /scenarios/* endpoints (the SSRF surface). Legacy bookmarks 301-redirect to / via next.config.js.
  • next.config.js:
    • Dropped the wide-open /api/* CORS block (we no longer expose APIs from this app).
    • Added a strict CSP: frame-src allowlists only https://chainstack.grafana.net, frame-ancestors 'none' (prevents our page being framed elsewhere), HSTS, X-Content-Type-Options: nosniff, Referrer-Policy: no-referrer-when-downgrade. Defense-in-depth against the historical XSS-probe traffic GA showed on the old __proto__ / constructor.prototype paths.
    • Redirects /compare-single, /compare-double, /injection-start, /injection-result-double/.
  • src/app/store/store.js: emptied. No client state needed once the form flow is gone.
  • .env.sample: removed NEXT_PUBLIC_BACKEND_APP_URL.
  • Dead components removed: Bento, Faq, Performance, ProtocolIcon (+ all chain SVGs), ResultCard, and four now-orphaned icons. ResultCard imported now-removed store exports and would have broken the build; the rest were only used by the deleted pages.

Motivation and Context

We are deprecating the compare app. The app contents is replaced with the Grafana dashboards (real-time data, multiple regions, more methods). The iframe simply surfaces them under the existing branded domain.

Known limitation — iframe will not render until Grafana support unblocks it

chainstack.grafana.net currently sends X-Frame-Options: deny on every public-dashboard response. This is a browser-level block; no URL parameter, sandbox attribute, or referrer trick bypasses it. Verified live with curl -I against the production dashboard URL.

Before merging, open a Grafana Cloud support ticket asking them to enable iframe embedding for the chainstack.grafana.net tenant on /public-dashboards/* paths, with frame-ancestors allowlisting https://compare.chainstack.com (and any preview origin you set up). Per the May-2026 Grafana Labs blog and Grafana Cloud docs, this is a support-gated tenant config — not a self-serve toggle.

Until that ticket resolves:

  • The iframe will display a blank box plus a "Refused to display ... X-Frame-Options" error in DevTools.
  • The "Open dashboard in a new tab" link below the iframe keeps the page functional.
  • Vercel preview testing can validate everything except the iframe rendering — header/footer layout, mobile sizing, redirects from the old routes, the fallback link, the CSP headers (check Network → Response Headers in DevTools).

How Has This Been Tested?

  • npm ci && npm run build locally — green. Next.js 14, route / prerendered as static (64.2 kB / 146 kB First Load JS).
  • Dashboard JSON audit: scraped Grafana's public API endpoint for Ethereum, Solana, and Hyperliquid global dashboards. Confirmed every dashboard-to-dashboard nav link uses target="_self". The only target="_blank" is the Chainstack logo (correct — it should open chainstack.com in a new tab).
  • Inventory check: 8 chains × 4 regions − 1 (TON has no US West) = 31 distinct public dashboards. All consistent in panel structure.

Vercel preview verification checklist (after merge or on preview branch)

  • Header renders correctly, Logo + Dashboard / Start-for-free buttons visible.
  • Iframe container is full-width within the lg:max-w-6xl shell, ~1400px tall.
  • DevTools console shows the X-Frame-Options block (expected until Grafana ticket lands).
  • "Open dashboard in a new tab" link works and opens the prod Grafana URL.
  • Visiting /compare-single, /compare-double, /injection-start, /injection-result-double 301-redirects to /.
  • Visiting /dashboard 301-redirects to the prod Grafana URL (preserved behavior).
  • Network tab → main document → Response Headers shows the new CSP, HSTS, nosniff, Referrer-Policy.

Screenshots (if appropriate)

N/A


Follow-ups (not in this PR)

  • Grafana Cloud support ticket (required for the iframe to actually render).
  • package.json cleanup — react-google-charts, react-type-animation, possibly simpler-state, immer, @mdx-js/*, and unused @iconicicons/react/@lemonsqueezy/wedges are likely dead now. Run depcheck and remove in a follow-up to keep this PR review-able.

Deprecates the in-app comparison flow (compare-single, compare-double,
injection-start, injection-result-double) in favor of an iframe-embedded
view of the existing Grafana Cloud public dashboards at
chainstack.grafana.net. The 31 chain/region public dashboards already
use target=_self on every nav link, so users can switch chains and
regions without leaving compare.chainstack.com.

Paired with the backend deprecation in performance-tool-backend
(feature/SEC-359-deprecate-prod-backend) which scales the vulnerable
/scenarios API to 0 replicas.

Changes:
- src/app/page.js: rewritten as a thin iframe shell with the Ethereum
  global dashboard as the entry point; users navigate to other
  chains/regions inside the iframe.
- src/app/{compare-single,compare-double,injection-start,
  injection-result-double}/: deleted (now-dead routes).
- next.config.js: drop wide-open /api/* CORS, add CSP that allowlists
  chainstack.grafana.net for frame-src, set frame-ancestors 'none',
  add HSTS / Referrer-Policy / nosniff. Redirect the four removed
  routes to / for legacy bookmarks.
- src/app/store/store.js: emptied; no entities needed once the form
  flow is gone.
- .env.sample: drop NEXT_PUBLIC_BACKEND_APP_URL.
- src/components/{Bento,Faq,Performance,ProtocolIcon,ResultCard}: deleted.
  ResultCard imported removed store exports, the rest were only used by
  the deleted pages.

Known limitation, tracked separately: chainstack.grafana.net currently
returns X-Frame-Options: deny on public-dashboard responses, so the
iframe will not render until Grafana Cloud support enables tenant-scoped
frame-ancestors for https://compare.chainstack.com. Open a ticket
referencing SEC-359 with that origin (plus any preview origin) before
merging. The "Open dashboard in a new tab" fallback link below the
iframe lets the page remain usable in the meantime.

Build verified locally with npm run build (Next.js 14, route /
prerendered as static, 64.2 kB).
@vercel
Copy link
Copy Markdown

vercel Bot commented May 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
chainstack-compare Ready Ready Preview, Comment May 22, 2026 3:45pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 11395421-27df-4e2c-abce-5753d8228cb1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/SEC-359-grafana-iframe

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…irects

- Header.js: remove the in-header "Dashboard" button and its GrafanaIcon
  import; delete the now-unused GrafanaIcon component file. The page is
  the dashboard now, so the duplicate nav entry is redundant.
- next.config.js: drop the /injection-start and /injection-result-double
  redirects. GA showed no measurable traffic on those paths, unlike
  /compare-single (435 views) and /compare-double (349 views) which
  keep their redirects.
Three layout improvements to handle Grafana's preference for widescreen:

- Iframe escapes the max-w-6xl wrapper. Header / title / footer stay
  constrained for brand consistency, but the iframe goes edge-to-edge
  (minus 8-16px gutter padding) so on 1920px+ monitors it gets the
  ~67% extra horizontal space Grafana's grid is designed for.
- Height switches from a fixed 1400px to calc(100vh - 200px) with an
  800px min, so it fills available vertical real estate on laptops up
  to 4K monitors without arbitrary empty space at the bottom.
- Below 768px (md breakpoint) the iframe is replaced with a styled
  "Best viewed on desktop" CTA. Grafana is genuinely unusable at phone
  widths; honest fallback beats a cramped iframe.

The "Open in new tab" link below the iframe is now md:block only since
the mobile card already provides that action.

Build verified locally with npm run build.
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.

1 participant