Skip to content

fix: fixes plugin names sanitization for live loaded plugins for connectors - #4236

Merged
Pratham-Mishra04 merged 1 commit into
devfrom
06-10-fix_fixes_plugin_names_sanitization_for_live_loaded_plugins_for_connectors
Jun 9, 2026
Merged

fix: fixes plugin names sanitization for live loaded plugins for connectors#4236
Pratham-Mishra04 merged 1 commit into
devfrom
06-10-fix_fixes_plugin_names_sanitization_for_live_loaded_plugins_for_connectors

Conversation

@roroghost17

@roroghost17 roroghost17 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

The plugin tracing configuration sheet previously built its plugin list by merging a hardcoded built-in plugin list with custom plugins fetched from the config store. This meant enterprise plugins, auto-loaded plugins, and any plugin registered under a name different from its config key (e.g. enterprise-prompts instead of prompts) were silently missing from the list. As a result, users could not configure span filtering for those plugins, and any manually entered filter names could silently no-op.

This PR replaces that approach with a single /api/plugins/loaded endpoint that returns the sanitized names of every plugin actually loaded at runtime — the exact names embedded in their trace spans — and uses that list throughout the tracing sheet and filter logic.

Changes

  • Extracted SanitizePluginSpanName from core/utils.go into core/schemas/span_filter.go as an exported function so the same normalization logic is shared between span construction and span filtering.
  • Added GetLoadedPluginNames() to Config, BifrostHTTPServer, and the PluginsLoader/ServerCallbacks interfaces, returning deduplicated, sorted, sanitized plugin names for all currently loaded plugins.
  • Added a GET /api/plugins/loaded route backed by getLoadedPlugins, which returns the runtime plugin list.
  • Added a getLoadedPlugins RTK Query endpoint (useGetLoadedPluginsQuery) in the UI.
  • Replaced the built-in/custom split in pluginTracingSheet.tsx with a single flat list sourced from useGetLoadedPluginsQuery, removing the separate "Built-in Plugins" and "Custom Plugins" sections.
  • Added TestSanitizePluginSpanName and TestSanitizedNameMatchesSpanExtraction to lock the invariant that names used to build spans round-trip correctly through PluginNameFromSpan.
  • Updated the OTel and Datadog connector docs to clarify that plugin names in span filters must match the name shown in the tracing sheet, and that enterprise plugins like enterprise-prompts and enterprise-governance differ from their config keys.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

# Core/Transports
go test ./core/schemas/... ./transports/bifrost-http/...

# UI
cd ui
pnpm i
pnpm test
pnpm build
  1. Start the gateway with a mix of built-in, enterprise, and custom plugins loaded.
  2. Open the Configure Plugin Tracing sheet for an observability connector.
  3. Verify the plugin list includes enterprise plugins (e.g. enterprise-prompts, enterprise-governance) and any auto-loaded plugins, not just the hardcoded built-in set.
  4. Call GET /api/plugins/loaded directly and confirm the returned names match what appears in the sheet and in actual trace span names (plugin.<name>.<stage>).
  5. Configure an include or exclude filter using a name from the sheet and verify spans are correctly filtered in the connected APM backend.

Breaking changes

  • Yes
  • No

PluginsLoader and ServerCallbacks interfaces gain a GetLoadedPluginNames() []string method. Any external implementations of these interfaces must add this method.

Related issues

Security considerations

The /api/plugins/loaded endpoint exposes the names of all loaded plugins. It should be protected by the same middleware chain as other /api/plugins routes, which it is via ChainMiddlewares.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

Summary by CodeRabbit

  • New Features

    • API endpoint exposing currently loaded plugin names
    • Observability UI: unified "Plugins" list with improved initialization and select-all behavior
    • Consistent plugin name normalization so filter matching aligns with displayed plugin names
  • Documentation

    • Clarified plugin name guidance for span filtering; instructs copying exact names from the UI
  • Tests

    • Added tests for plugin name normalization and loaded-plugins endpoint

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a centralized /api/plugins/loaded endpoint to expose runtime-loaded plugin names with consistent sanitization, and refactors the frontend plugin tracing UI to consume a single unified query instead of separate built-in and custom plugin lists. Plugin name sanitization logic is extracted as a reusable function and span name handling delegates to it.

