fix(events): detect RustCFML under reportAsLucee impersonation (v0.507+)#3327
fix(events): detect RustCFML under reportAsLucee impersonation (v0.507+)#3327bpamiri wants to merge 1 commit into
Conversation
RustCFML v0.507.0 defaults reportAsLucee to true: server.coldfusion.productName
now reports "Lucee" (with Lucee's productVersion) and the real engine version
moves to server.lucee.version behind a Lucee-major prefix ("7.0.519.0" means
RustCFML 0.519.0). $detectEngine keyed solely on productName == "RustCFML", so
v0.507+ fell through to the Lucee branch, instantiated LuceeAdapter, and every
RustCFMLAdapter override went dead (isRustCFML() false, supportsImageInfo()
true, the Lucee-only psq=false cfquery attribute applied, version gate
satisfied by the impersonated string).
Match the marker upstream documents as stable identity — their own
isRustCFML() BIF keys on it — server.lucee.versionName == "RustCFML", ordered
before the Lucee branch, deriving the version by dropping the impersonated
major segment. Pre-v0.507 scopes still hit the productName branch first; real
Lucee carries a different versionName and falls through unchanged.
Verified live against the v0.519.0 binary: detection selects RustCFML again
and the EngineCapabilitiesSpec guard fires (spec passes) with zero collateral
spec regressions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Peter Amiri <petera@pai.com>
There was a problem hiding this comment.
Wheels Bot — Reviewer
TL;DR — This PR fixes engine detection so RustCFML v0.507+ running in its default reportAsLucee mode is no longer misclassified as Lucee (which had turned RustCFMLAdapter into dead code). It adds a server.lucee.versionName == "RustCFML" detection branch ordered before the Lucee branch, plus a positive spec for the impersonation scope and a negative-path pin on the real-Lucee fixture. The change is small, correct, cross-engine safe, and well-tested. Verdict: approve.
Correctness
The new branch at vendor/wheels/events/onapplicationstart.cfc:562-569 is ordered correctly — after the productName == "RustCFML" branch (pre-v0.507 path) and before the generic Lucee branch, so both RustCFML variants resolve before real Lucee can claim the scope.
Version derivation is right: ListRest("7.0.519.0", ".") yields "0.519.0", dropping only the impersonated Lucee major. This produces the same 0.MINOR.PATCH shape the pre-v0.507 productName branch produces (the existing spec at line 202-203 uses "0.417.0"), and RustCFMLAdapter(serverVersion) consumes that format unchanged. Using ListRest (drop-first) rather than a hardcoded 7. strip also keeps a future 8.-prefix working.
Guards are safe: the StructKeyExists checks on lucee and versionName mean a Lucee scope lacking versionName cleanly falls through to the plain Lucee branch (no null deref).
Cross-engine
No concerns. ListRest, StructKeyExists, and string == are portable across Lucee 5/6/7, Adobe 2018-2025, and BoxLang. No closures, no struct member-function calls, no reserved-scope shadowing, no application-scope function members — none of the cross-engine invariants in CLAUDE.md are touched.
Tests
Good coverage. The new spec (engineAdapterSpec.cfc:206) exercises the exact v0.519.0 impersonating scope shape and asserts both serverName and the stripped serverVersion. The negative path is pinned by extending the existing Lucee fixture with a realistic versionName ("Gelert", line ~225), proving real Lucee still falls through. Uses BDD wheels.WheelsTest correctly.
Docs
- Changelog fragment present and correctly named:
changelog.d/rustcfml-reportaslucee-detection.fixed.md(.fixed type, no direct CHANGELOG.md edit). - The
$detectEngine()docblock is updated to explain the v0.507+ reportAsLucee behavior. - Nit (non-blocking): the PR carries docs + enhancement labels, but this is a fix. Worth a maintainer relabel for triage accuracy — not a code issue.
Commits
fix(events): detect RustCFML under reportAsLucee impersonation (v0.507+) — valid conventional-commit type/scope, header well under 100 chars, sign-off present (Signed-off-by: Peter Amiri) matching the author. The body explains the why (which markers are stable, why ordering matters), not just the what.
|
server.lucee.versionname tells you its RustCFML The purpose of the change was to make sure the various ways that frameworks check for Lucee could find it in order to go down the lucee compatibility path but if they looks at the actual lucee versionname they could see it was RustCFML |
Summary
RustCFML v0.507.0 turned on
reportAsLuceeby default:server.coldfusion.productNamenow reports"Lucee"(with Lucee's classicproductVersion), and the real engine version moves toserver.lucee.versionbehind a Lucee-major prefix (7.0.519.0= RustCFML 0.519.0). The upstream commit explicitly names Wheels' engine gate as the motivation and documentsserver.lucee.versionName == "RustCFML"as the stable identity marker (their ownisRustCFML()BIF keys on it).$detectEngine()identified RustCFML solely byproductName == "RustCFML", so on v0.507+ it fell through to the Lucee branch and selectedLuceeAdapter— makingRustCFMLAdapterdead code. Concrete misroutes observed:isRustCFML()→ false:EngineCapabilitiesSpecasserted JVM class-loading on a JVM-less engine (the ladder failure that surfaced this)supportsImageInfo()→ true (Base default):$imageTag()proceeds intocfimage action="info"paths that error on RustCFMLdatabaseAdapters/Base.cfcserverName == "Lucee"branch → the Lucee-onlypsq=falsecfquery attribute applied to every query$checkMinimumVersionsatisfied by the impersonated version string instead of the accept-any-version RustCFML branchFix
Add a detection branch matching
server.lucee.versionName == "RustCFML"ordered before the Lucee branch, derivingserverVersionby dropping the impersonated major segment (ListRest, so a future8.-prefix keeps working). Pre-v0.507 scopes still hit the originalproductNamebranch first; real Lucee carries a differentversionName(e.g.Gelert) and falls through unchanged.Tests
versionNameto pin the negative path.EngineCapabilitiesSpecguard fires and passes, and a bad-spec set diff vs the unfixed run shows zero collateral regressions. (It also exposed thatmigrationSpec's multi-column-index "fix" on the ladder was an artifact of thepsq=falsemisroute — it reverts to its known-failing baseline state with correct detection.)Upstream context: RustCFML/RustCFML#283, RustCFML/RustCFML#284, RustCFML/RustCFML#285 filed today for the three genuine v0.482–v0.511 engine regressions found in the same investigation.
🤖 Generated with Claude Code