fix(startup): add strict mongo preflight in production

This commit is contained in:
svemagie
2026-03-08 01:19:47 +01:00
parent dd5a45da92
commit 14d7d16f73
4 changed files with 67 additions and 2 deletions

View File

@@ -25,6 +25,7 @@
- Preferred: set a full `MONGO_URL` (example: `mongodb://user:pass@host:27017/indiekit?authSource=admin`).
- If `MONGO_URL` is not set, set `MONGO_USERNAME` and `MONGO_PASSWORD` explicitly; config builds the URL from `MONGO_USERNAME`, `MONGO_PASSWORD`, `MONGO_HOST`, `MONGO_PORT`, `MONGO_DATABASE`, `MONGO_AUTH_SOURCE`.
- Startup scripts now fail fast when `MONGO_URL` is absent and `MONGO_USERNAME` is missing, to avoid silent auth mismatches.
- Startup now runs `scripts/preflight-mongo-connection.mjs` before boot. In `NODE_ENV=production` this is strict and aborts start on Mongo auth/connect failures.
- For `MongoServerError: Authentication failed`, first verify `MONGO_PASSWORD`, then try `MONGO_AUTH_SOURCE=admin`.
## Content paths
@@ -65,7 +66,7 @@
- `start.sh` is intentionally ignored by Git (`.gitignore`) so server secrets are not committed.
- Use `start.example.sh` as the tracked template and keep real credentials in environment variables (or `.env` on the server).
- Startup scripts parse `.env` with the `dotenv` parser (not shell `source`), so values containing spaces are handled safely.
- Startup scripts run patch helpers before boot (`scripts/patch-lightningcss.mjs`, `scripts/patch-endpoint-media-scope.mjs`, `scripts/patch-endpoint-files-upload-route.mjs`, `scripts/patch-frontend-serviceworker-file.mjs`, `scripts/patch-conversations-collection-guards.mjs`).
- Startup scripts run preflight + patch helpers before boot (`scripts/preflight-mongo-connection.mjs`, `scripts/patch-lightningcss.mjs`, `scripts/patch-endpoint-media-scope.mjs`, `scripts/patch-endpoint-files-upload-route.mjs`, `scripts/patch-frontend-serviceworker-file.mjs`, `scripts/patch-conversations-collection-guards.mjs`).
- The media scope patch fixes a known upstream issue where file uploads can fail if the token scope is `create update delete` without explicit `media`.
- The files upload route patch fixes browser multi-upload by posting to `/files/upload` (session-authenticated) instead of direct `/media` calls without bearer token.
- The frontend serviceworker patch ensures `@indiekit/frontend/lib/serviceworker.js` exists at runtime to avoid ENOENT in the offline/service worker route.

View File

@@ -5,7 +5,7 @@
"main": "index.js",
"scripts": {
"postinstall": "node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-conversations-collection-guards.mjs",
"serve": "node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-conversations-collection-guards.mjs && node node_modules/@indiekit/indiekit/bin/cli.js serve --config indiekit.config.mjs",
"serve": "node scripts/preflight-mongo-connection.mjs && node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-conversations-collection-guards.mjs && node node_modules/@indiekit/indiekit/bin/cli.js serve --config indiekit.config.mjs",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],

View File

@@ -0,0 +1,61 @@
import { MongoClient } from "mongodb";
import config from "../indiekit.config.mjs";
const strictMode =
process.env.REQUIRE_MONGO === "1" ||
(process.env.REQUIRE_MONGO !== "0" && process.env.NODE_ENV === "production");
const hasMongoUrl = Boolean(process.env.MONGO_URL);
const mongoUser = process.env.MONGO_USERNAME || process.env.MONGO_USER || "";
const hasMongoPassword = Boolean(process.env.MONGO_PASSWORD);
if (!hasMongoUrl && (!mongoUser || !hasMongoPassword)) {
const message =
"[preflight] Missing Mongo credentials: set MONGO_URL or MONGO_USERNAME + MONGO_PASSWORD.";
if (strictMode) {
console.error(message);
process.exit(1);
}
console.warn(`${message} Continuing because strict mode is disabled.`);
process.exit(0);
}
const mongodbUrl = config.application?.mongodbUrl;
if (!mongodbUrl) {
const message = "[preflight] MongoDB URL could not be resolved from configuration.";
if (strictMode) {
console.error(message);
process.exit(1);
}
console.warn(`${message} Continuing because strict mode is disabled.`);
process.exit(0);
}
const client = new MongoClient(mongodbUrl, { connectTimeoutMS: 5000 });
try {
await client.connect();
await client.db().command({ ping: 1 });
console.log("[preflight] MongoDB connection OK");
} catch (error) {
const message = `[preflight] MongoDB connection failed: ${error.message}`;
if (strictMode) {
console.error(message);
process.exit(1);
}
console.warn(`${message} Continuing because strict mode is disabled.`);
} finally {
try {
await client.close();
} catch {
// no-op
}
}

View File

@@ -34,6 +34,9 @@ fi
export NODE_ENV="${NODE_ENV:-production}"
# Verify MongoDB credentials/connectivity before launching server.
/usr/local/bin/node scripts/preflight-mongo-connection.mjs
# Ensure runtime dependency patches are applied even if node_modules already exists.
/usr/local/bin/node scripts/patch-lightningcss.mjs
/usr/local/bin/node scripts/patch-endpoint-media-scope.mjs