Skip to content

feat(webapp): allow marking env vars as secret after creation - #2969

Open
JoanLaRosa wants to merge 1 commit into
triggerdotdev:mainfrom
JoanLaRosa:feat/make-env-var-secret
Open

feat(webapp): allow marking env vars as secret after creation#2969
JoanLaRosa wants to merge 1 commit into
triggerdotdev:mainfrom
JoanLaRosa:feat/make-env-var-secret

Conversation

@JoanLaRosa

@JoanLaRosa JoanLaRosa commented Jan 29, 2026

Copy link
Copy Markdown

Summary

  • Add an irreversible "Make secret" toggle to the edit environment variable dialog
  • The toggle is part of the edit form and submits on Save (not as a separate request)
  • Once toggled on and saved, the value is hidden and the switch becomes disabled — it cannot be reverted
  • Adds an optional isSecret field to the editValue repository method and Zod schema
  • Removes the standalone makeSecret action in favor of the unified form-based approach

Implements: https://feedback.trigger.dev/p/ability-to-set-a-non-secret-env-var-to-secret

Tested on local:

Before saving:
image
After saving:
image


Open with Devin

@changeset-bot

changeset-bot Bot commented Jan 29, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 8c97d18

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Jan 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a7fa760-4df9-4e78-860c-29ecd06bb095

📥 Commits

Reviewing files that changed from the base of the PR and between 920892b and 8c97d18.

📒 Files selected for processing (3)
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
  • apps/webapp/app/v3/environmentVariables/repository.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/repository.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


Walkthrough

The environment variable edit flow now tracks and submits isSecret. The edit panel adds a “Secret value” switch and guidance text. Existing secret variables remain disabled and cannot be reverted. The validation schema accepts boolean or "true" input. The repository marks the updated value as secret when isSecret is truthy.

Merge Risk: ⚪ Minimal · up to 8c97d

This localized change adds an irreversible option to mark an environment variable as secret during editing. No actionable merge-blocking risk remains beyond normal checks and review.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 3 files. 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 clearly and concisely describes the primary change: allowing existing environment variables to be marked as secret.
Description check ✅ Passed The description explains the implementation, irreversible behavior, testing performed, and provides screenshots. It does not include the repository checklist or a separate Changelog section, but the k…
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.
Full details: Description check

Explanation

The description explains the implementation, irreversible behavior, testing performed, and provides screenshots. It does not include the repository checklist or a separate Changelog section, but the key change and validation details are present.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@vibe-kanban-cloud

Copy link
Copy Markdown

Review Complete

Your review story is ready!

View Story

Comment !reviewfast on this PR to re-generate the story.

@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: 0

Caution

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

⚠️ Outside diff range comments (1)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx (1)

425-524: Close dialog and clear input value after makeSecret succeeds.

The input field uses defaultValue={variable.value}, so when makeSecret succeeds and marks the variable as secret, the previous value remains visible in the uncontrolled input. Additionally, the dialog doesn't close after makeSecret completes (only after edit actions). Add a handler to track the secret state change and close the dialog:

Suggested fix
  const fetcher = useFetcher<typeof action>();
  const makeSecretFetcher = useFetcher<typeof action>();
  const lastSubmission = fetcher.data as any;

  const isLoading = fetcher.state !== "idle";
  const isMakingSecret = makeSecretFetcher.state !== "idle";
+ const isSecretNow = variable.isSecret || makeSecretFetcher.data?.success;

  // Close dialog on successful submission
  useEffect(() => {
    if (lastSubmission?.success && fetcher.state === "idle") {
      setIsOpen(false);
    }
  }, [lastSubmission?.success, fetcher.state]);
