Skip to content

feat: add env.VAR_NAME support to observability plugin config fields via EnvVarInput and storage normalization#3577

Draft
BearTS wants to merge 1 commit into
devfrom
05-19-feat_add_support_for_env_variables_on_certain_fields_in_plugins
Draft

feat: add env.VAR_NAME support to observability plugin config fields via EnvVarInput and storage normalization#3577
BearTS wants to merge 1 commit into
devfrom
05-19-feat_add_support_for_env_variables_on_certain_fields_in_plugins

Conversation

@BearTS
Copy link
Copy Markdown
Contributor

@BearTS BearTS commented May 18, 2026

Summary

Plugin configuration fields that previously accepted only plain strings now support env.VAR_NAME references, allowing sensitive values like API keys, collector URLs, and push gateway credentials to be sourced from environment variables at runtime rather than stored as literals.

Changes

  • Maxim plugin: APIKey and LogRepoID fields changed from string to schemas.EnvVar. All usages updated to call .GetValue().
  • OTel plugin: CollectorURL and MetricsEndpoint changed from string to schemas.EnvVar. A missing collector_url validation guard was added to Init. All usages updated to call .GetValue().
  • Telemetry/Prometheus plugin: PushGatewayURL, BasicAuthConfig.Username, and BasicAuthConfig.Password changed from string to schemas.EnvVar. All usages updated to call .GetValue().
  • Config store normalization: Added normalizePluginConfigForStorage in framework/configstore/tables/plugin.go. This function recursively walks a plugin config map before it is marshaled and encrypted, collapsing any {value, env_var, from_env} shaped objects into plain strings ("env.VAR_NAME" or a literal value). This keeps the stored JSON consistent with the format used by config.json and ProxyConfig.MarshalForStorage.
  • UI schemas: otelConfigSchema, maximConfigSchema, and prometheusConfigSchema fields updated from z.string() to envVarSchema. Validation logic updated to use isEnvVarSet instead of string trimming, and format checks are skipped when a field is sourced from an env var (from_env: true).
  • UI forms: normalizeEnvVar helper exported from schemas.ts to safely coerce string | EnvVar | undefined into a proper EnvVar object. Form default values and resets updated to use it. isEnvVarSet exported and used to drive showBasicAuth state and basic auth inclusion logic.
  • UI components: Password/API key fields that previously used a manual show/hide Input with eye-icon buttons replaced with the EnvVarInput component using maskNonEnvValue. Collector URL and metrics endpoint fields similarly replaced with EnvVarInput. A note about env.VAR_NAME support added to the OTel headers table description.

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 ./plugins/maxim/... ./plugins/otel/... ./plugins/telemetry/... ./framework/configstore/...

# UI
cd ui
pnpm i
pnpm build
pnpm test

Environment variable resolution: Configure a plugin with collector_url: env.OTEL_COLLECTOR_URL (or equivalent), set the environment variable, and verify the plugin initializes using the resolved value rather than the literal string.

Storage normalization: Save a plugin config via the UI using an env.VAR_NAME reference, then inspect the stored JSON to confirm it contains the plain token string rather than a {value, env_var, from_env} object.

Literal values: Confirm that plain literal values (e.g., a real API key) continue to work and are stored as plain strings.

Breaking changes

  • Yes
  • No

Plugin Config structs for Maxim, OTel, and Telemetry have changed field types from string to schemas.EnvVar. Any code that directly assigns or reads these fields as strings must be updated to use schemas.EnvVar values and .GetValue(). Configs stored as plain strings in the database remain compatible due to the normalization hook.

Security considerations

Sensitive fields (API keys, passwords, push gateway credentials) are no longer required to be stored as plaintext literals. They can now reference environment variables, reducing the risk of secrets being written to the database. The normalizePluginConfigForStorage hook ensures that even if the UI submits an EnvVar object shape, only the resolved token or literal is persisted, preventing unexpected JSON object shapes from reaching the encrypted config column.

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1f4377ba-2fc9-4e3d-b7a7-c401dca1111a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds env-var-backed fields end‑to‑end: Zod schema helpers and validation, UI EnvVar inputs and normalization, plugin code resolving values via GetValue(), storage normalization/denormalization, and HTTP handlers mapping unresolved-env errors to 400.

