File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -62,14 +62,24 @@ describe('security headers', () => {
6262 expect ( csp ) . toContain ( 'https://mcp.figma.com' ) ;
6363 } ) ;
6464
65- test ( 'CSP includes Sentry origin when SENTRY_DSN is set ' , async ( ) => {
65+ test ( 'CSP includes Sentry origin parsed from SENTRY_DSN ' , async ( ) => {
6666 const app = createApp ( {
6767 ...baseEnv ,
68- SENTRY_DSN : 'https://abc@sentry.io/123' ,
68+ SENTRY_DSN : 'https://abc@o1.ingest.us. sentry.io/123' ,
6969 } ) ;
7070 const res = await app . fetch ( new Request ( 'http://localhost/api/health' ) ) ;
7171 const csp = res . headers . get ( 'content-security-policy' ) ?? '' ;
72- expect ( csp ) . toContain ( 'https://*.ingest.sentry.io' ) ;
72+ expect ( csp ) . toContain ( 'https://o1.ingest.us.sentry.io' ) ;
73+ } ) ;
74+
75+ test ( 'CSP supports self-hosted Sentry on a custom domain' , async ( ) => {
76+ const app = createApp ( {
77+ ...baseEnv ,
78+ SENTRY_DSN : 'https://abc@sentry.elintrio.com/123' ,
79+ } ) ;
80+ const res = await app . fetch ( new Request ( 'http://localhost/api/health' ) ) ;
81+ const csp = res . headers . get ( 'content-security-policy' ) ?? '' ;
82+ expect ( csp ) . toContain ( 'https://sentry.elintrio.com' ) ;
7383 } ) ;
7484} ) ;
7585
Original file line number Diff line number Diff line change @@ -107,7 +107,8 @@ function getEnvConfig(): EnvConfig {
107107// dropped for this reason.
108108//
109109// Current exceptions are gated by explicit operator opt-in:
110- // - Sentry (`*.ingest.sentry.io`): only when SENTRY_DSN is set.
110+ // - Sentry: origin is parsed from SENTRY_DSN (supports SaaS ingest and
111+ // self-hosted Sentry on custom domains). Only emitted when DSN is set.
111112// - Figma MCP (`mcp.figma.com`): only when SITE_URL is a loopback host
112113// (dev-only; production policy never includes it).
113114//
@@ -118,8 +119,20 @@ function getEnvConfig(): EnvConfig {
118119// whether HSTS is emitted (only when the deployment is HTTPS).
119120// ---------------------------------------------------------------------------
120121
122+ function sentryOriginFromDsn ( dsn : string | undefined ) : string | null {
123+ if ( ! dsn ) return null ;
124+ try {
125+ const url = new URL ( dsn ) ;
126+ return `${ url . protocol } //${ url . host } ` ;
127+ } catch ( err ) {
128+ console . warn ( 'Invalid SENTRY_DSN, skipping CSP allow-list entry:' , err ) ;
129+ return null ;
130+ }
131+ }
132+
121133function buildContentSecurityPolicy ( env : EnvConfig ) {
122- const sentry = env . SENTRY_DSN ? [ 'https://*.ingest.sentry.io' ] : [ ] ;
134+ const sentryOrigin = sentryOriginFromDsn ( env . SENTRY_DSN ) ;
135+ const sentry = sentryOrigin ? [ sentryOrigin ] : [ ] ;
123136 const figmaMcp = isLoopbackSite ( env ) ? [ 'https://mcp.figma.com' ] : [ ] ;
124137 return {
125138 defaultSrc : [ "'self'" ] ,
You can’t perform that action at this time.
0 commit comments