Changes

Plugin Name Sanitization and Loaded Plugins API

Layer / File(s) Summary
Plugin Name Sanitization Contract & Tests
core/schemas/span_filter.go, core/schemas/span_filter_test.go, core/utils.go
SanitizePluginSpanName normalizes plugin names to lowercase with space-to-hyphen replacement. Tests verify normalization behavior and enforce span-name round-trip invariants. sanitizeSpanName now delegates to the new function.
Backend Loaded Plugins Endpoint & Integration
transports/bifrost-http/handlers/plugins.go, transports/bifrost-http/handlers/plugins_test.go, transports/bifrost-http/lib/config.go, transports/bifrost-http/server/server.go
PluginsLoader interface gains GetLoadedPluginNames(). /api/plugins/loaded route registered and wired to handler. Config.GetLoadedPluginNames() enumerates BasePlugins, sanitizes, deduplicates, and sorts names. ServerCallbacks and BifrostHTTPServer expose the method via delegation; tests updated.
Frontend RTK Query Hook for Loaded Plugins
ui/lib/store/apis/pluginsApi.ts
New RTK Query endpoint getLoadedPlugins calls /plugins/loaded and exports useGetLoadedPluginsQuery hook.
Plugin Tracing UI Consolidation
ui/app/workspace/observability/sheets/pluginTracingSheet.tsx
Component now derives allPlugins from single useGetLoadedPluginsQuery instead of separate built-in/custom queries. UI consolidated into one "Plugins" section with unified toggle controls and initialization gated on load completion.
Plugin Span Filter Documentation
docs/enterprise/datadog-connector.mdx, docs/features/observability/otel.mdx
Documentation clarified to specify that plugin_span_filter matching requires exact plugin names from the UI's Configure Plugin Tracing sheet (span plugin.<name>.<stage> names), including guidance for enterprise deployments.

Sequence Diagram(s)

sequenceDiagram
  participant UI
  participant FrontendAPI
  participant PluginsHandler
  participant Config
  UI->>FrontendAPI: useGetLoadedPluginsQuery() request
  FrontendAPI->>PluginsHandler: GET /api/plugins/loaded
  PluginsHandler->>Config: GetLoadedPluginNames()
  Config-->>PluginsHandler: sanitized, deduped, sorted names
  PluginsHandler-->>FrontendAPI: { "plugins": [...] }
  FrontendAPI-->>UI: plugin list
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • maximhq/bifrost#3382: Introduced sanitization and plugin span matching behavior that relates to this PR's plugin-name normalization and loaded-plugins exposure.

Suggested reviewers

  • akshaydeo
  • danpiths

"I hop through spans with nimble paws so bright,
lowercase the names and hyphens make them right.
Backend hums a list, frontend sings along,
dedupe and sort — the toggles join the song. 🐇🎶"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main change: fixing plugin name sanitization for live-loaded plugins used in connectors' observability configuration.
Description check ✅ Passed The description comprehensively covers the purpose, changes, affected areas, testing instructions, and breaking changes, closely following the repository template structure.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 06-10-fix_fixes_plugin_names_sanitization_for_live_loaded_plugins_for_connectors

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@roroghost17
roroghost17 marked this pull request as ready for review June 9, 2026 21:30
@CLAassistant

CLAassistant commented Jun 9, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@greptile-apps

greptile-apps Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

Safe to merge — all filter modes are guarded against saving while the plugin list is loading, the new endpoint is behind the same middleware as existing plugin routes, and the round-trip invariant test prevents the span-name/filter-name mismatch from regressing.

The Go-side changes are straightforward atomic reads with deduplication and sorting. The new endpoint and interface methods have adequate test coverage. The initialization guard in the tracing sheet correctly handles loading, error, and empty states by keeping Save disabled. The only gap is that an API error shows an empty list with no user-visible explanation, which is a UX nit that does not risk data loss.

