feat(grafana): validate integration and add folder, health, and contact-point tools#5082
Conversation
…ct-point tools - Require alert-rule title/ruleGroup/data in the block (create would 400 without them) - Trim UID path params across dashboard and alert-rule tools to avoid copy-paste 404s - Use Grafana brand color for the block background - Surface previously-unsettable list params (limit, starred, annotation type) - Add get/update/delete folder, check data source health, get health, and create contact point tools - Strip non-TSDoc comments; regenerate docs and integrations.json
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview The workflow block gains matching operations and UI fields (contact-point type/settings, folder management, list limit / starred / annotation type), switches block→tool param mapping to per-operation Fixes: Docs, registry wiring, types, and a provision-alerting skill (plus audit-dashboards health-check step) are updated. Minor unrelated change: Reviewed by Cursor Bugbot for commit 014c928. Configure here. |
Greptile SummaryThis PR validates all existing Grafana tools against the live API docs and adds six new tools: get/update/delete folder, check data source health, get health, and create contact point. It also fixes several bugs in the existing block, including required-field enforcement on alert-rule creation, UID trimming on path params, and the previous
Confidence Score: 5/5Safe to merge — the new tools follow existing patterns correctly and the block param-routing refactor is logically sound. All six new tools correctly wire their params (via the block's pass-through mechanism where subBlock IDs match tool param names, and via explicit switch-case mapping where they don't). The update_folder two-step GET+PUT correctly applies SSRF protection on the mutation leg, consistent with update_dashboard and update_alert_rule. The previously reported contactPointType/annotationType interaction bug is fixed by the per-operation switch. No incorrect data flows, missing required side effects, or broken contracts were found. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
UI[Block UI\nOperation dropdown] --> Switch{params switch\nper operation}
Switch -->|grafana_create_contact_point| CP[create_contact_point\nPOST /api/v1/provisioning/contact-points]
Switch -->|grafana_get_folder| GF[get_folder\nGET /api/folders/:uid]
Switch -->|grafana_update_folder| UF_GET[GET /api/folders/:uid\ninitial fetch]
Switch -->|grafana_delete_folder| DF[delete_folder\nDELETE /api/folders/:uid\n?forceDeleteRules=true optional]
Switch -->|grafana_check_data_source_health| DSH[check_data_source_health\nGET /api/datasources/uid/:uid/health]
Switch -->|grafana_get_health| GH[get_health\nGET /api/health]
UF_GET --> TR[transformResponse\nstores _existingFolder]
TR --> PP[postProcess\nvalidateUrlWithDNS\nsecureFetchWithPinnedIP]
PP --> UF_PUT[PUT /api/folders/:uid\nwith version + new title]
CP --> Grafana[(Grafana API)]
GF --> Grafana
UF_PUT --> Grafana
DF --> Grafana
DSH --> Grafana
GH --> Grafana
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
UI[Block UI\nOperation dropdown] --> Switch{params switch\nper operation}
Switch -->|grafana_create_contact_point| CP[create_contact_point\nPOST /api/v1/provisioning/contact-points]
Switch -->|grafana_get_folder| GF[get_folder\nGET /api/folders/:uid]
Switch -->|grafana_update_folder| UF_GET[GET /api/folders/:uid\ninitial fetch]
Switch -->|grafana_delete_folder| DF[delete_folder\nDELETE /api/folders/:uid\n?forceDeleteRules=true optional]
Switch -->|grafana_check_data_source_health| DSH[check_data_source_health\nGET /api/datasources/uid/:uid/health]
Switch -->|grafana_get_health| GH[get_health\nGET /api/health]
UF_GET --> TR[transformResponse\nstores _existingFolder]
TR --> PP[postProcess\nvalidateUrlWithDNS\nsecureFetchWithPinnedIP]
PP --> UF_PUT[PUT /api/folders/:uid\nwith version + new title]
CP --> Grafana[(Grafana API)]
GF --> Grafana
UF_PUT --> Grafana
DF --> Grafana
DSH --> Grafana
GH --> Grafana
Reviews (3): Last reviewed commit: "fix(grafana): scope block param remaps p..." | Re-trigger Greptile |
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 014c928. Configure here.
|
@greptile review |
#5082 added a grafana update_folder tool that does SSRF-pinned fetch in its postProcess, re-introducing the client-bundle leak. Convert it to the internal API route pattern like the other update tools so the def is declarative and input-validation.server stays out of the client bundle.
* refactor(connectors): split client metadata from server runtime + cover node:net in client bundle The browser build broke with `Cannot find module 'node:net'`. Server-only SSRF code in `input-validation.server.ts` (`dns/promises`, and since PR #5060 `undici` → `node:net`/`node:tls`) is statically reachable from the client bundle via the tool/connector registries, which the workflow editor imports for metadata. Node networking builtins have no browser shim, so Turbopack cannot compile them for the client. Two changes: 1. Split each connector's client-safe declarative metadata into a sibling `meta.ts` (`<name>ConnectorMeta`), mirroring the `XBlockMeta` / `BLOCK_META_REGISTRY` pattern. `connectors/registry.ts` is now the client-safe `CONNECTOR_META_REGISTRY` (+ `getConnectorMeta` / `getAllConnectorMeta`); the full registry with runtime fns moves to `connectors/registry.server.ts`. Client components consume the meta registry; the sync engine and knowledge API routes consume the server registry. This removes connectors from the client's server-only graph. Connector metadata is byte-for-byte identical before/after; runtime fns are untouched. 2. Extend the existing #4899 `turbopack.resolveAlias` browser stub — which already mapped `dns`/`dns/promises` to an empty module for the browser — to also cover `net`/`tls` (+ `node:` variants), since `undici` now pulls those in. The remaining tool/provider definitions still reach `input-validation.server` server-side; the browser-only stub keeps those Node builtins out of the client bundle while the real modules stay on the server, so SSRF validation and IP pinning are unaffected. Connector authoring/validation skills updated to teach the meta.ts split. * fix(icons): use Square logo glyph only, drop wordmark * fix(connectors): share Discord max-messages default across meta and runtime Discord defined DEFAULT_MAX_MESSAGES separately in meta.ts (config placeholder) and discord.ts (sync behavior), which could drift. Export it from meta.ts and import it in the runtime, matching the single-source pattern used by the other connectors (e.g. gmail, intercom). * refactor(tools): route grafana/agiloft egress server-side, drop SSRF browser shim Move the server-only SSRF-pinned fetch out of the grafana (update_dashboard, update_alert_rule) and agiloft (11 record/search tools) definitions and into internal API routes, the same pattern the rest of the server-side tools (and agiloft's own attach/retrieve) already use. The tool definitions are now purely declarative (request → internal route), so they no longer import `input-validation.server` and the tools registry is fully client-safe. With connectors (meta split) and these tools no longer reaching server-only code from the client bundle, the browser no longer pulls in `dns`/`net`/`tls`: - Add `import 'server-only'` to `input-validation.server.ts` so any future client import fails loudly at build time instead of silently bloating the bundle. - Remove the `turbopack.resolveAlias` browser stub and delete `empty-node-fallback.browser.ts` — the root cause is fixed, the shim is gone. Behavior is unchanged: each route runs the exact merge/validation/fetch logic the tool ran before (every header, param branch, JSON-parse guard, error string, and SSRF pinning preserved); only the location of execution moved from the client- bundled definition to a server route. * fix(connectors): move onedrive tagDefinitions into meta; drop server-only guard - onedrive's tagDefinitions lived in the runtime file, so the client meta registry returned undefined for it and the add-connector tag opt-out section stopped rendering for onedrive. Move it into meta.ts like the other connectors so client and server see identical metadata (verified across all 50). - Remove the 'server-only' import from input-validation.server.ts: the meta/route split already keeps it out of the client bundle, and blocks/tools registries don't use the guard either. * fix(grafana): surface upstream error when the prefetch GET fails Check response.ok on the existing-resource GET in both update routes and return the upstream status/body, matching how the tool framework surfaced GET errors before the move to internal routes (the framework checks response.ok before transformResponse). Without this, a failed prefetch produced a generic 'Failed to fetch existing ...' message and dropped Grafana's error detail. * fix(grafana): reject invalid panels JSON instead of silently ignoring it Grafana's dashboard API treats panels as a required array and returns 400 on invalid JSON; this route already errors on every other JSON param. Return 'Invalid JSON for panels parameter' instead of swallowing the parse error and proceeding with a misleading success. * fix(grafana): trim dashboard/alert-rule UID in route URLs (carry over #5082) PR #5082 added .trim() on dashboardUid/alertRuleUid in the original tool URL builders. Those tools now build their URLs in the internal routes, so apply the same trim there to preserve that behavior. * fix(grafana): route update_folder egress server-side (carry over #5082) #5082 added a grafana update_folder tool that does SSRF-pinned fetch in its postProcess, re-introducing the client-bundle leak. Convert it to the internal API route pattern like the other update tools so the def is declarative and input-validation.server stays out of the client bundle. * fix(grafana): surface route failures in transformResponse instead of masking them The grafana update tools' transformResponse hardcoded success: true and dropped the route's error, so an upstream/validation failure (HTTP 200 with { success: false, error }) was reported to the workflow as a success. Forward data.success and data.error (matching the agiloft tools) so failures propagate as before the move to internal routes.
Summary
Type of Change
Testing
Tested manually;
bun run lintand typecheck pass clean for all Grafana files.Checklist