[object Object]

← back to Wallco Ai

wallco /designs: defense-in-depth vendor-name denylist on dropdown + card filter

dac62a72aca857545067f174862c853c3e8f3413 · 2026-05-20 08:26:54 -0700 · Steve Abrams

Steve directive 2026-05-20 — never include DW vendors in /designs dropdown
(or visible cards). PG was bulk-renamed and night-builder was patched, but
this server-side regex is the failsafe so PG drift can never re-leak.

VENDOR_DENYLIST regex covers: Thibaut, Koroseal, Schumacher, Maya Romanoff,
Scalamandre, Arte International, Cole & Son, Phillip Jeffries, Osborne &
Little, de Gournay, Fromental, Sister Parish, Dedar, Brewster, Mind the Gap,
Hygge, Designtex, Wolf Gordon, Carnegie, Coordonne, Daisy Bennett, China
Seas, York, Marburg, Romo, Fabricut, Stout, Knoll, Arteriors, Timorous
Beasties, HangUps.

Applied at two points in the /designs handler:
  1. dropdown construction: cats = ...filter(c => !DENY.test(c))
  2. card filter: filtered = DESIGNS.filter(d => designHasImage(d) && !DENY.test(d.category))

Vendor-named cards/categories live on /library (admin-only) instead.

Files touched

Diff

commit dac62a72aca857545067f174862c853c3e8f3413
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed May 20 08:26:54 2026 -0700

    wallco /designs: defense-in-depth vendor-name denylist on dropdown + card filter
    
    Steve directive 2026-05-20 — never include DW vendors in /designs dropdown
    (or visible cards). PG was bulk-renamed and night-builder was patched, but
    this server-side regex is the failsafe so PG drift can never re-leak.
    
    VENDOR_DENYLIST regex covers: Thibaut, Koroseal, Schumacher, Maya Romanoff,
    Scalamandre, Arte International, Cole & Son, Phillip Jeffries, Osborne &
    Little, de Gournay, Fromental, Sister Parish, Dedar, Brewster, Mind the Gap,
    Hygge, Designtex, Wolf Gordon, Carnegie, Coordonne, Daisy Bennett, China
    Seas, York, Marburg, Romo, Fabricut, Stout, Knoll, Arteriors, Timorous
    Beasties, HangUps.
    
    Applied at two points in the /designs handler:
      1. dropdown construction: cats = ...filter(c => !DENY.test(c))
      2. card filter: filtered = DESIGNS.filter(d => designHasImage(d) && !DENY.test(d.category))
    
    Vendor-named cards/categories live on /library (admin-only) instead.
---
 server.js | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/server.js b/server.js
index 4a1e759..0e37d31 100644
--- a/server.js
+++ b/server.js
@@ -3536,7 +3536,11 @@ app.get('/designs', (req, res) => {
   // HTML page so missing-file rows don't paint empty cards that 404 their
   // background-image url(). (data/generated/ is in deploy exclude list, so any
   // var_NNNN_* PNG generated locally but not rsynced is 404 on prod.)
-  let filtered = DESIGNS.filter(designHasImage);
+  // ALSO drop any design whose category matches a DW vendor name (defined
+  // a few lines below). Same Steve directive — vendor-named cards never go
+  // to public /designs (live on /library admin-only instead).
+  const _VENDOR_DENY = /\b(thibaut|koroseal|schumacher|maya[ -]romanoff|scalamandre|arte[ -]international|cole[ -]?(and|&)[ -]?son|phillip[ -]jeffries|osborne[ -]?(and|&)?[ -]?little|de[ -]gournay|fromental|sister[ -]parish|dedar|brewster|mind[ -]the[ -]gap|hygge|designtex|wolf[ -]gordon|carnegie|coordonn|daisy[ -]bennett|china[ -]seas|york|marburg|romo|fabricut|stout|knoll|arteriors|timorous[ -]beasties|hangups)\b/i;
+  let filtered = DESIGNS.filter(d => designHasImage(d) && !_VENDOR_DENY.test(String(d.category || '')));
   if (cat)    filtered = filtered.filter(d => d.category === cat);
   if (motifQ) filtered = filtered.filter(d => (d.motifs || []).includes(motifQ));
   if (hueQ)   filtered = filtered.filter(d => hueBucketOf(d.dominant_hex) === hueQ);
@@ -3571,7 +3575,16 @@ app.get('/designs', (req, res) => {
   const total = filtered.length;
   const pages = Math.max(1, Math.ceil(total / PER));
   const slice = filtered.slice((page-1)*PER, page*PER);
-  const cats  = [...new Set(DESIGNS.map(d => d.category))].sort();
+  // Defense-in-depth: NEVER include DW vendor names in the category dropdown.
+  // Steve directive 2026-05-20 — vendor names (Thibaut/Koroseal/Fromental/etc.)
+  // leaked into the dropdown via legacy dw-shopify imports + an AI-gen track
+  // that had a vendor-named slug. PG was bulk-renamed and night-builder's track
+  // string was scrubbed, but this regex is the failsafe so a future drift can't
+  // re-leak. Pair with the bulk PG rename if a new vendor name appears.
+  const VENDOR_DENYLIST = /\b(thibaut|koroseal|schumacher|maya[ -]romanoff|scalamandre|arte[ -]international|cole[ -]?(and|&)[ -]?son|phillip[ -]jeffries|osborne[ -]?(and|&)?[ -]?little|de[ -]gournay|fromental|sister[ -]parish|dedar|brewster|mind[ -]the[ -]gap|hygge|designtex|wolf[ -]gordon|carnegie|coordonn|daisy[ -]bennett|china[ -]seas|york|marburg|romo|fabricut|stout|knoll|arteriors|timorous[ -]beasties|hangups)\b/i;
+  const cats  = [...new Set(DESIGNS.map(d => d.category))]
+    .filter(c => c && !VENDOR_DENYLIST.test(c))
+    .sort();
 
   // Top motifs across full catalog (not filtered)
   const motifCounts = {};

← 48f26cf night-builder: scrub ALL DW vendor names from prompt templat  ·  back to Wallco Ai  ·  Pollock-splatter (12) + Sherman-circus (20) collections publ 33bc0da →