No files require special attention for correctness. pluginTracingSheet.tsx could improve its error-state UX by surfacing isError from useGetLoadedPluginsQuery.

Important Files Changed

Filename Overview
core/schemas/span_filter.go Exports SanitizePluginSpanName and updates PluginNameFromSpan doc to include prerequesthook; logic is unchanged and correct.
core/schemas/span_filter_test.go Adds TestSanitizePluginSpanName and TestSanitizedNameMatchesSpanExtraction which together lock the round-trip invariant between span construction and filtering.
core/utils.go Delegates sanitizeSpanName to the shared schemas.SanitizePluginSpanName, eliminating duplicate logic.
transports/bifrost-http/handlers/plugins.go Adds GetLoadedPluginNames() to PluginsLoader interface, registers GET /api/plugins/loaded, and provides getLoadedPlugins handler; middleware is correctly chained via ChainMiddlewares.
transports/bifrost-http/handlers/plugins_test.go Adds noopPluginsLoader.GetLoadedPluginNames() stub and TestGetLoadedPlugins which locks the response JSON shape the UI depends on.
transports/bifrost-http/lib/config.go Implements GetLoadedPluginNames() by atomically reading BasePlugins, sanitizing names, deduplicating, and sorting; correctly skips empty names.
transports/bifrost-http/server/server.go Adds GetLoadedPluginNames() to ServerCallbacks interface and implements it on BifrostHTTPServer with a nil-Config guard.
ui/app/workspace/observability/sheets/pluginTracingSheet.tsx Replaces two-query (built-in + custom) approach with a single useGetLoadedPluginsQuery call; initialization guard now correctly blocks all filter modes during loading or when the list is empty, but errors from the API leave an empty sheet and a permanently-disabled Save button with no user-visible error message.
ui/lib/store/apis/pluginsApi.ts Adds getLoadedPlugins RTK Query endpoint pointing to /plugins/loaded with providesTags: ["Plugins"] and correct transform.

Reviews (3): Last reviewed commit: "fix: fixes plugin names sanitization for..." | Re-trigger Greptile