Changes

Environment-Variable Config Integration

Layer / File(s) Summary
Schema contracts and validation helpers
ui/lib/types/schemas.ts
Exports isEnvVarSet and normalizeEnvVar; updates OTEL/Maxim/Prometheus schemas to accept env-var-backed fields and adjust validation when values are env-sourced.
Config storage normalization
framework/configstore/tables/plugin.go
Adds normalization/denormalization helpers and ErrUnresolvedEnvVars; TablePlugin.BeforeSave normalizes plugin config and rejects unresolved env.* tokens before marshaling; AfterFind denormalizes stored env.* strings back into EnvVar-shaped objects.
Maxim plugin env-var integration
plugins/maxim/main.go, plugins/maxim/plugin_test.go
Changes APIKey and LogRepoID to schemas.EnvVar; Init resolves via GetValue() and validates API key; tests updated to construct EnvVar configs and use GetValue() checks.
OTEL plugin env-var integration
plugins/otel/main.go
Changes CollectorURL and MetricsEndpoint to schemas.EnvVar; Init validates/resolves collector URL and metrics endpoint when enabled, passing resolved URLs into client/exporter; ValidateConfig uses resolved checks.
Telemetry / Prometheus backend
plugins/telemetry/main.go
Push gateway URL and basic-auth credentials become schemas.EnvVar; EnablePushGateway resolves and validates URL and credentials via GetValue() and conditionally applies basic auth.
HTTP handlers: plugin create/update
transports/bifrost-http/handlers/plugins.go
Map ErrUnresolvedEnvVars returned from storage create/update to 400 Bad Request with the error message instead of a generic 500.
Maxim form: EnvVarInput and normalization
ui/app/workspace/observability/fragments/maximFormFragment.tsx
Replaces API key and log repo inputs with EnvVarInput, removes visibility toggle, and normalizes defaults/resets using normalizeEnvVar.
OTEL form: EnvVarInput and normalization
ui/app/workspace/observability/fragments/otelFormFragment.tsx
Switches collector URL and metrics endpoint inputs to EnvVarInput, normalizes defaults/resets, and documents env.VAR_NAME usage for headers.
Prometheus form & view: EnvVarInput and env-var aware logic
ui/app/workspace/observability/fragments/prometheusFormFragment.tsx, ui/app/workspace/observability/views/plugins/prometheusView.tsx
Uses EnvVarInput for push gateway and basic-auth fields, derives showBasicAuth from isEnvVarSet, normalizes defaults/resets, and uses isEnvVarSet when saving basic_auth.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • akshaydeo
  • danpiths

🐰 I hopped through configs, fields in tow,
From schema roots to forms below,
I tucked env secrets where they may be,
Resolved at run, stored plainly—see?
Happy plugins, safely freed.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% 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 and specifically describes the main feature: adding environment variable support to plugin config fields via EnvVarInput and storage normalization.
Description check ✅ Passed The description follows the template structure with comprehensive coverage of summary, changes, type of change, affected areas, testing steps, breaking changes, and security considerations.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 05-19-feat_add_support_for_env_variables_on_certain_fields_in_plugins

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

Copy link
Copy Markdown
Contributor Author

BearTS commented May 18, 2026

@BearTS BearTS changed the title feat: add support for env variables on certain fields in plugins feat: add env.VAR_NAME support to observability plugin config fields via EnvVarInput and storage normalization May 18, 2026
@BearTS BearTS marked this pull request as ready for review May 18, 2026 21:57
@coderabbitai coderabbitai Bot requested review from akshaydeo and danpiths May 18, 2026 21:58
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 18, 2026

Confidence Score: 3/5

Not ready to merge without resolving the open breaking-behavior and validation issues in the plugin Init paths and storage normalization.

