[object Object]

← back to Wallco Ai

security: gate 4 internal /api routes admin-only + redact brand/vendor/owned_by_steve from public fliepaper-bugs spec (Yuri tick #3/M2)

9c864f62dd028cc991b8e6e218911ee9248c3a5e · 2026-05-26 15:22:30 -0700 · Steve

Files touched

Diff

commit 9c864f62dd028cc991b8e6e218911ee9248c3a5e
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue May 26 15:22:30 2026 -0700

    security: gate 4 internal /api routes admin-only + redact brand/vendor/owned_by_steve from public fliepaper-bugs spec (Yuri tick #3/M2)
---
 src/fliepaper-bugs.js | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/src/fliepaper-bugs.js b/src/fliepaper-bugs.js
index 436b86f..ef5fa40 100644
--- a/src/fliepaper-bugs.js
+++ b/src/fliepaper-bugs.js
@@ -139,6 +139,32 @@ function readCells() {
   }).filter(Boolean);
 }
 
+// Strip internal/brand fields before sending the spec to a public client.
+// spec.json holds vendor name, brand_reference ("Gucci"), owned_by_steve, and
+// per-colorway gucci_ref — none of which may appear in customer-facing surfaces
+// (see CLAUDE.md: no vendor names, no brand leaks). Admin routes keep the full spec.
+function redactSpecPublic(spec) {
+  if (!spec || typeof spec !== 'object') return spec;
+  const clone = JSON.parse(JSON.stringify(spec));
+  const SENSITIVE = /^(vendor|brand_reference|owned_by_steve|gucci_ref|gucci)$/i;
+  // brand token can also be baked into free-text values (e.g. a pattern's
+  // composition prose) — strip it there too so "Gucci" never reaches a client.
+  const BRAND_IN_TEXT = /,?\s*gucci(\s+resort)?/ig;
+  const cleanStr = (s) => s.replace(BRAND_IN_TEXT, '').replace(/\s{2,}/g, ' ').trim();
+  (function scrub(node, parent, key) {
+    if (Array.isArray(node)) return node.forEach((v, i) => scrub(v, node, i));
+    if (node && typeof node === 'object') {
+      for (const k of Object.keys(node)) {
+        if (SENSITIVE.test(k)) delete node[k];
+        else scrub(node[k], node, k);
+      }
+    } else if (typeof node === 'string' && parent != null) {
+      parent[key] = cleanStr(node);
+    }
+  })(clone, null, null);
+  return clone;
+}
+
 function mount(app, { isAdmin }) {
   const path_ = path;
   const pagesPublic = path_.join(__dirname, '..', 'public', 'collections', 'fliepaper-bugs.html');
@@ -163,7 +189,7 @@ function mount(app, { isAdmin }) {
       const spec = loadSpec();
       if (!spec) return res.status(500).json({ error: 'spec.json missing' });
       const cells = readCells();
-      res.json({ ok: true, spec, cells });
+      res.json({ ok: true, spec: redactSpecPublic(spec), cells });
     } catch (e) {
       res.status(500).json({ ok: false, error: e.message });
     }

← e59e6b0 TODO: close catastrophic-cohort tick — edge_seam_heal --grid  ·  back to Wallco Ai  ·  dogs curator: /admin/dogs-curator hot-or-not surface + /api/ 8d5f8a8 →