feat: Add New Relic integration#3322
feat: Add New Relic integration#3322vukasin-djuricic wants to merge 13 commits intosuperplanehq:mainfrom
Conversation
Add a New Relic integration that enables users to react to alerts and query telemetry data from New Relic. Components: - Run NRQL Query: execute NRQL queries via the NerdGraph API - Report Metric: send custom metrics (gauge/count/summary) to the Metric API - On Issue: webhook trigger for receiving New Relic alert issues Implements superplanehq#2552 Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
Add missing mapstructure tags to Configuration struct for consistent decoding, and quote AccountID in GraphQL query to avoid fragile coupling with regex validation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
Revert quoteGraphQL on AccountID - NerdGraph account(id: Int!) expects an unquoted integer, not a string. AccountID is already validated by regex. Handle null config values in optionalIntegrationConfig to prevent 500 errors when webhookSecret is stored as null, matching the pattern used by the Harness integration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
WebhookContext does not implement the GetBaseURL method added to the NodeWebhookContext interface upstream. Use NodeWebhookContext to match the pattern used by all other integration tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
Apply filterEmptyStrings to config.Statuses consistently with how config.Priorities is handled, preventing empty strings from matching an empty payload.State. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
| } | ||
|
|
||
| return string(value), nil | ||
| } |
There was a problem hiding this comment.
Duplicated optionalIntegrationConfig across integration packages
Low Severity
optionalIntegrationConfig is duplicated between pkg/integrations/newrelic/on_issue.go and pkg/integrations/prometheus/on_alert.go, with subtly different error-handling logic. The newrelic version additionally suppresses "not a string" errors (for null config values), while the prometheus version only suppresses errors containing the config name and "not found". Having two divergent implementations of the same concept risks inconsistent behavior across integrations and makes future maintenance harder.
Additional Locations (1)
There was a problem hiding this comment.
Follows the pattern from the Harness integration, which also handles null config values. Happy to refactor into a shared utility if preferred.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
Add required interval.ms field for count and summary metric types in ReportMetric, as the New Relic Metric API rejects these without it. Run prettier on on_issue.tsx and run_nrql_query.ts to fix formatting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
|
Hey @vukasin-djuricic, thanks for trying this one! I tried testing this, and there are quite a few issues. It could be my lack of domain knowledge with New Relic, I will list them bellow, but I strongly encourage you joining our Discord as comms will be faster. Action components do not workTried chaining together Trigger component doesn't workEven though configured properly - the trigger component did not receive and show an incident that was triggered on New Relic Trigger component webhook setupIt is possible to manage webhooks via UserAPI, there is no reason for us to push user to set up these things manually. Check dash0 pattern. Those are only the critical ones, I will not list the UX improvements yet until the core functionality is achieved. |
…REATED status
- Auto-provision webhook destination + channel on NR via NerdGraph when
OnIssue trigger is added (no more manual setup required)
- Cleanup destination + channel when trigger/integration is removed
- Handle 401/404 gracefully during cleanup to prevent infinite retry loops
- Use unique names (SuperPlane-<timestamp>) for destinations/channels
- Fix ReportMetric: coerce string values to numeric, add interval.ms for
count/summary metrics, validate summary value shape in Setup()
- Fix RunNRQLQuery: remove debug logs, results no longer return null
- Add CREATED status to OnIssue valid statuses (NR sends CREATED on new issues)
- Simplify OnIssue Setup() to just validate config + RequestWebhook()
- Fix IntegrationDetails select field showing wrong default (EU→US race condition)
- Add zero-value ingestion delay hint in NRQL query results UI
- Update installation instructions to reflect auto-provisioning
- Delete mutations now follow NR docs (ids + error { details })
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
35ac0a0 to
e58ec1d
Compare
- Add CREATED to frontend stateLabels map (was missing despite backend support) - Improve zero-value tip: only show when ALL result values are nullish, not any single one - Add test for null webhookSecret config handling (prevents 500 on optional null fields) - Remove hardcoded "SuperPlane" name from docs (channels now use unique timestamps) - Regenerate component docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
- Change NewRelicIssuePayload.AccountID from int to any, since NR sends accumulations.tag.account as a string in webhook payloads - Update frontend type to accept number | string for accountId - Fix zero-value tip: only treat null/undefined as empty, not 0 (a legitimate count of 0 should not trigger the ingestion delay hint) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
Add defensive numeric validation in NewClient() so account ID is verified before being interpolated into GraphQL queries, independent of the Sync() validation path. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: vumdjur <vdjuricic5322rn@raf.rs>
|
GitHub PR komentar: UpdateAll BugBot review comments addressed across 3 rounds: Round 1: mapstructure tags ✅, null webhookSecret handling ✅ (+test), empty-string filtering ✅, interval.ms ✅, accountId quoting (false positive — used directly, not with quoteGraphQL) ✅, Round 2: accountId changed from int→any (NR sends as string) ✅, zero-value tip fixed (only shows when ALL values null, not 0) ✅ Round 3: accountId validation added in NewClient() for defensive GraphQL injection prevention ✅ Video demohttps://www.youtube.com/watch?v=vfT2Lybz_cI Pre-existing issue found during testing
|
|
onIssue improvementsTo properly fix the
Expected outcome
@forestileao I need sanity check on this one ☝️ @vukasin-djuricic some additional UX changes: Integration setupSince we are creating webhooks automatically - there's no need to have onIssueThe details tab that I see and the one that is in your video look very different. Let's have details look like in your video with limited data, also let's just have single timestamp at the top instead of two of them. Report metric and Run QueryFor the Same for NRQL Query field |
| { | ||
| Name: "webhookSecret", | ||
| Label: "Webhook Secret", | ||
| Type: configuration.FieldTypeString, | ||
| Required: false, | ||
| Sensitive: true, | ||
| Description: "Optional secret for validating incoming webhook requests. If set, New Relic must send an Authorization: Bearer <secret> header.", | ||
| }, |
There was a problem hiding this comment.
What if we always set an webhook secret. But not a webhook secret that the user provided? On webhook context from webhook handler it is possible to Get and Set secret using GetSecret and SetSecret. Then it would enforce to always use secure authenticated webhooks in Superplane.
We have some examples in the codebase (try searching by .SetSecret)
| { | ||
| Name: "timeout", | ||
| Label: "Timeout (seconds)", | ||
| Type: configuration.FieldTypeNumber, | ||
| Required: false, | ||
| Default: 30, | ||
| Description: "Query timeout in seconds", | ||
| }, |
There was a problem hiding this comment.
Here it is possible to add
TypeOptions: &configuration.TypeOptions{ Number: &configuration.NumberTypeOptions{ Min: func() *int { min := 0; return &min }(), Max: func() *int { max := maxNRQLTimeout; return &max }(), }, },
So the UI or Agent will also know that 120 is the max timeout
| responseBody, err := client.NerdGraphQuery(context.Background(), graphQLQuery) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to execute NRQL query: %v", err) | ||
| } | ||
|
|
||
| var response NerdGraphNRQLResponse | ||
| err = json.Unmarshal(responseBody, &response) | ||
| if err != nil { | ||
| return fmt.Errorf("error parsing response: %v", err) | ||
| } |
There was a problem hiding this comment.
It would be nice if every client response is already in the retuning struct. then you wouldn't need to unmarshal the json outside the client.
| type NerdGraphNRQLResponse struct { | ||
| Data struct { | ||
| Actor struct { | ||
| Account struct { | ||
| NRQL struct { | ||
| Results []any `json:"results"` | ||
| } `json:"nrql"` | ||
| } `json:"account"` | ||
| } `json:"actor"` | ||
| } `json:"data"` | ||
| Errors []struct { | ||
| Message string `json:"message"` | ||
| } `json:"errors"` | ||
| } | ||
|
|
||
| func quoteGraphQL(s string) string { | ||
| b, _ := json.Marshal(s) | ||
| return string(b) | ||
| } |
There was a problem hiding this comment.
And we could move this to the client.go as well
|
@vukasin-djuricic The code looks good at all, just added minor comments |
|
Thanks for the thorough review! Working on the following based on your feedback: Security / Webhook:
Client refactor (forestileao):
UX (AleksandarCole):
Will push an update shortly. |




Implements #2552
Summary
This PR adds a New Relic integration to SuperPlane, enabling users to react to alerts and query telemetry data from New Relic.
Authorization uses two keys:
Supports both US and EU data center regions.
Components
Implementation Details
pkg/integrations/newrelic/— client, integration, two components, one trigger, webhook handler, example dataweb_src/src/pages/workflowv2/mappers/newrelic/— mappers for all three components with execution details, metadata, and event sectionsmake gen.components.docs→docs/components/NewRelic.mdxSync,Execute,Setup, webhook parsing, and edge cases across all componentshttp.NewRequestWithContextto avoid context leaksValidateCredentialschecks the response body for GraphQL errors (NerdGraph returns HTTP 200 even for auth failures)Video Demo
https://youtu.be/_6P0luCxrpA
Checklist
pkg/integrations/newrelic/web_src/src/pages/workflowv2/mappers/newrelic/make gen.components.docsrevive)