Three open concerns from prior review rounds remain unaddressed: the Telemetry Init guard was widened so a plugin configured with enabled=true and an empty or unresolvable push-gateway URL now hard-fails on startup instead of silently skipping; the OTel ValidateConfig and new Init guard both call GetValue() on CollectorURL, which returns empty string when the referenced env var is absent, rejecting a legitimately-configured env-var reference; and normalizePluginConfigForStorage plus checkEnvVarsResolved are both no-ops when Config is a typed struct rather than map[string]any.

plugins/telemetry/main.go (Init guard change), plugins/otel/main.go (ValidateConfig and Init guard), framework/configstore/tables/plugin.go (typed-struct bypass)

Important Files Changed

Filename Overview
framework/configstore/tables/plugin.go Adds BeforeSave normalization and AfterFind denormalization for EnvVar fields. Normalization and env-var resolution check are silently skipped when Config is a typed struct (not map[string]any).
plugins/otel/main.go CollectorURL and MetricsEndpoint changed to schemas.EnvVar. ValidateConfig and new Init guard use GetValue() which returns empty string for unresolved env var references.
plugins/telemetry/main.go PushGatewayURL, Username, Password changed to schemas.EnvVar. Init guard changed from Enabled && PushGatewayURL != empty to just Enabled, causing hard failure when URL is empty or unresolvable.
plugins/maxim/main.go APIKey and LogRepoID changed to schemas.EnvVar, all usages updated to GetValue(). Clean and straightforward migration.
transports/bifrost-http/handlers/plugins.go Adds ErrUnresolvedEnvVars handling for create and update paths. The updatePlugin path uses err.Error() instead of envErr.Error(), inconsistent with createPlugin.
ui/lib/types/schemas.ts Adds normalizeEnvVar and exports isEnvVarSet; updates plugin schemas to use envVarSchema. normalizeEnvVar treats plain env.VAR_NAME strings as literal values rather than reconstructing the from_env=true shape.
ui/app/workspace/observability/fragments/maximFormFragment.tsx Replaces manual password Input/eye-toggle with EnvVarInput; uses normalizeEnvVar for form defaults and resets.
ui/app/workspace/observability/fragments/otelFormFragment.tsx Collector URL and metrics endpoint fields replaced with EnvVarInput; normalizeEnvVar used for form defaults and resets.
ui/app/workspace/observability/fragments/prometheusFormFragment.tsx Push gateway URL, username, and password fields migrated to EnvVarInput. showBasicAuth state updated to use isEnvVarSet.
ui/app/workspace/observability/views/plugins/prometheusView.tsx basic_auth inclusion logic updated to use isEnvVarSet; type interfaces updated for string
plugins/maxim/plugin_test.go Tests updated to use schemas.NewEnvVar and .GetValue(). Functional coverage preserved.

Reviews (3): Last reviewed commit: "feat: add support for env variables on c..." | Re-trigger Greptile

Comment thread ui/lib/types/schemas.ts
Comment thread ui/lib/types/schemas.ts
Comment thread framework/configstore/tables/plugin.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (1)
plugins/maxim/plugin_test.go (1)

209-246: ⚡ Quick win

Add one unit case for a real env.* token.

These cases only cover schemas.NewEnvVar("literal"), so the new runtime path that resolves env.VAR_NAME is still untested unless the integration test runs with live credentials. A small t.Setenv(...) case here would cover the feature this PR is introducing.

💡 Example test shape
 	{
 		name: "Valid config with both fields",
 		config: Config{
 			APIKey:    *schemas.NewEnvVar("test-api-key"),
 			LogRepoID: *schemas.NewEnvVar("test-repo-id"),
 		},
 		expectError: false,
 	},
