Skip to content

Commit 551413a

Browse files
committed
Implement CredentialsProvider support
Fixes #600
1 parent 9a28c4c commit 551413a

File tree

7 files changed

+142
-6
lines changed

7 files changed

+142
-6
lines changed

deployment/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
<groupId>io.quarkus</groupId>
3333
<artifactId>quarkus-caffeine-deployment</artifactId>
3434
</dependency>
35+
<dependency>
36+
<groupId>io.quarkus</groupId>
37+
<artifactId>quarkus-credentials-deployment</artifactId>
38+
</dependency>
3539
<dependency>
3640
<groupId>io.quarkus</groupId>
3741
<artifactId>quarkus-smallrye-graphql-client-deployment</artifactId>

docs/modules/ROOT/pages/includes/attributes.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
:quarkus-version: 3.8.2
1+
:quarkus-version: 3.9.1
22
:quarkus-github-app-version: 2.4.2
33

44
:github-api-javadoc-root-url: https://github-api.kohsuke.org/apidocs/org/kohsuke/github

docs/modules/ROOT/pages/includes/quarkus-github-app.adoc

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,48 @@ endif::add-copy-button-to-env-var[]
102102
|
103103

104104

105+
a| [[quarkus-github-app_quarkus-github-app-credentials-provider]]`link:#quarkus-github-app_quarkus-github-app-credentials-provider[quarkus.github-app.credentials-provider]`
106+
107+
108+
[.description]
109+
--
110+
The credentials provider name.
111+
112+
This is the name of the "keyring" containing the GitHub App secrets.
113+
114+
Key names are defined in `Credentials`.
115+
116+
ifdef::add-copy-button-to-env-var[]
117+
Environment variable: env_var_with_copy_button:+++QUARKUS_GITHUB_APP_CREDENTIALS_PROVIDER+++[]
118+
endif::add-copy-button-to-env-var[]
119+
ifndef::add-copy-button-to-env-var[]
120+
Environment variable: `+++QUARKUS_GITHUB_APP_CREDENTIALS_PROVIDER+++`
121+
endif::add-copy-button-to-env-var[]
122+
--|string
123+
|
124+
125+
126+
a| [[quarkus-github-app_quarkus-github-app-credentials-provider-name]]`link:#quarkus-github-app_quarkus-github-app-credentials-provider-name[quarkus.github-app.credentials-provider-name]`
127+
128+
129+
[.description]
130+
--
131+
The credentials provider bean name.
132+
133+
This is a bean name (as in `@Named`) of a bean that implements `CredentialsProvider`. It is used to select the credentials provider bean when multiple exist. This is unnecessary when there is only one credentials provider available.
134+
135+
For Vault, the credentials provider bean name is `vault-credentials-provider`.
136+
137+
ifdef::add-copy-button-to-env-var[]
138+
Environment variable: env_var_with_copy_button:+++QUARKUS_GITHUB_APP_CREDENTIALS_PROVIDER_NAME+++[]
139+
endif::add-copy-button-to-env-var[]
140+
ifndef::add-copy-button-to-env-var[]
141+
Environment variable: `+++QUARKUS_GITHUB_APP_CREDENTIALS_PROVIDER_NAME+++`
142+
endif::add-copy-button-to-env-var[]
143+
--|string
144+
|
145+
146+
105147
a| [[quarkus-github-app_quarkus-github-app-webhook-proxy-url]]`link:#quarkus-github-app_quarkus-github-app-webhook-proxy-url[quarkus.github-app.webhook-proxy-url]`
106148

107149

runtime/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
<groupId>io.quarkus</groupId>
3939
<artifactId>quarkus-caffeine</artifactId>
4040
</dependency>
41+
<dependency>
42+
<groupId>io.quarkus</groupId>
43+
<artifactId>quarkus-credentials</artifactId>
44+
</dependency>
4145
<dependency>
4246
<groupId>io.quarkus</groupId>
4347
<artifactId>quarkus-smallrye-graphql-client</artifactId>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.quarkiverse.githubapp;
2+
3+
import io.quarkus.credentials.CredentialsProvider;
4+
5+
/**
6+
* The name of the credentials to use in your {@link CredentialsProvider}.
7+
*/
8+
public final class Credentials {
9+
10+
public static final String PRIVATE_KEY = "githubAppPrivateKey";
11+
public static final String WEBHOOK_SECRET = "githubAppWebhookSecret";
12+
13+
}

