fix(sidecar): state the fact on a field named by its hint alone

collectTextFields matched on class only, so a node the go side calls editable
off its hintText was left unstated and its typed value redacted.
This commit is contained in:
pj committed 2026-08-19 18:51:12 +05:30
1 parent 528b2c7756
commit 71219d71da
2 files changed
+29 -2

No files matched your search

@@ -1017,12 +1017,18 @@ internal fun secureFactsFromXml(xml: String): Map<String, Boolean> {
private fun secureFactKey(id: String, bounds: String) = "$id@$bounds"
// A text field is what the Go side calls editable off the same two attributes
// (internal/hierarchy): stating the fact on a narrower set would leave fields
// the rest of the system treats as typeable answering for nothing.
private fun collectTextFields(
node: com.fasterxml.jackson.databind.JsonNode,
into: MutableList<com.fasterxml.jackson.databind.node.ObjectNode>,
) {
if (node is com.fasterxml.jackson.databind.node.ObjectNode &&
nodeAttribute(node, "class").contains("EditText")
(
nodeAttribute(node, "class").contains("EditText") ||
nodeAttribute(node, "hintText").isNotEmpty()
)
) {
into.add(node)
}
@@ -1256,7 +1262,11 @@ class MaestroDriverBackend(private val serial: String?) : DriverBackend {
// can tell the runner the gesture reached nothing.
private fun requireOnScreen(x: Int, y: Int) {
val cached = extent
if (cached != null && !offScreen(x, y, cached.first, cached.second)) return
if (cached != null &&
!offScreen(x, y, cached.first, cached.second)
) {
return
}
val info = driver.deviceInfo()
val fresh = Pair(info.widthPixels, info.heightPixels)
extent = fresh
@@ -79,6 +79,23 @@ class SecureFactsTest {
)
}
// The Go side calls a node editable off its class or its hint, and a field
// it will happily type into has to be a field this can speak for.
@Test fun aFieldNamedByItsHintAloneIsStatedToo() {
val hinted = """
{"attributes":{"bounds":"[0,0,1080,2340]"},"children":[
{"attributes":{"resource-id":"Search","class":"android.view.View","hintText":"Search","bounds":"[10,10,200,50]"},"children":[]}
]}
"""
val xml = """<?xml version='1.0' encoding='UTF-8'?>
<hierarchy rotation="0">
<node index="0" resource-id="Search" class="android.view.View" password="false" bounds="[10,10,200,50]" />
</hierarchy>
"""
assertEquals(false, secureOf(withSecureFacts(hinted) { xml }, "Search"))
}
// Unstated means "may be a credential" downstream. Every way this can fail
// has to land there rather than on a false "not secure".
@Test fun aFactThatCannotBeReadIsLeftUnstated() {