Esta página ainda está em inglês. Ver em inglês.

Documentation

The Predicate List ADR 025 Named Was Not Quite Right

Accepted Decided 2026-09-18 security · scope · urls · snapshots

Context

ADR 025 decided that Janela bounds what a filter can ask for, and it was right about the problem: every one of Ransack’s 62 predicates was reachable on any attribute a dimension declared, a grouped query carried no LIMIT, and one filter accepted 5001 values. Building it (#8) proved all three still true and closed them.

Two things the ADR said turned out not to survive contact with the code. An accepted ADR is not rewritten, so this records what is true instead.

The list it named would have broken behaviour the project already documents. ADR 025 gave a categorical dimension eq, in and null, on the grounds that those are what a click produces (ADR 024). But not_null is already used, already tested in definition_query_test.rb, and has nothing to do with the hole being closed. Shipping the list as written would have refused a filter a host is entitled to use, loudly, in the name of security it does not buy.

The snapshot risk it described does not exist. ADR 025 warned that a stored snapshot taken under a predicate later disallowed “would raise when read”. It cannot. Snapshot#stored_result looks a pane up by key and returns the stored JSON; it never re-runs the query and never touches Ransack again. A snapshot’s filters are metadata Snapshot.take built with, not something a read validates against. The fear was reasonable and the code does not have it.

Decision

A categorical dimension allows eq, in, null and not_null. A time dimension allows those plus gteq, gt, lteq and lt. Reading a stored snapshot validates no predicates, because it runs no query.

Everything else ADR 025 decided stands: predicates are allowed by the kind of dimension rather than globally, anything outside the list raises Janela::BadRequest naming the attribute and what is allowed, and one ceiling of 1000 bounds both an unlimited grouped query and the number of values a single filter may carry (ADR 007).

The rule for adding to the list, so this does not become a place things accumulate: a predicate belongs there if a dashboard produces it, or if it is a boolean test of presence rather than a way to phrase a match. not_null qualifies on the second. cont, matches and start do not qualify on either, which is the whole point of the bound.

Consequences

The built list is one predicate wider than the decided one, and a host using not_null keeps working rather than being broken by a security fix. That is the right trade, and it is worth naming why it was close: a list written from first principles in an ADR, without running it against the tests, refused something real.

A regression test in snapshot_test.rb now pins the snapshot behaviour, so the failure mode ADR 025 imagined cannot appear later without a test noticing.

The general lesson, which is why this is an ADR rather than a commit message: an ADR that names a specific list is making a claim about the code, not only about the design, and that claim needs checking against the code before the ADR is accepted rather than while it is built.

All documentation This page in the repository