runtime/src/main/java/io/quarkiverse/githubapp/runtime/config/CheckedConfigProvider.java

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.quarkiverse.githubapp.runtime.config;
22

33
import java.security.PrivateKey;
4+
import java.util.Map;
45
import java.util.Optional;
56
import java.util.Set;
67
import java.util.TreeSet;
@@ -11,8 +12,12 @@
1112
import org.jboss.logging.Logger;
1213

1314
import io.quarkiverse.githubapp.ConfigFile;
15+
import io.quarkiverse.githubapp.Credentials;
1416
import io.quarkiverse.githubapp.GitHubEvent;
1517
import io.quarkiverse.githubapp.runtime.config.GitHubAppRuntimeConfig.Debug;
18+
import io.quarkus.arc.Arc;
19+
import io.quarkus.arc.ArcContainer;
20+
import io.quarkus.credentials.CredentialsProvider;
1621
import io.quarkus.runtime.LaunchMode;
1722
import io.quarkus.runtime.Startup;
1823

@@ -26,28 +31,45 @@ public class CheckedConfigProvider {
2631

2732
private final LaunchMode launchMode;
2833

34+
private final Optional<PrivateKey> privateKey;
35+
private final Optional<String> webhookSecret;
36+
2937
private final Set<String> missingPropertyKeys = new TreeSet<>();
3038

3139
@Inject
3240
CheckedConfigProvider(GitHubAppRuntimeConfig gitHubAppRuntimeConfig, LaunchMode launchMode) {
3341
this.gitHubAppRuntimeConfig = gitHubAppRuntimeConfig;
3442
this.launchMode = launchMode;
3543

44+
Map<String, String> credentials = getCredentials();
45+
String privateKeyFromCredentials = credentials.get(Credentials.PRIVATE_KEY);
46+
if (privateKeyFromCredentials != null && !privateKeyFromCredentials.isBlank()) {
47+
this.privateKey = Optional.of(new PrivateKeyConverter().convert(privateKeyFromCredentials.trim()));
48+
} else {
49+
this.privateKey = gitHubAppRuntimeConfig.privateKey;
50+
}
51+
String webhookSecretFromCredentials = credentials.get(Credentials.WEBHOOK_SECRET);
52+
if (webhookSecretFromCredentials != null && !webhookSecretFromCredentials.isBlank()) {
53+
this.webhookSecret = Optional.of(webhookSecretFromCredentials.trim());
54+
} else {
55+
this.webhookSecret = gitHubAppRuntimeConfig.webhookSecret;
56+
}
57+
3658
if (gitHubAppRuntimeConfig.appId.isEmpty()) {
3759
missingPropertyKeys.add("quarkus.github-app.app-id (.env: QUARKUS_GITHUB_APP_APP_ID)");
3860
}
39-
if (gitHubAppRuntimeConfig.privateKey.isEmpty()) {
61+
if (this.privateKey.isEmpty()) {
4062
missingPropertyKeys.add("quarkus.github-app.private-key (.env: QUARKUS_GITHUB_APP_PRIVATE_KEY)");
4163
}
42-
if (launchMode == LaunchMode.NORMAL && gitHubAppRuntimeConfig.webhookSecret.isEmpty()) {
64+
if (launchMode == LaunchMode.NORMAL && this.webhookSecret.isEmpty()) {
4365
missingPropertyKeys.add("quarkus.github-app.webhook-secret (.env: QUARKUS_GITHUB_APP_WEBHOOK_SECRET)");
4466
}
4567

4668
if (launchMode != LaunchMode.TEST) {
4769
checkConfig();
4870
}
4971

50-
if (gitHubAppRuntimeConfig.webhookSecret.isPresent() && launchMode.isDevOrTest()) {
72+
if (this.webhookSecret.isPresent() && launchMode.isDevOrTest()) {
5173
LOG.info("Payload signature checking is disabled in dev and test modes.");
5274
}
5375
}
@@ -71,11 +93,11 @@ public PrivateKey privateKey() {
7193
}
7294

7395
// The optional will never be empty; using orElseThrow instead of get to avoid IDE warnings.
74-
return gitHubAppRuntimeConfig.privateKey.orElseThrow();
96+
return privateKey.orElseThrow();
7597
}
7698

7799
public Optional<String> webhookSecret() {
78-
return gitHubAppRuntimeConfig.webhookSecret;
100+
return webhookSecret;
79101
}
80102

81103
public Optional<String> webhookProxyUrl() {
@@ -124,4 +146,29 @@ public void checkConfig() {
124146

125147
throw new GitHubAppConfigurationException(errorMessage);
126148
}
149+
150+
private Map<String, String> getCredentials() {
151+
if (gitHubAppRuntimeConfig.credentialsProvider.isEmpty()) {
152+
return Map.of();
153+
}
154+
155+
String beanName = gitHubAppRuntimeConfig.credentialsProviderName.orElse(null);
156+
CredentialsProvider credentialsProvider = getCredentialsProvider(beanName);
157+
String keyRingName = gitHubAppRuntimeConfig.credentialsProvider.get();
158+
159+
return credentialsProvider.getCredentials(keyRingName);
160+
}
161+
162+
private static CredentialsProvider getCredentialsProvider(String name) {
163+
ArcContainer container = Arc.container();
164+
CredentialsProvider credentialsProvider = name != null
165+
? (CredentialsProvider) container.instance(name).get()
166+
: container.instance(CredentialsProvider.class).get();
167+
168+
if (credentialsProvider == null) {
169+
throw new RuntimeException("Unable to find credentials provider of name " + (name == null ? "default" : name));
170+
}
171+
172+
return credentialsProvider;
173+
}
127174
}

runtime/src/main/java/io/quarkiverse/githubapp/runtime/config/GitHubAppRuntimeConfig.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
import java.security.PrivateKey;
55
import java.util.Optional;
66

7+
import io.quarkiverse.githubapp.Credentials;
78
import io.quarkus.runtime.annotations.ConfigGroup;
89
import io.quarkus.runtime.annotations.ConfigItem;
910
import io.quarkus.runtime.annotations.ConfigPhase;
1011
import io.quarkus.runtime.annotations.ConfigRoot;
1112
import io.quarkus.runtime.annotations.ConvertWith;
13+
import io.quarkus.runtime.configuration.TrimmedStringConverter;
1214

1315
@ConfigRoot(name = "github-app", phase = ConfigPhase.RUN_TIME)
1416
public class GitHubAppRuntimeConfig {
@@ -50,6 +52,30 @@ public class GitHubAppRuntimeConfig {
5052
@ConfigItem
5153
Optional<String> webhookSecret;
5254

55+
/**
56+
* The credentials provider name.
57+
* <p>
58+
* This is the name of the "keyring" containing the GitHub App secrets.
59+
* <p>
60+
* Key names are defined in {@link Credentials}.
61+
*/
62+
@ConfigItem
63+
@ConvertWith(TrimmedStringConverter.class)
64+
Optional<String> credentialsProvider;
65+
66+
/**
67+
* The credentials provider bean name.
68+
* <p>
69+
* This is a bean name (as in {@code @Named}) of a bean that implements {@code CredentialsProvider}.
70+
* It is used to select the credentials provider bean when multiple exist.
71+
* This is unnecessary when there is only one credentials provider available.
72+
* <p>
73+
* For Vault, the credentials provider bean name is {@code vault-credentials-provider}.
74+
*/
75+
@ConfigItem
76+
@ConvertWith(TrimmedStringConverter.class)
77+
Optional<String> credentialsProviderName;
78+
5379
/**
5480
* The Smee.io proxy URL used when testing locally.
5581
*/

0 commit comments

Comments
 (0)