Repository navigation
fix: stop rules from quietly taking the wrong branch - #202
Conversation
- A missing field now makes only its own comparison unknown, so `age < 18 || blacklisted` still matches a blacklisted applicant who sent no age (it used to fall through to the default branch). - `ordo validate` / `ordo lint` report a field the input schema does not declare (a typo like `confidense` used to pass and never match). - Input fields named `data` or `item` can be read (`data.x` used to miss the field). - `max(scores)` / `min(scores)` work on one array (they returned the array, so `max(scores) == 100` was always false). - Unknown string escapes keep their backslash, so regexes like "\d+" work. - `ordo trace ... | head` exits quietly instead of panicking. - Docs: contains_str, array elements as path segments, map_extract, no implicit string/number conversion.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
# Conflicts: # crates/ordo-core/src/context/store.rs # ordo-editor/apps/docs/en/guide/builtin-functions.md # ordo-editor/apps/docs/en/guide/expression-syntax.md # ordo-editor/apps/docs/en/guide/rule-structure.md # ordo-editor/apps/docs/en/platform/guard.md # ordo-editor/apps/docs/zh/guide/builtin-functions.md # ordo-editor/apps/docs/zh/guide/expression-syntax.md # ordo-editor/apps/docs/zh/guide/rule-structure.md # ordo-editor/apps/docs/zh/platform/guard.md
|
Dependency audit failed on RUSTSEC-2026-0349, a rustls 0.23.45 advisory published after main last ran CI. It isn't caused by this PR's changes, and main would fail the same check. b57b65b bumps rustls to 0.23.46 in Cargo.lock. Clippy and all workspace tests still pass with it. |
|
After the 0.23.46 bump, Dependency audit still fails on rustls 0.21.12 (RUSTSEC-2026-0346 and RUSTSEC-2026-0349). That version comes in through tonic 0.10's TLS stack (ordo-grpc / ordo-server), and main has exactly the same lock entry, so this PR doesn't cause it. The fixes only exist in rustls 0.23.46+, which means migrating to tonic/hyper 1.x. That's the same migration deny.toml already tracks for RUSTSEC-2026-0258. Neither advisory looks reachable here. 0346 only affects |
* chore: release 0.9.1 Bump crates and the npm wrapper to 0.9.1 to ship #202. * chore: upgrade tonic to 0.12 to drop rustls 0.21 tonic 0.10's TLS stack pulled in rustls 0.21.12, which has RUSTSEC-2026-0346 and RUSTSEC-2026-0349 and no fixed 0.21 release. tonic 0.12 uses rustls 0.23, so cargo deny passes again. - tonic 0.10 -> 0.12, prost 0.12 -> 0.13, tonic-build 0.10 -> 0.12; generated gRPC code regenerated. - UDS test client wraps UnixStream in hyper_util's TokioIo (hyper 1 IO traits).
Before: several ordinary rules returned a confident, wrong decision with no error. Checked against the released 0.9.0 CLI and server:
applicant.age < 18 || blacklisted == truewithblacklisted: trueand noagereturned APPROVED. The missing field made the whole condition false, so a blacklisted applicant went through.jev.intent.confidencetojev.intent.confidensepassedordo validateandordo lint. At run time the field is always missing, so every "not a refund" message falls into the refund path.dataoritemcouldn't be read:data.x == 1was always false.max(scores) == 100was always false, becausemax/mingiven one array returned the array itself."a\sb"turned intoasb, so regexes like"\d+"silently matched the wrong thing.ordo impact ... | headpanicked (exit 101).After:
||still matches, a false side of&&still fails, and anything still unknown stays false as before. This only runs after a missing-field error, so the normal path costs nothing extra.ordo validate/ordo lintreport each field the rules read that the schema does not declare ([intent] jev.intent.confidense is not in the input schema). Variables ($x) and external data ($data.x) are skipped. An object with no listed fields accepts any sub-path.data.xanditem.xread the input field when it exists (otherwise they behave as before).max(arr)/min(arr)return the largest/smallest element (nullfor an empty array).\n \t \r \\ \" \'are unchanged.max(arr)in built-in functions.How: Kleene-style evaluation in
RuleExecutoron the lenient missing-field path;undeclared_fields()inrule/input_schema.rs, called by the CLI validator; prefix fallback inContext::get; a sharedextreme()formin/max; one parser match arm;SIGPIPEreset in the CLImain.Tested on the merged tree:
cargo fmt --check,cargo clippy --all-targets --all-features -D warningsandcargo test --all-features --workspaceall pass, with new tests for each case. All four rule packs validate and all their tests pass. Earlier, 6000 concurrent execute calls against the built server all returned 200.Not covered: the binary
.ordoexecutor still treats a missing field as making the whole condition false.