mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
fix(verifier): a secure field's typed value never reaches the record
A folio login run wrote the account email and password in cleartext into llm-calls.jsonl, 166 times in one run, beside screenshots of the same screens. Three sites rendered it: the recent-action memory, the candidate list, and the trace. One helper now covers all three so a fourth cannot bypass it, and the driver still receives the real text. Android redacts every typed value because it cannot tell a secure field from any other. That asymmetry is deliberate and documented: safe by default on the target that cannot tell.
This commit is contained in:
1 parent
b1e95739ad
commit
38d328df90
12 files changed
+418
-16
No files matched your search
@@ -29,6 +29,12 @@ sanderling test --spec spec.ts --bundle-id com.example.app --duration 30m
|
||||
|
||||
The trace is written incrementally. An interrupted run is complete up to the step where it stopped.
|
||||
|
||||
## Typed values in the record
|
||||
|
||||
A run types into whatever the app puts on screen, login forms included, and the trace and the model call record are both shared. So a typed value is written down as `[redacted]` whenever the target may be a credential entry: the trace action, the recent-action memory the prompt carries, and the numbered candidate list all render it that way. The app still receives the real keystrokes; only the record is redacted, and the record still names the field that was typed into.
|
||||
|
||||
Which values that covers differs by platform, because the platforms differ in what they report. iOS and web state on every editable field whether it masks its input, so only the fields that do are redacted and the rest of the memory keeps its values. Android reports nothing: uiautomator's password attribute is dropped by the native tree mapper before the driver sees it, a password field is indistinguishable from a search box there, and so every typed value on Android is redacted.
|
||||
|
||||
## App state across runs
|
||||
|
||||
By default each run wipes app data before launch and starts cold. Pass `--clear-data=false` to resume whatever the previous run left behind (an account, cached responses, completed onboarding). See the [CLI reference](../cli/#sanderling-test).
|
||||
|
||||
@@ -78,7 +78,7 @@ s.ax.find({ testTag: "AccountCard", clickable: true })
|
||||
|
||||
Every key-value pair must match. A key means the same thing here as in the string form: `id`, `desc`, `idPrefix`, `descPrefix` and `tag` keep their matching rules, and every other key is an attribute name, with substring and boolean rules per attribute.
|
||||
|
||||
Known attribute names are typed; you get autocomplete on `testTag`, `text`, `content-desc`, the boolean states (`clickable`, `enabled`, `focused`, `checked`, `selected`), and the cross-platform aliases (`identifier`, `accessibilityIdentifier`, `accessibilityText`, `accessibilityLabel`, `label`, `resource-id`, `class`, `elementType`, `package`, `placeholderValue`, `hintText`). Boolean state attributes accept a native `true` / `false`. Other attribute keys still type-check as a string-valued fallback so raw driver attributes remain reachable.
|
||||
Known attribute names are typed; you get autocomplete on `testTag`, `text`, `content-desc`, the boolean states (`clickable`, `enabled`, `focused`, `checked`, `selected`, `secure`), and the cross-platform aliases (`identifier`, `accessibilityIdentifier`, `accessibilityText`, `accessibilityLabel`, `label`, `resource-id`, `class`, `elementType`, `package`, `placeholderValue`, `hintText`). Boolean state attributes accept a native `true` / `false`. Other attribute keys still type-check as a string-valued fallback so raw driver attributes remain reachable.
|
||||
|
||||
A key that names neither an accepted selector key nor an attribute some element on screen carries fails the run, naming the key and the accepted list. Such a key can never match, and an empty result is indistinguishable from a screen with no matching element: the generator declines to act, the runner waits out the step, and the run ends clean having explored nothing. The string form keeps its open kind space, since `<attr>:<value>` is the documented way to reach a raw driver attribute.
|
||||
|
||||
@@ -126,6 +126,7 @@ Fields available on every element returned by `find` / `findAll`:
|
||||
| `checked` | `boolean` | Checkbox or toggle state |
|
||||
| `focused` | `boolean` | Element has input focus |
|
||||
| `selected` | `boolean` | Selection state |
|
||||
| `secure` | `boolean \| null` | Field masks what is typed into it; `null` where the platform does not report it (Android never does) |
|
||||
| `bounds` | `{ left, top, right, bottom }` | Bounding box in device pixels |
|
||||
| `x` | `number` | Center X (derived from bounds) |
|
||||
| `y` | `number` | Center Y (derived from bounds) |
|
||||
|
||||
Reference in new issue
Block a user