Skip to content

fix(view): render debug bar env quick-switch links only when switching can work#3141

Merged
bpamiri merged 2 commits into
developfrom
peter/issue-3060-debugbar-quickswitch
Jun 13, 2026
Merged

fix(view): render debug bar env quick-switch links only when switching can work#3141
bpamiri merged 2 commits into
developfrom
peter/issue-3060-debugbar-quickswitch

Conversation

@bpamiri

@bpamiri bpamiri commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

The debug bar's Environment panel rendered the Testing / Maintenance / Production quick-switch anchors only when no reloadPassword was set — but since #2082, ?reload=<environment> only performs a switch when a non-empty reloadPassword is configured and a matching password parameter is supplied (additionally gated by allowEnvironmentSwitchViaUrl). So the links rendered exclusively in the one configuration where clicking them could never switch: the app restarted and silently stayed put.

This PR implements the issue's option (b) — render the links when switching CAN work, without leaking the password:

Verify-first

Reproduced on develop @ bb98ffecd before coding: debug.cfm:304 still gated the links on NOT Len($get("reloadPassword")) while onapplicationstart.cfc:182-205 requires a non-empty matching password to switch. The new spec's first run (pre-fix) failed exactly on the defect:

Failed renders no quick-switch links when reloadPassword is empty
Failed renders prompt-based quick-switch links when a reloadPassword is set and switching is allowed

