fix(bootstrap): filter empty process.env values to prevent Docker env crash loop (#6828)

Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy
files belong to #6620, not this PR) and the direct CHANGELOG.md edit (fragments-first);
keeps only the author's bootstrap change.

Co-authored-by: Andrian B. <andrewbalanesq@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
Andrew B.
2026-07-10 16:05:41 -05:00
committed by GitHub
parent dd057f590e
commit f79302ccd9
3 changed files with 33 additions and 1 deletions

View File

@@ -0,0 +1 @@
- **fix(bootstrap):** filter empty `process.env` values before spawning embedded services so a blank env var no longer crashes the Docker bootstrap in a restart loop (#6828 — thanks @AndrianBalanescu).

View File

@@ -173,7 +173,14 @@ export function bootstrapEnv({ dataDirOverride, quiet = false } = {}) {
const preferredEnvFiltered = Object.fromEntries(
Object.entries(preferredEnv).filter(([, v]) => typeof v === "string" && v.length > 0)
);
const merged = { ...persisted, ...preferredEnvFiltered, ...process.env };
// Filter empty strings from process.env so that Docker `-e KEY=` (which sets an
// empty string) does not override real values persisted in server.env or set
// in .env. Only shell/Docker vars that the operator actually set should win.
// Mirrors the filtering already applied to preferredEnv above. (fixes #6824)
const processEnvFiltered = Object.fromEntries(
Object.entries(process.env).filter(([, v]) => typeof v === "string" && v.length > 0)
);
const merged = { ...persisted, ...preferredEnvFiltered, ...processEnvFiltered };
// ── Auto-generate required secrets ────────────────────────────────────────
let needsPersist = false;

View File

@@ -120,6 +120,30 @@ test("bootstrapEnv fails closed when existing database cannot be inspected", ()
});
});
test("bootstrapEnv ignores blank process.env values that would override persisted secrets (#6824)", () => {
withTempEnv(({ dataDir }) => {
process.env.DATA_DIR = dataDir;
fs.mkdirSync(dataDir, { recursive: true });
// Persisted secrets in server.env
fs.writeFileSync(
path.join(dataDir, "server.env"),
"STORAGE_ENCRYPTION_KEY=persisted-key\nJWT_SECRET=persisted-jwt\n",
"utf8"
);
// Simulate Docker `-e STORAGE_ENCRYPTION_KEY=` — sets an empty string
process.env.STORAGE_ENCRYPTION_KEY = "";
process.env.JWT_SECRET = "";
const env = bootstrapEnv({ quiet: true });
// Empty process.env values must NOT override persisted secrets
assert.equal(env.STORAGE_ENCRYPTION_KEY, "persisted-key");
assert.equal(env.JWT_SECRET, "persisted-jwt");
});
});
test("bootstrapEnv ignores blank dataDirOverride values", () => {
withTempEnv(({ dataDir }) => {
process.env.DATA_DIR = dataDir;