+	{
+		name: "Valid config with env-backed API key",
+		config: Config{
+			APIKey:    *schemas.NewEnvVar("env.TEST_MAXIM_API_KEY"),
+			LogRepoID: *schemas.NewEnvVar(""),
+		},
+		expectError: false,
+	},
t.Setenv("TEST_MAXIM_API_KEY", "test-api-key")
🤖 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 `@plugins/maxim/plugin_test.go` around lines 209 - 246, Add a unit case that
exercises the env.* runtime path by setting an environment variable with
t.Setenv and using schemas.NewEnvVar("env.TEST_MAXIM_API_KEY") (or similar env
token) for Config.APIKey in the tests block; ensure the test uses the same
validation path as the other cases (checks APIKey.GetValue() or calls
Init(&tt.config, logger) as appropriate) so the new runtime resolution code is
executed without needing real credentials.
🤖 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 `@framework/configstore/tables/plugin.go`:
- Around line 49-61: The normalization currently requires all three EnvVar keys
(value, env_var, from_env) and len(val)==3 which misses valid sparse EnvVar
objects; update the heuristic in plugin.go to treat any object that has at least
the EnvVar shape as an EnvVar: check hasValue, hasEnvVar, hasFromEnv
individually (remove the len(val) == 3 requirement) and then if from_env (cast
val["from_env"] to bool) and env_var is present (cast to string) return that
env_var, otherwise if value is present (cast to string) return the value; keep
safe type assertions and fall back to returning the original object only when
neither key is usable.

In `@plugins/telemetry/main.go`:
- Around line 406-409: The current guard in the startup path checks both
config.PushGateway.Enabled and that config.PushGateway.PushGatewayURL.GetValue()
!= "" which causes a silent no-op when the URL is an unresolved env var; change
the logic so that whenever config.PushGateway.Enabled is true you always call
plugin.EnablePushGateway(config.PushGateway) (remove the extra GetValue()
non-empty check) so EnablePushGateway can validate the URL and return an error;
update the if-block around plugin.EnablePushGateway in main.go to only check
config.PushGateway != nil && config.PushGateway.Enabled and let
EnablePushGateway surface misconfiguration errors.
- Around line 785-786: Check that both resolved credentials are non-empty before
constructing the BasicAuth pusher: read username :=
config.BasicAuth.Username.GetValue() and password :=
config.BasicAuth.Password.GetValue() and only call pusher =
pusher.BasicAuth(username, password) when username != "" && password != ""; if
one is empty, skip building the pusher (or return/log an error) so you don't
create a pusher that will always fail later.

In `@ui/app/workspace/observability/fragments/maximFormFragment.tsx`:
- Around line 70-76: The new EnvVarInput instances (the ones using
value={field.value} and onChange={field.onChange}) are missing data-testid
attributes; add data-testid attributes following the convention
data-testid="<entity>-<element>-<qualifier>" on both EnvVarInput components (the
one with placeholder "Enter your Maxim API key..." and the other similar
control) so e2e selectors can target them (e.g.,
data-testid="maxim-api-key-input" or similar descriptive names) while keeping
existing props like disabled, maskNonEnvValue, value and onChange intact.

In `@ui/app/workspace/observability/fragments/otelFormFragment.tsx`:
- Around line 153-162: The new EnvVarInput components (used with
form.watch("otel_config.protocol"), hasOtelAccess, field.value, and
field.onChange) are missing data-testid attributes required for stable E2E
selectors; add data-testid attributes to each EnvVarInput instance using the
project naming convention data-testid="<entity>-<element>-<qualifier>" (for
example something like data-testid="otel-env-var-input-url" and
"otel-env-var-input-hostport") so both the input at the current block and the
other instance around lines 336–343 are selectable in tests.

In `@ui/lib/types/schemas.ts`:
- Around line 76-80: normalizeEnvVar currently treats any string like
"env.MY_VAR" as a literal value, breaking round-tripping for env-backed fields;
update the string branch in normalizeEnvVar to detect strings that start with
the "env." prefix and return an EnvVar object with value: "" (or empty),
env_var: the substring after "env.", and from_env: true; otherwise keep the
existing behavior for plain strings. Ensure you only change the typeof v ===
"string" branch in function normalizeEnvVar so stored "env.MY_VAR" values reopen
as env-backed fields.

---

