You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
GET /api/v1/data/<object>?filter={status:done(JSON 少个引号)—— findData 的解析容忍 try { JSON.parse } catch { /* keep as-is */ } 把原始字符串塞进 where,驱动层对字符串 where 静默忽略,返回未过滤的整页。
这是 #3948 那条原则(an unapplied filter must not look like a satisfied one)目前最恶性的破缺形态:#4134 是清零(少了),#4164 是丢一个谓词(多了一点),这里是整个过滤器蒸发(全都多了)。如果 filter 承担的是业务性收窄,多返回就是数据泄露的形状。
GET /data/:object/export 对同一个畸形输入早就是大声拒绝的 —— packages/rest/src/rest-server.ts:4730:
letfilter: any=undefined;if(typeofq.filter==='string'&&q.filter.length>0){try{filter=JSON.parse(q.filter);}catch{res.status(400).json({code: 'INVALID_REQUEST',error: 'filter must be JSON'});return;}}
Activity
fix(data): implicit field filters AND-merge with an explicit filter i…
os-zhuang commentedon Jul 30, 2026
补一条会显著改变这个 issue 工作量的发现:处方已经存在,就在同一个文件的兄弟路由里。
GET /data/:object/export对同一个畸形输入早就是大声拒绝的 ——packages/rest/src/rest-server.ts:4730:所以这不是一个「要定语义」的问题,而是同一个端点家族里两条路由对同一份畸形输入给出相反答案:
?filter={status:done(垃圾 JSON)GET /data/:object/export400 INVALID_REQUEST— "filter must be JSON" ✅GET /data/:object(list)200+ 未过滤整页 ❌而且方向是反直觉的:被硬化的是 export(一次导出,调用方看得见结果),没硬化的是 list(常被程序化消费,多返回最不容易被发现)。
实现建议就是把这段守卫搬到归一化层(
protocol.ts的 filter alias 链),让两条路由共用一个答案。错误码直接复用INVALID_REQUEST—— 它已在@objectstack/rest的 ledger 里注册,不需要新码。搬到 protocol 层而不是 list 路由,顺带覆盖POST /data/:object/query与 runtime dispatcher 那条路径。同一段代码里的小弟(同病,低危)
紧邻的
orderby解析(rest-server.ts:4745)在 JSON.parse 失败时静默undefined:排序被丢弃不改变结果集(仍是诚实的全集,只是顺序不是要的那个),所以危害远低于 filter;但如果调用方靠
orderby+top取「最新 N 条」,拿到的就是任意 N 条。修 filter 时顺手一起处理比较合算。Generated by Claude Code
fix(data): align malformed-filter rejections onto one wire code (#4181)
docs(api): the INVALID_FILTER catalog entry now describes what it cov…
fix(data): a filter the server cannot apply is rejected, not silently…
fix(rest): `GET /data/:object/export` honours a `search` term (#4230)
fix(data): sort / select / expand naming a missing field are rejected…
test(objectql): pin the two vacuous-filter carve-outs nothing held (#…
test(objectql): pin the two vacuous-filter carve-outs nothing held (#…
fix(spec,data): the five RPC query aliases resolve by one fold — spec…
fix(objectql,spec): filter folds to where on EVERY engine method; top…
fix(metadata-protocol): check query-parameter arity in findData's lis…
fix(rest): refuse a repeated ?filter= as a repetition, not as a malfo…