#!/bin/bash
#
# Prove this copy is still blank.
#
# Run it after any change to The Panel, and again on a new install before it
# goes live. It looks for the things that should never travel between sites:
# another company's name, another site's credentials, and leftover data.
#
# Exit code 0 means clean. 1 means look at what it printed.
#
# Usage:  bash deploy/null-check.sh [path]     default is the folder above this
#
set -uo pipefail

ROOT="${1:-$(cd "$(dirname "$0")/.." && pwd)}"
FAIL=0

echo "Checking: $ROOT"
echo

# ── 1. Credentials and data that must never be in a template ────────────────
echo "── Files that should not exist ─────────────────────────────────────────"
# The media check is anchored to the top level on purpose. An unanchored
# 'media' matches apps/media/ and templates/cms/media/, which are code, not
# uploads. The same unanchored pattern in ft-tenant-install.sh once stripped
# the whole Media Hub out of a new install.
FOUND=$( { find "$ROOT" \
        \( -name '.env' -o -name '.env.*' ! -name '.env.example' \
           -o -name 'db.sqlite3' -o -name '*credential*.json' \
           -o -name '*.pem' -o -name '*.key' \) -type f 2>/dev/null
      find "$ROOT/media" -maxdepth 0 -type d 2>/dev/null
    } | grep -v '/venv/' | head -20)
if [ -n "$FOUND" ]; then
    echo "$FOUND"
    FAIL=1
else
    echo "none"
fi
echo

# ── 2. Brand leakage ────────────────────────────────────────────────────────
# ftlink is allowed to name Final Target: that is the fleet master it reports
# to, not the identity of the site. Migrations are history and are never edited.
echo "── Final Target mentions outside ftlink and migrations ─────────────────"
# Also FT Panel and logo_FT: a two letter brand and a logo filename are
# not the company name, so the pattern above walked past both. The
# sidebar of every client install said "FT Panel" and fell back to
# Final Target's own logo when a tenant had none.
# \bFT matters: without the boundary, "LEFT PANEL" matches "FT Panel".
HITS=$(grep -rilE "finaltarget|final target|\bFT Panel|logo_FT" "$ROOT" \
        --include='*.py' --include='*.html' --include='*.txt' --include='*.sh' 2>/dev/null \
        | grep -v '/migrations/' \
        | grep -v '/apps/ftlink/' \
        | grep -v '/venv/' \
        | grep -v 'null-check.sh' \
        | grep -v 'ft-tenant-install.sh')
if [ -n "$HITS" ]; then
    echo "$HITS" | while read -r f; do
        echo "  ${f#"$ROOT"/}  ($(grep -icE "finaltarget|final target|\bFT Panel|logo_FT" "$f") line(s))"
    done
    FAIL=1
else
    echo "none"
fi
echo

# ── 3. Hardcoded reference prefixes ─────────────────────────────────────────
# This check exists because check 2 missed it. 'FT-' was hardcoded in five
# files and this script called the tree clean, because it greps for the
# company name and a two letter prefix is not the company name. Every client
# site would have issued Final Target ticket and order numbers to its own
# customers.
#
# References must come from apps.tenants.refs.prefix_for. Anything building
# one out of a literal is a leak whatever the letters are.
echo "── Hardcoded reference prefixes ────────────────────────────────────────"
PREFIXES=$(grep -rnE "['\"][A-Z]{2,4}-['\"]|f['\"][A-Z]{2,4}-?\{" "$ROOT/apps" \
            --include='*.py' 2>/dev/null \
            | grep -v '/migrations/' \
            | grep -v '__pycache__' \
            | grep -vE "'(SHA|RSA|DSA|AES|TLS|SSL|GMT|UTC|CSV|PDF|URL|API|GET|PUT|XML|SMS)-" \
            | grep -viE "https?-|utf-|iso-|content-|multipart-|text-")
if [ -n "$PREFIXES" ]; then
    echo "$PREFIXES" | sed "s|$ROOT/||"
    FAIL=1
else
    echo "none"
fi
echo

# ── 4. Hardcoded paths belonging to another install ─────────────────────────
echo "── Hardcoded /home or /var/www paths in settings ───────────────────────"
PATHS=$(grep -rn "'/home/\|'/var/www/" "$ROOT/config" 2>/dev/null)
if [ -n "$PATHS" ]; then
    echo "$PATHS"
    FAIL=1
