From 888b399a4f8c659093c6db466449f89b5bf5a82e Mon Sep 17 00:00:00 2001 From: gorkem-bwl Date: Wed, 4 Mar 2026 15:29:44 -0500 Subject: [PATCH 1/5] fix: dynamically set Swagger UI server URL from request ## Changes - Swagger UI now prepends the current server URL (protocol + host) to the servers list, so it works correctly in remote/Docker environments instead of always pointing to localhost. ## Closes Fixes #3339 --- server/src/app.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/server/src/app.ts b/server/src/app.ts index fea81ba07..f7cff5418 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -74,8 +74,22 @@ export const createApp = ({ }, }) ); - // Swagger UI - app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(openApiSpec)); + // Swagger UI — dynamically set server URL from request + app.use("/api-docs", swaggerUi.serve, (req, res, next) => { + const protocol = req.protocol; + const host = req.get("host"); + const dynamicSpec = { + ...openApiSpec, + servers: [ + { + url: `${protocol}://${host}/api/v1`, + description: "Current Server", + }, + ...openApiSpec.servers, + ], + }; + swaggerUi.setup(dynamicSpec)(req, res, next); + }); app.use("/api/v1/health", (req, res) => { res.json({ From 93b9abd5082c3237b6665ae320e0b42e1949eefc Mon Sep 17 00:00:00 2001 From: gorkem-bwl Date: Wed, 4 Mar 2026 15:38:34 -0500 Subject: [PATCH 2/5] fix: add migration to reset infrastructure thresholds from 5 to 100 ## Changes - Added migration 0004_fixInfrastructureThresholds that finds hardware monitors with threshold values of 5 (the old incorrect default) and updates them to 100 (effectively disabled) - Runs automatically on server startup like other migrations ## Closes Fixes #3327 --- .../0004_fixInfrastructureThresholds.ts | 65 +++++++++++++++++++ server/src/db/migration/index.ts | 2 + 2 files changed, 67 insertions(+) create mode 100644 server/src/db/migration/0004_fixInfrastructureThresholds.ts diff --git a/server/src/db/migration/0004_fixInfrastructureThresholds.ts b/server/src/db/migration/0004_fixInfrastructureThresholds.ts new file mode 100644 index 000000000..041f8a9dc --- /dev/null +++ b/server/src/db/migration/0004_fixInfrastructureThresholds.ts @@ -0,0 +1,65 @@ +import { MonitorModel } from "../models/Monitor.js"; +import { logger } from "@/utils/logger.js"; + +/** + * Fix infrastructure monitors that had thresholds incorrectly set to 5 + * due to the old default value. Updates them to 100 (disabled). + */ +export async function fixInfrastructureThresholds(): Promise { + const SERVICE_NAME = "Migration:FixInfrastructureThresholds"; + + try { + logger.info({ service: SERVICE_NAME, message: "Starting infrastructure threshold fix" }); + + const thresholdFields = [ + "cpuAlertThreshold", + "memoryAlertThreshold", + "diskAlertThreshold", + "tempAlertThreshold", + ]; + + // Find hardware monitors with any threshold set to 5 + const filter = { + type: "hardware", + $or: thresholdFields.map((field) => ({ [field]: 5 })), + }; + + const monitors = await MonitorModel.find(filter); + + if (monitors.length === 0) { + logger.info({ service: SERVICE_NAME, message: "No monitors with threshold value of 5 found" }); + return; + } + + logger.info({ + service: SERVICE_NAME, + message: `Found ${monitors.length} monitors with threshold value of 5`, + }); + + let updatedCount = 0; + + for (const monitor of monitors) { + const update: Record = {}; + + for (const field of thresholdFields) { + if ((monitor as any)[field] === 5) { + update[field] = 100; + } + } + + if (Object.keys(update).length > 0) { + await MonitorModel.updateOne({ _id: monitor._id }, { $set: update }); + updatedCount++; + } + } + + logger.info({ + service: SERVICE_NAME, + message: `Fixed ${updatedCount} monitors — thresholds updated from 5 to 100`, + }); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + logger.error({ service: SERVICE_NAME, message: `Error fixing thresholds: ${errorMessage}` }); + throw error; + } +} diff --git a/server/src/db/migration/index.ts b/server/src/db/migration/index.ts index 8ea374514..3b7b45ada 100644 --- a/server/src/db/migration/index.ts +++ b/server/src/db/migration/index.ts @@ -1,6 +1,7 @@ import { migrateStatusWindowThreshold } from "./0001_migrateStatusWindowThreshold.js"; import { convertChecksToTimeSeries } from "./0002_convertChecksToTimeSeries.js"; import { cleanupDuplicateMonitorStats } from "./0003_cleanupDuplicateMonitorStats.js"; +import { fixInfrastructureThresholds } from "./0004_fixInfrastructureThresholds.js"; import MigrationModel from "../models/Migration.js"; type MigrationEntry = { @@ -12,6 +13,7 @@ const migrations: MigrationEntry[] = [ { name: "0001_migrateStatusWindowThreshold", execute: migrateStatusWindowThreshold }, { name: "0002_convertChecksToTimeSeries", execute: convertChecksToTimeSeries }, { name: "0003_cleanupDuplicateMonitorStats", execute: cleanupDuplicateMonitorStats }, + { name: "0004_fixInfrastructureThresholds", execute: fixInfrastructureThresholds }, ]; const runMigrations = async (logger?: { info: Function; error: Function }) => { From b2e2b11ef2146afd5d444cf22c752843f93588cf Mon Sep 17 00:00:00 2001 From: gorkem-bwl Date: Wed, 4 Mar 2026 15:41:01 -0500 Subject: [PATCH 3/5] fix: support IPv6 addresses in ping monitor ## Changes - Fixed ping host sanitization regex that stripped everything after the first colon, which destroyed IPv6 addresses like 2001:db8::1 - New regex properly handles bracketed IPv6 ([::1]:port), bare IPv6, and IPv4/hostname:port formats separately ## Closes Fixes #3053 --- server/src/service/infrastructure/networkService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/service/infrastructure/networkService.ts b/server/src/service/infrastructure/networkService.ts index 702affed2..fe770bd0e 100644 --- a/server/src/service/infrastructure/networkService.ts +++ b/server/src/service/infrastructure/networkService.ts @@ -261,7 +261,8 @@ class NetworkService implements INetworkService { const sanitizedHost = rawUrl .replace(/^https?:\/\//, "") .replace(/\/.*$/, "") - .replace(/:.*/, ""); + .replace(/^\[(.+)\](?::.*)?$/, "$1") // Extract IPv6 from brackets, strip port + .replace(/^([^[\]:]+):(\d+)$/, "$1"); // Strip port from IPv4/hostname only const { response, error } = await this.timeRequest(() => this.ping.promise.probe(sanitizedHost)); if (!response) { From d2f3335b1aad748f3b09044575a95d5f2ad156d4 Mon Sep 17 00:00:00 2001 From: gorkem-bwl Date: Wed, 4 Mar 2026 16:32:01 -0500 Subject: [PATCH 4/5] fix: add type annotations to Swagger middleware parameters Fixes TypeScript build error TS7006 for implicit 'any' types on req, res, next. --- server/src/app.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/app.ts b/server/src/app.ts index f7cff5418..58684532c 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -75,7 +75,7 @@ export const createApp = ({ }) ); // Swagger UI — dynamically set server URL from request - app.use("/api-docs", swaggerUi.serve, (req, res, next) => { + app.use("/api-docs", swaggerUi.serve, (req: express.Request, res: express.Response, next: express.NextFunction) => { const protocol = req.protocol; const host = req.get("host"); const dynamicSpec = { From 8df263fd938a7a2fd2a267414ff0bd04b5993c2d Mon Sep 17 00:00:00 2001 From: gorkem-bwl Date: Wed, 4 Mar 2026 16:44:20 -0500 Subject: [PATCH 5/5] fix: also migrate threshold value of 0 to 100, fix formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses review feedback — thresholds set to 0 also caused issues and should be migrated to 100 (disabled) alongside the value of 5. --- .../0004_fixInfrastructureThresholds.ts | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/server/src/db/migration/0004_fixInfrastructureThresholds.ts b/server/src/db/migration/0004_fixInfrastructureThresholds.ts index 041f8a9dc..6d369f311 100644 --- a/server/src/db/migration/0004_fixInfrastructureThresholds.ts +++ b/server/src/db/migration/0004_fixInfrastructureThresholds.ts @@ -2,7 +2,7 @@ import { MonitorModel } from "../models/Monitor.js"; import { logger } from "@/utils/logger.js"; /** - * Fix infrastructure monitors that had thresholds incorrectly set to 5 + * Fix infrastructure monitors that had thresholds incorrectly set to 0 or 5 * due to the old default value. Updates them to 100 (disabled). */ export async function fixInfrastructureThresholds(): Promise { @@ -11,29 +11,24 @@ export async function fixInfrastructureThresholds(): Promise { try { logger.info({ service: SERVICE_NAME, message: "Starting infrastructure threshold fix" }); - const thresholdFields = [ - "cpuAlertThreshold", - "memoryAlertThreshold", - "diskAlertThreshold", - "tempAlertThreshold", - ]; + const thresholdFields = ["cpuAlertThreshold", "memoryAlertThreshold", "diskAlertThreshold", "tempAlertThreshold"]; - // Find hardware monitors with any threshold set to 5 + // Find hardware monitors with any threshold set to 0 or 5 const filter = { type: "hardware", - $or: thresholdFields.map((field) => ({ [field]: 5 })), + $or: thresholdFields.flatMap((field) => [{ [field]: 0 }, { [field]: 5 }]), }; const monitors = await MonitorModel.find(filter); if (monitors.length === 0) { - logger.info({ service: SERVICE_NAME, message: "No monitors with threshold value of 5 found" }); + logger.info({ service: SERVICE_NAME, message: "No monitors with threshold value of 0 or 5 found" }); return; } logger.info({ service: SERVICE_NAME, - message: `Found ${monitors.length} monitors with threshold value of 5`, + message: `Found ${monitors.length} monitors with threshold value of 0 or 5`, }); let updatedCount = 0; @@ -42,7 +37,7 @@ export async function fixInfrastructureThresholds(): Promise { const update: Record = {}; for (const field of thresholdFields) { - if ((monitor as any)[field] === 5) { + if ((monitor as any)[field] === 0 || (monitor as any)[field] === 5) { update[field] = 100; } } @@ -55,7 +50,7 @@ export async function fixInfrastructureThresholds(): Promise { logger.info({ service: SERVICE_NAME, - message: `Fixed ${updatedCount} monitors — thresholds updated from 5 to 100`, + message: `Fixed ${updatedCount} monitors — thresholds updated from 0/5 to 100`, }); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error);