← back to Dw Pitch Followup
pitch: FIX critical George 401 — resolve GEORGE_AUTH from secrets master (restores sends + threading + last-corr)
6c560f3e3e771df2cf0e663525de7eab0b402b66 · 2026-07-14 11:15:53 -0700 · Steve
The app resolved an empty George password, so every George call 401d — sends, reply-threading, and "last corresponded" were silently failing (and pm2 --update-env wiped the process-env cred on restart). Now resolves the canonical GEORGE_AUTH ("user:pass") from secrets-manager/.env, surviving restarts. Verified: lastcorr returns a real thread.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Files touched
Diff
commit 6c560f3e3e771df2cf0e663525de7eab0b402b66
Author: Steve <steve@designerwallcoverings.com>
Date: Tue Jul 14 11:15:53 2026 -0700
pitch: FIX critical George 401 — resolve GEORGE_AUTH from secrets master (restores sends + threading + last-corr)
The app resolved an empty George password, so every George call 401d — sends, reply-threading, and "last corresponded" were silently failing (and pm2 --update-env wiped the process-env cred on restart). Now resolves the canonical GEORGE_AUTH ("user:pass") from secrets-manager/.env, surviving restarts. Verified: lastcorr returns a real thread.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
server.js | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/server.js b/server.js
index 2a4420e..fe5c1ca 100644
--- a/server.js
+++ b/server.js
@@ -35,11 +35,22 @@ const GEORGE = process.env.GEORGE_URL || 'http://127.0.0.1:9850';
// Resolve George secrets: prefer our own env, else read them straight from george-gmail/.env
// (same fallback George itself uses — launchd/pm2 don't load .env into process.env).
const GEORGE_ENV = process.env.GEORGE_ENV_PATH || '/Users/macstudio3/Projects/george-gmail/.env';
-function envFromGeorge(key) {
- try { const m = fs.readFileSync(GEORGE_ENV, 'utf8').match(new RegExp('^' + key + '=(.+)$', 'm')); return m ? m[1].trim().replace(/^["']|["']$/g, '') : ''; } catch { return ''; }
+// The canonical fleet cred lives in the secrets-manager master (GEORGE_AUTH = "user:pass").
+const SECRETS_ENV = process.env.SECRETS_ENV_PATH || '/Users/macstudio3/Projects/secrets-manager/.env';
+function envFrom(file, key) {
+ try { const m = fs.readFileSync(file, 'utf8').match(new RegExp('^' + key + '=(.+)$', 'm')); return m ? m[1].trim().replace(/^["']|["']$/g, '') : ''; } catch { return ''; }
}
-const GEORGE_BASIC_PASS = process.env.GEORGE_BASIC_AUTH_PASS || envFromGeorge('GEORGE_BASIC_AUTH_PASS');
-const GEORGE_AUTH = 'Basic ' + Buffer.from(`admin:${GEORGE_BASIC_PASS}`).toString('base64');
+function envFromGeorge(key) { return envFrom(GEORGE_ENV, key); }
+// George Basic auth. Prefer the canonical GEORGE_AUTH ("user:pass") from the secrets master so
+// the cred survives `pm2 restart --update-env` (the process-env password used to vanish on a
+// bare restart → every George call silently 401'd, killing sends + threading + last-corr).
+function resolveGeorgeAuth() {
+ const direct = process.env.GEORGE_AUTH || envFrom(SECRETS_ENV, 'GEORGE_AUTH') || envFromGeorge('GEORGE_AUTH');
+ if (direct) return direct.startsWith('Basic ') ? direct : ('Basic ' + Buffer.from(direct.includes(':') ? direct : ('admin:' + direct)).toString('base64'));
+ const pass = process.env.GEORGE_BASIC_AUTH_PASS || envFromGeorge('GEORGE_BASIC_AUTH_PASS');
+ return 'Basic ' + Buffer.from('admin:' + pass).toString('base64');
+}
+const GEORGE_AUTH = resolveGeorgeAuth();
// Human-approval token for EXTERNAL sends. George fail-closes without it (blocks any
// non-@designerwallcoverings.com recipient). Attaching it = the Send-now click is the
// human approval; George still stamps a source footer on every message.
← c6d5609 pitch: card/UX batch — dismiss-completed, park vendor memos,
·
back to Dw Pitch Followup
·
pitch: Sent log is now LIVE — merge Gmail Sent (recipient-en f9b6323 →