+
+ useEffect(() => {
+   if (makeSecretFetcher.data?.success && makeSecretFetcher.state === "idle") {
+     setIsOpen(false);
+   }
+ }, [makeSecretFetcher.data?.success, makeSecretFetcher.state]);

  const [form, { id, environmentId, value }] = useForm({
    id: `edit-environment-variable-${variable.id}-${variable.environment.id}`,
    // TODO: type this
    lastSubmission: lastSubmission as any,
    onValidate({ formData }) {
      return parse(formData, { schema });
    },
    shouldRevalidate: "onSubmit",
  });

Then update the input and switch to reflect the immediate secret state:

  <Input
    {...conform.input(value, { type: "text" })}
    placeholder={variable.isSecret ? "Set new secret value" : "Not set"}
-   defaultValue={variable.value}
+   key={`${variable.id}-${variable.environment.id}-${isSecretNow ? "secret" : "plain"}`}
+   defaultValue={isSecretNow ? "" : variable.value}
    type={"text"}
  />
  <Switch
    variant="medium"
    label={<span className="text-text-bright">Secret value</span>}
-   checked={variable.isSecret}
-   disabled={variable.isSecret || isMakingSecret}
+   checked={isSecretNow}
+   disabled={isSecretNow || isMakingSecret}
    onCheckedChange={(checked) => {
      if (checked) {
        handleMakeSecret();
      }
    }}
  />
  <Hint>
