Skip to content

Commit 2b77c42

Browse files
committed
Return the regenerated token by reading it back at the pushed revision
Motivation: The regenerated token was passed out of the content transformer through an AtomicReference, which is an awkward side channel. Modifications: - Read the app identity registry back at the revision the push produced and return the token from it, instead of capturing the token in the transformer. Result: - No behavior change; the caller still always receives the secret its own commit produced.
1 parent 803ad60 commit 2b77c42

2 files changed

Lines changed: 13 additions & 6 deletions

File tree

server/src/main/java/com/linecorp/centraldogma/server/metadata/AppIdentityService.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import java.util.Objects;
3434
import java.util.UUID;
3535
import java.util.concurrent.CompletableFuture;
36-
import java.util.concurrent.atomic.AtomicReference;
3736

3837
import org.jspecify.annotations.Nullable;
3938

@@ -183,9 +182,6 @@ CompletableFuture<Token> regenerateTokenSecret(Author author, String appId,
183182

184183
final String commitSummary = "Regenerate the secret of the token: " + appId;
185184

186-
// Capture the regenerated token so that the caller gets the secret this commit produced
187-
// even if another commit lands right after this one.
188-
final AtomicReference<Token> newTokenRef = new AtomicReference<>();
189185
final AppIdentityRegistryTransformer transformer = new AppIdentityRegistryTransformer(
190186
(headRevision, registry) -> {
191187
final AppIdentity appIdentity = registry.get(appId); // Raise an exception if not found.
@@ -228,7 +224,6 @@ CompletableFuture<Token> regenerateTokenSecret(Author author, String appId,
228224
final Token newToken = new Token(token.appId(), newSecret, token.isSystemAdmin(),
229225
token.allowGuestAccess(), token.creation(),
230226
token.deactivation(), null);
231-
newTokenRef.set(newToken);
232227
final Map<String, AppIdentity> newAppIds =
233228
updateMap(registry.appIds(), appId, newToken);
234229
// A deactivated token has no entry in the secret map, so the new secret is not
@@ -238,9 +233,14 @@ CompletableFuture<Token> regenerateTokenSecret(Author author, String appId,
238233
removeFromMap(registry.secrets(), oldSecret);
239234
return new AppIdentityRegistry(newAppIds, newSecrets, registry.certificateIds());
240235
});
236+
// Read the registry back at the revision this commit produced so that the caller gets
237+
// the secret of this commit even if another commit lands right after.
241238
return appIdentityRegistryRepo.push(INTERNAL_PROJECT_DOGMA, Project.REPO_DOGMA, author,
242239
commitSummary, transformer)
243-
.thenApply(unused -> newTokenRef.get());
240+
.thenCompose(revision -> appIdentityRegistryRepo.fetch(
241+
INTERNAL_PROJECT_DOGMA, Project.REPO_DOGMA, TOKEN_JSON,
242+
revision))
243+
.thenApply(holder -> (Token) holder.object().get(appId));
244244
}
245245

246246
CompletableFuture<Revision> activateToken(Author author, String appId) {

server/src/main/java/com/linecorp/centraldogma/server/metadata/RepositorySupport.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ CompletableFuture<HolderWithRevision<T>> fetch(String projectName, String repoNa
6666
return fetch(projectManager().get(projectName).repos().get(repoName), path);
6767
}
6868

69+
CompletableFuture<HolderWithRevision<T>> fetch(String projectName, String repoName, String path,
70+
Revision revision) {
71+
requireNonNull(projectName, "projectName");
72+
requireNonNull(repoName, "repoName");
73+
return fetch(projectManager().get(projectName).repos().get(repoName), path, revision);
74+
}
75+
6976
private CompletableFuture<HolderWithRevision<T>> fetch(Repository repository, String path) {
7077
requireNonNull(path, "path");
7178
final Revision revision = normalize(repository);

0 commit comments

Comments
 (0)