const path = require('path') const request = require('supertest') const express = require('express') const fs = require('fs') // Import the middleware factory (don't name this `csp` to avoid shadowing!) const createCspMiddleware = require('../index.cjs') describe('Content Security Policy middleware', () => { const validPolicyPath = path.join(__dirname, '../csp-policy.yml') const malformedPolicyPath = path.join(__dirname, 'bad-policy.yml') const missingPolicyPath = path.join(__dirname, 'xxxxxx.yml') const minimalPolicyPath = path.join(__dirname, 'minimal-policy.yml') const customPolicyPath = path.join(__dirname, 'custom-policy.yml') beforeAll(() => { // Write a malformed YAML file (missing colon, bad list syntax) fs.writeFileSync(malformedPolicyPath, `default-src 'self'\nthis-is: [bad yaml]`) // Write a minimal custom policy fs.writeFileSync( minimalPolicyPath, ` contentSecurityPolicy: false `, ) // Write a simple custom policy fs.writeFileSync( customPolicyPath, ` contentSecurityPolicy: directives: default-src: ["'self'"] script-src: ["'self'", "https://cdn.example.com"] `, ) }) afterAll(() => { //fs.unlinkSync(missingPolicyPath) fs.unlinkSync(minimalPolicyPath) fs.unlinkSync(malformedPolicyPath) fs.unlinkSync(customPolicyPath) }) it('should load and apply CSP directives from YAML', async () => { const app = express() const csp = createCspMiddleware(validPolicyPath) app.use(csp) app.get('/', (req, res) => res.send('Hello World')) const res = await request(app).get('/') console.log(res.headers) expect(res.headers['content-security-policy']).toBeDefined() expect(res.text).toBe('Hello World') }) it('should include specific CSP directives in header', async () => { const app = express() const csp = createCspMiddleware(validPolicyPath) app.use(csp) app.get('/', (req, res) => res.send('Hello')) const res = await request(app).get('/') const cspHeader = res.headers['content-security-policy'] expect(cspHeader).toMatch(/default-src 'self'/) expect(cspHeader).toMatch(/script-src 'self'[^;]*example\.com/) expect(cspHeader).toMatch(/style-src 'self'[^;]*'unsafe-inline'/) }) it('should throw an error for malformed YAML', () => { expect(() => { createCspMiddleware(malformedPolicyPath) }).toThrow(/Implicit keys|bad indentation|unexpected token/i) }) it('should show defaults for missing YAML', async () => { const app = express() const csp = createCspMiddleware(missingPolicyPath) app.use(csp) app.get('/', (req, res) => res.send('Test Custom')) const res = await request(app).get('/') res.headers.TEST = 'Missing' console.log(res.headers) const cspHeader = res.headers['content-security-policy'] expect(cspHeader).toMatch(/default-src 'self'/) }) it('should show nothing for minimal YAML', async () => { const app = express() const csp = createCspMiddleware(minimalPolicyPath) app.use(csp) app.get('/', (req, res) => res.send('Test Custom')) const res = await request(app).get('/') res.headers.TEST = 'Minimal' console.log(res.headers) const cspHeader = res.headers['content-security-policy'] const allowed = ['x-powered-by', 'content-type', 'content-length'] Object.keys(res.headers).forEach((key) => { if (!allowed.includes(key.toLowerCase())) { expect(key).not.toMatch(/^(content|x)-/i) } }) }) it('should apply a custom policy file correctly', async () => { const app = express() const csp = createCspMiddleware(customPolicyPath) app.use(csp) app.get('/', (req, res) => res.send('Test Custom')) const res = await request(app).get('/') res.headers.TEST = 'Custom' console.log(res.headers) const cspHeader = res.headers['content-security-policy'] expect(cspHeader).toMatch(/default-src 'self'/) expect(cspHeader).toMatch(/script-src 'self' https:\/\/cdn\.example\.com/) }) })