Skip to content

Commit 9a54fe1

Browse files
authored
Merge pull request #1 from sdirishguy/fix/apostrophe-rendering-and-eslint-cleanup
feat: implement comprehensive security, accessibility, and testing im…
2 parents d7e49f0 + 8950c5b commit 9a54fe1

25 files changed

+8279
-2880
lines changed

audit-ci.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"allowlist": [],
3+
"level": "moderate",
4+
"report-type": "important"
5+
}

e2e/navigation.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test, expect } from '@playwright/test'
2+
3+
test('home to projects', async ({ page }) => {
4+
await page.goto('/')
5+
await expect(page).toHaveTitle(/DavidPDonohue/i)
6+
await page.getByRole('link', { name: /projects/i }).click()
7+
await expect(page).toHaveURL(/\/projects$/)
8+
})

eslint.config.mjs

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,21 @@
1-
import { dirname } from "path";
2-
import { fileURLToPath } from "url";
3-
import { FlatCompat } from "@eslint/eslintrc";
1+
import { dirname } from 'path'
2+
import { fileURLToPath } from 'url'
3+
import { FlatCompat } from '@eslint/eslintrc'
44

5-
const __filename = fileURLToPath(import.meta.url);
6-
const __dirname = dirname(__filename);
5+
const __filename = fileURLToPath(import.meta.url)
6+
const __dirname = dirname(__filename)
7+
const compat = new FlatCompat({ baseDirectory: __dirname })
78

8-
const compat = new FlatCompat({
9-
baseDirectory: __dirname,
10-
});
11-
12-
const eslintConfig = [
13-
...compat.extends("next/core-web-vitals", "next/typescript"),
9+
const config = [
10+
...compat.extends('next/core-web-vitals'),
1411
{
1512
rules: {
1613
'react/no-unescaped-entities': 'warn',
17-
'@typescript-eslint/no-explicit-any': 'warn',
18-
'@typescript-eslint/no-empty-object-type': 'warn',
1914
'react-hooks/rules-of-hooks': 'warn',
20-
'@next/next/no-img-element': 'warn'
21-
}
22-
}
23-
];
15+
'@next/next/no-img-element': 'warn',
16+
'jsx-a11y/anchor-is-valid': 'warn',
17+
},
18+
},
19+
]
2420

25-
export default eslintConfig;
21+
export default config

jest.config.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const nextJest = require('next/jest')
2+
const createJestConfig = nextJest({ dir: './' })
3+
4+
/** @type {import('jest').Config} */
5+
const customConfig = {
6+
testEnvironment: 'jest-environment-jsdom',
7+
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
8+
moduleNameMapper: {
9+
'^@/(.*)$': '<rootDir>/src/$1',
10+
},
11+
}
12+
13+
module.exports = createJestConfig(customConfig)

jest.setup.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import '@testing-library/jest-dom'

next.config.ts

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,14 @@
1-
import type { NextConfig } from "next";
1+
import type { NextConfig } from 'next'
22

33
const nextConfig: NextConfig = {
4+
reactStrictMode: true,
45
output: 'export',
56
trailingSlash: true,
67
images: {
7-
unoptimized: true
8+
unoptimized: true,
89
},
9-
// Ensure all assets are properly handled
10-
assetPrefix: '',
11-
basePath: '',
12-
// Disable features that don't work with static export
13-
webpack: (config, { isServer }) => {
14-
if (!isServer) {
15-
// Ensure client-side code is properly bundled
16-
config.resolve.fallback = {
17-
...config.resolve.fallback,
18-
fs: false,
19-
net: false,
20-
tls: false,
21-
};
22-
}
23-
return config;
24-
},
25-
};
10+
eslint: { ignoreDuringBuilds: false },
11+
typescript: { ignoreBuildErrors: false },
12+
}
2613

27-
export default nextConfig;
14+
export default nextConfig

nginx/security-headers.conf

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Include this file from the server block that serves your exported `out/` directory.
2+
#
3+
# Example:
4+
# server {
5+
# listen 80;
6+
# server_name davidpdonohue.com;
7+
# root /var/www/personal-portfolio/out;
8+
# include /etc/nginx/snippets/security-headers.conf;
9+
# }
10+
11+
# Strict transport (enable on HTTPS vhost)
12+
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
13+
14+
# Mitigate XSS + enforce sources (adjust domains you actually use)
15+
add_header Content-Security-Policy "
16+
default-src 'self';
17+
script-src 'self' 'unsafe-inline' 'unsafe-eval';
18+
style-src 'self' 'unsafe-inline';
19+
img-src 'self' data: blob:;
20+
font-src 'self' https://fonts.gstatic.com;
21+
connect-src 'self' https:;
22+
frame-ancestors 'none';
23+
base-uri 'self';
24+
form-action 'self';
25+
" always;
26+
27+
# Other hardening headers
28+
add_header X-Frame-Options "DENY" always;
29+
add_header X-Content-Type-Options "nosniff" always;
30+
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
31+
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

0 commit comments

Comments
 (0)