Context
env_put() in scripts/lib/selfhost-deploy-common.sh creates a same-directory temp file via mktemp (line 59), whose header comment (lines 45-49) explicitly justifies this as guaranteeing an atomic swap ("guarantees cat "$tmp" >"$file" never crosses a filesystem boundary"). But the actual write is cat "$tmp" >"$file" followed by rm -f "$tmp" (lines 78-79) — a truncate-then-copy, not a rename. This is exactly the non-atomic operation the same-directory temp file was supposed to make safe via mv. A crash/kill/power-loss mid-write (this runs during self-host deploys, e.g. env_put LOOPOVER_IMAGE "$IMAGE" at the end of deploy-selfhost-image.sh) can leave .env truncated or corrupted.
This codebase already uses the correct idiom elsewhere: scripts/backup-metrics.sh:59, scripts/browserless-metrics.sh:94, and scripts/export-ams-reporting-db.sh:126,140,165 all do mv "$tmp" "$FILE" for the same same-directory-temp-file reason.
Requirements
Change env_put()'s write from cat "$tmp" >"$file"; rm -f "$tmp" to an atomic mv "$tmp" "$file", mirroring the pattern already used in backup-metrics.sh/browserless-metrics.sh/export-ams-reporting-db.sh. One caveat the fix must handle: mktemp creates the temp file at mode 600, while the target file (created via touch at line 56 if it doesn't already exist) may have a different mode. A naive mv would silently narrow .env's permissions on every write. The fix must preserve the target file's original mode across the swap (e.g. stat the existing file's mode before the mktemp call and chmod the temp file to match before the mv, or an equivalent approach) — do not ship a bare mv that can change .env's permissions as a side effect.
Deliverables
Test Coverage Requirements
test/unit/selfhost-deploy-common.test.ts exists but does not cover env_put today. Add tests for both the atomicity fix and the mode-preservation requirement.
Expected Outcome
.env writes during self-host deploys are truly atomic (a crash mid-write can never leave a truncated/corrupted file), and the file's permissions are never silently changed as a side effect of the fix.
Links & Resources
scripts/lib/selfhost-deploy-common.sh:45-49 (the comment claiming atomicity), :56-79 (env_put's actual implementation); scripts/backup-metrics.sh:59, scripts/browserless-metrics.sh:94, scripts/export-ams-reporting-db.sh:126,140,165 (the correct mv pattern already used elsewhere in this repo)
Context
env_put()inscripts/lib/selfhost-deploy-common.shcreates a same-directory temp file viamktemp(line 59), whose header comment (lines 45-49) explicitly justifies this as guaranteeing an atomic swap ("guaranteescat "$tmp" >"$file"never crosses a filesystem boundary"). But the actual write iscat "$tmp" >"$file"followed byrm -f "$tmp"(lines 78-79) — a truncate-then-copy, not a rename. This is exactly the non-atomic operation the same-directory temp file was supposed to make safe viamv. A crash/kill/power-loss mid-write (this runs during self-host deploys, e.g.env_put LOOPOVER_IMAGE "$IMAGE"at the end ofdeploy-selfhost-image.sh) can leave.envtruncated or corrupted.This codebase already uses the correct idiom elsewhere:
scripts/backup-metrics.sh:59,scripts/browserless-metrics.sh:94, andscripts/export-ams-reporting-db.sh:126,140,165all domv "$tmp" "$FILE"for the same same-directory-temp-file reason.Requirements
Change
env_put()'s write fromcat "$tmp" >"$file"; rm -f "$tmp"to an atomicmv "$tmp" "$file", mirroring the pattern already used inbackup-metrics.sh/browserless-metrics.sh/export-ams-reporting-db.sh. One caveat the fix must handle:mktempcreates the temp file at mode 600, while the target file (created viatouchat line 56 if it doesn't already exist) may have a different mode. A naivemvwould silently narrow.env's permissions on every write. The fix must preserve the target file's original mode across the swap (e.g.statthe existing file's mode before themktempcall andchmodthe temp file to match before themv, or an equivalent approach) — do not ship a baremvthat can change.env's permissions as a side effect.Deliverables
env_put()writes viamv(atomic rename) instead ofcat+rm.env_put, and asserts the mode is unchanged.test/unit/selfhost-deploy-common.test.ts's existingmaybe_infisical_runtests use.Test Coverage Requirements
test/unit/selfhost-deploy-common.test.tsexists but does not coverenv_puttoday. Add tests for both the atomicity fix and the mode-preservation requirement.Expected Outcome
.envwrites during self-host deploys are truly atomic (a crash mid-write can never leave a truncated/corrupted file), and the file's permissions are never silently changed as a side effect of the fix.Links & Resources
scripts/lib/selfhost-deploy-common.sh:45-49(the comment claiming atomicity),:56-79(env_put's actual implementation);scripts/backup-metrics.sh:59,scripts/browserless-metrics.sh:94,scripts/export-ams-reporting-db.sh:126,140,165(the correctmvpattern already used elsewhere in this repo)