else
    echo "none"
fi
echo

# ── 4b. One company's artwork shipped inside the template ───────────────────
# Found 27 August 2026. static/images/ft.png is one company's mark, and
# cms/base.html, login.html and 2fa_verify.html all fell back to it. So a
# client's panel tab, login screen and 2FA screen showed another company's
# icon, and nothing in this script noticed: check 2 greps for the company name
# and for logo_FT, and a file called ft.png is neither.
#
# Icons now come from the tenant's own apple touch icon, favicon, or initials.
# There is no artwork fallback at all, because the correct answer to "this
# client has no icon" is a blank tab, not somebody else's brand.
echo "── Another company's artwork used as a fallback ─────────────────────────"
ART=$(grep -rn "images/ft\.\|logo_FT\|ft-logo\|ft_logo" "$ROOT/templates" 2>/dev/null \
        | grep -v 'null-check.sh')
if [ -n "$ART" ]; then
    echo "$ART" | sed "s|$ROOT/||"
    FAIL=1
else
    echo "none"
fi
echo

# ── 5. Hardcoded analytics identifiers ──────────────────────────────────────
# Found 25 August 2026. GA_MEASUREMENT_ID carried Final Target's own tag as a
# default in base.py and production.py, so every install shipped with it.
# Nothing read it, which is the only reason nothing leaked. GA_PROPERTY_ID sat
# on the line above, is read by apps/accounts/ga_utils.py, and defaulted to
# Final Target's property, so any install without its own value would report
# Final Target's traffic to whoever opened the panel.
#
# Checks 2 and 3 both walked past these: an ID is neither the company name nor
# a reference prefix. Analytics identifiers belong in the Settings row or in
# .env, never in a default. G-XXXXXXXXXX is skipped because it is the
# placeholder in the Settings form, and a check that cries wolf every run gets
# ignored. Javascript is scanned too, minus .min.js: a theme's own consent.js
# is exactly where a hardcoded pair hid on a live site, while minified vendor
# bundles produce nothing but false matches.
echo "── Hardcoded Google Analytics identifiers ──────────────────────────────"
GAHITS=$(grep -rnE "G-[A-Z0-9]{6,}|GA_[A-Z_]*ID[^=]*=[^)]*default=['\"][^'\"]" "$ROOT" \
            --include='*.py' --include='*.html' --include='*.js' 2>/dev/null \
            | grep -v '/migrations/' \
            | grep -v '/venv/' \
            | grep -v '__pycache__' \
            | grep -v '\.min\.js:' \
            | grep -vE "G-X{6,}" \
            | grep -v 'null-check.sh')
if [ -n "$GAHITS" ]; then
    echo "$GAHITS" | sed "s|$ROOT/||"
    FAIL=1
else
    echo "none"
fi
echo

# ── 6. Seed commands that write another site's content ──────────────────────
echo "── Seed commands ───────────────────────────────────────────────────────"
SEEDS=$(find "$ROOT" -name 'seed_*.py' -not -path '*/venv/*' 2>/dev/null)
if [ -n "$SEEDS" ]; then
    echo "$SEEDS"
    FAIL=1
else
    echo "none"
fi
echo

# ── 7. Every Python file must parse ─────────────────────────────────────────
# A syntax error takes the whole site down on restart, and it is invisible in a
# diff. Cheaper to catch here than in a traceback at 3am.
echo "── Python syntax ───────────────────────────────────────────────────────"
BROKEN=$(python3 - "$ROOT" <<'PYCHECK'
import ast, os, sys
root = sys.argv[1]
for dp, dns, fns in os.walk(root):
    dns[:] = [d for d in dns if d not in ('venv', '__pycache__', '.git')]
    for fn in fns:
        if fn.endswith('.py'):
            p = os.path.join(dp, fn)
            try:
                ast.parse(open(p, encoding='utf-8').read())
            except SyntaxError as e:
                print(f"  {p[len(root)+1:]}: {e.msg}, line {e.lineno}")
PYCHECK
)
if [ -n "$BROKEN" ]; then
    echo "$BROKEN"
    FAIL=1
else
    echo "all files parse"
fi
echo

if [ "$FAIL" -eq 0 ]; then
    echo "Clean. This copy carries no identity but its own."
else
    echo "Not clean. Each item above would follow this template onto a client site."
fi
exit "$FAIL"
