You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by jd...@apache.org on 2026/07/29 03:51:19 UTC

(grails-core) branch 8.0.x updated (3c5b1b9045 -> f1fbe86956)

This is an automated email from the ASF dual-hosted git repository.

jdaugherty pushed a change to branch 8.0.x
in repository https://gitbox.apache.org/repos/asf/grails-core.git


    from 3c5b1b9045 Merge pull request #16053 from codeconsole/locale-autonym-titlecase
     add 4aa9a0b51d Add compile-time check for GORM query strings flattened from GString
     add 46c4ba2486 Track GString origin through variable aliasing, not just literal coercion
     add cceff551fb Extend query safety check with branch-sensitivity fix and two new warnings
     add d3e1ea8485 Add protectSqlInjectionAttacks opt-out for the global query safety check
     add 6e0a8bafe0 Adopt @RestoreSystemProperties in GlobalGormQuerySafetyASTTransformationSpec
     add cb3a5753c7 Detect inline .toString()/cast flattening at the GORM query call site
     new f1fbe86956 Merge pull request #15971 from apache/feat/gorm-query-safety-ast-check

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../common/compiler/GroovyTransformOrder.groovy    |   8 +-
 ...=> GlobalGormQuerySafetyASTTransformation.java} |  40 +-
 .../transform/GormQuerySafetyTransformer.java      | 690 +++++++++++++++++++++
 ...org.codehaus.groovy.transform.ASTTransformation |   1 +
 ...obalGormQuerySafetyASTTransformationSpec.groovy |  78 +++
 .../GormQuerySafetyTransformerSpec.groovy          | 543 ++++++++++++++++
 .../en/guide/security/securingAgainstAttacks.adoc  |  56 ++
 .../src/en/guide/upgrading/upgrading80x.adoc       |  21 +
 8 files changed, 1421 insertions(+), 16 deletions(-)
 copy grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/query/transform/{GlobalDetachedCriteriaASTTransformation.java => GlobalGormQuerySafetyASTTransformation.java} (50%)
 create mode 100644 grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/query/transform/GormQuerySafetyTransformer.java
 create mode 100644 grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/query/transform/GlobalGormQuerySafetyASTTransformationSpec.groovy
 create mode 100644 grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/query/transform/GormQuerySafetyTransformerSpec.groovy


(grails-core) 01/01: Merge pull request #15971 from apache/feat/gorm-query-safety-ast-check

