ghostguild-org/tests/server/middleware/security-headers.test.js
Jennie Robinson Faber e3410c52a5
Some checks failed
Test / vitest (push) Successful in 11m5s
Test / playwright (push) Failing after 9m24s
Test / visual (push) Failing after 9m20s
Test / Notify on failure (push) Successful in 3s
fix(csp): allow secure.helcim.app for HelcimPay.js
The HelcimPay modal loads from secure.helcim.app, but the CSP only
listed myposjs.helcim.com (script/connect) and secure.helcim.com
(frame, likely a stale typo). Add secure.helcim.app to script-src,
connect-src, and frame-src so the join flow's payment modal can load.
2026-04-26 15:59:36 +01:00

106 lines
3.7 KiB
JavaScript

import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { createMockEvent } from '../helpers/createMockEvent.js'
import securityHeadersMiddleware from '../../../server/middleware/02.security-headers.js'
describe('security-headers middleware', () => {
const originalNodeEnv = process.env.NODE_ENV
afterEach(() => {
process.env.NODE_ENV = originalNodeEnv
})
describe('always-present headers', () => {
beforeEach(() => {
process.env.NODE_ENV = 'development'
})
it('sets X-Content-Type-Options to nosniff', () => {
const event = createMockEvent({ path: '/' })
securityHeadersMiddleware(event)
expect(event._testSetHeaders['x-content-type-options']).toBe('nosniff')
})
it('sets X-Frame-Options to DENY', () => {
const event = createMockEvent({ path: '/' })
securityHeadersMiddleware(event)
expect(event._testSetHeaders['x-frame-options']).toBe('DENY')
})
it('sets X-XSS-Protection to 0', () => {
const event = createMockEvent({ path: '/' })
securityHeadersMiddleware(event)
expect(event._testSetHeaders['x-xss-protection']).toBe('0')
})
it('sets Referrer-Policy', () => {
const event = createMockEvent({ path: '/' })
securityHeadersMiddleware(event)
expect(event._testSetHeaders['referrer-policy']).toBe('strict-origin-when-cross-origin')
})
it('sets Permissions-Policy', () => {
const event = createMockEvent({ path: '/' })
securityHeadersMiddleware(event)
expect(event._testSetHeaders['permissions-policy']).toBe('camera=(), microphone=(), geolocation=()')
})
})
describe('production-only headers', () => {
it('sets HSTS in production', () => {
process.env.NODE_ENV = 'production'
const event = createMockEvent({ path: '/' })
securityHeadersMiddleware(event)
expect(event._testSetHeaders['strict-transport-security']).toBe('max-age=31536000; includeSubDomains')
})
it('does not set HSTS in development', () => {
process.env.NODE_ENV = 'development'
const event = createMockEvent({ path: '/' })
securityHeadersMiddleware(event)
expect(event._testSetHeaders['strict-transport-security']).toBeUndefined()
})
it('sets CSP in production', () => {
process.env.NODE_ENV = 'production'
const event = createMockEvent({ path: '/' })
securityHeadersMiddleware(event)
expect(event._testSetHeaders['content-security-policy']).toBeDefined()
})
it('does not set CSP in development', () => {
process.env.NODE_ENV = 'development'
const event = createMockEvent({ path: '/' })
securityHeadersMiddleware(event)
expect(event._testSetHeaders['content-security-policy']).toBeUndefined()
})
})
describe('CSP directives', () => {
beforeEach(() => {
process.env.NODE_ENV = 'production'
})
it('includes Helcim sources in CSP', () => {
const event = createMockEvent({ path: '/' })
securityHeadersMiddleware(event)
const csp = event._testSetHeaders['content-security-policy']
expect(csp).toContain('myposjs.helcim.com')
expect(csp).toContain('api.helcim.com')
expect(csp).toContain('secure.helcim.app')
})
it('includes Cloudinary sources in CSP', () => {
const event = createMockEvent({ path: '/' })
securityHeadersMiddleware(event)
const csp = event._testSetHeaders['content-security-policy']
expect(csp).toContain('res.cloudinary.com')
})
it('includes Plausible sources in CSP', () => {
const event = createMockEvent({ path: '/' })
securityHeadersMiddleware(event)
const csp = event._testSetHeaders['content-security-policy']
expect(csp).toContain('plausible.io')
})
})
})