Repository: compiler-explorer/compiler-explorer
Pull request #7707 (2025-05-21 20:17:57)

Fix issues introduced in #7681
- healthcheck got accidentally unwired
- CSP was accidentially "done" (was a TODO)



Patch:
diff --git a/lib/app/controllers.ts b/lib/app/controllers.ts
index b573ae94f..01022fce6 100644
--- a/lib/app/controllers.ts
+++ b/lib/app/controllers.ts
@@ -40,6 +40,7 @@ export interface ApiControllers {
     assemblyDocumentationController: AssemblyDocumentationController;
     formattingController: FormattingController;
     noScriptController: NoScriptController;
+    healthcheckController: HealthcheckController;
 }
 
 /**
@@ -68,7 +69,12 @@ export function setupControllersAndHandlers(
     const noScriptController = new NoScriptController(compileHandler, formDataHandler);
 
     // Initialize healthcheck controller (handled separately in web server setup)
-    new HealthcheckController(compilationQueue, healthCheckFilePath, compileHandler, isExecutionWorker);
+    const healthcheckController = new HealthcheckController(
+        compilationQueue,
+        healthCheckFilePath,
+        compileHandler,
+        isExecutionWorker,
+    );
 
     return {
         siteTemplateController,
@@ -76,5 +82,6 @@ export function setupControllersAndHandlers(
         assemblyDocumentationController,
         formattingController,
         noScriptController,
+        healthcheckController,
     };
 }
diff --git a/lib/app/main.ts b/lib/app/main.ts
index db3cca5c2..eb8b98244 100644
--- a/lib/app/main.ts
+++ b/lib/app/main.ts
@@ -116,6 +116,7 @@ export async function initialiseApplication(options: ApplicationOptions): Promis
         ),
         clientOptionsHandler: clientOptionsHandler,
         storageSolution: storageSolution,
+        healthcheckController: controllers.healthcheckController,
     };
 
     const {webServer, router, renderConfig, renderGoldenLayout} = await setupWebServer(
diff --git a/lib/app/server-config.ts b/lib/app/server-config.ts
index ebd79712d..dc4e1c219 100644
--- a/lib/app/server-config.ts
+++ b/lib/app/server-config.ts
@@ -229,10 +229,8 @@ export function setupBasicRoutes(
  * Middleware for content security policy
  */
 function csp(req: Request, res: Response, next: NextFunction) {
-    res.setHeader(
-        'Content-Security-Policy',
-        "default-src 'self' 'unsafe-eval' 'unsafe-inline' *.godbolt.org *.compiler-explorer.com *.googleapis.com *.hcaptcha.com *.cloudflare.com cdn.jsdelivr.net; frame-ancestors *",
-    );
+    // TODO: Consider if CSP should be re-enabled
+    // res.setHeader('Content-Security-Policy', `default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; frame-src 'self';`);
     next();
 }
 
diff --git a/lib/app/server.interfaces.ts b/lib/app/server.interfaces.ts
index 428ed7a66..a32bdb3ed 100644
--- a/lib/app/server.interfaces.ts
+++ b/lib/app/server.interfaces.ts
@@ -24,6 +24,7 @@
 
 import type {Express, Request, Response, Router} from 'express';
 import type {GoldenLayoutRootStruct} from '../clientstate-normalizer.js';
+import type {HttpController} from '../handlers/api/controller.interfaces.js';
 import type {ShortLinkMetaData} from '../handlers/handler.interfaces.js';
 import type {ClientOptionsSource} from '../options-handler.interfaces.js';
 import type {PropertyGetter} from '../properties.interfaces.js';
@@ -86,4 +87,5 @@ export interface ServerDependencies {
     sponsorConfig: Sponsors;
     clientOptionsHandler: ClientOptionsSource;
     storageSolution: string;
+    healthcheckController: HttpController;
 }
diff --git a/lib/app/server.ts b/lib/app/server.ts
index ae6dd5666..da8cf3f91 100644
--- a/lib/app/server.ts
+++ b/lib/app/server.ts
@@ -69,6 +69,9 @@ export async function setupWebServer(
         dependencies,
     );
 
+    // Add healthcheck before logging middleware to prevent excessive log entries
+    webServer.use(dependencies.healthcheckController.createRouter());
+
     setupBaseServerConfig(options, renderConfig, webServer, router);
     setupLoggingMiddleware(appArgs.devMode, router);
 


Test patch:
diff --git a/test/app/rendering-tests.ts b/test/app/rendering-tests.ts
index 7d93c2b5c..793225194 100644
--- a/test/app/rendering-tests.ts
+++ b/test/app/rendering-tests.ts
@@ -22,7 +22,7 @@
 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 // POSSIBILITY OF SUCH DAMAGE.
 
-import type {NextFunction, Request, Response} from 'express';
+import express, {type NextFunction, type Request, type Response} from 'express';
 import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
 
 import {createRenderHandlers} from '../../lib/app/rendering.js';
@@ -94,6 +94,9 @@ describe('Rendering Module', () => {
                     getJSON: vi.fn().mockReturnValue('{}'),
                 },
                 storageSolution: 'localStorage',
+                healthcheckController: {
+                    createRouter: vi.fn().mockReturnValue(express.Router()),
+                },
                 sponsorConfig: {
                     getLevels: vi.fn().mockReturnValue([]),
                     pickTopIcons: vi.fn().mockReturnValue([]),
diff --git a/test/app/server-tests.ts b/test/app/server-tests.ts
index 5d059d555..e4a322766 100644
--- a/test/app/server-tests.ts
+++ b/test/app/server-tests.ts
@@ -55,7 +55,7 @@ function createMockAppArgs(overrides: Partial<AppArguments> = {}): AppArguments
     };
 }
 
-import type {Request, Response} from 'express';
+import express, {type Request, type Response} from 'express';
 import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
 
 import type {AppArguments} from '../../lib/app.interfaces.js';
@@ -114,6 +114,9 @@ describe('Server Module', () => {
                     if (key === 'allowedShortUrlHostRe') return '.*';
                     return '';
                 }),
+                healthcheckController: {
+                    createRouter: vi.fn().mockReturnValue(express.Router()),
+                },
                 sponsorConfig: {
                     getLevels: vi.fn().mockReturnValue([]),
                     pickTopIcons: vi.fn().mockReturnValue([]),