← back to Wallco Ai
fix(scripts): DB password from DATABASE_URL (.env), not empty PGPASSWORD env
4e68e65e18d8e01de45ee9c71cc5532312015070 · 2026-06-09 17:27:27 -0700 · Steve Abrams
The secret-scrub left these reading os.environ PGPASSWORD (not exported) → empty
pw → PG auth fail. _pg_password() now parses DATABASE_URL from .env (mirrors
edges-batch-scan.py); PGPASSWORD env still overrides. SELECT 1 verified all 4 paths.
Files touched
M scripts/build-tif.pyM scripts/fix-seam.pyM scripts/monterey-top12-manifest.pyM scripts/regen-id-collisions.py
Diff
commit 4e68e65e18d8e01de45ee9c71cc5532312015070
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 9 17:27:27 2026 -0700
fix(scripts): DB password from DATABASE_URL (.env), not empty PGPASSWORD env
The secret-scrub left these reading os.environ PGPASSWORD (not exported) → empty
pw → PG auth fail. _pg_password() now parses DATABASE_URL from .env (mirrors
edges-batch-scan.py); PGPASSWORD env still overrides. SELECT 1 verified all 4 paths.
---
scripts/build-tif.py | 19 ++++++++++++++++++-
scripts/fix-seam.py | 21 +++++++++++++++++++--
scripts/monterey-top12-manifest.py | 19 ++++++++++++++++++-
scripts/regen-id-collisions.py | 23 ++++++++++++++++++++++-
4 files changed, 77 insertions(+), 5 deletions(-)
diff --git a/scripts/build-tif.py b/scripts/build-tif.py
index c3c063e..c7895d3 100755
--- a/scripts/build-tif.py
+++ b/scripts/build-tif.py
@@ -40,9 +40,26 @@ import shutil
import subprocess
from pathlib import Path
from collections import Counter
+from urllib.parse import urlparse
import psycopg2
from psycopg2.extras import RealDictCursor
+
+
+def _pg_password():
+ """Resolve Postgres password: PGPASSWORD env var takes precedence, then
+ parse it out of DATABASE_URL in .env. Never hard-code the secret."""
+ if os.environ.get("PGPASSWORD"):
+ return os.environ["PGPASSWORD"]
+ env_file = ROOT / ".env"
+ if env_file.exists():
+ for line in env_file.read_text().splitlines():
+ if line.startswith("DATABASE_URL="):
+ url = line.split("=", 1)[1].strip().strip('"')
+ parsed = urlparse(url)
+ if parsed.password:
+ return parsed.password
+ return ""
from PIL import Image, ImageStat
ROOT = Path(__file__).resolve().parents[1]
@@ -70,7 +87,7 @@ VTRACER_BIN = shutil.which("vtracer") # optional real vectorizer
def db():
return psycopg2.connect(
host="127.0.0.1", port=5432,
- user="dw_admin", password="DW2024SecurePass",
+ user="dw_admin", password=_pg_password(),
dbname="dw_unified",
)
diff --git a/scripts/fix-seam.py b/scripts/fix-seam.py
index b74f85b..9f253a2 100644
--- a/scripts/fix-seam.py
+++ b/scripts/fix-seam.py
@@ -14,10 +14,27 @@ Usage:
python3 scripts/fix-seam.py --scan-flagged
"""
import os, sys, argparse, json, subprocess
+from urllib.parse import urlparse
from PIL import Image, ImageFilter
ROOT = os.path.expanduser('~/Projects/wallco-ai')
OUT = os.path.join(ROOT, 'data', 'seam-fix')
+
+
+def _pg_password():
+ """Resolve Postgres password: PGPASSWORD env var takes precedence, then
+ parse it out of DATABASE_URL in .env. Never hard-code the secret."""
+ if os.environ.get("PGPASSWORD"):
+ return os.environ["PGPASSWORD"]
+ env_file = os.path.join(ROOT, ".env")
+ if os.path.exists(env_file):
+ for line in open(env_file):
+ if line.startswith("DATABASE_URL="):
+ url = line.split("=", 1)[1].strip().strip('"')
+ parsed = urlparse(url)
+ if parsed.password:
+ return parsed.password
+ return ""
LEDGER = os.path.join(OUT, 'fix-log.jsonl')
SAMPLE_STEP = 20
THRESHOLD = 20
@@ -62,7 +79,7 @@ def find_disk_path(design_id):
# 1. PG canonical
sql = f"SELECT local_path FROM spoon_all_designs WHERE id={design_id} LIMIT 1;"
try:
- env = {**os.environ, 'PGPASSWORD':'DW2024SecurePass'}
+ env = {**os.environ, 'PGPASSWORD': _pg_password()}
r = subprocess.run(['psql','-h','127.0.0.1','-U','dw_admin','-d','dw_unified','-At','-c',sql],
capture_output=True, text=True, env=env, timeout=10)
lp = r.stdout.strip()
@@ -143,7 +160,7 @@ def main():
a,b = args.range.split('-')
ids += list(range(int(a), int(b)+1))
if args.scan_flagged:
- env = {**os.environ, 'PGPASSWORD':'DW2024SecurePass'}
+ env = {**os.environ, 'PGPASSWORD': _pg_password()}
r = subprocess.run(['psql','-h','127.0.0.1','-U','dw_admin','-d','dw_unified','-At','-c',
"SELECT id FROM spoon_all_designs WHERE id BETWEEN 40000 AND 50000 AND is_published AND user_removed IS NOT TRUE ORDER BY id;"],
capture_output=True, text=True, env=env, timeout=30)
diff --git a/scripts/monterey-top12-manifest.py b/scripts/monterey-top12-manifest.py
index 73aa8c4..cfb1508 100644
--- a/scripts/monterey-top12-manifest.py
+++ b/scripts/monterey-top12-manifest.py
@@ -14,10 +14,27 @@ Usage:
"""
import argparse, json, os, subprocess, sys
from pathlib import Path
+from urllib.parse import urlparse
ROOT = Path(__file__).resolve().parents[1]
+def _pg_password():
+ """Resolve Postgres password: PGPASSWORD env var takes precedence, then
+ parse it out of DATABASE_URL in .env. Never hard-code the secret."""
+ if os.environ.get("PGPASSWORD"):
+ return os.environ["PGPASSWORD"]
+ env_file = ROOT / ".env"
+ if env_file.exists():
+ for line in env_file.read_text().splitlines():
+ if line.startswith("DATABASE_URL="):
+ url = line.split("=", 1)[1].strip().strip('"')
+ parsed = urlparse(url)
+ if parsed.password:
+ return parsed.password
+ return ""
+
+
def psql_json(sql):
# Connect the same way the app does on this host (peer auth / DATABASE_URL=dw_unified).
env = dict(os.environ)
@@ -25,7 +42,7 @@ def psql_json(sql):
capture_output=True, text=True, env=env)
if r.returncode != 0:
# fall back to dw_admin TCP if peer auth isn't available
- env["PGPASSWORD"] = env.get("PGPASSWORD", "DW2024SecurePass")
+ env["PGPASSWORD"] = _pg_password()
r = subprocess.run(["psql", "-h", "127.0.0.1", "-U", "dw_admin", "-d", "dw_unified",
"-At", "-c", sql], capture_output=True, text=True, env=env)
if r.returncode != 0:
diff --git a/scripts/regen-id-collisions.py b/scripts/regen-id-collisions.py
index bdddbfa..7c1d97d 100644
--- a/scripts/regen-id-collisions.py
+++ b/scripts/regen-id-collisions.py
@@ -1,4 +1,25 @@
import json, subprocess, os
+from pathlib import Path
+from urllib.parse import urlparse
+
+_ROOT = Path(__file__).resolve().parents[1]
+
+
+def _pg_password():
+ """Resolve Postgres password: PGPASSWORD env var takes precedence, then
+ parse it out of DATABASE_URL in .env. Never hard-code the secret."""
+ if os.environ.get("PGPASSWORD"):
+ return os.environ["PGPASSWORD"]
+ env_file = _ROOT / ".env"
+ if env_file.exists():
+ for line in env_file.read_text().splitlines():
+ if line.startswith("DATABASE_URL="):
+ url = line.split("=", 1)[1].strip().strip('"')
+ parsed = urlparse(url)
+ if parsed.password:
+ return parsed.password
+ return ""
+
SEL = ("SELECT id, is_published::int, COALESCE(category,''), md5(COALESCE(prompt,'')), "
"COALESCE(substr(prompt,1,100),''), COALESCE(generator,''), COALESCE(parent_design_id::text,''), "
@@ -7,7 +28,7 @@ SEL = ("SELECT id, is_published::int, COALESCE(category,''), md5(COALESCE(prompt
"FROM all_designs WHERE id BETWEEN 1 AND 14999 ORDER BY id;")
def run_mac2(sql):
- env = dict(os.environ, PGPASSWORD="DW2024SecurePass")
+ env = dict(os.environ, PGPASSWORD=_pg_password())
r = subprocess.run(["psql","-h","127.0.0.1","-U","dw_admin","-d","dw_unified","-tAF","\t","-c",sql],
capture_output=True, text=True, env=env)
if r.returncode != 0: raise RuntimeError("mac2 psql: "+r.stderr)
← 4a2ef63 restore script: generalize via CATEGORY_REGEX, hard-exclude
·
back to Wallco Ai
·
security: strip DB DSN passwords from audit/digest docs (use 52ea65f →