Nitpick comments:
In `@plugins/maxim/plugin_test.go`:
- Around line 209-246: Add a unit case that exercises the env.* runtime path by
setting an environment variable with t.Setenv and using
schemas.NewEnvVar("env.TEST_MAXIM_API_KEY") (or similar env token) for
Config.APIKey in the tests block; ensure the test uses the same validation path
as the other cases (checks APIKey.GetValue() or calls Init(&tt.config, logger)
as appropriate) so the new runtime resolution code is executed without needing
real credentials.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d50fc59b-bda4-4fbc-8448-3f029581b1dc

📥 Commits

Reviewing files that changed from the base of the PR and between 30ed554 and 1f5fe0c.

📒 Files selected for processing (10)
  • framework/configstore/tables/plugin.go
  • plugins/maxim/main.go
  • plugins/maxim/plugin_test.go
  • plugins/otel/main.go
  • plugins/telemetry/main.go
  • ui/app/workspace/observability/fragments/maximFormFragment.tsx
  • ui/app/workspace/observability/fragments/otelFormFragment.tsx
  • ui/app/workspace/observability/fragments/prometheusFormFragment.tsx
  • ui/app/workspace/observability/views/plugins/prometheusView.tsx
  • ui/lib/types/schemas.ts

Comment on lines +49 to +61
// Detect an EnvVar object: must have exactly "value", "env_var", and "from_env" keys — no more.
// This mirrors what schemas.EnvVar serializes to, keeping the heuristic tight.
_, hasValue := val["value"]
_, hasEnvVar := val["env_var"]
_, hasFromEnv := val["from_env"]
if hasValue && hasEnvVar && hasFromEnv && len(val) == 3 {
if fromEnv, _ := val["from_env"].(bool); fromEnv {
envVar, _ := val["env_var"].(string)
return envVar // "env.VAR_NAME"
}
value, _ := val["value"].(string)
return value
}
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t require all three EnvVar keys to normalize.

The new heuristic only converts objects with exactly value, env_var, and from_env. That misses valid sparse EnvVar payloads, even though the schema layer accepts those keys as optional. In those cases this hook will persist JSON objects instead of the plain-string format the rest of the PR is standardizing on.

💡 Suggested fix
 	case map[string]any:
