Sonarqube version
9.7.2 community.
Steps to reproduce
- Open the web UI in a browser window with content security policy enabled
- When prompted, enter the credentials
Expected behavior
The Sonarqube UI loads.
Actual behavior
The “Loading …” page with the rotating circle stays on forever. Errors appear in the browser’s debugger console.
A more technical description
The initial error message appearing in the browser console is:
Refused to execute inline script because it violates the following Content Security Policy directive: “script-src ‘self’”. Either the ‘unsafe-inline’ keyword, a hash (‘sha256-ba+QeiwMoR6CFSj9qTUv59/UFi4ZvVlinT0aq7bQvP0=’), or a nonce (‘nonce-…’) is required to enable inline execution.
This leaves most likely something un-initialized, since a more explicit error follows:
index.ts:105 Application failed to start! Error: sonar-ui-common init: web context needs to be initialized by Initializer.setUrlContext before being used
at Object.n.getUrlContext (init.js:62)
at t.submit (request.js:85)
at o (index.ts:75)
at index.ts:51
at new Promise ()
at Module.287 (index.ts:50)
at r (bootstrap:101)
at Object.285 (main.m.4ca8e4df.js:1)
at r (bootstrap:101)
at a (bootstrap:45)
i @ index.ts:105
(anonymous) @ index.ts:61
Promise.then (async)
287 @ index.ts:56
r @ bootstrap:101
285 @ main.m.4ca8e4df.js:1
r @ bootstrap:101
a @ bootstrap:45
(anonymous) @ bootstrap:238
(anonymous) @ main.m.4ca8e4df.js:1
What follows is a few more 404 errors caused by incorrectly generated script URLs (host.name being the host on which the web UI runs, and /sonarqube being the root path):
bootstrap:166 GET https://host.name/sonarqube/undefined/js/app.m.2c1363e2.chunk.js net::ERR_ABORTED 404
r.e @ bootstrap:166
j @ index.ts:81
287 @ index.ts:56
r @ bootstrap:101
285 @ main.m.4ca8e4df.js:1
r @ bootstrap:101
a @ bootstrap:45
(anonymous) @ bootstrap:238
(anonymous) @ main.m.4ca8e4df.js:1
bootstrap:166 GET https://host.name/sonarqube/undefined/js/11.m.33d9b55d.chunk.js net::ERR_ABORTED 404
r.e @ bootstrap:166
j @ index.ts:81
287 @ index.ts:56
r @ bootstrap:101
285 @ main.m.4ca8e4df.js:1
r @ bootstrap:101
a @ bootstrap:45
(anonymous) @ bootstrap:238
(anonymous) @ main.m.4ca8e4df.js:1
bootstrap:166 GET https://host.name/sonarqube/undefined/js/vendors-app.m.c1fec354.chunk.js net::ERR_ABORTED 404
When the application loads correctly (when I bypass the envoy proxy), the generated URLs don’t contain the /undefined path part. As far as I could research this, that’s because window.baseUrl is undefined, in the error case, and evaluates to https://host.name/sonarqube/ in the success case. The string undefined is interpreted as a relative URL, and as such gets appended to the page’s URL on requests to paths of the form undefined/js/some.script.js, resulting in https://host.name/sonarqube/undefined/js/some.script.js.
The reason for this is that envoy as configured by istio sets a content-security-policy header like this:
content-security-policy: frame-ancestors ‘none’; script-src ‘self’; object-src ‘none’;
This is a sane setting, added by istio by default. Inline scripts are considered inherently unsafe.