From 101886e5222a5ec4f1edacf68557a479485967cb Mon Sep 17 00:00:00 2001 From: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com> Date: Sun, 8 Mar 2026 17:52:35 +0000 Subject: [PATCH 1/2] Downgrade error to a warning as it does not prevent server startup. --- packages/host/src/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/host/src/server.ts b/packages/host/src/server.ts index 6152fee6..86cfdfaf 100644 --- a/packages/host/src/server.ts +++ b/packages/host/src/server.ts @@ -887,7 +887,7 @@ export class FactorioServer extends events.EventEmitter { try { this._whitelistWatcher = fs.watch(filePath); } catch (err: any) { - this._logger.error(`Unable to watch whitelist, bidirectional sync will not be available:\n${err}`); + this._logger.warn(`Unable to watch whitelist, bidirectional sync will not be available:\n${err}`); return; } From 5b5b2c28f73c24064d9288e20d6054a790b44b49 Mon Sep 17 00:00:00 2001 From: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com> Date: Sun, 8 Mar 2026 18:34:21 +0000 Subject: [PATCH 2/2] Always write a whitelist on server start --- packages/host/src/Instance.ts | 11 +++++++++++ test/integration/instance.js | 31 ++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/host/src/Instance.ts b/packages/host/src/Instance.ts index 952470be..67951204 100644 --- a/packages/host/src/Instance.ts +++ b/packages/host/src/Instance.ts @@ -866,6 +866,17 @@ end`.replace(/\r?\n/g, " "); this.server.writePath("server-whitelist.json"), JSON.stringify([...this._host.whitelist], null, "\t") ); + } else { + // Always create the whitelist even if unused + // This allows it to be watched for changes without a server restart + try { + // wx will throw an error if the file already exists to prevent overwrite + await fs.writeFile(this.server.writePath("server-whitelist.json"), "\n[]\n", { flag: "wx" }); + } catch (err: any) { + if (err.code !== "EEXIST") { + throw err; + } + } } await this.syncMods(); diff --git a/test/integration/instance.js b/test/integration/instance.js index 2955e001..7cba7de8 100644 --- a/test/integration/instance.js +++ b/test/integration/instance.js @@ -1,11 +1,13 @@ "use strict"; +const path = require("path"); const assert = require("assert").strict; const lib = require("@clusterio/lib"); +const fs = require("fs-extra"); const { testMatrix } = require("../common"); const { slowTest, exec, execCtl, execCtlProcess, sendRcon, getControl, - requiresFactorio, hasFactorio, + requiresFactorio, hasFactorio, instancesDir, } = require("./index"); const instId = 48; @@ -67,6 +69,32 @@ describe("Clusterio Instance", function() { await execCtl(`instance stop ${instAltName}`); await execCtl(`instance delete ${instAltName}`); }); + describe("whitelist creation", function() { + const whitelistPath = path.join(instancesDir, instName, "server-whitelist.json"); + before(async function() { + this.timeout(20000); + await execCtl(`${instSetConfig} factorio.sync_whitelist disabled`); + await execCtl(`${instSetConfig} factorio.enable_whitelist false`); + }); + afterEach(async function() { + this.timeout(20000); + await execCtl(`instance stop ${instName}`); + }); + it("should always create a whitelist json even if unused", async function() { + slowTest(this); + await fs.remove(whitelistPath); + await execCtl(`instance start ${instName}`); + const whitelist = await fs.readJSON(whitelistPath); + assert.deepEqual(whitelist, []); + }); + it("should not overwrite the existing whitelist if sync is disabled", async function() { + slowTest(this); + await fs.writeJSON(whitelistPath, ["test_user"]); + await execCtl(`instance start ${instName}`); + const whitelist = await fs.readJSON(whitelistPath); + assert.deepEqual(whitelist, ["test_user"]); + }); + }); for (const [savePatchingEnabled, scriptCommandsEnabled] of testMatrix([true, false], [true, false])) { const strSavePatching = `save patching: ${savePatchingEnabled ? "Enabled" : "Disabled"}`; const strScriptCommands = `script commands: ${scriptCommandsEnabled ? "Enabled" : "Disabled"}`; @@ -81,6 +109,7 @@ describe("Clusterio Instance", function() { before(async function() { this.timeout(20000); // Create and start a patched save + await execCtl(`${instSetConfig} factorio.enable_whitelist true`); await execCtl(`${instSetConfig} factorio.enable_save_patching ${savePatchingEnabled}`); await execCtl(`${instSetConfig} factorio.enable_script_commands ${scriptCommandsEnabled}`); await execCtl(`instance save create ${instName}`);