-		// Detect an EnvVar object: must have exactly "value", "env_var", and "from_env" keys — no more.
-		// This mirrors what schemas.EnvVar serializes to, keeping the heuristic tight.
-		_, hasValue := val["value"]
-		_, hasEnvVar := val["env_var"]
-		_, hasFromEnv := val["from_env"]
-		if hasValue && hasEnvVar && hasFromEnv && len(val) == 3 {
+		_, hasValue := val["value"]
+		_, hasEnvVar := val["env_var"]
+		_, hasFromEnv := val["from_env"]
+		isEnvVarShape := len(val) > 0
+		for k := range val {
+			if k != "value" && k != "env_var" && k != "from_env" {
+				isEnvVarShape = false
+				break
+			}
+		}
+		if isEnvVarShape && (hasValue || hasEnvVar || hasFromEnv) {
 			if fromEnv, _ := val["from_env"].(bool); fromEnv {
 				envVar, _ := val["env_var"].(string)
 				return envVar // "env.VAR_NAME"
 			}
 			value, _ := val["value"].(string)
 			return value
 		}
🤖 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 `@framework/configstore/tables/plugin.go` around lines 49 - 61, The
normalization currently requires all three EnvVar keys (value, env_var,
from_env) and len(val)==3 which misses valid sparse EnvVar objects; update the
heuristic in plugin.go to treat any object that has at least the EnvVar shape as
an EnvVar: check hasValue, hasEnvVar, hasFromEnv individually (remove the
len(val) == 3 requirement) and then if from_env (cast val["from_env"] to bool)
and env_var is present (cast to string) return that env_var, otherwise if value
is present (cast to string) return the value; keep safe type assertions and fall
back to returning the original object only when neither key is usable.

Comment thread plugins/telemetry/main.go Outdated
Comment thread plugins/telemetry/main.go Outdated
Comment thread ui/app/workspace/observability/fragments/maximFormFragment.tsx
Comment thread ui/app/workspace/observability/fragments/otelFormFragment.tsx
Comment thread ui/lib/types/schemas.ts
Comment on lines +76 to +80
// Normalize a string | EnvVar | undefined to a proper EnvVar object
export function normalizeEnvVar(v?: string | { value?: string; env_var?: string; from_env?: boolean }): { value: string; env_var: string; from_env: boolean } {
if (!v) return { value: "", env_var: "", from_env: false };
if (typeof v === "string") return { value: v, env_var: "", from_env: false };
return { value: v.value ?? "", env_var: v.env_var ?? "", from_env: v.from_env ?? false };
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore env-token round-tripping in normalizeEnvVar.

Saved env-backed values now come back from storage as plain strings like env.MY_VAR, but this helper currently rehydrates them as literal values. That makes persisted env-backed fields reopen in plain-text mode and can trigger the literal URL/API-key validators on edit.

💡 Suggested fix
 export function normalizeEnvVar(v?: string | { value?: string; env_var?: string; from_env?: boolean }): { value: string; env_var: string; from_env: boolean } {
 	if (!v) return { value: "", env_var: "", from_env: false };
-	if (typeof v === "string") return { value: v, env_var: "", from_env: false };
+	if (typeof v === "string") {
+		const trimmed = v.trim();
+		if (trimmed.startsWith("env.")) {
+			return { value: "", env_var: trimmed, from_env: true };
+		}
+		return { value: v, env_var: "", from_env: false };
+	}
 	return { value: v.value ?? "", env_var: v.env_var ?? "", from_env: v.from_env ?? false };
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Normalize a string | EnvVar | undefined to a proper EnvVar object
export function normalizeEnvVar(v?: string | { value?: string; env_var?: string; from_env?: boolean }): { value: string; env_var: string; from_env: boolean } {
if (!v) return { value: "", env_var: "", from_env: false };
if (typeof v === "string") return { value: v, env_var: "", from_env: false };
return { value: v.value ?? "", env_var: v.env_var ?? "", from_env: v.from_env ?? false };
// Normalize a string | EnvVar | undefined to a proper EnvVar object
export function normalizeEnvVar(v?: string | { value?: string; env_var?: string; from_env?: boolean }): { value: string; env_var: string; from_env: boolean } {
if (!v) return { value: "", env_var: "", from_env: false };
if (typeof v === "string") {
const trimmed = v.trim();
if (trimmed.startsWith("env.")) {
return { value: "", env_var: trimmed, from_env: true };
}
return { value: v, env_var: "", from_env: false };
}
return { value: v.value ?? "", env_var: v.env_var ?? "", from_env: v.from_env ?? false };
}
🤖 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/lib/types/schemas.ts` around lines 76 - 80, normalizeEnvVar currently
treats any string like "env.MY_VAR" as a literal value, breaking round-tripping
for env-backed fields; update the string branch in normalizeEnvVar to detect
strings that start with the "env." prefix and return an EnvVar object with
value: "" (or empty), env_var: the substring after "env.", and from_env: true;
otherwise keep the existing behavior for plain strings. Ensure you only change
the typeof v === "string" branch in function normalizeEnvVar so stored
"env.MY_VAR" values reopen as env-backed fields.

@BearTS BearTS force-pushed the 05-19-feat_add_support_for_env_variables_on_certain_fields_in_plugins branch from 1f5fe0c to 6b36179 Compare May 18, 2026 22:28
Comment thread plugins/otel/main.go
@BearTS BearTS force-pushed the 05-19-feat_add_support_for_env_variables_on_certain_fields_in_plugins branch from 6b36179 to bbf11c2 Compare May 18, 2026 23:02
@BearTS BearTS marked this pull request as draft May 18, 2026 23:14
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 20, 2026

CLA assistant check
All committers have signed the CLA.

@BearTS BearTS force-pushed the 05-19-feat_add_support_for_env_variables_on_certain_fields_in_plugins branch from bbf11c2 to 134fe71 Compare May 21, 2026 07:03
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.

2 participants