Conversation
Prevent team scope from marking secret as sensitive when only dev env is selected
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
| ctx.addIssue({ | ||
| code: z.ZodIssueCode.custom, | ||
| message: | ||
| "Marking secrets as sensitive in Vercel is not supported for development environments. Add another target environment or disable Sensitive.", | ||
| path: ["sensitive"] | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| const VercelSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: true }; |
There was a problem hiding this comment.
🔴 When targetEnvironments is empty and sensitive is true, the new Team-scope check config.targetEnvironments.every(...) fires vacuously ([].every(fn) === true in JavaScript), producing the misleading error "not supported for development environments" alongside the correct "At least one environment is required" error. Fix: add config.targetEnvironments.length > 0 && before the .every() call in both the backend schema (vercel-sync-schemas.ts line 54) and the frontend schema (vercel-sync-destination-schema.ts line 53).
Extended reasoning...
What the bug is and how it manifests
Both the backend (backend/src/services/secret-sync/vercel/vercel-sync-schemas.ts, lines 54–63) and frontend (frontend/src/components/secret-syncs/forms/schemas/vercel-sync-destination-schema.ts, lines 53–63) Vercel sync schemas have a new superRefine check that fires when scope === Team and every selected environment is Development. The intent is to prevent marking a Team-scoped sync as sensitive when it only targets dev environments. However, the guard omits a length check, making it susceptible to JavaScript's vacuous truth behavior.
The specific code path that triggers it
if (
config.scope === VercelSyncScope.Team &&
config.targetEnvironments.every((env) => env === VercelEnvironmentType.Development)
) { ctx.addIssue(...) }When targetEnvironments is an empty array [], [].every(fn) unconditionally returns true in JavaScript (vacuous truth — there are no elements that violate the predicate). This means the entire condition evaluates to true whenever scope === Team, sensitive === true, and targetEnvironments is empty.
Why existing code doesn't prevent it
In Zod v3, superRefine runs even after inner field refinements (such as .min(1)) have already added validation errors. The .min(1) constraint on targetEnvironments is a refinement, not a type narrowing — it adds an issue but does not abort parsing. The empty array [] still satisfies the TypeScript type VercelEnvironmentType[], so the discriminated union branch matches and the value is passed to superRefine.
Impact
A user who submits the form (or makes a direct API call) with scope=Team, targetEnvironments=[], and sensitive=true will see two error messages simultaneously:
- ✅ "At least one environment is required" — correct and actionable
- ❌ "Marking secrets as sensitive in Vercel is not supported for development environments. Add another target environment or disable Sensitive." — misleading, since no environments were selected at all; the message implies development environments exist and should be replaced
The second message actively misdirects the user.
Step-by-step proof
- User sets
scope = Team, checkssensitive = true, and leavestargetEnvironmentsas[](empty). - Zod evaluates the discriminated union —
scope === Teammatches the second branch. .min(1)refinement ontargetEnvironmentsadds:"At least one environment is required".superRefineis called with{ scope: 'team', targetEnvironments: [], sensitive: true, ... }.!config.sensitiveisfalse, so the early return is skipped.config.scope === VercelSyncScope.Team→true.[].every(env => env === VercelEnvironmentType.Development)→true(vacuous truth).ctx.addIssue()fires, adding the misleading message.- Both errors are returned to the caller.
How to fix it
Add a length guard before the .every() call in both files:
if (
config.scope === VercelSyncScope.Team &&
config.targetEnvironments.length > 0 && // <-- add this
config.targetEnvironments.every((env) => env === VercelEnvironmentType.Development)
) {
ctx.addIssue({ ... });
}This ensures the sensitive/dev-environment error only fires when at least one environment has actually been selected and all of them are Development.
Prevent team scope from marking secret as sensitive when only dev env is selected