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

jamesfredley pushed a commit to branch fix/forge-analytics-security
in repository https://gitbox.apache.org/repos/asf/grails-core.git


The following commit(s) were added to refs/heads/fix/forge-analytics-security 
by this push:
     new f3cd7001af Scope no-op transaction factory to datasource-disabled tests
f3cd7001af is described below

commit f3cd7001afcb1b952f3abd56220f71460042f687
Author: James Fredley <[email protected]>
AuthorDate: Fri Jul 17 19:51:55 2026 -0400

    Scope no-op transaction factory to datasource-disabled tests
    
    Assisted-by: opencode:gpt-5.6-sol
---
 .../AnalyticsControllerSecuritySpec.groovy         | 52 ++++++++++++++++++++++
 .../NoOpTransactionOperationsFactory.groovy        |  1 +
 2 files changed, 53 insertions(+)

diff --git 
a/grails-forge/grails-forge-analytics-postgres/src/test/groovy/org/grails/forge/analytics/postgres/AnalyticsControllerSecuritySpec.groovy
 
b/grails-forge/grails-forge-analytics-postgres/src/test/groovy/org/grails/forge/analytics/postgres/AnalyticsControllerSecuritySpec.groovy
index 4f4a55d262..9309780b93 100644
--- 
a/grails-forge/grails-forge-analytics-postgres/src/test/groovy/org/grails/forge/analytics/postgres/AnalyticsControllerSecuritySpec.groovy
+++ 
b/grails-forge/grails-forge-analytics-postgres/src/test/groovy/org/grails/forge/analytics/postgres/AnalyticsControllerSecuritySpec.groovy
@@ -54,6 +54,7 @@ import jakarta.inject.Inject
 class AnalyticsControllerSecuritySpec extends Specification {
 
     @Inject @Client('/') HttpClient client
+    @Inject @Client('/analytics') HttpClient analyticsClient
     @Inject ApplicationRepository applicationRepository
     @Inject FeatureRepository featureRepository
     @Inject JdbcOperations jdbcOperations
@@ -90,6 +91,48 @@ class AnalyticsControllerSecuritySpec extends Specification {
         0 * applicationRepository._
     }
 
+    void 'report generation data accepts valid bearer token'() {
+        given:
+        Generated generated = new Generated(
+                ApplicationType.WEB,
+                GormImpl.HIBERNATE5,
+                ServletImpl.TOMCAT,
+                DevelopmentReloading.DEVTOOLS,
+                JdkVersion.DEFAULT_OPTION
+        )
+        generated.setSelectedFeatures([new 
SelectedFeature('google-cloud-function')])
+        applicationRepository.save(_) >> { arguments -> arguments[0] }
+
+        when:
+        def response = 
client.toBlocking().exchange(HttpRequest.POST('/analytics/report', 
generated).bearerAuth(validToken()), String)
+
+        then:
+        response.status == HttpStatus.ACCEPTED
+        1 * featureRepository.saveAll(_)
+        0 * jdbcOperations._
+    }
+
+    void 'report generation data accepts valid bearer token with analytics 
client'() {
+        given:
+        Generated generated = new Generated(
+                ApplicationType.WEB,
+                GormImpl.HIBERNATE5,
+                ServletImpl.TOMCAT,
+                DevelopmentReloading.DEVTOOLS,
+                JdkVersion.DEFAULT_OPTION
+        )
+        generated.setSelectedFeatures([new 
SelectedFeature('google-cloud-function')])
+        applicationRepository.save(_) >> { arguments -> arguments[0] }
+
+        when:
+        def response = 
analyticsClient.toBlocking().exchange(HttpRequest.POST('report', 
generated).bearerAuth(validToken()), String)
+
+        then:
+        response.status == HttpStatus.ACCEPTED
+        1 * featureRepository.saveAll(_)
+        0 * jdbcOperations._
+    }
+
     void 'report generation data rejects bearer token with wrong audience'() {
         given:
         Generated generated = new Generated(
@@ -161,6 +204,15 @@ class AnalyticsControllerSecuritySpec extends 
Specification {
         ]).orElseThrow()
     }
 
+    @NonNull
+    private String validToken() {
+        tokenGenerator.generateToken([
+                sub: '1234567890',
+                iss: 'forge-test',
+                aud: 'forge-analytics'
+        ]).orElseThrow()
+    }
+
     @NonNull
     private String wrongCallerToken() {
         tokenGenerator.generateToken([
diff --git 
a/grails-forge/grails-forge-analytics-postgres/src/test/groovy/org/grails/forge/analytics/postgres/NoOpTransactionOperationsFactory.groovy
 
b/grails-forge/grails-forge-analytics-postgres/src/test/groovy/org/grails/forge/analytics/postgres/NoOpTransactionOperationsFactory.groovy
index a94187ae2d..59919658a1 100644
--- 
a/grails-forge/grails-forge-analytics-postgres/src/test/groovy/org/grails/forge/analytics/postgres/NoOpTransactionOperationsFactory.groovy
+++ 
b/grails-forge/grails-forge-analytics-postgres/src/test/groovy/org/grails/forge/analytics/postgres/NoOpTransactionOperationsFactory.groovy
@@ -33,6 +33,7 @@ import java.util.Optional
 
 @Factory
 @Requires(env = 'test')
+@Requires(property = 'datasources.default.enabled', value = 'false')
 class NoOpTransactionOperationsFactory {
 
     @Singleton

Reply via email to