perf: add long-lived cache headers for content-hashed static assets#747
perf: add long-lived cache headers for content-hashed static assets#747
Conversation
- Add location /assets/ with Cache-Control: public, max-age=1y, immutable for Vite's content-hashed JS/CSS output (prefix match avoids caching unhashed public/ files like favicon.svg) - Add location = /index.html with Cache-Control: no-cache so browsers always revalidate the entry point and pick up new deployments - Extract 6 security headers into web/security-headers.conf include snippet to avoid duplication across location blocks (nginx does not inherit add_header from server block into location blocks) - Add charset utf-8 to server block - Add proxy_http_version 1.1 to API proxy (consistency with WebSocket block, enables keepalive to backend) Closes #686 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the Nginx configuration for the web application, primarily focusing on optimizing client-side caching, streamlining security header management, and improving API proxy behavior. These changes aim to boost application performance by reducing unnecessary network requests for static assets, ensure fresh content delivery for the main entry point, and maintain robust security practices across different content types. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
🧰 Additional context used🧠 Learnings (5)📓 Common learnings📚 Learning: 2026-03-17T22:08:13.456ZApplied to files:
📚 Learning: 2026-03-22T16:44:15.487ZApplied to files:
📚 Learning: 2026-03-22T16:44:15.487ZApplied to files:
📚 Learning: 2026-03-19T11:33:01.580ZApplied to files:
🔇 Additional comments (6)
WalkthroughThis change refactors nginx configuration to extract security headers into a separate included file and adds explicit cache-control directives. The Dockerfile now copies a new 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces performance improvements by configuring caching headers for static assets and the main entrypoint file. It correctly uses long-lived caches for content-hashed assets and forces revalidation for index.html. The refactoring of security headers into a separate file is a good improvement for maintainability. I have one suggestion to complete the implementation of keepalive connections for the API proxy, which was one of the stated goals of the changes.
| # API proxy to backend service | ||
| location /api/ { | ||
| proxy_pass http://backend:3001; | ||
| proxy_http_version 1.1; |
There was a problem hiding this comment.
To enable HTTP keepalive connections to the upstream server, you also need to clear the Connection header. The proxy_http_version 1.1; directive is not sufficient on its own, as nginx will otherwise send a Connection: close header by default in proxied requests. Adding proxy_set_header Connection ""; will complete the keepalive implementation and improve performance by reusing connections to the backend.
proxy_http_version 1.1;
proxy_set_header Connection "";
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/security-headers.conf`:
- Line 9: Update the Content-Security-Policy header declaration (the add_header
line that sets Content-Security-Policy) to include additional hardening
directives: add object-src 'none' to block plugins, base-uri 'self' to prevent
<base> tag injection, and form-action 'self' to restrict form submissions; keep
existing directives intact and ensure the full policy string remains quoted and
applied with the always flag.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 93ee353c-6017-4558-8d59-03aa8956c7d6
📒 Files selected for processing (3)
docker/web/Dockerfileweb/nginx.confweb/security-headers.conf
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Build Sandbox
- GitHub Check: Build Web
- GitHub Check: Build Backend
- GitHub Check: Analyze (python)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to docker/Dockerfile.web : `nginxinc/nginx-unprivileged` base with non-root user (UID 101), Vue 3 SPA (PrimeVue + Tailwind CSS), SPA routing, API/WebSocket proxy to backend
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Applied to files:
docker/web/Dockerfile
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to docker/Dockerfile.web : `nginxinc/nginx-unprivileged` base with non-root user (UID 101), Vue 3 SPA (PrimeVue + Tailwind CSS), SPA routing, API/WebSocket proxy to backend
Applied to files:
docker/web/Dockerfileweb/nginx.conf
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile : Docker: 3-stage build (builder → setup → distroless runtime) for backend, Chainguard Python, non-root (UID 65532), CIS-hardened
Applied to files:
docker/web/Dockerfile
🔇 Additional comments (8)
web/nginx.conf (6)
10-10: LGTM!Adding
charset utf-8at server level ensures consistent UTF-8 encoding for all text responses.
23-27: LGTM!Good documentation of nginx's
add_headerinheritance behavior and clean extraction to an include file.
29-33: LGTM!Exact-match location for
/index.htmlwithno-cacheensures browsers revalidate the entry point on each visit, correctly picking up new hashed asset references after deployments.
35-40: LGTM!Prefix-match for
/assets/correctly targets Vite's content-hashed output. Theimmutabledirective combined with one-yearmax-ageis ideal for content-hashed assets—browsers won't revalidate until the hash changes.
67-67: LGTM!Adding
proxy_http_version 1.1aligns the API proxy with the WebSocket block and enables HTTP/1.1 features like connection keepalive to the backend.
42-45: The current configuration already provides the correct cache behavior for SPA fallback routes.When
try_filesinternally redirects to/index.html, nginx restarts location matching and the exact matchlocation = /index.htmlis evaluated for the redirected request. Therefore, theCache-Control: no-cacheheader from that location block is applied to all index.html responses, including SPA fallback paths. No changes are needed.docker/web/Dockerfile (1)
33-35: LGTM!The security headers configuration file is correctly copied to
/etc/nginx/security-headers.conf, matching the include path used innginx.conf. Grouping config file copies together maintains good organization.web/security-headers.conf (1)
1-10: Well-structured security headers with good documentation.The extraction of security headers into a shared snippet is clean and maintainable. The CSP correctly accommodates PrimeVue's need for inline styles while maintaining strict controls elsewhere.
…agents - Add proxy_set_header Connection "" to API proxy for proper keepalive (Gemini: proxy_http_version 1.1 alone sends Connection: close) - Harden CSP with object-src 'none', base-uri 'self', form-action 'self' (CodeRabbit: reduces attack surface for plugins, base tag injection, form submission targets) - Update docs/security.md Cache-Control table and prose to document the new 3-tier dashboard caching strategy (docs-consistency agent) Pre-reviewed by 3 local agents + 2 external reviewers, 3 findings addressed Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
🤖 I have created a release *beep* *boop* --- ## [0.4.8](v0.4.7...v0.4.8) (2026-03-22) ### Features * add auto_cleanup config and improve update UX ([#741](#741)) ([289638f](289638f)) * add reporting lines, escalation paths, and workflow handoffs to templates ([#745](#745)) ([c374cc9](c374cc9)) * differentiate template operational configs ([#742](#742)) ([9b48345](9b48345)) * diversify personality preset assignments across templates ([#743](#743)) ([15487a5](15487a5)) * improve template metadata -- skill taxonomy, descriptions, tags, and display names ([#752](#752)) ([f333f24](f333f24)) ### Bug Fixes * resolve log analysis findings (Ollama prefix, logging, init) ([#748](#748)) ([8f871a4](8f871a4)) * use git tag for dev release container image tags ([#749](#749)) ([f30d071](f30d071)) * use subordinate_id/supervisor_id in HierarchyResolver ([#751](#751)) ([118235b](118235b)) ### Performance * add long-lived cache headers for content-hashed static assets ([#747](#747)) ([4d350b5](4d350b5)) * use worksteal distribution for pytest-xdist ([#750](#750)) ([b7dd7de](b7dd7de)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
Summary
location /assets/withCache-Control: public, max-age=31536000, immutablefor Vite's content-hashed JS/CSS output -- uses prefix match instead of regex to avoid caching unhashedpublic/files likefavicon.svglocation = /index.htmlwithCache-Control: no-cacheso browsers always revalidate the entry point and pick up new deployments (304s keep it fast)web/security-headers.confinclude snippet to avoid duplication across location blocks (nginx does not inheritadd_headerfrom server block into location blocks that define their own)charset utf-8to server blockproxy_http_version 1.1to API proxy block (consistency with WebSocket block, enables keepalive to backend)Test plan
docker compose -f docker/compose.yml build web)curl -I /assets/index-*.jsreturnsCache-Control: public, max-age=31536000, immutable+ all 6 security headerscurl -I /assets/index-*.cssreturns same cache + security headerscurl -I /returnsCache-Control: no-cache+ all 6 security headerscurl -I /nonexistent-route(SPA fallback) returnsCache-Control: no-cache+ all 6 security headerscurl -I /favicon.svg(unhashed) returns security headers but NO long cacheReview coverage
Pre-reviewed by 3 agents (docs-consistency, infra-reviewer, issue-resolution-verifier). 0 findings -- all checks pass, all acceptance criteria resolved.
Closes #686