security: Enforce the Content-Security-Policy header - #15
Closed
TheCodeDestroyer wants to merge 5 commits into
Closed
security: Enforce the Content-Security-Policy header#15TheCodeDestroyer wants to merge 5 commits into
TheCodeDestroyer wants to merge 5 commits into
Conversation
- Add Spartan Development d.o.o. (Full Stack Developer, Sep 2026) as the current entry at the top of the career carousel - Set the Optiweb tenure end date to Aug 2026 - Update the llms.txt intro to name Spartan as the current employer; the experience listing is generated from the same constant Reflects the employer change effective 1 Sep 2026. Spartan bullets are written in present tense as the active role and intentionally omit the CTO track, which is planned for a Q1 2027 update to this same card.
Closes 22 of the 23 children of thecodedestroyer_github_io-35m. Only the test-harness issue (.23) is left open. Security (P0) - next + eslint-config-next 16.2.9 -> 16.3.3, clearing 4 high and 5 moderate advisories (middleware/proxy bypass, SSRF in Server Actions and rewrites, DoS in Server Actions and image optimization, cache confusion, unbounded Edge Server Action payload, Server Function endpoint disclosure). - postcss 8.5.16 -> 8.5.26 as a direct bump rather than an override, which also lifts nanoid transitively. - pnpm.overrides collapsed from 17 entries to 4. Every deleted entry was proven dead with `pnpm why`; the two security entries that remain are load-bearing (brace-expansion via rimraf>glob, minimatch via eslint-plugin-import-x). pnpm audit is now clean for both --prod and dev, down from 23 advisories. Bugs (P1) - scroll-smooth moved from <body> to the actual scroll container in page.tsx, so navbar anchors ease instead of hard-jumping. - Dropped react-device-detect. It read navigator.userAgent at module-eval time, so isMobile was always false during SSR and every section hydrated with a mismatch. The mobile opt-out is now a CSS media query, which the server and client agree on by construction. - useLayoutEffect -> useEffect in SectionWrapper (SSR'd client component). - "Contact me" was a <button> assigning window.location.href. It is now a real anchor at all three call sites, so it is crawlable, announced as a link, and supports middle-click/cmd-click/copy-link. contact.util.ts deleted. CI (P1) - checkout@v4->v7, setup-node@v4->v7, pnpm/action-setup@v2->v6; the hand-rolled store cache replaced with setup-node's native cache: 'pnpm'. - Added --frozen-lockfile, a build step, a concurrency group, and a pull_request trigger; push now scoped to main. Node 22 -> 24. Deprecations and a11y (P2) - Disclosure.Button/.Panel -> DisclosureButton/DisclosurePanel. - framer-motion 12 -> motion 13 (the package was renamed). - prefers-reduced-motion is now respected across the section entrance animation, the border-spin ring, the halo, and anchor scrolling. - Security response headers added. The CSP ships report-only on purpose; see -35m.26 for what must be verified on a preview before enforcing it. Cleanup and additions (P3) - Custom 404 page, web manifest, icon set, explicit robots, sitemap lastmod. - Static imports replace five no-op next/dynamic wrappers in a Server Component, removing a request round-trip. - Removed zod, stale tsconfig path aliases, dead CSS tokens, a no-op clsx, a redundant zustand spread, and an unused image quality. Notes - pnpm 10.25 defaults minimumReleaseAge to 1209600, which it reads as MINUTES (~840 days), blocking all resolution. Worked around per-invocation with --config.minimumReleaseAge=0; no config file was changed. See -35m.25. - pnpm-lock.yaml is Prettier-formatted and lint-checked. Both conventions are now documented in the README. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes thecodedestroyer_github_io-35m.23, the last child of the maintenance sweep epic. The repo had zero tests; CI ran eslint, prettier and tsc only. Five tests, ~0.8s, always against the production build rather than `next dev` — the section ids, metadata routes and prerendered markup are all build-time output, so the dev server would be testing a different artifact. - smoke: `/` returns 200, the h1 renders, and every value of the `Sections` enum is attached as an element id. Sourced from the enum, not a literal list, so a renamed section fails here instead of silently breaking deep links. - metadata routes: /llms.txt, /robots.txt and /sitemap.xml return 200 with the expected content type AND a per-entry body marker. Status and content type alone are not enough — an empty sitemap generator still emits a well-formed `<urlset></urlset>`, which is the regression most worth catching. - navbar highlight: asserts `aria-current` before and after scrolling to #technologies. Deliberately not asserting the `text-accent` class: both come from the same `isCurrent` ternary, so the class adds no signal and would go red on any Tailwind token rename. Playwright over Cypress, despite Cypress being on the site's own skill list: the ESLint preset sets `no-unused-expressions: error`, which bans the Chai property assertions Cypress leans on, and Cypress's injected globals need a second tsconfig. Playwright needed no eslint.config.mjs override at all, has `webServer` built in (Cypress would need start-server-and-test as a second dependency), and exposes `reducedMotion` as a first-class context option. Each test was verified to fail when its subject breaks, not just to pass: pinning the navbar highlight to the first section fails the post-scroll assertion while the load-state one still passes, which is what proves the scroll half is not a no-op. CI: the tests run in the existing job after the build, since `next start` needs that artifact. Splitting would mean uploading .next plus a second checkout and install for no parallelism. Job renamed lint -> ci to match what it now does. The report artifact upload is scoped to the E2E step so it does not warn on lint or build failures. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rename Content-Security-Policy-Report-Only to Content-Security-Policy now that the policy has been verified. Verified against the production build (next start) in headless Chrome, desktop and mobile viewports: zero violations on first paint, while scrolling every section, during the motion entrance animations, hovering the halo cards (--mouse-x/--mouse-y inline writes) and toggling the mobile nav; JSON-LD parses as a Person; /_next/image negotiates avif and webp; manifest.webmanifest and all icon routes load. Playwright suite passes against the enforcing build. Also add upgrade-insecure-requests, which browsers ignore in report-only mode, and keep X-Frame-Options: DENY deliberately as zero-cost belt-and-braces now that frame-ancestors 'none' is enforced. next dev under the enforcing header logs one React-dev-only eval() console.error but hydrates, connects HMR and blocks nothing, so no dev gating and no 'unsafe-eval'. No report-to sink, on purpose: re-verify by hand on a Vercel preview after any policy change. Closes thecodedestroyer_github_io-35m.26 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes beads issue thecodedestroyer_github_io-35m.26.
What
Content-Security-Policy-Report-Only→Content-Security-Policyinnext.config.ts.upgrade-insecure-requests(browsers ignore it in report-only mode, so it only starts doing anything now).X-Frame-Options: DENYdeliberately as zero-cost belt-and-braces beside the now-enforcedframe-ancestors 'none'.next dev's single React-dev-onlyeval()console.error must not be silenced with'unsafe-eval'.Verification (local production build, headless Chrome)
Checked with the report-only header first and then again with the enforcing one — identical, clean results both times:
--mouse-x/--mouse-yinline writes) and toggling the mobile nav (desktop 1440×900 and mobile 390×844).Person;/_next/imagenegotiates avif (10.6 KB), webp (21 KB) and png fallback;manifest.webmanifestplus all six icon routes return 200.next dev(vialocalhost): hydrates, HMR connects, nothing blocked — only React's dev-buildeval()console.error, which React never triggers in production.pnpm lintandpnpm test(Playwright, 5/5) pass against the enforcing build.The Vercel preview of this branch is used for the on-Vercel checks (
/_vercel/insightsand/_vercel/speed-insightsscript + beacons), which do not exist off-Vercel.Note on the diff
This branch is based on the four local
maincommits that had not been pushed yet (b9e1322..122507e), so the PR shows them untilmainis pushed; the CSP change itself is the single commitf2da3c7.🤖 Generated with Claude Code