Posted by jd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jdaugherty pushed a commit to branch 8.0.x
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit f1fbe869561aa539269a3c0bc67d1368b5fd533c
Merge: 3c5b1b9045 cb3a5753c7
Author: James Daugherty <jd...@jdresources.net>
AuthorDate: Tue Jul 28 23:51:14 2026 -0400

    Merge pull request #15971 from apache/feat/gorm-query-safety-ast-check
    
    Compile-time check for GORM query strings flattened from GString (alternative to #15968)

 .../common/compiler/GroovyTransformOrder.groovy    |   8 +-
 .../GlobalGormQuerySafetyASTTransformation.java    |  76 +++
 .../transform/GormQuerySafetyTransformer.java      | 690 +++++++++++++++++++++
 ...org.codehaus.groovy.transform.ASTTransformation |   1 +
 ...obalGormQuerySafetyASTTransformationSpec.groovy |  78 +++
 .../GormQuerySafetyTransformerSpec.groovy          | 543 ++++++++++++++++
 .../en/guide/security/securingAgainstAttacks.adoc  |  56 ++
 .../src/en/guide/upgrading/upgrading80x.adoc       |  21 +
 8 files changed, 1472 insertions(+), 1 deletion(-)

diff --cc grails-doc/src/en/guide/upgrading/upgrading80x.adoc
index 2bb8748368,32210c30cf..40f77ca298
--- a/grails-doc/src/en/guide/upgrading/upgrading80x.adoc
+++ b/grails-doc/src/en/guide/upgrading/upgrading80x.adoc
@@@ -1528,235 -1513,25 +1528,256 @@@ Both hooks may be used on the same plug
  
  **Bean-definition overriding edge case.** Grails defaults `spring.main.allow-bean-definition-overriding` to `true`, and under that default nothing changes: an application bean (from the application class, `resources.groovy` or `resources.xml`) that uses the same name as a plugin bean still replaces the plugin's bean. However, because plugin beans now register earlier and application beans register in a separate, later step, an application that explicitly sets `spring.main.allow-bean-def [...]
  
+ 
+ ==== 34. Compile-Time GORM Query Safety Check
+ 
+ Grails 8 adds a compile-time check that can **break existing builds**: passing a GORM query method (`find`, `findAll`, `executeQuery`, `executeUpdate`, and the Neo4j Cypher equivalents) a `String`-typed variable that was built from an interpolated `GString` is now a compile error, not just a discouraged pattern.
+ 
+ [source,groovy]
+ ----
+ def vulnerable() {
+     String query = "from Book as b where b.title = ${params.title}"  // fails to compile
+     def books = Book.executeQuery(query)
+ }
+ ----
+ 
+ This is flagged because passing the `GString` *directly* to `executeQuery` is safe — GORM binds the interpolated value as a query parameter — but assigning it to a `String`-typed local first causes Groovy to coerce it to a plain `String` at that point, silently discarding the safe binding; the interpolated value is then embedded as raw, unescaped query text. See <<sqlInjection,SQL injection>> for the full explanation and examples.
+ 
+ If your application has this pattern, fix it by keeping the query a `GString` all the way to the call, or by using named/positional parameters instead. For a call site that has been reviewed and is genuinely safe, add `@SuppressWarnings("GormUnsafeQueryString")` to the enclosing method rather than restructuring the code.
+ 
+ This check runs automatically wherever `grails-datamapping-core` is on the compile classpath, with no opt-in configuration required. If it produces a false positive with no workaround, the whole check can be disabled by setting the `protectSqlInjectionAttacks` system property to `false` (it defaults to `true`) — this is a last-resort, build-wide kill switch, not a substitute for the per-call-site `@SuppressWarnings` above.
+ 
+ The same check also emits (non-build-breaking) **compile-time warnings**, not errors, for two related but lower-confidence patterns: a `String`-typed field assigned an interpolated `GString` and later read through `this.field` in a query call, and query text built with `+` concatenation from a non-constant value with no `GString` involved. Neither of these fails the build, but both are worth reviewing — see <<sqlInjection,SQL injection>> for examples of both.
+ 
  **Most applications and plugins need no action.** Behavior only changes where a plugin bean and a conditional Boot bean competed for the same name or type — the plugin bean now wins, which is almost always the intended outcome.
 +
 +==== 34. Extension API Compatibility Notes
 +
 +Most Grails applications do not call the Grails extension APIs listed below directly.
 +They can affect applications, plugins, or build logic that import these public classes or override these public extension points directly.
 +Unsupported internal implementation details are not covered here.
 +
 +[cols="1,2,2", options="header"]
 +|===
 +| Module
 +| Changed or removed API
 +| Migration note
 +
 +| `grails-codecs`
 +| `org.grails.plugins.codecs.CodecsGrailsPlugin` no longer overrides `doWithSpring()`
 +| Do not depend on that plugin override to contribute codec bean definitions.
 +Custom plugins should register their own beans from their own `doWithSpring()` implementation.
 +
 +| `grails-controllers`
 +| `ControllersAutoConfiguration.dispatcherServletRegistration(...)` now returns Spring Boot 4's `org.springframework.boot.webmvc.autoconfigure.DispatcherServletRegistrationBean`
 +| Update direct imports, overrides, and binary integrations that referenced the Spring Boot 3 return type.
 +
 +| `grails-converters`
 +| `grails.web.JSONBuilder`
 +| Use Groovy's `groovy.json.JsonBuilder` or `groovy.json.StreamingJsonBuilder` for JSON builder code.
 +
 +| `grails-core`
 +| `GrailsApplicationPostProcessor`, `ProfilingGrailsApplicationPostProcessor`, and `DefaultGrailsPluginManager` plugin-discovery wiring changed
 +| Update custom bootstrapping code or subclasses that construct `GrailsApplicationPostProcessor` or `DefaultGrailsPluginManager` directly to pass the plugin-discovery dependency.
 +`ProfilingGrailsApplicationPostProcessor` keeps its `GrailsApplicationLifeCycle`, `ApplicationContext`, and `Class...` constructor shape, but the application context must expose the `grailsPluginDiscovery` bean.
 +This was introduced during the Grails 7.1 plugin-loading changes and remains required in Grails 8.
 +
 +| `grails-core`
 +| `grails.plugins.PluginFilter`, `IncludingPluginFilter`, `ExcludingPluginFilter`, `NoOpPluginFilter`, and related filter types
 +| Import replacement types from the `org.apache.grails.core.plugins.filters` package, such as `PluginFilter`, `IncludingPluginFilter`, `ExcludingPluginFilter`, and `NoOpPluginFilter`.
 +
 +| `grails-core`
 +| Legacy mixin transform APIs such as `grails.util.Mixin`, `MixinTargetAware`, and `MixinTransformation`
 +| Replace legacy mixin usage with Groovy traits, extension methods, or explicit composition.
 +
 +| `grails-core`
 +| `grails.validation.ConstraintsEvaluator`
 +| Use `org.grails.datastore.gorm.validation.constraints.eval.ConstraintsEvaluator`.
 +
 +| `grails-core`
 +| `BinaryGrailsPluginDescriptor`, `CorePluginFinder`, and `BinaryGrailsPlugin.getBinaryDescriptor()`
 +| Use the current plugin-discovery APIs and `BinaryGrailsPlugin.getPluginDescriptor()`.
 +
 +| `grails-domain-class`
 +| `ConstraintEvaluatorAdapter` and `GrailsDomainClassAutoConfiguration.constraintsEvaluator(...)`
 +| Code that imported the auto-configuration method should use the current `validateableConstraintsEvaluator(...)` bean path and the datastore constraint evaluator APIs.
 +
 +| `grails-fields`
 +| `BeanPropertyAccessor.getBeanClass()`, its setter, `PropertyPathAccessor.getBeanClass()`, `FormFieldsTagLib.input(...)`, and direct `render*` helper methods
 +| Use the `beanType` property exposed by the accessors.
 +Custom field renderers should go through the documented `f:field`, `f:widget`, and `f:displayWidget` tags and templates instead of calling private render helpers directly.
 +
 +| `grails-gradle-plugins`
 +| `ApplicationContextCommandTask`, `ApplicationContextScriptTask`, `ProfileCompilerTask`, and `GrailsRunTask` are abstract; `GrailsGradlePlugin.createBuildPropertiesTask(...)` no longer returns a task value; several `IntegrationTestGradlePlugin` constants were removed
 +| Register these task types through Gradle task registration and update custom plugins that subclass `GrailsGradlePlugin` or read integration-test constants to use Gradle source sets, configurations, and the current test-phase APIs.
 +
 +| `grails-shell-cli`
 +| `AetherGrapeEngine` and `AetherGrapeEngineFactory`
 +| Use `MavenResolverGrapeEngine` and `MavenResolverGrapeEngineFactory` if you extend the legacy shell dependency resolver.
 +
 +| `grails-shell-cli`
 +| JLine 2 `complete(...)` signatures
 +| Implement the JLine 3 `org.jline.reader.Completer` contract, `complete(LineReader, ParsedLine, List<Candidate>)`.
 +
 +| `grails-spring`
 +| `GrailsApplicationContext.onRefresh()`
 +| Custom context subclasses should use supported Spring lifecycle extension points instead of overriding this removed hook.
 +Spring theme APIs removed from the same area are covered in section 10.
 +|===
 +
 +==== 35. CLI Commands Move to Companion `-cli` Artifacts
 +
 +Grails commands (`ApplicationCommand` implementations) no longer ship inside runtime plugin
 +artifacts. Each command-bearing module publishes a companion artifact under its own coordinate with
 +a `-cli` suffix, and commands are registered in a dedicated `META-INF/grails-cli.factories` file
 +instead of `META-INF/grails.factories`.
 +
 +**Package rename.** The command contract moved from `grails.dev.commands.*` (in `grails-core`) to
 +`org.apache.grails.core.cli.*` (in the new `org.apache.grails:grails-core-cli` artifact). Update
 +imports in your `grails-app/commands` classes:
 +
 +[source,groovy]
 +----
 +// Grails 7
 +import grails.dev.commands.ApplicationCommand
 +import grails.dev.commands.ExecutionContext
 +
 +// Grails 8
 +import org.apache.grails.core.cli.ApplicationCommand
 +import org.apache.grails.core.cli.ExecutionContext
 +----
 +
 +**New `grailsCli` configuration.** The Grails Gradle plugin registers a `grailsCli` configuration
 +that is compile-visible for `grails-app/commands` sources and on the command-runner classpath, but
 +never on `runtimeClasspath` — so commands and their CLI-only dependencies are excluded from
 +`bootRun`, `bootJar`, and `bootWar`.
 +
 +**CLI dependencies are discovered automatically.** The plugin adds
 +`org.apache.grails:grails-core-cli` (the command contract) and `org.apache.grails:grails-console`
 +(the command runner) to `grailsCli`, and walks the application's resolved dependency graph —
 +including transitive plugins — for jars carrying the `Grails-Cli-Artifact` manifest attribute,
 +adding each advertised companion automatically. The per-command Gradle tasks (e.g. `dbmUpdate`)
 +are registered from those companions as well, so no `buildscript` classpath entry is required. In
 +most applications, upgrading therefore requires **no build changes** to keep plugin commands
 +working:
 +
 +[source,groovy]
 +.build.gradle
 +----
 +dependencies {
 +    // the dbm-* commands are discovered automatically: the plugin jar advertises
 +    // org.apache.grails:grails-data-hibernate7-dbmigration-cli, which is added to grailsCli
 +    implementation 'org.apache.grails:grails-data-hibernate7-dbmigration'
 +}
 +----
 +
 +The `console` and `shell` tasks also draw from the provisioned cli tier, so the
 +`console "org.apache.grails:grails-console"` dependency that earlier Grails versions generated in
 +`build.gradle` is no longer needed and can be removed (the `console` configuration itself remains
 +for additional console-only dependencies).
 +
 +Disable the discovery with `grails { cliAutoProvision = false }` and declare the cli tier
 +explicitly when full control over the command classpath is preferred:
 +
 +[source,groovy]
 +.build.gradle
 +----
 +grails {
 +    cliAutoProvision = false
 +}
 +
 +dependencies {
 +    implementation 'org.apache.grails:grails-data-hibernate7-dbmigration'
 +    grailsCli 'org.apache.grails:grails-core-cli'
 +    grailsCli 'org.apache.grails:grails-console'
 +    grailsCli 'org.apache.grails:grails-data-hibernate7-dbmigration-cli'
 +}
 +----
 +
 +The renamed framework command packages are:
 +
 +|===
 +|Grails 7 | Grails 8 (`-cli` artifact)
 +
 +|`grails.dev.commands.*` (grails-core)
 +|`org.apache.grails.core.cli.*` (grails-core-cli)
 +
 +|`org.grails.web.mapping.reporting.UrlMappingsReportCommand`
 +|`org.apache.grails.web.mapping.cli.UrlMappingsReportCommand` (grails-web-url-mappings-cli)
 +
 +|`scaffolding.*` commands
 +|`org.apache.grails.scaffolding.cli.*` (grails-scaffolding-cli)
 +
 +|`grails.plugin.hibernate.commands.SchemaExportCommand`
 +|`org.apache.grails.data.hibernate5.cli` / `...hibernate7.cli` (grails-data-hibernate5-cli / -7-cli)
 +
 +|`org.grails.plugins.databasemigration.command.*`
 +|`org.apache.grails.data.hibernate5.dbmigration.cli` / `...hibernate7.dbmigration.cli`
 +
 +|`grails.plugin.springsecurity` s2 commands
 +|`org.apache.grails.security.cli.*` (grails-spring-security-cli)
 +|===
 +
 +**Third-party plugins must be rebuilt against Grails 8 for their commands to be available.**
 +Apply the new `org.apache.grails.gradle.grails-plugin-cli` Gradle plugin, move command sources from
 +`grails-app/commands` to `src/cli/groovy`, and update the contract imports — recompiling then
 +regenerates the `grails-cli.factories` registration automatically and the companion `-cli`
 +artifact is published alongside the plugin (see
 +xref:commandLine#creatingCustomCommands[Creating Custom Commands] for the complete workflow).
 +Hand-authored command registrations must move from
 +`src/main/resources/META-INF/grails.factories` to `.../grails-cli.factories`. A Grails 7 command
 +plugin dropped onto a Grails 8 application unchanged will not have its commands discovered.
 +
 +**What this change means for upgrading an application.** Plugin re-releases are *not* a
 +prerequisite for upgrading the application itself — the impact of the CLI split is bounded as
 +follows:
 +
 +* *Plugins that ship no commands* are entirely unaffected by this change.
 +* *Command-bearing plugins that have not yet been rebuilt for Grails 8* keep their runtime
 +  functionality — controllers, services, taglibs, and other artefacts continue to work exactly as
 +  before, because the runtime plugin jar never depended on the command contract. Only the plugin's
 +  *commands* are unavailable: their registrations in the legacy `grails.factories` location are
 +  ignored (the clean break above), so they disappear from the command list rather than fail. The
 +  commands return once the plugin publishes a Grails 8 release with a companion `-cli` artifact.
 +* *The application's own commands* in `grails-app/commands` need only the import rename shown
 +  above; the build wiring is automatic.
 +
 +NOTE: The statements above are about the CLI split specifically. Independently of it, Grails 8
 +removes APIs that were deprecated in Grails 7 — a Grails 7 plugin that avoided those deprecations
 +generally continues to work on Grails 8 unchanged, while one that relied on them (or on other
 +Grails 8 changes such as Spring Boot 4) needs an update for that reason.
 +
 +==== 36. jQuery Webjar Upgraded to 4.0.0
 +
 +The jQuery webjar managed by the `grails-bom` (`org.webjars.npm:jquery`) moves from 3.7.1 to 4.0.0.
 +jQuery 4 is a major release: it drops Internet Explorer and other legacy browsers and removes long-deprecated utilities such as `jQuery.trim`, `jQuery.type`, `jQuery.isArray`, `jQuery.isFunction`, `jQuery.proxy`, and `jQuery.isWindow`.
 +See the https://jquery.com/upgrade-guide/4.0/[jQuery 4.0 Upgrade Guide] for the complete list of changes.
 +
 +Because the version is managed by the BOM, any application that references the jQuery webjar without an explicit version picks up 4.0.0 automatically once it adopts the Grails 8 BOM.
 +This includes the generated create-app welcome page, whose assets have been verified against 4.0.0.
 +
 +If your application's own JavaScript relies on the removed APIs, migrate those call sites.
 +If you are not ready to migrate, pin the previous version in your gradle build:
 +
 +[source,properties]
 +.gradle.properties
 +----
 +jquery.version=3.7.1
 +----
 +
 +==== 37. spring-security-ui Rewritten on Bootstrap 5
 +
 +The `spring-security-ui` plugin's screens are rewritten on Bootstrap 5 with no bundled styling of their own.
 +The plugin no longer ships or depends on jQuery UI, jquery-form, jGrowl, DataTables, bgiframe or the bundled jdMenu/positionBy plugins, and every plugin stylesheet and image has been removed — dialogs are Bootstrap modals, tabs are nav-tabs, notifications render through `g:flashMessages`, and the autocomplete search uses a native `datalist`.
 +jQuery (4.x) and Bootstrap are expected from the host application, as provided by the create-app layout.
 +
 +Plugin pages now render through the host application's own layout — configured with `grails.plugin.springsecurity.ui.gsp.parentLayout` (default `main`) — inheriting its theme, including Bootstrap dark mode, locale selector and branding.
 +The security menu and login state are contributed to the host navbar through `nav` and `navActions` content blocks, which the create-app layout renders with `<g:pageProperty name="page.nav"/>` and `<g:pageProperty name="page.navActions"/>`; a custom layout that wants the menu in its navbar renders the same page properties.
 +
 +If you upgrade an application that customized the plugin:
 +
 +* Views previously copied into the application with `s2ui-override` reference removed stylesheets and rely on the old table-based markup of the `s2ui` field-row tags, which now emit Bootstrap form groups; regenerate or update those copies.
 +* CSS written against the old `s2ui_*` and `jd_menu` classes no longer has anything to match; restyle against Bootstrap classes.
 +* Applications that used the plugin's transitive webjars (jQuery UI, jGrowl, DataTables, jquery-form) must now declare those dependencies themselves.
 +* The `grails.plugin.springsecurity.ui.Constants` class and the `spring-security-ui-register.js` and `spring-security-ui-*` stylesheet assets have been removed.
 +* `LogoutController` now declares a computed `allowedMethods` restricting its action to POST while `logout.postOnly` is active (the default), making the restriction visible to tooling such as the create-app welcome page.