|
| 1 | +--- |
| 2 | +'@objectstack/rest': minor |
| 3 | +--- |
| 4 | + |
| 5 | +fix(rest)!: a public form's lookup picker searches and sorts by the first display field the caller may query, so a picker whose first display field is masked for its caller serves its rows instead of answering 403 (#21062) |
| 6 | + |
| 7 | +Clause-②: yes (narrowing) |
| 8 | + |
| 9 | +<!-- adr-0087: not-required (no-migration-prescription) a change of which display field the public lookup picker (`GET /forms/:slug/lookup/:field`) searches and sorts by: the first display field the caller may query, by the security service's answer, where it used to be the first display field. No authorable key, spelling, export or stored shape moves: `@objectstack/rest` exports nothing new and nothing less, `FormFieldPublicPickerSchema` keeps parsing every value it parsed, and no stored row is read or rewritten. A picker's `displayFields` keep their meaning as the projected fields. The other categories are closed on facts: the package publishes (not `unpublished`); no ADR-0087 id covers which field a picker keys on (not `already-registered`); and the change is route behaviour, not a declaration (not `runtime-interface-only` / `type-surface-only`). --> |
| 10 | + |
| 11 | +**BREAKING**: this widens what the public lookup picker serves and narrows it in one composition. The narrowing: with a security service that lacks `ISecurityService.getQueryableFields`, or that answers no answer for the object, the picker passes over every display field whose declaration carries a `maskingRule`, for every caller, including a caller the rule is lifted for. So its search and order move to the next display field that declares no rule, and a picker whose display fields all declare a rule is refused `403 PERMISSION_DENIED` without the engine being asked, where it used to be served. The security service this repository ships implements the method, so a deployment using it is not narrowed. It ships as `minor` under the launch-window convention for accept-set narrowings. No export or published type changes. |
| 12 | + |
| 13 | +**What changed.** The public lookup picker (`GET /forms/:slug/lookup/:field`) |
| 14 | +matches the visitor's search and orders its rows by one key. That key used to |
| 15 | +be the first entry of `publicPicker.displayFields`. It is now the first entry |
| 16 | +the caller may query on, as the security service answers it |
| 17 | +(`ISecurityService.getQueryableFields`). A field whose masking rule applies to |
| 18 | +a caller is served to that caller masked, and the engine refuses to search or |
| 19 | +sort on it with `403 PERMISSION_DENIED`. A picker whose first display field |
| 20 | +declares such a rule therefore answered `403` to every caller the rule applies |
| 21 | +to, on every request. It now serves its rows, sorted and searched on the next |
| 22 | +display field the caller may query. The masked field is still returned in each |
| 23 | +row, masked, as before. |
| 24 | + |
| 25 | +**When no display field is queryable** for the caller, the picker answers |
| 26 | +`403 PERMISSION_DENIED` with the engine's refusal for those fields, without |
| 27 | +running a query. |
| 28 | + |
| 29 | +**Unchanged.** A picker with no masked display field, and a caller the masking |
| 30 | +rule is lifted for, keep the first display field as the key, with the security |
| 31 | +service this repository ships. A deployment with no security service keeps the |
| 32 | +first display field. |
| 33 | + |
| 34 | +**What to do.** Nothing. To choose the field a picker searches when its first |
| 35 | +display field is masked for some of its callers, list a field those callers may |
| 36 | +query among `displayFields`: the first such entry is the one searched and |
| 37 | +sorted on. A picker whose only display fields are masked for its callers is |
| 38 | +refused, so give it one they may query. |
| 39 | + |
| 40 | +**What to do after upgrading, if your security service predates `getQueryableFields`.** |
| 41 | +Implement `getQueryableFields` on it: it answers which fields a caller may filter, |
| 42 | +sort, group or aggregate by, and the picker then keys on the first display field |
| 43 | +in that answer. Until it does, give each picker at least one display field that |
| 44 | +declares no `maskingRule`, or the picker is refused for every caller. |
0 commit comments