Skip to content

fix(fn-dashboard): do not mask empty panel query fields - #230

Open
GurinderRawala wants to merge 1 commit into
custom-dashboardsfrom
custom-dashboards-reporting-empty-rawsql
Open

fix(fn-dashboard): do not mask empty panel query fields#230
GurinderRawala wants to merge 1 commit into
custom-dashboardsfrom
custom-dashboards-reporting-empty-rawsql

Conversation

@GurinderRawala

@GurinderRawala GurinderRawala commented Aug 11, 2026

Copy link
Copy Markdown

Problem

A reporting-backed custom dashboard panel failed to render:

error: [Grafana proxy]:: Failed to resolve FN-redacted query {
  dashboardUID: 'cd-7e2676fddaf74e218328',
  queryCount: 1,
  queries: [ { refId: 'A', datasourceUid: 'mfe-bigquery-prod',
               rawSqlPrefix: '[MFE_REDACTED:p:4:A]' } ]
}

Root cause

maskRawQueryFields masked any query field whose value was a string — including the empty string:

if _, err := cur.String(); err == nil {
    obj.Set(field, mask)   // "" -> "[MFE_REDACTED:p:4:A]"
}

Verified against simplejson: CheckGet("rawSql") on "" returns ok=true and String() returns ("", nil), so an empty value took the mask branch.

For a panel that intentionally carries no SQL, that fabricates a marker promising the proxy a query which does not exist. The proxy's contract is to fail closed on any value carrying the redaction prefix — it must parse a valid key rather than forward a literal placeholder upstream. So it resolves panel 4, finds rawSql: "", hits if (!originalSql) return null, and rejects the entire /api/ds/query batch.

Fix

Skip masking when the query field is empty or whitespace-only. Safe by construction: there is no query text to leak, and the marker exists solely to stand in for text that was removed.

Two shapes depend on an intentionally empty query field:

  • CodeRabbit reporting-backed panels — data comes from the reporting API via a crReportingTag on the target rather than from SQL.
  • Variable metricFindQueries — these already arrive with an empty rawSql and a tempVar<N> refId. The proxy has a dedicated pass-through for exactly this shape (if (raw.length === 0)), which the fabricated marker was routing around. So this also removes a latent inconsistency that predates the reporting work.

Why not gate on "is this a custom dashboard?"

The requested framing was to skip tag generation for custom dashboards specifically, but that isn't the right seam:

  1. The fork has no notion of a custom dashboard. pkg/api has no cd- prefix or dashboard-kind concept; introducing one would mean threading a classification through the mask path purely to express "this panel has no SQL" — which the panel already states by having no SQL.
  2. Custom dashboards still contain SQL panels. A generated dashboard is typically mixed. Disabling masking per-dashboard would unmask real SQL on the SQL-backed panels — a regression of the property the mask exists to guarantee.
  3. An empty query is meaningless to mask on any dashboard. The condition is a property of the value, not of the dashboard.

The narrower predicate fixes the reported failure, keeps every non-empty query masked, and adds no new coupling.

Verification

Check Result
go build ./pkg/api/ clean
go test ./pkg/api/ -run "TestMask|TestIsCodeRabbitMFE|TestMfe|TestPanelAndVariable" ok
gofmt -l clean

Three regression tests added:

  • empty rawSql is left untouched, and a sibling crReportingTag survives intact
  • whitespace-only query is left untouched
  • a mixed dashboard still masks the non-empty query on another panel -> [MFE_REDACTED:p:5:A]

I confirmed the tests actually catch the bug: with the guard removed all three fail with actual: "[MFE_REDACTED:p:4:A]"; with it restored all pass.

Pre-existing failure, unrelated: TestDashboardSnapshotAPIEndpoint_singleSnapshot panics with no guardian factory implementation provided. I confirmed it fails identically on a stashed/clean tree.

Related

Pairs with mono#25309, which generates these reporting-backed panels. Both are needed for a reporting panel to render.

Summary by CodeRabbit

  • Bug Fixes
    • Empty or whitespace-only dashboard query fields are now preserved instead of being redacted.
    • Non-empty query fields continue to be masked as expected.
    • Reporting metadata remains unchanged during masking.

A reporting-backed custom dashboard panel failed to render with:

  [Grafana proxy]:: Failed to resolve FN-redacted query
    rawSqlPrefix: '[MFE_REDACTED:p:4:A]'

`maskRawQueryFields` masked any query field whose value was a string,
including the empty string. For a panel that intentionally carries no SQL that
fabricates a `[MFE_REDACTED:p:<id>:<refId>]` marker promising the proxy a query
which does not exist. The proxy must parse a valid key out of any value with
that prefix, resolves the panel, finds an empty `rawSql`, and fails the whole
`/api/ds/query` batch closed rather than rendering the panel.

Empty query fields are now left untouched. This is safe by construction: there
is no query text to leak, and the marker's only purpose is to stand in for text
that was removed.

Two shapes depend on an intentionally empty query field:
  - CodeRabbit reporting-backed panels, whose data comes from the reporting API
    via a `crReportingTag` on the target rather than from SQL.
  - Variable metricFindQueries, which already arrive with an empty rawSql and a
    `tempVar<N>` refId; the proxy has a dedicated pass-through for these that
    the fabricated marker was bypassing.

Scoped to the masking predicate rather than gated on dashboard kind: the fork
has no notion of a "custom" dashboard, and an empty query is meaningless to
mask for any dashboard.

Three regression tests cover an empty rawSql, a whitespace-only query, and a
mixed dashboard where a non-empty query on another panel is still masked.
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 34e68259-8088-4c28-be93-493536e0ba2b

📥 Commits

Reviewing files that changed from the base of the PR and between 65df42e and d9bf1e7.

📒 Files selected for processing (2)
  • pkg/api/dashboard_mfe_mask.go
  • pkg/api/dashboard_mfe_mask_test.go
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • coderabbitai/bitbucket (manual)
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: build-and-test
🔇 Additional comments (2)
pkg/api/dashboard_mfe_mask.go (1)

193-212: LGTM!

pkg/api/dashboard_mfe_mask_test.go (1)

263-327: LGTM!


📝 Walkthrough

Walkthrough

maskRawQueryFields now leaves empty and whitespace-only string query fields unchanged. It continues to replace non-empty query strings with the supplied redaction marker. Regression tests cover empty rawSql, whitespace-only rawSql, unrelated reporting tags, and mixed empty and non-empty queries.

Poem

I’m a rabbit with queries tucked tight,
Empty fields stay clear and bright.
Whitespace rests without a scar,
Busy queries mask what they are.
Hop, hop—tests guard the bar!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the change to preserve empty dashboard panel query fields.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch custom-dashboards-reporting-empty-rawsql
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch custom-dashboards-reporting-empty-rawsql

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

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