-
Notifications
You must be signed in to change notification settings - Fork 0
Move public demo to a standalone demo.diffsentry.app container #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
619de0b
feat(web): add VITE_FORCE_DEMO build flag for standalone demo
mk7luke d4e1ae2
fix(web): don't redirect the forced root demo build to /demo
mk7luke c0b5b8e
build: add build:web:demo (forced standalone demo bundle)
mk7luke 847e438
feat: standalone demo container (Dockerfile.demo + nginx)
mk7luke 3a1092f
feat: add demo service (host port 3027) to compose
mk7luke 372b027
fix(demo): harden CSP with pinned inline-script hash + .dockerignore
mk7luke 9736fbc
fix(demo): set /health MIME via default_type, not add_header
mk7luke ba41efb
fix(demo): mark the SPA shell no-store so a stale index.html can't re…
mk7luke 59b77ad
fix(demo): re-assert security headers on the /assets location
mk7luke File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # Build-context hygiene. Both Dockerfile and Dockerfile.demo run `npm ci` and | ||
| # build fresh INSIDE the image; a later `COPY web/ ./` (or `COPY web/ ./web/`) | ||
| # must not overlay the host's platform-specific node_modules onto the | ||
| # container's install, nor drag stale build output into the context. | ||
| **/node_modules | ||
| **/dist | ||
| web/dev-dist | ||
|
|
||
| # VCS, scratch, and local-only tooling | ||
| .git | ||
| .gitignore | ||
| .superpowers | ||
| .playwright-mcp | ||
| **/*.log | ||
|
|
||
| # Never bake secrets into the build context (mounted at runtime, not built in) | ||
| .env | ||
| *.pem |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # Standalone public demo (demo.diffsentry.app). Builds the SPA with demo mode | ||
| # hard-forced (VITE_FORCE_DEMO=true, served at root, no service worker), then | ||
| # serves the static bundle with nginx. No server, DB, keys, or .diffsentry.yaml. | ||
| FROM node:22-alpine AS build | ||
| WORKDIR /app | ||
| COPY web/package.json web/package-lock.json ./web/ | ||
| RUN npm --prefix web ci | ||
| COPY web/ ./web/ | ||
| ENV VITE_FORCE_DEMO=true | ||
| RUN npm --prefix web run build | ||
|
|
||
| FROM nginx:alpine | ||
| COPY deploy/demo-nginx.conf /etc/nginx/conf.d/default.conf | ||
| COPY --from=build /app/web/dist /usr/share/nginx/html | ||
| EXPOSE 80 | ||
| HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://127.0.0.1:80/health || exit 1 |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| server { | ||
| listen 80; | ||
| listen [::]:80; | ||
| server_name demo.diffsentry.app localhost; | ||
| root /usr/share/nginx/html; | ||
| index index.html; | ||
|
|
||
| add_header X-Frame-Options SAMEORIGIN always; | ||
| add_header X-Content-Type-Options nosniff always; | ||
| add_header Referrer-Policy strict-origin-when-cross-origin always; | ||
| # Built React app, fixtures only — no secrets, no auth, no user input, no API | ||
| # (demo makes zero network calls). The app's index.html ships one inline | ||
| # theme/FOUC bootstrap script; rather than open script-src to 'unsafe-inline' | ||
| # (which the sibling diffsentry.app nginx deliberately avoids), we pin its | ||
| # sha256 so only that exact script runs inline. If that bootstrap is ever | ||
| # edited, this hash must be recomputed — the mismatch is fail-loud (a visible | ||
| # CSP console error), so the demo smoke catches it. 'unsafe-inline' style | ||
| # covers injected component styles (CodeMirror, etc.). No 'unsafe-eval'. | ||
| add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'sha256-UDmC3IkULnzs9gwNDZm9m/uQ3xynmJVzhBrYq5MnW6Q='; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'; base-uri 'self'; frame-ancestors 'none'" always; | ||
|
|
||
| # The SPA shell (index.html) is the release manifest — it points at hashed | ||
| # /assets bundles that are replaced on every deploy. A stale cached shell would | ||
| # request bundles that no longer exist, i.e. broken loads. Default everything | ||
| # to no-store; the /assets location below overrides this with immutable for the | ||
| # content-addressed bundles. Set at server level (not a per-location add_header | ||
| # on the shell) so index.html keeps the security + CSP headers above — a | ||
| # location-level add_header would drop that inheritance. | ||
| add_header Cache-Control "no-store" always; | ||
|
|
||
| gzip on; | ||
| gzip_types text/css application/javascript application/json image/svg+xml; | ||
|
|
||
| # Hashed Vite assets are content-addressed and safe to cache hard. | ||
| location /assets/ { | ||
| expires 30d; | ||
| add_header Cache-Control "public, immutable" always; | ||
| # nginx replaces (does not merge) inherited add_headers when a location | ||
| # defines its own, so re-assert the security headers here — otherwise the | ||
| # hashed JS/CSS ship without them. CSP is intentionally omitted: a CSP | ||
| # *response* header has no effect on a static sub-resource (script/style/ | ||
| # font) — only the enclosing document's CSP governs it — so there is nothing | ||
| # to gain by duplicating the long policy string here. | ||
| add_header X-Frame-Options SAMEORIGIN always; | ||
| add_header X-Content-Type-Options nosniff always; | ||
| add_header Referrer-Policy strict-origin-when-cross-origin always; | ||
| } | ||
|
|
||
|
diffsentry[bot] marked this conversation as resolved.
|
||
| # SPA client routing: unknown paths serve the app shell. | ||
| location / { | ||
| try_files $uri $uri/ /index.html; | ||
| } | ||
|
|
||
|
diffsentry[bot] marked this conversation as resolved.
|
||
| location = /health { | ||
| default_type text/plain; | ||
| return 200 'ok'; | ||
| } | ||
| } | ||
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
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.