-   {variable.isSecret
+   {isSecretNow
      ? "This variable is secret and cannot be changed back."
      : "Once enabled, the value will be hidden and cannot be revealed again."}
  </Hint>
🧹 Nitpick comments (1)
apps/webapp/app/v3/environmentVariables/repository.ts (1)

92-115: Prefer a type alias over an interface for Repository.

Since this change extends the interface, consider converting it to a type alias to match the TS style guideline.

♻️ Proposed refactor
-export interface Repository {
+export type Repository = {
   create(projectId: string, options: CreateEnvironmentVariables): Promise<CreateResult>;
   edit(projectId: string, options: EditEnvironmentVariable): Promise<Result>;
   editValue(projectId: string, options: EditEnvironmentVariableValue): Promise<Result>;
   getProject(projectId: string): Promise<ProjectEnvironmentVariable[]>;
   /**
    * Get the environment variables for a given environment, it does NOT return values for secret variables
    */
   getEnvironmentWithRedactedSecrets(
     projectId: string,
     environmentId: string
   ): Promise<EnvironmentVariableWithSecret[]>;
   /**
    * Get the environment variables for a given environment
    */
   getEnvironment(projectId: string, environmentId: string): Promise<EnvironmentVariable[]>;
   /**
    * Return all env vars, including secret variables with values. Should only be used for executing tasks.
    */
   getEnvironmentVariables(projectId: string, environmentId: string): Promise<EnvironmentVariable[]>;
   delete(projectId: string, options: DeleteEnvironmentVariable): Promise<Result>;
   deleteValue(projectId: string, options: DeleteEnvironmentVariableValue): Promise<Result>;
   makeSecret(projectId: string, options: MakeSecretEnvironmentVariableValue): Promise<Result>;
-}
+};

As per coding guidelines: Use types over interfaces for TypeScript.

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0674d74 and f717869.

📒 Files selected for processing (3)
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
  • apps/webapp/app/v3/environmentVariables/repository.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries

Files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: julienvanbeveren
Repo: triggerdotdev/trigger.dev PR: 2417
File: apps/webapp/app/routes/api.v1.projects.$projectRef.envvars.$slug.import.ts:56-61
Timestamp: 2025-08-19T09:49:07.011Z
Learning: In the Trigger.dev codebase, environment variables should default to `isSecret: false` when not explicitly marked as secrets in the syncEnvVars functionality. This is the intended behavior for both regular variables and parent variables.
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2155
File: hosting/docker/.env.example:4-7
Timestamp: 2025-06-06T23:55:01.933Z
Learning: In the trigger.dev project, .env.example files should contain actual example secret values rather than placeholders, as these help users understand the expected format. The files include clear warnings about not using these defaults in production and instructions for generating proper secrets.
📚 Learning: 2025-12-08T15:19:56.823Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2760
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx:278-281
Timestamp: 2025-12-08T15:19:56.823Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx, the tableState search parameter uses intentional double-encoding: the parameter value contains a URL-encoded URLSearchParams string, so decodeURIComponent(value("tableState") ?? "") is required to fully decode it before parsing with new URLSearchParams(). This pattern allows bundling multiple filter/pagination params as a single search parameter.

Applied to files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp

Applied to files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
📚 Learning: 2025-04-17T10:27:25.337Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 1923
File: packages/core/src/v3/schemas/api.ts:813-827
Timestamp: 2025-04-17T10:27:25.337Z
Learning: Creating secret environment variables is restricted to the dashboard UI only, and not allowed via the API/SDK for now. The `EnvironmentVariableWithSecret` type in the API schema is for reading/displaying purposes only.

Applied to files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : Access environment variables via `env` export from `apps/webapp/app/env.server.ts`, never use `process.env` directly

Applied to files:

  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
📚 Learning: 2025-08-19T09:49:07.011Z
Learnt from: julienvanbeveren
Repo: triggerdotdev/trigger.dev PR: 2417
File: apps/webapp/app/routes/api.v1.projects.$projectRef.envvars.$slug.import.ts:56-61
Timestamp: 2025-08-19T09:49:07.011Z
Learning: In the Trigger.dev codebase, environment variables should default to `isSecret: false` when not explicitly marked as secrets in the syncEnvVars functionality. This is the intended behavior for both regular variables and parent variables.

Applied to files:

  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
🧬 Code graph analysis (3)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx (1)
apps/webapp/app/v3/environmentVariables/repository.ts (2)
  • MakeSecretEnvironmentVariableValue (50-53)
  • MakeSecretEnvironmentVariableValue (54-54)
apps/webapp/app/v3/environmentVariables/repository.ts (1)
apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts (1)
  • projectId (584-624)
apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts (1)
apps/webapp/app/v3/environmentVariables/repository.ts (3)
  • MakeSecretEnvironmentVariableValue (50-53)
  • MakeSecretEnvironmentVariableValue (54-54)
  • Result (63-70)
🔇 Additional comments (5)
apps/webapp/app/v3/environmentVariables/repository.ts (1)

50-54: MakeSecretEnvironmentVariableValue schema looks good.

The payload shape aligns with the new action and keeps validation consistent.

apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts (2)

8-18: No review needed for the type import.


634-702: makeSecret flow looks solid.

Guards cover missing project, missing value, and already-secret states before the update.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx (2)

31-31: No review needed for this import change.


109-198: Schema and action wiring for makeSecret are consistent.

The discriminated union and action handler stay aligned with the repository method.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@JoanLaRosa
JoanLaRosa force-pushed the feat/make-env-var-secret branch from f717869 to 3a2939b Compare January 29, 2026 15:47

@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: 0

Caution

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

⚠️ Outside diff range comments (2)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx (2)

406-418: Reset isSecret when the dialog opens to avoid unintended irreversible changes.
If a user toggles to secret and cancels, the state stays true; a later save can silently mark it secret.

🛠️ Suggested fix
   const [isOpen, setIsOpen] = useState(false);
   const [isSecret, setIsSecret] = useState(variable.isSecret);
   const fetcher = useFetcher<typeof action>();
   const lastSubmission = fetcher.data as any;

   const isLoading = fetcher.state !== "idle";

+  useEffect(() => {
+    if (isOpen) {
+      setIsSecret(variable.isSecret);
+    }
+  }, [isOpen, variable.isSecret]);

439-474: Add a confirmation gate before making a variable secret.
The action is irreversible, but the current submit flow doesn’t confirm the change.

🛠️ Suggested fix
   const isLoading = fetcher.state !== "idle";
+  const shouldConfirmSecret = !variable.isSecret && isSecret;
@@
-        <fetcher.Form method="post" {...form.props}>
+        <fetcher.Form
+          method="post"
+          {...form.props}
+          onSubmit={(event) => {
+            if (
+              shouldConfirmSecret &&
+              !window.confirm("Making this value secret is irreversible. Continue?")
+            ) {
+              event.preventDefault();
+            }
+          }}
+        >
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f717869 and 3a2939b.

📒 Files selected for processing (3)
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
  • apps/webapp/app/v3/environmentVariables/repository.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries

Files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
🧠 Learnings (8)
📓 Common learnings
Learnt from: julienvanbeveren
Repo: triggerdotdev/trigger.dev PR: 2417
File: apps/webapp/app/routes/api.v1.projects.$projectRef.envvars.$slug.import.ts:56-61
Timestamp: 2025-08-19T09:49:07.011Z
Learning: In the Trigger.dev codebase, environment variables should default to `isSecret: false` when not explicitly marked as secrets in the syncEnvVars functionality. This is the intended behavior for both regular variables and parent variables.
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 1923
File: packages/core/src/v3/schemas/api.ts:813-827
Timestamp: 2025-04-17T10:27:25.337Z
Learning: Creating secret environment variables is restricted to the dashboard UI only, and not allowed via the API/SDK for now. The `EnvironmentVariableWithSecret` type in the API schema is for reading/displaying purposes only.
📚 Learning: 2025-08-14T18:35:44.370Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2390
File: apps/webapp/app/env.server.ts:764-765
Timestamp: 2025-08-14T18:35:44.370Z
Learning: The BoolEnv helper in apps/webapp/app/utils/boolEnv.ts uses z.preprocess with inconsistent default value types across the codebase - some usages pass boolean defaults (correct) while others pass string defaults (incorrect), leading to type confusion. The helper should enforce boolean-only defaults or have clearer documentation.

Applied to files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
📚 Learning: 2025-08-19T09:49:07.011Z
Learnt from: julienvanbeveren
Repo: triggerdotdev/trigger.dev PR: 2417
File: apps/webapp/app/routes/api.v1.projects.$projectRef.envvars.$slug.import.ts:56-61
Timestamp: 2025-08-19T09:49:07.011Z
Learning: In the Trigger.dev codebase, environment variables should default to `isSecret: false` when not explicitly marked as secrets in the syncEnvVars functionality. This is the intended behavior for both regular variables and parent variables.

Applied to files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp

Applied to files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : Access environment variables via `env` export from `apps/webapp/app/env.server.ts`, never use `process.env` directly

Applied to files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to {packages/core,apps/webapp}/**/*.{ts,tsx} : Use zod for validation in packages/core and apps/webapp

Applied to files:

  • apps/webapp/app/v3/environmentVariables/repository.ts
📚 Learning: 2025-12-08T15:19:56.823Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2760
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx:278-281
Timestamp: 2025-12-08T15:19:56.823Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx, the tableState search parameter uses intentional double-encoding: the parameter value contains a URL-encoded URLSearchParams string, so decodeURIComponent(value("tableState") ?? "") is required to fully decode it before parsing with new URLSearchParams(). This pattern allows bundling multiple filter/pagination params as a single search parameter.

Applied to files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
📚 Learning: 2025-08-14T12:13:20.455Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2392
File: packages/cli-v3/src/utilities/gitMeta.ts:195-218
Timestamp: 2025-08-14T12:13:20.455Z
Learning: In the GitMeta schema (packages/core/src/v3/schemas/common.ts), all fields are intentionally optional to handle partial data from various deployment contexts (local, GitHub Actions, GitHub App). Functions like getGitHubAppMeta() are designed to work with missing environment variables rather than validate their presence.

Applied to files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx
🧬 Code graph analysis (1)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx (1)
apps/webapp/app/components/primitives/Switch.tsx (1)
  • Switch (64-119)
🔇 Additional comments (2)
apps/webapp/app/v3/environmentVariables/repository.ts (1)

50-55: LGTM for isSecret preprocessing.
Accepts form string payloads while keeping boolean validation intact.

apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts (1)

363-443: Secret flag persistence looks consistent.
The isSecret update happens inside the same transaction as the secret write, which is the right place for it.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@JoanLaRosa
JoanLaRosa force-pushed the feat/make-env-var-secret branch from 3a2939b to d509417 Compare January 29, 2026 15:54
@JoanLaRosa
JoanLaRosa marked this pull request as ready for review January 29, 2026 15:57
coderabbitai[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

…ation

Move the secret toggle into the edit form so it submits on Save
instead of firing a separate request immediately. Remove the standalone
makeSecret action/method and include isSecret as an optional field on
the existing editValue flow.
@JoanLaRosa
JoanLaRosa force-pushed the feat/make-env-var-secret branch from d509417 to 8c97d18 Compare August 26, 2026 17:47
@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@JoanLaRosa

JoanLaRosa commented Aug 26, 2026

Copy link
Copy Markdown
Author

⚠️ Prior approval is stale, please re-review.

@matt-aitken your approval was submitted against d509417, which is no longer the head of this branch. I rebased onto latest main and the rebase required manual conflict resolution in three files, so the code you approved is not the code currently on the branch:

  • apps/webapp/app/v3/environmentVariables/repository.ts — kept both lastUpdatedBy (new on main) and isSecret on EditEnvironmentVariableValue.
  • apps/webapp/app/v3/environmentVariables/environmentVariablesRepository.server.ts — collapsed main's version/lastUpdatedBy update and my isSecret update into a single environmentVariableValue.update call.
  • .../environment-variables/route.tsx — reconciled conformgetInputProps (main migrated the form API) and dropped an unused import.

New head is 8c97d18. I don't have write access on this repo, so I can't dismiss the old review or hit re-request review myself — could you dismiss it and take another pass? Webapp typecheck shows no new errors from these files and oxfmt/lint/knip pass on push.

@devin-ai-integration devin-ai-integration 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.

Devin Review found 2 potential issues.

Open in Devin Review

revealAll: boolean;
}) {
const [isOpen, setIsOpen] = useState(false);
const [isSecret, setIsSecret] = useState(variable.isSecret);

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.

🟡 Secret toggle stays on after cancelling the edit dialog

The isSecret state lives on the panel component, which stays mounted when the dialog closes (useState at line 812). Toggling Secret value on and then cancelling leaves it on; reopening the row shows it still enabled, so an unrelated later Save marks the variable secret irreversibly.

Prompt for agents
In EditEnvironmentVariablePanel the `isSecret` state is initialized once from `variable.isSecret` via useState, but the component does not unmount when the Dialog closes, so the toggle value persists across open/close cycles. Because marking a variable secret is irreversible, a user who toggles the switch on, cancels the dialog, then later reopens and saves an unrelated change will silently and permanently make the variable secret. Reset `isSecret` back to `variable.isSecret` whenever the dialog transitions to closed (e.g. in the onOpenChange handler), so a cancelled toggle does not leak into a later save.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

environmentId: z.string(),
value: z.string(),
lastUpdatedBy: EnvironmentVariableUpdaterSchema.optional(),
isSecret: z.preprocess((val) => val === "true" || val === true, z.boolean()).optional(),

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.

🟡 Missing .server-changes note for new user-facing feature

This PR adds a user-facing feature (marking env vars secret after creation) and touches only webapp files, but includes no .server-changes/ file. CONTRIBUTING.md and AGENTS.md require one for user-facing server-only changes.

Prompt for agents
Per CONTRIBUTING.md and AGENTS.md, a user-facing change that only touches server apps (apps/webapp) requires a .server-changes/ markdown file so it appears in release notes. This PR adds a user-visible feature (allow marking environment variables as secret after creation) but adds no such file. Add a .server-changes/ file with frontmatter area: webapp and type: feature, and a concise one-line user-facing description.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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