Skip to content

Commit

Permalink
fix: add credential runtime hint for graalvm compilation (#3200)
Browse files Browse the repository at this point in the history
fixes #2569

As reported in #2569, Graalvm is not detecting `Credentials` class used in `GcpProperties`, even though Credentials has been marked by @NestedConfigurationProperty.
**What is affected?**
- spring-cloud-gcp-core external configurations for `spring.cloud.gcp.credentials.encoded-key` and `spring.cloud.gcp.credentials.location`
- module specific configs for credentials. e.g. `spring.cloud.gcp.firestore.credentials.encoded-key`


**What is not affected?**
Setting `GOOGLE_APPLICATION_CREDENTIALS` goes through ADC and does not involve `spring.cloud.gcp.credentials.encoded-key` property, thus is not affected.


Changes in this pr:
- Added runtime hint for `Credentials` on `GcpProperties` to resolve this. This change also fixes for non-core module's autoconfiguration because each of them depends on GcpContextAutoConfiguration from core. e.g. [GcpFirestoreAutoConfiguration](https://github.com/GoogleCloudPlatform/spring-cloud-gcp/blob/29229f726218228a9ed424e35644a1305b25b545/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/firestore/GcpFirestoreAutoConfiguration.java#L58)
- Added test to starter firestore sample:
  - test: [FirestoreSampleAppNativeIntegrationTests.java](https://github.com/GoogleCloudPlatform/spring-cloud-gcp/pull/3200/files#diff-7b778ea3f2104c8b617c4424bdfd9ff78e2c806728d75935e907c32e1f67705f), this test only runs when "it.firestore.native=true", and does not run the CommandRunner in sample app.
  - test setup: 
    - pass encoded ci sa key to native test config for firestore samples. 
    - enable this new test for native test config
  • Loading branch information
zhumin8 committed Sep 13, 2024
1 parent 84e4fc4 commit f7fc095
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/NativeTests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ jobs:
components: 'native-image'
github-token: ${{ secrets.GITHUB_TOKEN }}
native-image-job-reports: 'true'
- name: Setup env for test
run: echo "SPRING_CLOUD_GCP_CI_NATIVE_SA_KEY_BASE64=$(echo -n $SA_KEY | base64 -w 0)" >> "$GITHUB_ENV"
env:
SA_KEY: ${{ secrets.SPRING_CLOUD_GCP_CI_NATIVE_SA_KEY }}
- name: Native Tests in Modules
id: intTest
env:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2024 Google LLC
*
* Licensed 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 com.google.cloud.spring.autoconfigure.core;

import com.google.cloud.spring.core.Credentials;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;

public class CredentialsRuntimeHints implements RuntimeHintsRegistrar {

@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints
.reflection()
.registerType(
TypeReference.of(Credentials.class),
hint ->
hint.withMembers(
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS,
MemberCategory.DECLARED_FIELDS));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
import com.google.cloud.spring.core.CredentialsSupplier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.context.annotation.ImportRuntimeHints;

/** Top-level auto-config settings. */
@ConfigurationProperties("spring.cloud.gcp")
@ImportRuntimeHints(CredentialsRuntimeHints.class)
public class GcpProperties implements CredentialsSupplier {

/** GCP project ID where services are running. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2024 Google LLC
*
* Licensed 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 com.google.cloud.spring.autoconfigure.core;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection;

import com.google.cloud.spring.core.Credentials;
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.RuntimeHints;

class CredentialsRuntimeHintsTest {
@Test
void registerCredentials() {
RuntimeHints runtimeHints = new RuntimeHints();
CredentialsRuntimeHints registrar = new CredentialsRuntimeHints();
registrar.registerHints(runtimeHints, null);
assertThat(runtimeHints).matches(reflection().onType(Credentials.class));
}
}
2 changes: 2 additions & 0 deletions spring-cloud-gcp-samples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
<it.secretmanager>true</it.secretmanager>
<it.datastore>true</it.datastore>
<it.firestore>true</it.firestore>
<it.firestore.native>true</it.firestore.native>
<it.kms>true</it.kms>
<it.bigquery>true</it.bigquery>
<it.metrics>true</it.metrics>
Expand All @@ -160,6 +161,7 @@
<spring.r2dbc.password>${env.DB_PASSWORD}</spring.r2dbc.password>
<spring.cloud.gcp.alloydb.instance-connection-uri>projects/spring-cloud-gcp-ci-native/locations/us-central1/clusters/testcluster/instances/testpostgres</spring.cloud.gcp.alloydb.instance-connection-uri>
<spring.cloud.gcp.alloydb.database-name>code_samples_test_db</spring.cloud.gcp.alloydb.database-name>
<spring.cloud.gcp.firestore.credentials.encoded-key>${env.SPRING_CLOUD_GCP_CI_NATIVE_SA_KEY_BASE64}</spring.cloud.gcp.firestore.credentials.encoded-key>
</systemPropertyVariables>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportRuntimeHints;

Expand All @@ -53,6 +54,7 @@ public static void main(String[] args) {
}

@Bean
@ConditionalOnProperty(name = "run.commandline.runner", havingValue = "true", matchIfMissing = true)
public CommandLineRunner commandLineRunner() {
return args -> {
writeDocumentFromMap();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2024 Google LLC
*
* Licensed 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 com.example;

import static org.junit.jupiter.api.Assertions.assertNotNull;

import com.google.cloud.spring.autoconfigure.firestore.GcpFirestoreProperties;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@EnabledIfSystemProperty(named = "it.firestore.native", matches = "true")
@ExtendWith(SpringExtension.class)
@TestPropertySource("classpath:application-test.properties")
@SpringBootTest(properties = "run.commandline.runner=off")
public class FirestoreSampleAppNativeIntegrationTests {

private final Logger logger =
LoggerFactory.getLogger(FirestoreSampleAppNativeIntegrationTests.class);
@Autowired private ApplicationContext applicationContext;

@Test
void credentialsPropertiesAreAccessibleTest() {
logger.info(
"This test is only needed for graalvm compilation test"
+ " to verify the encoded-key property is accessible."
+ " Turn on by it.firestore.native=true");
String encodedKeyFromAutoConfig =
applicationContext.getBean(GcpFirestoreProperties.class).getCredentials().getEncodedKey();
assertNotNull(encodedKeyFromAutoConfig);
}
}

0 comments on commit f7fc095

Please sign in to comment.