Skip to content

Commit a4ba018

Browse files
committed
test(email): pin the allowlist entry rules
Covers isValidEmailSyntax's allowDomains branch (single-label domains stay valid, malformed bare domains that the old startsWith('@') check accepted do not), the 254-character cap, the DNS label limit, and validateAllowlistEntry waiving address-level policy for bare domains. Verified both new rules fail when the behavior is reverted.
1 parent 0a53c88 commit a4ba018

1 file changed

Lines changed: 54 additions & 1 deletion

File tree

apps/sim/lib/messaging/email/validation.test.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import { isValidEmailSyntax } from '@sim/utils/string'
12
import { describe, expect, it } from 'vitest'
2-
import { quickValidateEmail } from '@/lib/messaging/email/validation'
3+
import { quickValidateEmail, validateAllowlistEntry } from '@/lib/messaging/email/validation'
34

45
describe('quickValidateEmail', () => {
56
it.concurrent('should validate a correct email', () => {
@@ -145,3 +146,55 @@ describe('quickValidateEmail', () => {
145146
expect(result.checks.domain).toBe(true)
146147
})
147148
})
149+
150+
describe('isValidEmailSyntax', () => {
151+
it.concurrent('should only accept a bare domain when allowDomains is set', () => {
152+
expect(isValidEmailSyntax('@example.com')).toBe(false)
153+
expect(isValidEmailSyntax('@example.com', true)).toBe(true)
154+
})
155+
156+
it.concurrent('should accept single-label domains, which self-hosted deployments use', () => {
157+
expect(isValidEmailSyntax('@intranet', true)).toBe(true)
158+
expect(isValidEmailSyntax('@localhost', true)).toBe(true)
159+
})
160+
161+
it.concurrent('should reject bare domains the old startsWith("@") check let through', () => {
162+
for (const entry of ['@', '@-bad.com', '@bad-.com', '@example.com.', '@exa mple.com']) {
163+
expect(isValidEmailSyntax(entry, true)).toBe(false)
164+
}
165+
})
166+
167+
it.concurrent('should enforce the 254-character cap', () => {
168+
const at254 = `${'a'.repeat(242)}@example.com`
169+
const at255 = `${'a'.repeat(243)}@example.com`
170+
expect(at254).toHaveLength(254)
171+
expect(at255).toHaveLength(255)
172+
expect(isValidEmailSyntax(at254)).toBe(true)
173+
expect(isValidEmailSyntax(at255)).toBe(false)
174+
})
175+
176+
it.concurrent('should enforce the 63-character DNS label limit on bare domains', () => {
177+
expect(isValidEmailSyntax(`@${'a'.repeat(63)}.com`, true)).toBe(true)
178+
expect(isValidEmailSyntax(`@${'a'.repeat(64)}.com`, true)).toBe(false)
179+
})
180+
})
181+
182+
describe('validateAllowlistEntry', () => {
183+
it.concurrent('should accept a valid address', () => {
184+
expect(validateAllowlistEntry('user@example.com')).toBeNull()
185+
})
186+
187+
it.concurrent('should waive address-level policy for bare domain entries', () => {
188+
expect(validateAllowlistEntry('@mailinator.com')).toBeNull()
189+
expect(validateAllowlistEntry('user@mailinator.com')).toBe(
190+
'Disposable email addresses are not allowed'
191+
)
192+
})
193+
194+
it.concurrent('should surface the underlying rejection reason', () => {
195+
expect(validateAllowlistEntry('notanemail')).toBe('Invalid email format')
196+
expect(validateAllowlistEntry('user..name@example.com')).toBe(
197+
'Email contains suspicious patterns'
198+
)
199+
})
200+
})

0 commit comments

Comments
 (0)