Skip to content

Commit aec5b31

Browse files
fix(env): give the workspace env denial its own write-access message
WorkspaceEnvAccessError reported "must be an admin of these secrets" for both denials, so a caller lacking workspace write to ADD a key was told to get secret-admin on a key that does not exist yet. Carry the reason and mirror the route's two messages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PCXbU36FwJBmtJKaH83BUm
1 parent 6d05f8c commit aec5b31

2 files changed

Lines changed: 36 additions & 10 deletions

File tree

apps/sim/lib/environment/utils.test.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,15 @@ describe('upsertWorkspaceEnvVars', () => {
6161
knownKeys: new Set(['STRIPE_KEY']),
6262
})
6363

64-
await expect(
65-
upsertWorkspaceEnvVars('ws-1', { STRIPE_KEY: 'rotated' }, 'user-1')
66-
).rejects.toBeInstanceOf(WorkspaceEnvAccessError)
64+
const error = await upsertWorkspaceEnvVars('ws-1', { STRIPE_KEY: 'rotated' }, 'user-1').catch(
65+
(e) => e
66+
)
6767

68+
expect(error).toBeInstanceOf(WorkspaceEnvAccessError)
69+
expect(error).toMatchObject({
70+
reason: 'not-secret-admin',
71+
message: 'You must be an admin of these secrets to edit them',
72+
})
6873
expect(encryptionMockFns.mockEncryptSecret).not.toHaveBeenCalled()
6974
expect(mockRecordAudit).not.toHaveBeenCalled()
7075
})
@@ -76,10 +81,17 @@ describe('upsertWorkspaceEnvVars', () => {
7681
knownKeys: new Set<string>(),
7782
})
7883

79-
await expect(
80-
upsertWorkspaceEnvVars('ws-1', { NEW_KEY: 'value' }, 'user-1')
81-
).rejects.toBeInstanceOf(WorkspaceEnvAccessError)
84+
const error = await upsertWorkspaceEnvVars('ws-1', { NEW_KEY: 'value' }, 'user-1').catch(
85+
(e) => e
86+
)
8287

88+
expect(error).toBeInstanceOf(WorkspaceEnvAccessError)
89+
// Distinct from the secret-admin denial: the route answers this case with a
90+
// write-access message, and the agent surfaces whatever we throw verbatim.
91+
expect(error).toMatchObject({
92+
reason: 'write-access-required',
93+
message: 'Write access is required to add new secrets',
94+
})
8395
expect(encryptionMockFns.mockEncryptSecret).not.toHaveBeenCalled()
8496
})
8597

apps/sim/lib/environment/utils.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,21 @@ const WORKSPACE_ENV_LOCK_TIMEOUT_MS = 5_000
2424
const EFFECTIVE_ENVIRONMENT_CACHE_TTL_MS = 2_000
2525
const EFFECTIVE_ENVIRONMENT_CACHE_MAX_ENTRIES = 1_000
2626

27+
type WorkspaceEnvDenialReason = 'not-secret-admin' | 'write-access-required'
28+
29+
/** Mirrors the messages the workspace environment route returns for the same denials. */
30+
const WORKSPACE_ENV_DENIAL_MESSAGES: Record<WorkspaceEnvDenialReason, string> = {
31+
'not-secret-admin': 'You must be an admin of these secrets to edit them',
32+
'write-access-required': 'Write access is required to add new secrets',
33+
}
34+
2735
/** Thrown when the acting user may not write one of the requested env keys. */
2836
export class WorkspaceEnvAccessError extends Error {
29-
constructor(readonly keys: string[]) {
30-
super('You must be an admin of these secrets to edit them')
37+
constructor(
38+
readonly reason: WorkspaceEnvDenialReason,
39+
readonly keys: string[]
40+
) {
41+
super(WORKSPACE_ENV_DENIAL_MESSAGES[reason])
3142
this.name = 'WorkspaceEnvAccessError'
3243
}
3344
}
@@ -365,7 +376,7 @@ export async function upsertWorkspaceEnvVars(
365376
reason: 'not-secret-admin',
366377
keys: forbidden,
367378
})
368-
throw new WorkspaceEnvAccessError(forbidden)
379+
throw new WorkspaceEnvAccessError('not-secret-admin', forbidden)
369380
}
370381
const addingNew = updatedKeys.some((key) => !knownKeys.has(key))
371382
if (addingNew && permission !== 'admin' && permission !== 'write') {
@@ -375,7 +386,10 @@ export async function upsertWorkspaceEnvVars(
375386
reason: 'write-access-required',
376387
keys: updatedKeys.filter((key) => !knownKeys.has(key)),
377388
})
378-
throw new WorkspaceEnvAccessError(updatedKeys.filter((key) => !knownKeys.has(key)))
389+
throw new WorkspaceEnvAccessError(
390+
'write-access-required',
391+
updatedKeys.filter((key) => !knownKeys.has(key))
392+
)
379393
}
380394

381395
const newlyEncrypted: Record<string, string> = {}

0 commit comments

Comments
 (0)