[grid] Fix DefaultSlotMatcher matching requests differentiated only by undeclared automationName - #17898
[grid] Fix DefaultSlotMatcher matching requests differentiated only by undeclared automationName#17898diemol wants to merge 1 commit into
Conversation
…ionName extensionCapabilitiesMatch() only inspected extension capability names the stereotype declared, so a stereotype declaring none at all (e.g. a plain browser node) matched any requested automationName by default. This let a native-automation request differentiated solely by automationName match an unrelated browser-only node. Add automationNameMatch(), gated on the stereotype showing some existing Appium-awareness (a relevant extension capability, or a non-W3C-compliant platformVersion), so relay-node matching keeps working while a stereotype with no such awareness no longer matches on an undeclared automationName. Fixes #17845 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PR Summary by QodoGrid: Prevent slot matching on undeclared appium:automationName
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Code Review by Qodo
1. Appium-aware heuristic too broad
|
| if (!automationNameMatch(stereotype, capabilities)) { | ||
| return false; | ||
| } | ||
|
|
There was a problem hiding this comment.
1. matches missing javadoc 📘 Rule violation ✧ Quality
The public method matches(Capabilities, Capabilities) was modified but still has no Javadoc block documenting parameters/return value, which violates the requirement for complete Javadoc on changed public API methods. This reduces API clarity and makes behavior changes harder to audit and consume correctly.
Agent Prompt
## Issue description
A changed public method (`matches`) lacks a Javadoc block, but the checklist requires complete Javadoc (including `@param` and `@return`) for all changed public API methods.
## Issue Context
`DefaultSlotMatcher.matches(...)` is `public` and was modified in this PR (new `automationNameMatch(...)` gating). The method should be documented so callers and maintainers can understand matching semantics and expectations for the two `Capabilities` parameters.
## Fix Focus Areas
- java/src/org/openqa/selenium/grid/data/DefaultSlotMatcher.java[59-103]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| name -> | ||
| name.contains("platformVersion") | ||
| || (name.contains(":") | ||
| && !name.toLowerCase().contains("options") | ||
| && EXTENSION_CAPABILITIES_PREFIXES.stream().noneMatch(name::contains))); |
There was a problem hiding this comment.
2. Appium-aware heuristic too broad 🐞 Bug ≡ Correctness
automationNameMatch() treats any non-vendor extension capability key (any : capability not in goog:/moz:/ms:/safari:/se: and not *options*) as “Appium-aware”, so a non-Appium node advertising an unrelated custom extension capability will bypass the automationName gate. This can re-allow Appium requests differentiated only by automationName to be considered eligible for the wrong slot whenever other non-extension checks match.
Agent Prompt
### Issue description
`automationNameMatch()` currently infers “Appium-aware” from *any* non-vendor extension capability key. This is overly broad and causes unrelated custom extension caps to disable the new automationName protection.
### Issue Context
- `EXTENSION_CAPABILITIES_PREFIXES` only lists vendor browser prefixes (`goog:`, `moz:`, `ms:`, `safari:`, `se:`). Many non-Appium nodes can still advertise other extension keys (e.g. `prefixed:cheese` in tests), which should not imply Appium support.
- The intent of this PR is to treat *Appium signals* as Appium-awareness (e.g., `appium:*` keys and the existing non-W3C `platformVersion` signal), not arbitrary extension caps.
### Fix Focus Areas
- java/src/org/openqa/selenium/grid/data/DefaultSlotMatcher.java[48-55]
- java/src/org/openqa/selenium/grid/data/DefaultSlotMatcher.java[195-213]
- java/test/org/openqa/selenium/grid/data/DefaultSlotMatcherTest.java[526-571]
### Suggested change
Constrain `stereotypeIsAppiumAware` to true only when the stereotype declares Appium-specific keys (e.g. `name.startsWith("appium:")`) and/or the existing `platformVersion` signal (preferably exact key match rather than substring). This preserves relay flexibility while preventing unrelated extension caps from bypassing the new automationName gate.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| return capabilities.getCapabilityNames().stream() | ||
| .noneMatch(name -> name.contains("automationName")); | ||
| } |
There was a problem hiding this comment.
3. Automationname key substring match 🐞 Bug ≡ Correctness
automationNameMatch() rejects requests by checking whether any requested capability key contains the substring automationName, which can accidentally match unrelated custom keys. This can cause false negatives (unexpected no-match) for non-Appium requests that happen to use a different capability name containing that substring.
Agent Prompt
### Issue description
The request-side check uses `name.contains("automationName")`, which is overly broad and can treat unrelated custom capability names as an Appium automationName request.
### Issue Context
This method is intended to special-case Appium’s `automationName` differentiation. Substring matching risks blocking unrelated capabilities like `my:automationNameOverride`.
### Fix Focus Areas
- java/src/org/openqa/selenium/grid/data/DefaultSlotMatcher.java[211-213]
### Suggested change
Replace substring matching with exact key matching against the intended keys (e.g. `"appium:automationName"` and possibly legacy/non-namespaced `"automationName"` if supported), using `equals` (or `equalsIgnoreCase` only if the project treats capability names case-insensitively elsewhere).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
🔗 Related Issues
Fixes #17845
💥 What does this PR do?
DefaultSlotMatcher.extensionCapabilitiesMatch()only inspects extension capability names the stereotype declares. If a stereotype declares no extension (:-namespaced) capabilities at all — e.g. a plain browser node — the check short-circuits totrueregardless of what the request asks for. This lets a request differentiated solely by an identity extension capability (appium:automationName) match a completely unrelated, non-Appium node, as long asbrowserNameis absent from the request andplatformNameresolves to the samePlatformfamily.This adds a new
automationNameMatch()check, called alongside the existing extension-capability checks inmatches(). It only rejects a match when the stereotype shows no existing Appium-awareness at all (no relevant extension capability, and no non-W3C-compliantplatformVersion, which the code already treats as an Appium signal) while the request specifies anautomationName. Stereotypes that already show some Appium-awareness (e.g. relay nodes advertisingappium:platformVersionbut omittingautomationName) are left untouched, preserving existing relay-node matching behavior.🔧 Implementation Notes
The issue proposed an unconditional bidirectional
automationNamecheck. That approach was tested against the existing test suite and found to break two passing relay-node tests, where Appium relay nodes intentionally omitautomationNamewhile still being valid targets for varied automation sessions. The fix here gates the check on stereotype Appium-awareness instead, using the sameplatformVersionsignal the codebase already relies on elsewhere in this file, so relay-node flexibility is preserved while the reported misroute is closed.🤖 AI assistance
automationNameMatch()and the two regression tests, drafted from the issue's analysis and root-caused/iterated against the existing test suite to avoid regressing relay-node matching.💡 Additional Considerations
None.
🔄 Types of changes