8 · Deep codebase audit
Objective — run a deeper codebase audit while the selected non-production target is live and the stakes are low: project structure, composer security audit, a deployed-vendor/ backdoor-signature re-scan, Git hygiene, FVDUT storage persistence, secret + debug-code scans (with the word-boundary fix for dd()), storage-tracked-file triage, CodeCanyon frontend anti-patterns, and an optional schema audit — so every finding caught here is one that doesn’t surface in production.
Steps at a glance:
- Verify project structure — Confirm the standard Laravel layout, the artisan version, and the vault
.gitignore. - Composer security audit — Surface known vulnerabilities in dependencies, fix the urgent ones, and re-verify.
- Git hygiene — Confirm secrets and heavy trees never entered history.
- Storage persistence (FVDUT) — FVDUT = Files, Vendors, Directories, Uploads, Temp — folders that must
survive a release swap via
shared_dirs. - Secret + debug-code scans — Scan app code for hardcoded credentials and leftover debug calls.
- Triage files tracked in
storage/— Files committed understorage/are ambiguous: Deployer replacesstorage/with a symlink toshared/storage/, so tracked files never reach the running app — but vendor packages often write runtime config tostorage_path(''), and deleting those breaks the package silently. - CodeCanyon frontend anti-patterns — None block a deploy; all are worth logging as
VENDOR/Frontendbacklog items. - Schema audit — Inspect the selected non-production schema with Atlas or a free tool and categorize tables so you know what’s safe to touch.
- Database performance baseline — Capture a DB performance baseline and surface obvious slow queries / N+1 patterns before any real traffic arrives — every slow path caught here is one you don’t debug live.
- Deploy any fixes — Commit any real fixes found above and redeploy.
Background
Section titled “Background”The first live non-production target is the right moment for a thorough codebase audit: the app is deployed and verifiable, but no real users depend on it. Work top to bottom; most findings become backlog items, a few are real fixes you redeploy.
Read Zaj-PROJECT.md first and load the selected non-production row before any redeploy command:
SOURCE_BRANCH="develop" # example; use the selected source branch from Zaj-PROJECT.mdDEPLOY_TARGET="<selected-nonproduction-deploy-target>" # selected Deploy target from Zaj-PROJECT.md# Expected: values match the environment row being auditedWhere this page sits in the phase:
flowchart LR NonProd[Non-production deploy live] --> Deep[Deep pass on this page] Deep --> Backlog[Most findings → backlog] Deep --> Fix[Few fixes → redeploy] Deep --> P10[Phase 10 static audit re-verify]1. Verify project structure
Section titled “1. Verify project structure”Confirm the standard Laravel layout, the artisan version, and the vault .gitignore.
-
List the standard directories and the vault ignore.
Terminal window ls -la app/ config/ database/ public/ resources/ routes/ storage/ls -la artisan composer.json package.json .env.examplephp artisan --versioncat Admin-Local/1-Project/2-Vault/.gitignore # expect `*` and `!.gitignore`# Expected: all standard dirs/files exist; Laravel version prints; vault ignores all but itself- ✅ All standard directories/files exist, Laravel version prints, and the vault
.gitignoreignores everything but itself.
- ✅ All standard directories/files exist, Laravel version prints, and the vault
2. Composer security audit
Section titled “2. Composer security audit”Surface known vulnerabilities in dependencies, fix the urgent ones, and re-verify.
-
Run the audit.
Terminal window composer audit# Expected: a list of advisories (or "No security vulnerability advisories found")- ✅ The audit output is reviewed against the severity table.
-
Fix and re-verify the urgent advisories.
Terminal window composer update vendor/package && composer audit # fix + re-verifygit add composer.json composer.lock && git commit -m "Security: update packages for vulnerability fixes"# Expected: re-audit shows the fixed advisory gone; the lockfile change is committed- ✅ Critical/High advisories are resolved and the lockfile change is committed.
Triage by severity:
| Severity | Action |
|---|---|
| Critical | Update immediately |
| High | Update before launch |
| Medium | Update soon |
| Low | Track for next release |
2.5. Re-scan the deployed vendor/ for backdoor signatures
Section titled “2.5. Re-scan the deployed vendor/ for backdoor signatures”The seam audit in Phase 2 proved a clean tree boots locally. Staging is the first time composer install ran on a real server, and composer install does not replace a package already present at the locked version — so if composer.lock happens to pin a tampered release (or a stale server composer cache served a bad copy), the backdoor rides onto staging silently. Re-run the same signature scan against the deployed tree now, while no real user depends on it.
-
Grep the deployed
vendor/for the known injection fingerprints.Terminal window REL=~/domains/nonprod.example.com/deploy/currentssh <non-prod-alias> "set +eMATCHES=\$(grep -rIlE 'getCourant|HeaderCodec|envato\.|verify\.js|\\\$\\.getScript|gzinflate|str_rot13' $REL/vendor/ 2>/dev/null)STATUS=\$?if [ \$STATUS -eq 0 ] && [ -n \"\$MATCHES\" ]; thenprintf '%s\n' \"\$MATCHES\" | sed -n '1,20p'echo ' ⚠️ review every hit above against §5 of the Phase-2 seam audit'exit 2elif [ \$STATUS -eq 1 ]; thenecho ' ✅ no backdoor signature in the deployed vendor/'exit 0elseecho \"STOP — grep failed with status \$STATUS\"exit \$STATUSfi"# Expected: "✅ no backdoor signature..." — any hit exits 2 and must be read + classified before trusting staging- ✅ The deployed
vendor/returns no backdoor signature (or every hit is read, classified, and resolved per the Phase-2 seam audit).
- ✅ The deployed
-
If a signature appears, the locked release is tampered — clean it, don’t just
composer install.Terminal window # composer install is a NO-OP on an already-installed package — force a reinstall of the flagged package(s):ssh <non-prod-alias> "cd $REL && composer reinstall <vendor>/<package> 2>&1 | tail -3"# then re-grep to prove the signature is gone:ssh <non-prod-alias> "grep -rIlE 'getCourant|HeaderCodec|envato\.|verify\.js' $REL/vendor/ 2>/dev/null \&& echo ' ❌ still present' || echo ' ✅ signature gone'"# Also pin a clean release in composer.lock locally and redeploy, so the next env is clean from the start.- ✅ Any flagged package is reinstalled from clean upstream (signature gone), and the clean release is pinned in
composer.lockfor the next environment.
- ✅ Any flagged package is reinstalled from clean upstream (signature gone), and the clean release is pinned in
3. Git hygiene
Section titled “3. Git hygiene”Confirm secrets and heavy trees never entered history.
-
Scan history for
vendor/,node_modules/, and.env.Terminal window git log --all --full-history -- vendor/ | head -5 # expect emptygit log --all --full-history -- node_modules/ | head -5 # expect emptygit log --all --full-history -- .env | head -5 # expect emptygit log --all --full-history -- ".env.*" | head -5 # expect empty (except .env.example)# Expected: all four scans return empty (apart from .env.example)- ✅
vendor/,node_modules/, and.envare absent from Git history.
- ✅
4. Storage persistence (FVDUT)
Section titled “4. Storage persistence (FVDUT)”FVDUT = Files, Vendors, Directories, Uploads, Temp — folders that must survive a release swap via shared_dirs.
-
Confirm
shared_dirscovers storage + uploads, and symlinks are present.Terminal window grep -A10 "shared_dirs" deploy.php # expect `storage` + any custom upload dirsls -la public/ | grep "^l" # local symlinks presentssh <non-prod-alias> "ls -la ~/domains/nonprod.example.com/deploy/current/public/ | grep '^l'"# Expected: shared_dirs lists storage + uploads; symlinks present locally and on the server- ✅
shared_dirspersists storage + uploads and symlinks are present on both ends.
- ✅
5. Secret + debug-code scans
Section titled “5. Secret + debug-code scans”Scan app code for hardcoded credentials and leftover debug calls.
-
Scan for secrets, debug code, and confirm
APP_DEBUG=false.Terminal window grep -rn "password\s*=" --include="*.php" app/ config/ | grep -v ".env\|example\|fake\|test" | headgrep -rn "api_key\|apikey\|secret_key" --include="*.php" app/ config/ | grep -v ".env\|example" | headgrep -rn "://.*:.*@" --include="*.php" app/ config/ | head # credentials in URLs# Debug code — word-boundary regex so `->add(` does NOT false-positive on `dd(`grep -rnE "(^|[^a-zA-Z_>])(dd|dump|var_dump|print_r)\(" --include="*.php" app/ | headgrep -rn "console.log" resources/js/ | headssh <non-prod-alias> "grep APP_DEBUG ~/domains/nonprod.example.com/deploy/shared/.env" # expect false# Expected: no hardcoded secrets, no real debug calls in shipped paths, APP_DEBUG=false- ✅ No hardcoded secrets, no debug code in staging paths, and
APP_DEBUG=false.
- ✅ No hardcoded secrets, no debug code in staging paths, and
A related noise source is the server log itself when you scan it for real errors:
6. Triage files tracked in storage/
Section titled “6. Triage files tracked in storage/”Files committed under storage/ are ambiguous: Deployer replaces storage/ with a symlink to shared/storage/, so tracked files never reach the running app — but vendor packages often write runtime config to storage_path('<file>'), and deleting those breaks the package silently. This scan is investigation only; the default action for every file is KEEP.
-
List tracked
storage/files and search for their references.Terminal window git ls-files storage/ | grep -vE '\.gitkeep$|\.gitignore$'# For each suspect, search reads AND writes across vendor/packages/app:# B=$(basename <FILE>)# grep -rnE "$B|storage_path.*$B|file_put_contents.*$B|->put\(.*$B" vendor/ packages/ app/ config/ routes/# Expected: a list of suspect files; default action for each is KEEP- ✅ Each tracked
storage/file is triaged (default KEEP) using the reference table.
- ✅ Each tracked
Classify each suspect:
| Reference found in | Action |
|---|---|
vendor/ or packages/ | KEEP + add to shared_files |
app/ / config/ / project code | KEEP + shared_files (or move out of storage/) |
| Nowhere | Default KEEP; remove only if certain it has no vendor origin — and log it |
| Uncertain | KEEP + shared_files |
7. CodeCanyon frontend anti-patterns
Section titled “7. CodeCanyon frontend anti-patterns”None block a deploy; all are worth logging as VENDOR/Frontend backlog items.
-
Scan for global SDKs, unguarded charts, duplicate includes, and double-registered service workers.
Terminal window # Global third-party SDKs that should be route-scopedgrep -rln "js.stripe.com\|paypal.com/sdk\|checkout.razorpay.com" resources/views/layouts/ resources/views/components/ 2>/dev/null# Charts (check for empty-state guards)grep -rln "ApexCharts\|Chart.js\|echarts\|chartist" resources/views/ 2>/dev/null# Duplicate framework includesgrep -rcn "@livewireScripts\|livewire.min.js" resources/views/ 2>/dev/null# Service worker double-registrationgrep -rn "serviceWorker.register" resources/views/ public/ 2>/dev/null# Expected: hits become VENDOR/Frontend backlog items (none block the deploy)- ✅ Any anti-pattern hits are logged as
VENDOR/Frontendbacklog items.
- ✅ Any anti-pattern hits are logged as
Fixes: scope payment SDKs to checkout via @stack('scripts'); guard charts with @if($data->count()) + a “no data” fallback; keep @livewireScripts in the root layout only; register the service worker once.
8. Schema audit
Section titled “8. Schema audit”Inspect the selected non-production schema with Atlas or a free tool and categorize tables so you know what’s safe to touch.
-
Inspect and categorize the selected target tables.
With Atlas or a free tool (
mysqldump --no-data, TablePlus, DBeaver), inspect the selected non-production schema and categorize tables.- ✅ Tables are categorized so you know what’s safe to modify.
Category rules:
| Category | Examples | Rule |
|---|---|---|
| Core vendor | users, settings, payments | NEVER modify |
| Plugin / feature | ai_*, chat_*, blog_* | Check vendor docs first |
| Laravel system | migrations, jobs, cache | NEVER modify |
Custom (_zaj) | users_zaj, custom_* | Yours — safe to modify |
9. Database performance baseline
Section titled “9. Database performance baseline”Capture a DB performance baseline and surface obvious slow queries / N+1 patterns before any real traffic arrives — every slow path caught here is one you don’t debug live.
-
Check the slow query log and threshold.
Terminal window ssh <non-prod-alias> "mysql -e \"SHOW VARIABLES LIKE 'slow_query_log%'; SHOW VARIABLES LIKE 'long_query_time';\""ssh <non-prod-alias> "tail -100 /var/log/mysql/mysql-slow.log 2>/dev/null \|| echo 'Slow query log not accessible on shared hosting — use EXPLAIN on hot queries instead'"# Expected: the log's on/off state + threshold, or a fallback note for shared hosting- ✅ You know whether the slow query log is available.
-
EXPLAINa hot query and list the largest tables.Terminal window ssh <non-prod-alias> "mysql DB_NAME -e \"EXPLAIN SELECT * FROM HOT_TABLE WHERE HOT_COL = 1 LIMIT 10;\""ssh <non-prod-alias> "mysql -e \"SELECT table_name, table_rows FROM information_schema.tables \WHERE table_schema=DATABASE() ORDER BY table_rows DESC LIMIT 10;\""# Expected: hot table uses an index (`key` is not NULL); top tables are recorded- ✅ Hot tables use indexes and the heaviest tables are recorded.
If Debugbar or Telescope is installed on staging, hit the dashboard and two or three list pages as an authenticated user and record: no single query > 1s, no N+1 pattern, hot tables show key used in EXPLAIN, and average page query count is reasonable.
Record in the current 90-DevLog/Sessions/ note (DATABASE/Performance): homepage query count ___, dashboard query count ___, slowest observed query ___ ms. If any tuning work remains, add it to Zaj-BACKLOG.md with owner, trigger, and acceptance criterion.
10. Deploy any fixes
Section titled “10. Deploy any fixes”Commit any real fixes found above and redeploy.
-
Commit and redeploy the audit fixes.
Terminal window git add . && git commit -m "Audit: investigation fixes — <describe>"git push origin "$SOURCE_BRANCH" && dep deploy "$DEPLOY_TARGET"# Expected: fixes committed, pushed, and redeployed to the selected non-production target- ✅ Any audit fixes are committed and redeployed.
Checklist
Section titled “Checklist”Do not mark this step done until every box below is checked.
- 🤖 Structure + audit — structure verified;
composer auditclean of Critical/High. - 🤖 Deployed
vendor/clean — backdoor-signature grep over the server’s installedvendor/returns nothing (or any hit was reinstalled from clean upstream and re-verified). - 🤖 Git history clean —
vendor/,node_modules/,.envabsent from Git history. - 🤖 Storage persists —
shared_dirspersists storage + uploads; symlinks present on server. - 🤖 No secrets / debug — no hardcoded secrets; no debug code in staging paths;
APP_DEBUG=false. - 🤖 Triage + anti-patterns —
storage/-tracked files triaged (default KEEP); frontend anti-patterns logged. - 🤖 Fixes redeployed — any fixes committed and redeployed.