Reject invalid databinding indexes#15804
Conversation
Report binding errors for malformed or negative indexed binding paths before array, collection, or domain association access. Apply the same guard to the web data binder association path and cover the core and web binding behavior with regressions. Assisted-by: Hephaestus:openai/gpt-5.5
There was a problem hiding this comment.
Pull request overview
This PR hardens Grails data binding by rejecting malformed or negative indexed binding paths (e.g., list[-1], list[bad]) before attempting array/collection/domain-association access, converting what previously could throw or apply Groovy negative-index semantics into binding errors captured by the binding error listener flow.
Changes:
- Add
parseIndexedPropertyIndex(...)to centralize index parsing/validation and emit binding errors on malformed/negative indexes. - Use the new index parsing in both core (
SimpleDataBinder) and web (GrailsWebDataBinder) indexed-binding paths to prevent invalid index access. - Add regression tests covering negative and malformed indexes for Lists, arrays, and domain association collection binding.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| grails-web-databinding/src/main/groovy/grails/web/databinding/GrailsWebDataBinder.groovy | Validates indexed binding paths for domain association collections before attempting indexed updates. |
| grails-databinding-core/src/main/groovy/grails/databinding/SimpleDataBinder.groovy | Introduces shared index parsing/validation and uses it for array/collection indexed binding. |
| grails-databinding-core/src/test/groovy/grails/databinding/CollectionBindingSpec.groovy | Adds regression coverage ensuring negative/malformed indexes are rejected for List and array binding. |
| grails-test-suite-persistence/src/test/groovy/grails/web/databinding/GrailsWebDataBinderSpec.groovy | Adds web-layer regression coverage for rejecting invalid indexed domain association binding to Lists. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## 8.0.x #15804 +/- ##
==================================================
+ Coverage 49.4679% 49.4870% +0.0191%
- Complexity 16684 16704 +20
==================================================
Files 1947 1947
Lines 92468 92489 +21
Branches 16150 16157 +7
==================================================
+ Hits 45742 45770 +28
+ Misses 39620 39612 -8
- Partials 7106 7107 +1
🚀 New features to boost your workflow:
|
|
Didn't this work in prior Grails versions? The negative index could be used to bind to the end of an array. I agree this is probably a good change, but it needs discussed. Also, this PR is not adhering to our PR policy - we need explanations for why this is necessary, etc. There are several checklists when creating a PR that are not completed by this PR. |
|
Thanks. I updated the PR body to follow the summary policy more explicitly: it now separates "What was found", "What was fixed", and "Verification". Yes, negative collection indexes likely worked before via Groovy list semantics. The concern is that indexed binding paths come from request parameters, so |
|
Maintenance pass complete. Copilot generated no inline review comments and there are no review threads to resolve. I reviewed the Codecov patch-coverage note for GrailsWebDataBinder: the behavior is covered by the persistence-suite GrailsWebDataBinderSpec tests rather than local grails-web-databinding module coverage, and I reran the focused CollectionBindingSpec plus GrailsWebDataBinderSpec successfully. The maintainer question about negative-index compatibility remains open as a behavior discussion, not resolved. |
Document that indexed binding to arrays, collections, and many-ended associations requires non-negative integer indexes, that invalid indexes are reported as binding errors without mutating the target, and that map keys are unaffected. Align the Set binding example comment with the integer index requirement. Assisted-by: opencode:gpt-5.5
|
Pre-release review pass (2026-07-02, dual-reviewer: GPT-5.5 oracle + Codex CLI): NEEDS-IMPROVEMENT, now addressed. Findings: the user-facing behavior change (negative/malformed indexes rejected as binding errors instead of Groovy negative-index semantics or exceptions) was undocumented in the data binding guide (high, docs-only) - fixed in |
🚨 TestLens detected 1 failed test 🚨Here is what you can do:
Test SummaryCI - Groovy Joint Validation Build / build_grails > :grails-test-examples-scaffolding:integrationTest
🏷️ Commit: e2e5674 Test FailuresUserControllerSpec > User list (:grails-test-examples-scaffolding:integrationTest in CI - Groovy Joint Validation Build / build_grails)Muted TestsSelect tests to mute in this pull request:
Reuse successful test results:
Click the checkbox to trigger a rerun:
Learn more about TestLens at testlens.app. |
|
@jamesfredley please fix the formatting on this summary |
The Problem
Indexed data-binding paths accepted the index text before consistently validating it, which produced two bad outcomes:
books[-1].titlewere interpreted with Groovy's negative-collection-indexing semantics and mutated the wrong element. Since the binding path normally comes from request parameters or another external source, treatingitems[-1]as "mutate the last existing item" lets an externally-supplied index select a different element than the literal index says.books[bad].titlecould throw during binding instead of being reported as a normal binding error.Oracle review found the same unsafe path in
GrailsWebDataBinderfor data-source-aware domain-association binding, so this covers both the core binder and the web binder override.The Fix
Treat negative and malformed indexed paths as invalid binding input.
Files
SimpleDataBinder.groovy- shared non-negative integer index parser + error path.GrailsWebDataBinder.groovy- same guard on the domain-association path.CollectionBindingSpec.groovy,GrailsWebDataBinderSpec.groovy- regressions for List/array and web-domain association binding.dataBinding.adoc- documents the non-negative integer index requirement and the map-key exception.Testing
:grails-databinding-core:test --tests "grails.databinding.CollectionBindingSpec",:grails-web-databinding:check, and:grails-test-suite-persistence:test --tests "...GrailsWebDataBinderSpec"pass. Aggregate report: 13,654 tests, 0 failures.Open discussion
Whether apps relied on the prior Groovy negative-index behavior is a product/behavior question left open for maintainers; this branch treats negative indexes as invalid input.