Repository navigation
Conversation
4a9d33a to
514a601
Compare
HTML pages and worker scripts from the apps dev server now carry, as Content-Security-Policy-Report-Only, the policy the sandbox shim applies to uploaded apps, minus frame-ancestors. Inline scripts, eval, http: requests, https: images, blob: workers, frames and form posts that production would block are reported locally before upload, without being blocked. A policy already on the response is kept. The policy is off under Vitest and for appType 'custom' hosts such as Storybook, which serve their own HTML, and server.proxy paths, matched as Vite's proxy matches them, are left alone. script-src also allows the inline React Refresh preamble by the hash of the served text, and connect-src allows the HMR WebSocket. A dev-only script logs each violation with the rule involved. A check-app-csp-drift script compares the copied directives with their source in a web-ui checkout. Refs: APPS-2962 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
514a601 to
298fe58
Compare
🎉 All green!🧪 All tests passed 🔗 Commit SHA: 298fe58 | Docs | View more details | Give us feedback! |
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. 🚀 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
🔵 Needs a closer look
Response-method interception across Vite versions and browser-specific CSP behavior warrant final human validation despite the reported passing tests and manual checks.
No open issues 🎉
What changed in this PR
Adds report-only Content Security Policy checks to the Datadog Apps Vite dev server, helping developers discover sandbox-policy violations before uploading apps without blocking local execution.
Changes:
- Adds CSP headers to HTML and worker responses, with allowances for React Refresh and HMR.
- Injects a deduplicated browser-console logger, excluding Vitest and custom HTML hosts.
- Adds policy-drift tooling, unit and integration coverage, and documentation of known limitations.
| File | Description |
|---|---|
packages/plugins/apps/src/vite/raw-http.fixtures.ts |
Adds a socket-based HTTP test client to avoid nock interference. |
packages/plugins/apps/src/vite/index.ts |
Registers CSP middleware and the dev-only logger. |
packages/plugins/apps/src/vite/index.test.ts |
Tests middleware registration and exemptions. |
packages/plugins/apps/src/vite/dev-server-request-guard.ts |
Exports the shared request-host helper. |
packages/plugins/apps/src/vite/dev-server-request-guard.test.ts |
Tests Host and HTTP/2 authority handling. |
packages/plugins/apps/src/vite/dev-server-csp.ts |
Implements report-only headers and development allowances. |
packages/plugins/apps/src/vite/dev-server-csp.test.ts |
Tests policy generation and HTTP response handling. |
packages/plugins/apps/src/vite/dev-server-csp.integration.test.ts |
Tests CSP and logger integration with Vite. |
packages/plugins/apps/src/vite/dev-server-csp.fixtures.ts |
Provides preamble and policy test helpers. |
packages/plugins/apps/src/vite/dev-server-csp-violations.ts |
Adds the browser violation logger and injection tag. |
packages/plugins/apps/src/vite/dev-server-csp-violations.test.ts |
Tests warning messages, deduplication, and script tags. |
packages/plugins/apps/src/vite/check-app-csp-drift.test.ts |
Tests drift detection and script error handling. |
packages/plugins/apps/src/vite/app-csp.ts |
Stores and formats the copied sandbox policy. |
packages/plugins/apps/scripts/check-app-csp-drift.js |
Compares the policy copy against a web-ui checkout. |
packages/plugins/apps/README.md |
Documents report-only behavior and coverage gaps. |
packages/plugins/apps/package.json |
Exposes the policy-drift command. |
Review effort: Balanced
Motivation
Architecture
flowchart TD browser["Browser: GET page or worker script"] --> csp["createAppCspMiddleware, registered in configureServer"] csp -->|"server.proxy path: passed on unwrapped"| vite["Vite's own middlewares: index HTML, public dir, transforms"] csp -->|"other paths: drop If-None-Match, wrap writeHead, write, end and flushHeaders"| vite vite -->|"text/html, or a Sec-Fetch-Dest worker"| policy["Content-Security-Policy-Report-Only beside any policy already set: APP_CSP_DIRECTIVES, plus the React Refresh preamble hash and the HMR WebSocket origins"] vite -->|"anything else"| unchanged["Sent unchanged"] html["transformIndexHtml, dev only"] --> logger["Logger script: logs each securitypolicyviolation once"]APP_CSP_DIRECTIVEScopies web-ui'sgetAppCspat73db81f;check-app-csp-driftcompares them locally, since CI can't read web-ui.Changes
11 changes across the dev server CSP files, index.ts, the drift script, README.md and tests
dev-server-csp.tsdev-server-csp-violations.tsapp-csp.tsindex.tsappType: 'custom'hosts such as Storybook.index.tsgetRequestHost.dev-server-request-guard.tscheck-app-csp-driftscript.check-app-csp-drift.js,package.jsonREADME.mddev-server-csp.test.ts,dev-server-csp.integration.test.ts,dev-server-csp-violations.test.ts,check-app-csp-drift.test.tsdev-server-csp.fixtures.ts,raw-http.fixtures.tsdev-server-request-guard.test.ts,index.test.tsQA Instructions
298fe58b): a template app on Vite 8,datadog-apps dev, a Datadog staging org, Chrome:Manual QA reproduction
In a template app's
vite.config.ts, importdatadogVitePluginfrom<build-plugins checkout>/packages/published/vite-plugin/dist/src/index.mjs.index.html, in<head>:src/main.tsx, after the imports:src/App.tsx: addconst [count, setCount] = useState(0);and render:src/cspProbes.ts:src/probeWorker.ts:vite.bundled.config.ts(bundled dev mode run):vite.swc.config.ts:vite.config.tswith@vitejs/plugin-react-swcandbase: '/qa-base/'.Run:
#csp-probesand the console on each page; for HMR, click the counter and editCount v1.Blast Radius
dev-verify; Vitest andappType: 'custom'hosts are exempt.Out of Scope / Follow-ups
7 items deferred
vite previewsends no policy.configurePreviewServerif needed.bypass, and list-formwriteHead, aren't covered.server.originnot allowedDocumentation
🤖 Generated with Claude Code