HarperFast / HarperFast/studio
[RUM] Secrets operation failures publish Harper's composed error text to Error Tracking
- Dominant language
- TypeScript
- Stars
- 5
- Forks
- 4
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 40
Description
`operationErrorMessage` in [`src/integrations/api/instance/secrets/secrets.ts:58`](https://github.com/HarperFast/studio/blob/stage/src/integrations/api/instance/secrets/secrets.ts#L58) lifts Harper's response-body text into a `new Error(...)`:
```ts
function operationErrorMessage(error: unknown): string {
const body = (error as { response?: { data?: { error?: string; message?: string } } })?.response?.data;
return body?.error ?? body?.message ?? String(error);
}
```
Three call sites throw it (`createSecret`, `updateSecret`, `deleteSecret`). Those rejections reach React Query's global handler, which calls `console.error`, and the RUM SDK reports a `console.error` as an error event — so whatever Harper composed for a failed secrets operation is published to Datadog Error Tracking, where it is retained and searchable.
## Why the existing redaction doesn't cover it
`beforeSend` redacts URL- and scp-shaped tokens out of error text, and (as of the fix referenced below) withholds the message of a **relayed** error entirely. That withholding keys on `error.type`, which RUM takes from the thrown value's `name`. These are plain `new Error(...)`, so they arrive as `type: "Error"` and fall outside the rule.
Harper composes those operation errors by interpolation, the same way it composes the deploy failures where this class was first found — so the text can carry a name, path, or identifier the customer supplied, in whatever shape they supplied it. Free text with spaces is not URL-shaped and no bounded redaction rule spans it.
## Suggested direction
Give the relay a type the filter can see, rather than adding another message-shape rule: throw a named error class (mirroring `SSEOperationError`) from `operationErrorMessage`'s call sites and add it to `RELAYED_ERROR_TYPES`. That reuses the mechanism already in place and keeps the "is this text ours?" decision at the throw site, where it is known.
## Scale
Zero events in the last 7 days of production RUM — the path fires only when a secrets operation fails. It is filed as a latent exposure found while fixing the same class on the deploy path, not as an active leak.
## Related
- Fixed on the SSE deploy path by the PR linked below.
- Found by the cross-model pre-push review of that PR, which flagged it as a pre-existing sibling outside the diff.
Contributor guide
Research direction
Start at src/integrations/api/instance/secrets/secrets.ts:58 and trace the createSecret, updateSecret, and deleteSecret call sites into the RUM beforeSend filtering and RELAYED_ERROR_TYPES configuration. Compare the existing SSEOperationError handling, then verify that failed secrets-operation text is classified as relayed and no longer published as an error event.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- observability-sre, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100