Comment thread transports/bifrost-http/lib/config.go Outdated
Comment thread core/schemas/span_filter.go Outdated
Comment thread transports/bifrost-http/handlers/plugins.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@transports/bifrost-http/handlers/plugins.go`:
- Around line 171-177: Add a unit test for PluginsHandler.getLoadedPlugins that
mirrors other handler tests: create a mock plugins loader (e.g.,
mockPluginsLoaderWithNames) returning a known slice like
["logging","telemetry","governance"], instantiate PluginsHandler with that
loader, call getLoadedPlugins on a new fasthttp.RequestCtx (set method to GET),
then assert ctx.Response.StatusCode() == 200 and that the JSON body contains a
"plugins" array of the expected length and values; also use
SetLogger(&mockLogger{}) as in other tests to silence logging.

In `@transports/bifrost-http/server/server.go`:
- Around line 1162-1166: GetLoadedPluginNames currently calls
s.Config.GetLoadedPluginNames() without checking s.Config for nil; add the same
defensive nil-check used in GetModelsForProvider and
GetUnfilteredModelsForProvider: if s.Config == nil return an empty []string,
otherwise return s.Config.GetLoadedPluginNames(); update the
GetLoadedPluginNames method on BifrostHTTPServer to mirror those methods'
pattern.

In `@ui/app/workspace/observability/sheets/pluginTracingSheet.tsx`:
- Around line 63-67: The include-mode initialization is treating an empty array
from useGetLoadedPluginsQuery as "still loading" because it checks
allPlugins.length === 0, which deadlocks when the backend legitimately returns
[] and prevents wasOpenRef.current from being set and Save from enabling; change
the guard to detect loading by checking whether allPlugins is undefined/null
(i.e., use allPlugins === undefined or data === undefined) instead of length,
and ensure the logic around wasOpenRef.current and the include-mode
initialization in the component that references useGetLoadedPluginsQuery,
allPlugins, useGetPluginQuery, and wasOpenRef.current treats an empty array as a
valid loaded state so initialization and Save can proceed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 34f34495-6ec3-47e6-a562-4e7744fcbd5a

📥 Commits

Reviewing files that changed from the base of the PR and between ca21298 and 8dbaa21.

📒 Files selected for processing (11)
  • core/schemas/span_filter.go
  • core/schemas/span_filter_test.go
  • core/utils.go
  • docs/enterprise/datadog-connector.mdx
  • docs/features/observability/otel.mdx
  • transports/bifrost-http/handlers/plugins.go
  • transports/bifrost-http/handlers/plugins_test.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/server/server.go
  • ui/app/workspace/observability/sheets/pluginTracingSheet.tsx
  • ui/lib/store/apis/pluginsApi.ts

Comment thread transports/bifrost-http/handlers/plugins.go
Comment thread transports/bifrost-http/server/server.go
Comment thread ui/app/workspace/observability/sheets/pluginTracingSheet.tsx
@roroghost17
roroghost17 force-pushed the 06-10-fix_fixes_plugin_names_sanitization_for_live_loaded_plugins_for_connectors branch from 8dbaa21 to 525b897 Compare June 9, 2026 21:59
Comment thread ui/app/workspace/observability/sheets/pluginTracingSheet.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ui/app/workspace/observability/sheets/pluginTracingSheet.tsx (1)

66-82: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Block initialization/save when loaded-plugins query fails.

Line 76 only gates on loading. If /plugins/loaded fails, allPlugins falls back to [], initialization still completes, and Save can wipe an existing include filter.

Suggested patch
-	const { data: allPlugins = [], isLoading: isLoadingLoadedPlugins } = useGetLoadedPluginsQuery();
+	const {
+		data: loadedPlugins,
+		isLoading: isLoadingLoadedPlugins,
+		isError: isLoadedPluginsError,
+	} = useGetLoadedPluginsQuery();
+	const allPlugins = loadedPlugins ?? [];
@@
-			if (filter?.mode === "include" && isLoadingLoadedPlugins) return;
+			if (filter?.mode === "include" && (isLoadingLoadedPlugins || isLoadedPluginsError)) return;
@@
-	}, [open, targetPlugin, allPlugins, isLoadingLoadedPlugins]);
+	}, [open, targetPlugin, allPlugins, isLoadingLoadedPlugins, isLoadedPluginsError]);
@@
 		if (!targetPlugin) {
 			toast.error(`${destination} is not configured yet. Save its configuration before configuring plugin tracing.`);
 			return;
 		}
+		if (isLoadedPluginsError) {
+			toast.error("Could not load plugin list. Please retry.");
+			return;
+		}
@@
-	}, [toggles, targetPlugin, updatePlugin, onClose, pluginName, destination]);
+	}, [toggles, targetPlugin, updatePlugin, onClose, pluginName, destination, isLoadedPluginsError]);
@@
-							disabled={isLoading || !wasOpenRef.current}
+							disabled={isLoading || !wasOpenRef.current || isLoadedPluginsError}

Also applies to: 87-113, 170-170

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/app/workspace/observability/sheets/pluginTracingSheet.tsx` around lines 66
- 82, The initialization currently proceeds when the loaded-plugins query fails
because it only checks isLoadingLoadedPlugins; update the effect(s) that set
toggles (where you call setToggles(resolveToggleState(...))) to also check the
loaded-plugins error state returned by useGetLoadedPluginsQuery (e.g., isError
or error) and abort initialization/save if the query errored so you don't treat
allPlugins fallback [] as a valid source; specifically, in the effect that
references open, targetPlugin, allPlugins, isLoadingLoadedPlugins (and the other
similar blocks noted), add a guard like "if (isErrorLoadedPlugins) return"
before calling resolveToggleState or allowing Save to proceed. Ensure you
reference the existing hooks/variables (useGetLoadedPluginsQuery, allPlugins,
isLoadingLoadedPlugins, isErrorLoadedPlugins, targetPlugin, resolveToggleState)
when implementing the check.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/schemas/span_filter_test.go`:
- Around line 67-69: The test failure message for SanitizePluginSpanName has the
got/want arguments swapped; update the t.Errorf call in the test (the assertion
around SanitizePluginSpanName(tt.in)) so the formatting order is
t.Errorf("SanitizePluginSpanName(%q) = %q, want %q", tt.in, got, tt.want) —
i.e., pass the variable holding the actual result (got) before the expected
value (tt.want) so failures print correctly.

---

Outside diff comments:
In `@ui/app/workspace/observability/sheets/pluginTracingSheet.tsx`:
- Around line 66-82: The initialization currently proceeds when the
loaded-plugins query fails because it only checks isLoadingLoadedPlugins; update
the effect(s) that set toggles (where you call
setToggles(resolveToggleState(...))) to also check the loaded-plugins error
state returned by useGetLoadedPluginsQuery (e.g., isError or error) and abort
initialization/save if the query errored so you don't treat allPlugins fallback
[] as a valid source; specifically, in the effect that references open,
targetPlugin, allPlugins, isLoadingLoadedPlugins (and the other similar blocks
noted), add a guard like "if (isErrorLoadedPlugins) return" before calling
resolveToggleState or allowing Save to proceed. Ensure you reference the
existing hooks/variables (useGetLoadedPluginsQuery, allPlugins,
isLoadingLoadedPlugins, isErrorLoadedPlugins, targetPlugin, resolveToggleState)
when implementing the check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d4d7ea3c-cf66-46f0-9331-c32616e378f6

📥 Commits

Reviewing files that changed from the base of the PR and between 8dbaa21 and 525b897.

📒 Files selected for processing (11)
  • core/schemas/span_filter.go
  • core/schemas/span_filter_test.go
  • core/utils.go
  • docs/enterprise/datadog-connector.mdx
  • docs/features/observability/otel.mdx
  • transports/bifrost-http/handlers/plugins.go
  • transports/bifrost-http/handlers/plugins_test.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/server/server.go
  • ui/app/workspace/observability/sheets/pluginTracingSheet.tsx
  • ui/lib/store/apis/pluginsApi.ts

Comment thread core/schemas/span_filter_test.go
@roroghost17
roroghost17 force-pushed the 06-10-fix_fixes_plugin_names_sanitization_for_live_loaded_plugins_for_connectors branch from 525b897 to e8a8e48 Compare June 9, 2026 22:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/app/workspace/observability/sheets/pluginTracingSheet.tsx`:
- Line 76: The current guard if (isLoadingLoadedPlugins || allPlugins.length ===
0) incorrectly treats an empty allPlugins array as "not loaded" and prevents
initialization; change the condition to only block when loading: check
isLoadingLoadedPlugins (or a dedicated loading flag) but allow empty arrays to
proceed so wasOpenRef.current gets set to true and enabling Save; ensure
initialization logic that calls resolveToggleState(filter, allPlugins),
buildFilter({}), and sets plugin_span_filter can handle an empty allPlugins
array as a valid loaded state (references: isLoadingLoadedPlugins, allPlugins,
wasOpenRef.current, resolveToggleState, buildFilter, plugin_span_filter).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0dccfbd3-e1f6-4be0-97f2-81f48112849f