Evidence (Lucee 7 Docker harness, port 63003)

  • New spec vendor/wheels/tests/specs/events/DebugBarEnvQuickSwitchSpec.cfc: red pre-fix (2 fail), green post-fix (3 pass / 0 fail / 0 error).
  • Full core suite /wheels/core/tests?db=sqlite&format=json: 4448 pass / 12 fail / 0 error — the 12 failures are the tolerated internal.testClientSpec baseline artifacts.
  • Live hand-test with set(reloadPassword="smokepw"): dev homepage renders data-wdb-reload="/?reload=testing" (+ maintenance, production) prompt links; smokepw appears 0 times in the 1MB page; curl '/?reload=testing&password=smokepw' then GET / returns 404 with no debug bar — the testing-environment dev-UI gate, i.e. the switch the JS builds actually works (matches the issue's control repro).
  • With reloadPassword="": no quick-switch links; plain reload anchor still renders (spec-asserted).

Docs

  • digging-deeper/debug-panel.mdx and core-concepts/environments-and-configuration.mdx updated from the dead-link caveat (added by the 2026-06-11 guide audit, referencing this issue) to the working prompt-based behavior.
  • changelog.d/debugbar-env-quickswitch.fixed.md fragment added.

Fixes #3060

🤖 Generated with Claude Code

…g can work

Since #2082 the ?reload=<environment> switch requires a non-empty
reloadPassword plus a matching password parameter (and is gated by
allowEnvironmentSwitchViaUrl), but the debug bar still rendered the
Testing/Maintenance/Production quick-switch anchors only when NO
reloadPassword was set — the exact configuration where switching is
impossible. Clicking one restarted the app and silently stayed in the
current environment.

The Environment panel now renders the links only when a reloadPassword
is configured AND allowEnvironmentSwitchViaUrl resolves true. The links
never embed the password: a new wdbEnvSwitch() handler prompts for it
at click time and issues the documented
?reload=<environment>&password=... request. The plain ?reload=true
reload anchor keeps its existing no-password gate.

Guides (debug-panel.mdx, environments-and-configuration.mdx) updated to
describe the working behavior instead of the dead-link caveat.

Fixes #3060

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Peter Amiri <peter@alurium.com>
wheels-bot[bot]
wheels-bot Bot previously requested changes Jun 12, 2026

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wheels Bot — Reviewer

TL;DR: This PR fixes the inverted gate on the debug bar's environment quick-switch links (issue #3060, dead since #2082) with a well-evidenced red-green spec, accurate guide updates, and a proper changelog fragment. The approach — prompt for the reload password at click time instead of embedding it — is right, and the gate logic is sound (allowEnvironmentSwitchViaUrl is always a resolved boolean by request end per onapplicationstart.cfc). However, one reachable edge violates the PR's own "password is never embedded in the page" guarantee: baseReloadURL passes the raw cgi.query_string through, and a residual password= parameter lands inside the new data-wdb-reload attributes. Verdict: request changes — the fix is small and squarely within this PR's stated contract.

Security

Residual password= in the query string is embedded into the new quick-switch attributesvendor/wheels/events/onrequestend/debug.cfm:317

<a href="##" data-wdb-reload="#EncodeForHTMLAttribute(local.baseReloadURL & local.ei)#" ...>

local.baseReloadURL appends the raw query string (debug.cfm:20-21) and the strip loop at debug.cfm:24-30 removes only reload=<env|true> pairs — it never strips password=. The redirect that does strip reload,password,lock (onapplicationstart.cfc:474-483) only fires when redirectAfterReload is true, which defaults to false in development and testing (events/init/orm.cfm:26; auto-enabled only for production/maintenance at lines 52-54).

Reachable via the documented flow: request ?reload=development&password=pw (e.g. switching back into development). The app switches, no strip-redirect fires, the dev page renders the debug bar, and the quick-switch links carry data-wdb-reload="/&password=pw?reload=testing" — the live reload password in the page, contradicting the spec's assertion and the PR description. The same applies to an allowIPBasedDebugAccess admin switching into testing.

This exposure is new with this PR: before it, the quick-switch anchors rendered only when no password was set (nothing real to leak), and the plain reload anchor (debug.cfm:188) hides whenever a password is set — so these links are the first password-set-configuration consumers of baseReloadURL.

Note the same trace also shows a correctness byproduct: after the strip removes ?reload=development, the Contains "?" check at debug.cfm:31 misfires and the rebuilt target is malformed (/&password=pw?reload=testing), so the switch built from such a page would not even route correctly.

Proposed fix: filter the query string by key when building baseReloadURL, mirroring the existing redirect filter:

<cfif Len(cgi.query_string)>
	<cfset local.cleanPairs = []>
	<cfloop list="#cgi.query_string#" index="local.pair" delimiters="&">
		<cfif NOT ListFindNoCase("reload,password,lock", ListFirst(local.pair, "="))>
			<cfset ArrayAppend(local.cleanPairs, local.pair)>
		</cfif>
	</cfloop>
	<cfif ArrayLen(local.cleanPairs)>
		<cfset local.baseReloadURL &= "?" & ArrayToList(local.cleanPairs, "&")>
	</cfif>
</cfif>

This replaces the literal-value strip loop at lines 24-30 (which can then be deleted), fixes the malformed ?/& ordering, and keeps the spec's "never embedded" claim true. The key set reload,password,lock matches onapplicationstart.cfc:480.

Tests

Non-blocking observation: the spec's expect(output contains "spec-secret-pw-3060").toBeFalse() (DebugBarEnvQuickSwitchSpec.cfc) holds only because the harness's cgi.query_string is password-free — the CGI scope is read-only in a spec, as debugBarEncodingSpec.cfc:11-12 already documents for the same template. Worth a one-line comment in the spec acknowledging the vector it cannot exercise, so the assertion isn't read as covering it. Otherwise the spec is exemplary: red pre-fix on the exact defect, mirrors the established debugBarEncodingSpec.cfc harness (state save/restore, url.format handling), covers both gate dimensions plus the plain-reload-anchor contract, and avoids the cross-engine traps (no loops in finally, no catch-scope locals, hoisted state).

Everything that checked out

  • Gate correctness: $get("allowEnvironmentSwitchViaUrl") is guaranteed a real boolean at render time — the boot sentinel "must never escape $init()" and is resolved right after the settings includes (onapplicationstart.cfc:4,148-158,360-368).
  • URL composition: baseReloadURL always ends ?reload= / &reload= (debug.cfm:31-36), so the JS's target+'&password='+encodeURIComponent(pw) is well-formed on clean pages; prompt() cancel/empty are handled.
  • Output encoding: data-wdb-reload and the loop variable both safe (EncodeForHTMLAttribute, hardcoded env list).
  • Docs: debug-panel.mdx and environments-and-configuration.mdx accurately describe the new behavior and correctly drop the dead-link caveat; #3062's plain-reload contract correctly left untouched.
  • Changelog: proper changelog.d/debugbar-env-quickswitch.fixed.md fragment, no direct CHANGELOG.md edit.
  • Commit: fix(view): … conforms to commitlint (type, header < 100 chars), explains the why, DCO sign-off present.

Once the query-string filter lands (and ideally the spec comment), this is good to merge.

@bpamiri bpamiri enabled auto-merge (squash) June 12, 2026 18:26
…ebugbar-quickswitch

Resolved conflict in debug-panel.mdx: kept the PR's post-#3060 quick-switch link
documentation (links render only when reloadPassword AND allowEnvironmentSwitchViaUrl)
while preserving develop's #3062 reload-fails-closed Aside update.

Signed-off-by: Peter Amiri <petera@pai.com>
@bpamiri bpamiri dismissed wheels-bot[bot]’s stale review June 13, 2026 13:13

Stale: changes-requested on superseded SHA de8af56; current head 3648e31 passes all required checks, re-review hit
green-without-posting twice (#3049 approve flake). Dismissing so auto-merge can land.

@bpamiri bpamiri merged commit 5e1e828 into develop Jun 13, 2026
18 of 19 checks passed
@bpamiri bpamiri deleted the peter/issue-3060-debugbar-quickswitch branch June 13, 2026 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Debug bar renders environment quick-switch links only in the configuration where switching is impossible (dead links since #2082)

1 participant