Add local header testing infrastructure
ci/woodpecker/push/woodpecker Pipeline was successful
Details
ci/woodpecker/push/woodpecker Pipeline was successful
Details
This commit is contained in:
parent
0c3c133431
commit
cc0142f000
|
@ -8,6 +8,7 @@
|
|||
"test": "npm run test:lighthouse && npm run test:playwright",
|
||||
"test:playwright": "npx playwright test",
|
||||
"test:lighthouse": "node tests/lighthouse.js",
|
||||
"test:headers": "playwright test tests/headers.spec.js",
|
||||
"setup": "npx playwright install"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -23,7 +24,13 @@
|
|||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.42.1",
|
||||
"chrome-launcher": "^1.1.2",
|
||||
"lighthouse": "^11.4.0",
|
||||
"puppeteer": "^22.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
"lighthouse": "^11.6.0",
|
||||
"playwright": "^1.42.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
const { test, expect } = require('@playwright/test');
|
||||
|
||||
test.describe('Security Headers Tests', () => {
|
||||
test('should have all required security headers', async ({ page }) => {
|
||||
// Navigate to the page
|
||||
await page.goto('http://localhost:8080');
|
||||
|
||||
// Get response headers
|
||||
const response = await page.waitForResponse('http://localhost:8080');
|
||||
const headers = response.headers();
|
||||
|
||||
// Define required headers and their expected values
|
||||
const requiredHeaders = {
|
||||
'Content-Security-Policy': expect.stringContaining("default-src 'self'"),
|
||||
'X-Content-Type-Options': 'nosniff',
|
||||
'X-Frame-Options': 'DENY',
|
||||
'X-XSS-Protection': '1; mode=block',
|
||||
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
||||
'Permissions-Policy': expect.stringContaining('geolocation=()'),
|
||||
'Strict-Transport-Security': expect.stringContaining('max-age=31536000'),
|
||||
};
|
||||
|
||||
// Check each required header
|
||||
for (const [header, expectedValue] of Object.entries(requiredHeaders)) {
|
||||
const headerValue = headers[header.toLowerCase()];
|
||||
expect(headerValue).toBeDefined();
|
||||
if (typeof expectedValue === 'string') {
|
||||
expect(headerValue).toBe(expectedValue);
|
||||
} else {
|
||||
expect(headerValue).toMatch(expectedValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('should have correct CSP directives', async ({ page }) => {
|
||||
await page.goto('http://localhost:8080');
|
||||
const response = await page.waitForResponse('http://localhost:8080');
|
||||
const headers = response.headers();
|
||||
const csp = headers['content-security-policy'];
|
||||
|
||||
// Check for essential CSP directives
|
||||
expect(csp).toContain("default-src 'self'");
|
||||
expect(csp).toContain("script-src 'self' 'unsafe-inline'");
|
||||
expect(csp).toContain("style-src 'self' 'unsafe-inline'");
|
||||
expect(csp).toContain("img-src 'self' data: https: http:");
|
||||
expect(csp).toContain("font-src 'self'");
|
||||
expect(csp).toContain("connect-src 'self'");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,35 @@
|
|||
const express = require('express');
|
||||
const path = require('path');
|
||||
const app = express();
|
||||
const port = 8080;
|
||||
|
||||
// Security headers middleware
|
||||
app.use((req, res, next) => {
|
||||
// Content Security Policy
|
||||
res.setHeader(
|
||||
'Content-Security-Policy',
|
||||
"default-src 'self'; " +
|
||||
"script-src 'self' 'unsafe-inline'; " +
|
||||
"style-src 'self' 'unsafe-inline'; " +
|
||||
"img-src 'self' data: https: http:; " +
|
||||
"font-src 'self'; " +
|
||||
"connect-src 'self'"
|
||||
);
|
||||
|
||||
// Other security headers
|
||||
res.setHeader('X-Content-Type-Options', 'nosniff');
|
||||
res.setHeader('X-Frame-Options', 'DENY');
|
||||
res.setHeader('X-XSS-Protection', '1; mode=block');
|
||||
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
|
||||
res.setHeader('Permissions-Policy', 'geolocation=(), microphone=(), camera=()');
|
||||
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
// Serve static files from the docker/resume directory
|
||||
app.use(express.static(path.join(__dirname, '../docker/resume')));
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Local development server running at http://localhost:${port}`);
|
||||
});
|
Loading…
Reference in New Issue