← back to Dw Signup Fulfillment
prevent customer data in George failure logs
9e5aa29b6e58f1e13b91eb366c8fb0e634893f0d · 2026-09-02 10:56:27 -0700 · Steve Abrams
Files touched
M lib/email.jsM lib/verify.js
Diff
commit 9e5aa29b6e58f1e13b91eb366c8fb0e634893f0d
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Sep 2 10:56:27 2026 -0700
prevent customer data in George failure logs
---
lib/email.js | 21 ++++++++++-----------
lib/verify.js | 8 ++++----
2 files changed, 14 insertions(+), 15 deletions(-)
diff --git a/lib/email.js b/lib/email.js
index b00efa7..d215204 100644
--- a/lib/email.js
+++ b/lib/email.js
@@ -34,16 +34,15 @@ function georgePost(payload) {
}, res => {
let d = ''; res.on('data', c => d += c);
res.on('end', () => {
- // Always surface the HTTP status + a short body preview so a caller can LOG *why*
- // a send failed (e.g. 401). George's response body never contains our auth secret.
+ // Surface only status and a sanitized error code. Never retain George's raw
+ // response body because a downstream service could echo customer content.
const httpStatus = res.statusCode;
- const bodyPreview = String(d).slice(0, 300);
let parsed = null;
try { parsed = JSON.parse(d); } catch { /* George returned non-JSON */ }
- const base = { ok: httpStatus < 400, status: httpStatus, httpStatus, bodyPreview };
- resolve(parsed && typeof parsed === 'object'
- ? { ...base, ...parsed, status: httpStatus, httpStatus, bodyPreview }
- : base);
+ const candidate = parsed && typeof parsed === 'object'
+ ? (parsed.error || parsed.code || parsed.message || '') : '';
+ const errorCode = String(candidate).replace(/[^a-zA-Z0-9_.: -]/g, '').slice(0, 120);
+ resolve({ ok: httpStatus < 400, status: httpStatus, httpStatus, errorCode });
});
});
req.on('error', e => resolve({ ok: false, status: 0, error: e.message }));
@@ -86,12 +85,12 @@ async function sendEmail({ to, subject, html, source }) {
}
const result = await georgePost(payload);
// CREDENTIAL-SAFE failure/success logging — the fix for the swallowed George outage.
- // Logs ONLY the George HTTP status, its error/body preview, and the operational
- // recipient/source. NEVER logs the Authorization header, the Basic-auth, or the send token.
+ // Logs ONLY George's HTTP status, sanitized error code, and operational source.
+ // Never logs recipient/customer content, response bodies, auth, or the send token.
if (result && result.ok === false) {
- log(`SEND FAILED via George: to=${to} source=${src} status=${result.status != null ? result.status : '?'} error=${result.error || ''} body=${String(result.bodyPreview || '').replace(/\s+/g, ' ').slice(0, 160)}`);
+ log(`SEND FAILED via George: source=${src} status=${result.status != null ? result.status : '?'} errorCode=${result.errorCode || result.error || ''}`);
} else {
- log(`sent via George: to=${to} source=${src} status=${result && result.status != null ? result.status : '?'}`);
+ log(`sent via George: source=${src} status=${result && result.status != null ? result.status : '?'}`);
}
// Fire-and-forget office copy — a separate message; its failure never affects the real send.
if (officeCopyActive(src) && to !== OFFICE_COPY_TO) {
diff --git a/lib/verify.js b/lib/verify.js
index aa6f028..356cdcd 100644
--- a/lib/verify.js
+++ b/lib/verify.js
@@ -78,11 +78,11 @@ async function startVerification({ email: to, customerId, firstName }) {
const tpl = email.verifyEmail({ firstName: first, url, count: config.FREE_SAMPLE_COUNT });
const mail = await email.sendEmail({ to: addr, subject: tpl.subject, html: tpl.html, source: 'retail-verify' });
// CREDENTIAL-SAFE: never let a failed send hide again. Log + PROPAGATE the George reason/
- // status so retail-webhook.js records *why* the letter didn't go out. Never logs the verify
- // token (carried in `url`), the auth header, or the George body beyond a short preview.
+ // status so retail-webhook.js records *why* the letter didn't go out. Never logs the
+ // recipient, verify token (carried in `url`), auth header, or George response body.
if (mail && mail.ok === false) {
- console.warn(`[verify] verify-email SEND FAILED to=${addr} status=${mail.status != null ? mail.status : '?'} error=${mail.error || ''} body=${String(mail.bodyPreview || '').replace(/\s+/g, ' ').slice(0, 160)}`);
- return { ok: false, reason: 'send_failed', status: (mail.status != null ? mail.status : null), error: mail.error || null, sent: { to: addr, subject: tpl.subject, dryRun: mail.dryRun || false } };
+ console.warn(`[verify] verify-email SEND FAILED status=${mail.status != null ? mail.status : '?'} errorCode=${mail.errorCode || mail.error || ''}`);
+ return { ok: false, reason: 'send_failed', status: (mail.status != null ? mail.status : null), errorCode: mail.errorCode || mail.error || null, sent: { to: addr, subject: tpl.subject, dryRun: mail.dryRun || false } };
}
// verifyUrl carries the bearer token — callers must redact it before logging.
return { ok: true, sent: { to: addr, subject: tpl.subject, dryRun: mail.dryRun || false }, verifyUrl: url };
← b7b23da TK-11114: un-swallow George send failures (credential-safe l
·
back to Dw Signup Fulfillment
·
auto-data-snapshot: 2026-09-02T11:28:31 (2 data files) — arm e8c174a →