[object Object]

← back to Filemaker Mcp

fix: resolve George basic-auth from live fleet cred (was empty 'admin:', 401'd since 2026-07-13 rotation → froze Shopify→FileMaker sync at order #32600)

aa0cdddff7fe8aa7783feb9100ca16ab80155b55 · 2026-07-14 10:24:40 -0700 · Steve Abrams

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files touched

Diff

commit aa0cdddff7fe8aa7783feb9100ca16ab80155b55
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jul 14 10:24:40 2026 -0700

    fix: resolve George basic-auth from live fleet cred (was empty 'admin:', 401'd since 2026-07-13 rotation → froze Shopify→FileMaker sync at order #32600)
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
 bin/shopify-sync.js |  5 +++--
 lib/george-auth.js  | 40 ++++++++++++++++++++++++++++++++++++++++
 lib/notify.js       |  6 ++++--
 3 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/bin/shopify-sync.js b/bin/shopify-sync.js
index e78fa80..953cfcf 100644
--- a/bin/shopify-sync.js
+++ b/bin/shopify-sync.js
@@ -7,6 +7,7 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, appendFileSync } fr
 import { fileURLToPath } from 'node:url';
 import { dirname, join } from 'node:path';
 import { syncOrder } from '../lib/sync-core.js';
+import { georgeAuthHeader, GEORGE_URL } from '../lib/george-auth.js';
 
 const __dir = dirname(fileURLToPath(import.meta.url));
 const ROOT = join(__dir, '..');
@@ -20,8 +21,8 @@ if (!existsSync(DATA)) mkdirSync(DATA, { recursive: true });
 const STATE_F = join(DATA, 'sync-state.json');
 const LEDGER = join(DATA, 'sync-ledger.jsonl');
 
-const GEORGE = 'http://127.0.0.1:9850';
-const GEORGE_AUTH = 'Basic ' + Buffer.from('admin:').toString('base64');
+const GEORGE = GEORGE_URL;
+const GEORGE_AUTH = georgeAuthHeader(); // fleet cred, resolved from canonical DW-MCP/.env (rotated 2026-07-13)
 const DW_SENDER = 'store+1541177456@t.shopifyemail.com'; // the DW customer-order sender (excludes vendor confirmations)
 const STORE = process.env.FM_SHOPIFY_STORE || process.env.SHOPIFY_STORE;
 const SHOP_TOKEN = process.env.SHOPIFY_ORDERS_TOKEN;
diff --git a/lib/george-auth.js b/lib/george-auth.js
new file mode 100644
index 0000000..ff9e77e
--- /dev/null
+++ b/lib/george-auth.js
@@ -0,0 +1,40 @@
+// Resolve the George (Gmail agent, :9850) basic-auth credential from the SAME
+// canonical fleet source George itself reads, so a rotation there propagates
+// here automatically instead of silently breaking this pipeline.
+//
+// History: before 2026-07-13 these callers hardcoded an empty password
+// ('admin:'). On 2026-07-13 the fleet cred was rotated to a real 32-char pass
+// AND George was hardened to fail-closed on empty/invalid creds. The empty
+// password started returning 401, which made bin/shopify-sync.js throw
+// 'George search failed: 401' at its first step — freezing the Shopify→FileMaker
+// order sync at order #32600 (see data/sync.out.log FATAL loop). This resolver
+// prevents a recurrence: it always tracks the live fleet cred.
+//
+// Priority: GEORGE_BASIC_AUTH env → fleet DW-MCP/.env → local filemaker-mcp/.env.
+import { readFileSync } from 'node:fs';
+import { join } from 'node:path';
+
+function fromEnvFile(path, key) {
+  try {
+    const m = readFileSync(path, 'utf8').match(new RegExp('^' + key + '=(.+)$', 'm'));
+    return m ? m[1].trim() : '';
+  } catch {
+    return '';
+  }
+}
+
+export function georgeCred() {
+  const HOME = process.env.HOME || '';
+  return (
+    process.env.GEORGE_BASIC_AUTH ||
+    fromEnvFile(join(HOME, 'Projects/Designer-Wallcoverings/DW-MCP/.env'), 'GEORGE_BASIC_AUTH') ||
+    fromEnvFile(join(HOME, 'Projects/filemaker-mcp/.env'), 'GEORGE_BASIC_AUTH') ||
+    'admin:' // legacy fallback — now rejected by George, so it 401s loudly rather than silently
+  );
+}
+
+export function georgeAuthHeader() {
+  return 'Basic ' + Buffer.from(georgeCred()).toString('base64');
+}
+
+export const GEORGE_URL = process.env.GEORGE_URL || 'http://127.0.0.1:9850';
diff --git a/lib/notify.js b/lib/notify.js
index 26f12ee..8c04f48 100644
--- a/lib/notify.js
+++ b/lib/notify.js
@@ -2,10 +2,12 @@ import { appendFileSync, readFileSync, mkdirSync, existsSync } from 'node:fs';
 import { fileURLToPath } from 'node:url';
 import { dirname, join } from 'node:path';
 
+import { georgeAuthHeader, GEORGE_URL } from './george-auth.js';
+
 const NOTIFY_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
 const FLAGGED_QUEUE = join(NOTIFY_ROOT, 'data', 'flagged-skus.jsonl');
-const GEORGE = process.env.GEORGE_URL || 'http://127.0.0.1:9850';
-const GEORGE_AUTH = 'Basic ' + Buffer.from((process.env.GEORGE_BASIC || 'admin:')).toString('base64');
+const GEORGE = GEORGE_URL;
+const GEORGE_AUTH = georgeAuthHeader(); // fleet cred, resolved from canonical DW-MCP/.env (rotated 2026-07-13)
 
 // Idempotency key for a flagged SKU: one row per (order, invoice, sku).
 const flagKey = (orderId, invoiceNumber, sku) => `${orderId}:${invoiceNumber}:${sku}`;

← 22d9eff Add Greenland cork disco script: stamps Date Discontinued on  ·  back to Filemaker Mcp  ·  fix: idempotency guard — skip invoice creation when FileMake 65eb72c →