7.9 KiB
Session — security.azcomputerguru.com: live deploy + smoke test (found/fixed prod auth bug)
User
- User: Howard Enos (howard)
- Machine: Howard-Home
- Role: tech
Session Summary
Continued the security-assessment work (same HOWARD-HOME session; see the two companion logs from today). Howard requested: make UI elements slightly larger, test every field for usable info, and a big new multi-tenant client portal + ACG sales view. Did the unambiguous pieces, deferred the portal to a feature request, then (on Howard's "b" greenlight) deployed to the live IX host and functionally tested — which surfaced a production-breaking bug.
Bumped the wizard UI sizing ~10-12% (text, inputs, spacing, wider sheet, bigger buttons) and committed
it. Built app/fieldcheck.cjs and audited every questions.json field: 59 fields / 25 scorable, all 25
emit a usable finding on worst-case answers, no orphan/missing score keys, all findings complete, all 13
requiredControls resolve — every field yields usable info. Captured the portal vision as FR-1 in
FEATURES.md (personas, no-auto-sync guardrail, quote→active workflow, 3 auth options) and asked the
foundational auth decision; Howard chose to defer it to a feature request and focus on testing. Added an
executive summary + top-3 prioritized actions + ACG footer to the export (client = recommendations,
internal = + ACG service).
Deployed to IX (172.16.3.10, cPanel account azcomputerguru, docroot
/home/azcomputerguru/public_html/security, PHP 8.1.34) over SSH: backed up the live files, uploaded to
.new, lint-gated (php -l + JSON validate), then atomic-swapped into place. config.php (live secrets)
was never touched. The public URL was already live behind Cloudflare Access (a public hit returns CF
Access 403), so this was an update, not first-time setup.
Smoke-testing on the server found a production-breaking bug: api.php's allow-list check did a
single strcasecmp($email, ALLOWED_EMAIL) against the WHOLE comma-separated list, so once a 2nd address
(howard@) was added on Jun 19, every API call (lookup/save/load/list/export) returned forbidden — the
live backend had been unusable. Fixed it to split + membership-check (matching index.php), redeployed,
and re-verified: action=list reads the DB; internal export renders posture/exec-summary/findings/ACG-
service/REQUIRED/captured-intake; client export renders posture+recommendations with zero upsell leaks
and no raw intake. Inserted a weak-answer test row, exported both views, then deleted it — prod DB back
to its 2 real rows. Committed everything to submodule main and advanced the claudetools pin so git
matches the live server.
Key Decisions
- Deploy via root SSH + base64 file upload, lint-gated atomic swap. Backup → upload
.new→php -l/JSON-validate →mvinto place. Never overwriteconfig.php. Safe for a live site. - Functional-test via PHP CLI + a shipped harness, not inline
php -r. Inlinessh "php -r '...'"mangled through nested quoting (printed PHP usage); a base64'd.phpharness that includes api.php and drives$_GET[action]is reliable. Bypasses the Apache/Cloudflare vhost routing (origin-direct curl 404'd — a vhost/SNI artifact, not a broken deploy). - Test row written to the tool's own MySQL then deleted — acceptable for a smoke test (its own DB,
not Syncro/RMM), clearly tagged
ZZ-SMOKE-DELETE, cleaned up. - Portal deferred to FR-1 (Howard's call) rather than building a multi-tenant auth model speculatively.
- MSYS
sshfor password+askpass, not native Windows OpenSSH (which fails the .sh askpass) — matches the working pfsense-ssh.sh pattern.
Problems Encountered
- PROD BUG — api.php 403 for everyone (single strcasecmp vs comma list). Found via live smoke test; fixed + redeployed + verified. This is why "test every function" mattered.
- Native Windows OpenSSH askpass failed
CreateProcessW error:193(can't exec a .sh askpass) → used MSYS baressh. Logged --friction. - Inline
php -rover ssh mangled (nested quote stripping) → shipped a base64'd .php harness. Logged --friction (reffeedback_windows_quote_stripping). - Origin-direct curl 404'd (vhost/SNI; CF proxies the real path) → tested via PHP CLI instead.
- Submodule reset to old scaffold earlier (stale gitlink + a concurrent submodule-update) → restored to origin/main and advanced the claudetools pin to stop the churn.
Configuration Changes
security-assessment submodule (all on main, pushed; claudetools pin advanced each time):
app/index.php— UI sizing bump (66eb7cb).app/api.php— export exec-summary/top-3/footer (3e3a9ab); allow-list auth fix (f246091).FEATURES.md(new) — FR-1 portal request;app/fieldcheck.cjs(new) — field-audit dev tool (3a2301b).- Local scratch
app/_deploytest.php+app/_smoke.phpcreated for testing, removed after (not committed). Live IX server:index.php,api.php,questions.jsonupdated in the docroot (backups.bak-20260621-181744);config.phpuntouched. ClaudeTools: this session log +errorlog.md(2 friction entries).
Credentials & Secrets
None created/discovered. Used existing vault infrastructure/ix-server (root SSH 172.16.3.10:22, password
field credentials.password; also a WHM API token credentials.whm-api-token = full-access root). DB creds
live in the server's config.php (vault msp-tools/security-assessment-db). No secrets printed/committed.
Infrastructure & Servers
- IX server 172.16.3.10 (ext 72.194.62.5), Rocky Linux WHM/cPanel, PHP 8.1.34 (ea-php81), root SSH :22.
- Site docroot:
/home/azcomputerguru/public_html/security(cPanel acctazcomputerguru, sub of azcomputerguru.com, vhost 172.16.3.10:80/:443). - security.azcomputerguru.com behind Cloudflare Access (Zero Trust app
8ce5f31c-...; allow mike@ + howard@). Origin answers via CF; origin-direct curl needs--resolve/Host and still 404'd (CF-proxied path is the working one). - Live DB (acgsec_assess): 2 real rows (id 1 Darrell Delphen, id 2 empty) after test cleanup.
Commands & Outputs
# find docroot
ssh root@172.16.3.10 'grep -i security.azcomputerguru.com /etc/userdatadomains'
# -> azcomputerguru==root==sub==azcomputerguru.com==/home/azcomputerguru/public_html/security==...ea-php81
# deploy pattern: backup -> base64 upload to .new -> php -l -> chown user -> mv (atomic)
base64 local.php | ssh root@ix "base64 -d > docroot/file.new"
# functional test (bypasses Apache/CF): shipped harness includes api.php
php _deploytest.php list # {"items":[{id:2...},{id:1,...}]} (after the auth fix)
php _deploytest.php export <id> internal # posture/exec/findings/ACG service/Captured intake
php _deploytest.php export <id> client # posture/recommendations, 0 ACG-service, no Captured intake
# BUG before fix: php _deploytest.php list -> {"error":"forbidden"}
Pending / Incomplete Tasks
- Live browser UI click-through (through Cloudflare Access) — the only thing not tested; needs a human logged into https://security.azcomputerguru.com (look up a client, answer fields, watch posture, Export both views). Backend fully verified server-side.
- #1 GuruRMM endpoint prefill — deferred (infra: no Syncro→RMM mapping, no reachable RMM API from IX).
- FR-1 multi-tenant portal — filed in FEATURES.md, awaiting the auth decision when Howard wants it.
Reference Information
- Submodule
mainHEADf246091(claudetools pin27c1d97at time of fix). - Commits this turn:
66eb7cbsizing,3a2301bFR-1+fieldcheck,3e3a9abexport exec-summary,f246091api auth fix. - Live server backups:
*.bak-20260621-181744in the docroot (rollback if needed). - Export endpoint:
api.php?action=export&id=<id>&view=internal|client(origin requires the CF Access email header). - Companion logs:
2026-06-21-howard-security-assessment-scoring.md,...-unifi-pfsense-control-verbs.md,...-gururmm-bug-018-019.md.