← back to Secrets Manager
secrets: backup-before-overwrite guard in writeEnvFile (timestamped .bak on real change, prune last 5) — born from the ZENDESK secret incident
34dcb5ddb64d0b0ec46625853ff41945d3fa8ede · 2026-08-11 07:20:34 -0700 · steve
Files touched
Diff
commit 34dcb5ddb64d0b0ec46625853ff41945d3fa8ede
Author: steve <steve@designerwallcoverings.com>
Date: Tue Aug 11 07:20:34 2026 -0700
secrets: backup-before-overwrite guard in writeEnvFile (timestamped .bak on real change, prune last 5) — born from the ZENDESK secret incident
---
cli.js | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/cli.js b/cli.js
index 394588b..6d41835 100755
--- a/cli.js
+++ b/cli.js
@@ -124,6 +124,22 @@ function writeEnvFile(p, kv, preserveComments = true) {
} else {
for (const [k, v] of Object.entries(kv)) body += `${k}=${envEscape(v)}\n`;
}
+ // Backup-before-overwrite guard (2026-08-11): never destroy a prior secret value in
+ // place. If the file exists and its content is ACTUALLY changing, snapshot it to a
+ // timestamped .bak first (0600), then prune to the last 5 for this file. Born from the
+ // ZENDESK_CHAT_CLIENT_SECRET incident — an `add` overwrote a value with no recovery path.
+ if (fs.existsSync(p)) {
+ const prev = fs.readFileSync(p, 'utf8');
+ if (prev !== body) {
+ const bak = `${p}.bak.${Date.now()}`;
+ try {
+ fs.copyFileSync(p, bak); fs.chmodSync(bak, 0o600);
+ const dir = path.dirname(p), base = path.basename(p) + '.bak.';
+ const olds = fs.readdirSync(dir).filter(f => f.startsWith(base)).sort();
+ for (const o of olds.slice(0, -5)) { try { fs.unlinkSync(path.join(dir, o)); } catch {} }
+ } catch {}
+ }
+ }
fs.writeFileSync(p, body);
try { fs.chmodSync(p, 0o600); } catch {}
}
← 1465ee8 auto-data-snapshot: 2026-08-11T07:04:50 (1 data files) — reg
·
back to Secrets Manager
·
auto-data-snapshot: 2026-08-12T09:56:27 (1 data files) — reg cc73261 →