📥 Commits

Reviewing files that changed from the base of the PR and between 525b897 and e8a8e48.

📒 Files selected for processing (11)
  • core/schemas/span_filter.go
  • core/schemas/span_filter_test.go
  • core/utils.go
  • docs/enterprise/datadog-connector.mdx
  • docs/features/observability/otel.mdx
  • transports/bifrost-http/handlers/plugins.go
  • transports/bifrost-http/handlers/plugins_test.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/server/server.go
  • ui/app/workspace/observability/sheets/pluginTracingSheet.tsx
  • ui/lib/store/apis/pluginsApi.ts

Comment thread ui/app/workspace/observability/sheets/pluginTracingSheet.tsx

Pratham-Mishra04 commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Merge activity

  • Jun 9, 10:32 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jun 9, 10:33 PM UTC: @Pratham-Mishra04 merged this pull request with Graphite.

@Pratham-Mishra04
Pratham-Mishra04 merged commit ad34c78 into dev Jun 9, 2026
15 of 16 checks passed
@Pratham-Mishra04
Pratham-Mishra04 deleted the 06-10-fix_fixes_plugin_names_sanitization_for_live_loaded_plugins_for_connectors branch June 9, 2026 22:33
akshaydeo pushed a commit that referenced this pull request Jun 12, 2026
…ectors (#4236)

## Summary

The plugin tracing configuration sheet previously built its plugin list by merging a hardcoded built-in plugin list with custom plugins fetched from the config store. This meant enterprise plugins, auto-loaded plugins, and any plugin registered under a name different from its config key (e.g. `enterprise-prompts` instead of `prompts`) were silently missing from the list. As a result, users could not configure span filtering for those plugins, and any manually entered filter names could silently no-op.

This PR replaces that approach with a single `/api/plugins/loaded` endpoint that returns the sanitized names of every plugin actually loaded at runtime — the exact names embedded in their trace spans — and uses that list throughout the tracing sheet and filter logic.

## Changes

- Extracted `SanitizePluginSpanName` from `core/utils.go` into `core/schemas/span_filter.go` as an exported function so the same normalization logic is shared between span construction and span filtering.
- Added `GetLoadedPluginNames()` to `Config`, `BifrostHTTPServer`, and the `PluginsLoader`/`ServerCallbacks` interfaces, returning deduplicated, sorted, sanitized plugin names for all currently loaded plugins.
- Added a `GET /api/plugins/loaded` route backed by `getLoadedPlugins`, which returns the runtime plugin list.
- Added a `getLoadedPlugins` RTK Query endpoint (`useGetLoadedPluginsQuery`) in the UI.
- Replaced the built-in/custom split in `pluginTracingSheet.tsx` with a single flat list sourced from `useGetLoadedPluginsQuery`, removing the separate "Built-in Plugins" and "Custom Plugins" sections.
- Added `TestSanitizePluginSpanName` and `TestSanitizedNameMatchesSpanExtraction` to lock the invariant that names used to build spans round-trip correctly through `PluginNameFromSpan`.
- Updated the OTel and Datadog connector docs to clarify that plugin names in span filters must match the name shown in the tracing sheet, and that enterprise plugins like `enterprise-prompts` and `enterprise-governance` differ from their config keys.

## Type of change

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [x] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [x] Plugins
- [x] UI (React)
- [x] Docs

## How to test

```sh
# Core/Transports
go test ./core/schemas/... ./transports/bifrost-http/...

# UI
cd ui
pnpm i
pnpm test
pnpm build
```

1. Start the gateway with a mix of built-in, enterprise, and custom plugins loaded.
2. Open the **Configure Plugin Tracing** sheet for an observability connector.
3. Verify the plugin list includes enterprise plugins (e.g. `enterprise-prompts`, `enterprise-governance`) and any auto-loaded plugins, not just the hardcoded built-in set.
4. Call `GET /api/plugins/loaded` directly and confirm the returned names match what appears in the sheet and in actual trace span names (`plugin.<name>.<stage>`).
5. Configure an `include` or `exclude` filter using a name from the sheet and verify spans are correctly filtered in the connected APM backend.

## Breaking changes

- [x] Yes
- [ ] No

`PluginsLoader` and `ServerCallbacks` interfaces gain a `GetLoadedPluginNames() []string` method. Any external implementations of these interfaces must add this method.

## Related issues

## Security considerations

The `/api/plugins/loaded` endpoint exposes the names of all loaded plugins. It should be protected by the same middleware chain as other `/api/plugins` routes, which it is via `ChainMiddlewares`.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * API endpoint exposing currently loaded plugin names
  * Observability UI: unified "Plugins" list with improved initialization and select-all behavior
  * Consistent plugin name normalization so filter matching aligns with displayed plugin names

* **Documentation**
  * Clarified plugin name guidance for span filtering; instructs copying exact names from the UI

* **Tests**
  * Added tests for plugin name normalization and loaded-plugins endpoint
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.

3 participants