Skip to content

Warn once on GString-interpolated GORM HQL queries#15968

Open
jamesfredley wants to merge 1 commit into
8.0.xfrom
feat/gorm-query-safety-warnings
Open

Warn once on GString-interpolated GORM HQL queries#15968
jamesfredley wants to merge 1 commit into
8.0.xfrom
feat/gorm-query-safety-warnings

Conversation

@jamesfredley

Copy link
Copy Markdown
Contributor

Description

What was found

Problem Impact
Developers may interpolate values into HQL via GString Injection risk / unsafe query patterns
Google Doc 2.6 listed GORM query safety as not covered No current open PR
Hard failures would break existing apps Prefer warn-first starter

What changed

Area Change
Utility GormQuerySafetyWarnings detects GString queries with values
Behavior Logs a one-time warning per operation/query shape
Hibernate path Wire into Hibernate GORM static query APIs
Docs Securing against attacks + executeQuery/find refs + upgrade note
Tests Warning once / no-warn for plain strings

Out of scope / follow-up

Topic Status
Compile-time AST ban of unsafe GString HQL Follow-up
Throwing by default Not this PR (warn only)
Full internal query audit Follow-up

Related MD topics

Source Topic
Google Doc 2.6 GORM query safety audit

Contributor Checklist

Issue and Scope

  • Background explains query-safety gap.
  • Warn-only, non-breaking starter.
  • Single focused change.
  • Targets 8.0.x.

Code Quality

  • Unit tests for warning helper.
  • Focused datamapping tests intended for CI.
  • No mass reformatting.
  • AI starting point labeled.

Licensing and Attribution

  • Apache License 2.0.
  • Contributor rights confirmed.
  • ai-generated-starting-point label applied.

Documentation

  • Security and ref docs updated.
  • PR description explains what changed and why.

Assisted-by: Sisyphus:xai/grok-4.5 [gpt-coding]

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]

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 GormQuerySafetyWarnings to detect GString HQL 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.

Comment on lines +30 to +49
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)
Comment on lines +484 to 487
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

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.47619% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.6216%. Comparing base (06f5567) to head (8fdd94d).

Files with missing lines Patch % Lines
...atastore/gorm/query/GormQuerySafetyWarnings.groovy 90.4762% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@                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                
Files with missing lines Coverage Δ
...atastore/gorm/query/GormQuerySafetyWarnings.groovy 90.4762% <90.4762%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@testlens-app

testlens-app Bot commented Jul 11, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: 8fdd94d
▶️ Tests: 29051 executed
⚪️ Checks: 60/60 completed


Learn more about TestLens at testlens.app.

@borinquenkid borinquenkid self-requested a review July 11, 2026 00:31

@borinquenkid borinquenkid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants