Warn once on GString-interpolated GORM HQL queries#15968
Conversation
Add GormQuerySafetyWarnings and call it from Hibernate query paths. Recommend named parameters in docs. Does not throw; warns with query shape. Assisted-by: Sisyphus:xai/grok-4.5 [gpt-coding]
There was a problem hiding this comment.
Pull request overview
This PR adds a warn-first safety mechanism for GORM HQL queries expressed as GString (interpolated) to encourage migration toward explicit named parameters, while preserving the existing behavior of binding interpolated values as query parameters. It wires the warning into Hibernate GORM static HQL query execution paths and updates the Grails 8 docs to explain the new warning and recommended patterns.
Changes:
- Introduces
GormQuerySafetyWarningsto detectGStringHQL queries and warn once per operation/query shape. - Hooks the warning into Hibernate GORM static HQL query preparation/execution.
- Updates reference/security/upgrade docs with safer query examples and migration guidance.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| grails-doc/src/en/ref/Domain Classes/find.adoc | Adds guidance to prefer named params; documents the new GString warning behavior. |
| grails-doc/src/en/ref/Domain Classes/executeQuery.adoc | Adds guidance to prefer named params; documents the new GString warning behavior. |
| grails-doc/src/en/guide/upgrading/upgrading80x.adoc | Adds an upgrade note explaining the new warning and recommended query patterns. |
| grails-doc/src/en/guide/security/securingAgainstAttacks.adoc | Refreshes SQL/HQL injection guidance and references the new warning behavior. |
| grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/query/GormQuerySafetyWarningsSpec.groovy | Adds unit tests for “warn once” and for avoiding logging interpolated values. |
| grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/query/GormQuerySafetyWarnings.groovy | Implements one-time warning logic and query-shape redaction for GString queries. |
| grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy | Wires the warning helper into Hibernate static HQL query preparation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private static final String GSTRING_VALUE_PLACEHOLDER = '${...}' | ||
| private static final Set<String> WARNED_GSTRING_QUERY_SHAPES = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>()) | ||
|
|
||
| private GormQuerySafetyWarnings() { | ||
| } | ||
|
|
||
| static boolean warnIfGStringQuery(Logger logger, CharSequence query, String operation) { | ||
| if (!(query instanceof GString) || ((GString) query).values.length == 0) { | ||
| return false | ||
| } | ||
|
|
||
| String queryShape = buildQueryShape((GString) query) | ||
| if (!logger.warnEnabled) { | ||
| return false | ||
| } | ||
|
|
||
| String warningKey = "${operation}\n${queryShape}" | ||
| if (!WARNED_GSTRING_QUERY_SHAPES.add(warningKey)) { | ||
| return false | ||
| } |
| return false | ||
| } | ||
|
|
||
| logger.warn('GString-interpolated HQL passed to [{}]. GORM binds interpolated values as query parameters, but explicit named parameters are recommended for query safety and readability. Query shape: [{}]', operation, queryShape) |
| String operation = isNative ? 'native SQL query' : (isUpdate ? 'executeUpdate' : 'find/executeQuery') | ||
| GormQuerySafetyWarnings.warnIfGStringQuery(log, hql, operation) | ||
| Map<String, Object> coercedParams = namedParams?.collectEntries { k, v -> [k.toString(), v] } ?: [:] | ||
| def ctx = HqlQueryContext.prepare(persistentEntity, hql, coercedParams, positionalParams, querySettings, hints, isNative, isUpdate) |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## 8.0.x #15968 +/- ##
==================================================
+ Coverage 49.6039% 49.6216% +0.0177%
- Complexity 16956 16973 +17
==================================================
Files 1999 2000 +1
Lines 93791 93812 +21
Branches 16421 16425 +4
==================================================
+ Hits 46524 46551 +27
+ Misses 40100 40094 -6
Partials 7167 7167
🚀 New features to boost your workflow:
|
✅ All tests passed ✅🏷️ Commit: 8fdd94d Learn more about TestLens at testlens.app. |
borinquenkid
left a comment
There was a problem hiding this comment.
This solution only works on H7, it needs to work also H5 and neo4j. I am building a compile time solution but if you want to expand the scope to all the other datastores that is a choice.
Description
What was found
What changed
GormQuerySafetyWarningsdetects GString queries with valuesOut of scope / follow-up
Related MD topics
Contributor Checklist
Issue and Scope
8.0.x.Code Quality
Licensing and Attribution
ai-generated-starting-pointlabel applied.Documentation
Assisted-by: Sisyphus:xai/grok-4.5 [gpt-coding]