From 23f7c46a4e8a98d23aebb8a04983ef4adecd422f Mon Sep 17 00:00:00 2001 From: James Fredley Date: Fri, 17 Jul 2026 17:42:07 -0400 Subject: [PATCH 1/2] Characterize data-binding allowlist through public binding API Assisted-by: opencode:gpt-5.6-sol --- ...ultDatabindingWhitelistBehaviorSpec.groovy | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 grails-test-suite-web/src/test/groovy/org/grails/web/binding/DefaultDatabindingWhitelistBehaviorSpec.groovy diff --git a/grails-test-suite-web/src/test/groovy/org/grails/web/binding/DefaultDatabindingWhitelistBehaviorSpec.groovy b/grails-test-suite-web/src/test/groovy/org/grails/web/binding/DefaultDatabindingWhitelistBehaviorSpec.groovy new file mode 100644 index 00000000000..10b437ec313 --- /dev/null +++ b/grails-test-suite-web/src/test/groovy/org/grails/web/binding/DefaultDatabindingWhitelistBehaviorSpec.groovy @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.grails.web.binding + +import grails.artefact.Artefact +import grails.persistence.Entity +import grails.testing.web.controllers.ControllerUnitTest +import grails.validation.Validateable +import grails.web.databinding.DataBindingUtils +import spock.lang.Specification + +class DefaultDatabindingWhitelistBehaviorSpec extends Specification implements ControllerUnitTest { + + void 'domain binding includes simple and association properties but excludes special and unlisted properties'() { + given: + Date dateCreated = new Date() + Date lastUpdated = new Date() + Map source = [ + name: 'Ada', + address: [street: 'Analytical Engine Way'], + id: 99L, + version: 7L, + dateCreated: dateCreated, + lastUpdated: lastUpdated, + ignored: 'not bindable' + ] + + when: + WhitelistDomain domain = new WhitelistDomain() + DataBindingUtils.bindObjectToInstance(domain, source) + + then: + domain.name == 'Ada' + domain.address.street == 'Analytical Engine Way' + domain.id == null + domain.version == null + domain.dateCreated == null + domain.lastUpdated == null + domain.ignored == null + } + + void 'Validateable command binding includes declared special properties but excludes unlisted properties'() { + given: + Date dateCreated = new Date() + Date lastUpdated = new Date() + params.name = 'Grace' + params.'address.street' = 'Compiler Lane' + params.id = '99' + params.version = '7' + params.dateCreated = dateCreated + params.lastUpdated = lastUpdated + params.ignored = 'not bindable' + + when: + WhitelistCommand command = controller.bindCommand().command + + then: + command.name == 'Grace' + command.address.street == 'Compiler Lane' + command.id == 99L + command.version == 7L + command.dateCreated == dateCreated + command.lastUpdated == lastUpdated + command.ignored == null + } +} + +@Entity +class WhitelistDomain { + String name + WhitelistAddress address = new WhitelistAddress() + Long id + Long version + Date dateCreated + Date lastUpdated + Object ignored + + static hasOne = [address: WhitelistAddress] +} + +@Entity +class WhitelistAddress { + String street +} + +@Artefact('Controller') +class WhitelistBehaviorController { + def bindCommand(WhitelistCommand command) { + [command: command] + } +} + +class WhitelistCommand implements Validateable { + String name + WhitelistAddress address = new WhitelistAddress() + Long id + Long version + Date dateCreated + Date lastUpdated + Object ignored +} From 1c34ff07919855f0c2886d61bb9b68a95bccc463 Mon Sep 17 00:00:00 2001 From: Walter Duque de Estrada Date: Sat, 25 Jul 2026 22:50:22 -0500 Subject: [PATCH 2/2] Address review feedback on databinding whitelist characterization spec - Rename the Object-typed field to untypedProperty and reword test names: the property is excluded because it is raw Object-typed (DefaultASTDatabindingHelper#shouldFieldBeInWhiteList), not because it is generically "unlisted". - Drop the misleading hasOne association, which adds nothing to the contract under test since the typed address field alone puts it in the generated whitelist, and the mapping is incomplete (no belongsTo back-reference on WhitelistAddress). - Trim the domain test to its non-duplicated assertions and cross-reference DefaultASTDatabindingHelperDomainClassSpecialPropertiesSpec, which already pins id/version/dateCreated/lastUpdated exclusion for domain classes. Co-Authored-By: Claude Sonnet 5 --- ...ultDatabindingWhitelistBehaviorSpec.groovy | 35 ++++++------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/grails-test-suite-web/src/test/groovy/org/grails/web/binding/DefaultDatabindingWhitelistBehaviorSpec.groovy b/grails-test-suite-web/src/test/groovy/org/grails/web/binding/DefaultDatabindingWhitelistBehaviorSpec.groovy index 10b437ec313..83bf8f5687e 100644 --- a/grails-test-suite-web/src/test/groovy/org/grails/web/binding/DefaultDatabindingWhitelistBehaviorSpec.groovy +++ b/grails-test-suite-web/src/test/groovy/org/grails/web/binding/DefaultDatabindingWhitelistBehaviorSpec.groovy @@ -27,18 +27,15 @@ import spock.lang.Specification class DefaultDatabindingWhitelistBehaviorSpec extends Specification implements ControllerUnitTest { - void 'domain binding includes simple and association properties but excludes special and unlisted properties'() { + // Domain exclusion of id/version/dateCreated/lastUpdated is already pinned by + // DefaultASTDatabindingHelperDomainClassSpecialPropertiesSpec (GRAILS-11173, #15681); this spec + // only covers the Object/def-typed exclusion and nested association binding. + void 'domain binding includes simple and association properties but excludes Object/def-typed properties'() { given: - Date dateCreated = new Date() - Date lastUpdated = new Date() Map source = [ name: 'Ada', address: [street: 'Analytical Engine Way'], - id: 99L, - version: 7L, - dateCreated: dateCreated, - lastUpdated: lastUpdated, - ignored: 'not bindable' + untypedProperty: 'not bindable' ] when: @@ -48,14 +45,10 @@ class DefaultDatabindingWhitelistBehaviorSpec extends Specification implements C then: domain.name == 'Ada' domain.address.street == 'Analytical Engine Way' - domain.id == null - domain.version == null - domain.dateCreated == null - domain.lastUpdated == null - domain.ignored == null + domain.untypedProperty == null } - void 'Validateable command binding includes declared special properties but excludes unlisted properties'() { + void 'Validateable command binding includes declared special properties but excludes Object/def-typed properties'() { given: Date dateCreated = new Date() Date lastUpdated = new Date() @@ -65,7 +58,7 @@ class DefaultDatabindingWhitelistBehaviorSpec extends Specification implements C params.version = '7' params.dateCreated = dateCreated params.lastUpdated = lastUpdated - params.ignored = 'not bindable' + params.untypedProperty = 'not bindable' when: WhitelistCommand command = controller.bindCommand().command @@ -77,7 +70,7 @@ class DefaultDatabindingWhitelistBehaviorSpec extends Specification implements C command.version == 7L command.dateCreated == dateCreated command.lastUpdated == lastUpdated - command.ignored == null + command.untypedProperty == null } } @@ -85,13 +78,7 @@ class DefaultDatabindingWhitelistBehaviorSpec extends Specification implements C class WhitelistDomain { String name WhitelistAddress address = new WhitelistAddress() - Long id - Long version - Date dateCreated - Date lastUpdated - Object ignored - - static hasOne = [address: WhitelistAddress] + Object untypedProperty } @Entity @@ -113,5 +100,5 @@ class WhitelistCommand implements Validateable { Long version Date dateCreated Date lastUpdated - Object ignored + Object untypedProperty }