Skip to content

Commit

Permalink
Test
Browse files Browse the repository at this point in the history
  • Loading branch information
C4tWithShell committed Dec 11, 2023
1 parent 513f32a commit 66d786a
Show file tree
Hide file tree
Showing 11 changed files with 313 additions and 269 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=1.16.2
version=1.16.1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2022 Michael Clarke
* Copyright (C) 2020-2023 Michael Clarke
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -28,9 +28,14 @@
import com.github.mc1arke.sonarqube.plugin.almclient.github.v3.model.AppToken;
import com.github.mc1arke.sonarqube.plugin.almclient.github.v3.model.InstallationRepositories;
import com.github.mc1arke.sonarqube.plugin.almclient.github.v3.model.Repository;
import com.google.common.annotations.VisibleForTesting;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.DefaultJwtBuilder;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.server.ServerSide;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
Expand All @@ -41,16 +46,8 @@
import java.time.Clock;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.server.ServerSide;

@ServerSide
@ComputeEngineSide
Expand All @@ -75,68 +72,70 @@ public RestApplicationAuthenticationProvider(Clock clock, LinkHeaderReader linkH
this.objectMapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}

@VisibleForTesting
protected List<AppInstallation> getAppInstallations(ObjectMapper objectMapper, String apiUrl, String jwtToken) throws IOException {
@Override
public RepositoryAuthenticationToken getInstallationToken(String apiUrl, String appId, String apiPrivateKey,
String projectPath) throws IOException {

Instant issued = clock.instant().minus(10, ChronoUnit.SECONDS);
Instant expiry = issued.plus(2, ChronoUnit.MINUTES);
String jwtToken = new DefaultJwtBuilder().setIssuedAt(Date.from(issued)).setExpiration(Date.from(expiry))
.claim("iss", appId).signWith(createPrivateKey(apiPrivateKey), SignatureAlgorithm.RS256).compact();

List<AppInstallation> appInstallations = new ArrayList<>();
Optional<RepositoryAuthenticationToken> repositoryAuthenticationToken = findTokenFromAppInstallationList(getV3Url(apiUrl) + "/app/installations", jwtToken, projectPath);

return repositoryAuthenticationToken.orElseThrow(() -> new InvalidConfigurationException(InvalidConfigurationException.Scope.PROJECT,
"No token could be found with access to the requested repository using the given application ID and key"));
}

private Optional<RepositoryAuthenticationToken> findTokenFromAppInstallationList(String apiUrl, String jwtToken, String projectPath) throws IOException {
URLConnection appConnection = urlProvider.createUrlConnection(apiUrl);
appConnection.setRequestProperty(ACCEPT_HEADER, APP_PREVIEW_ACCEPT_HEADER);
appConnection.setRequestProperty(AUTHORIZATION_HEADER, BEARER_AUTHORIZATION_HEADER_PREFIX + jwtToken);

try (Reader reader = new InputStreamReader(appConnection.getInputStream())) {
appInstallations.addAll(Arrays.asList(objectMapper.readerFor(AppInstallation[].class).readValue(reader)));
AppInstallation[] appInstallations = objectMapper.readerFor(AppInstallation[].class).readValue(reader);
for (AppInstallation appInstallation : appInstallations) {
Optional<RepositoryAuthenticationToken> repositoryAuthenticationToken = findAppTokenFromAppInstallation(appInstallation, jwtToken, projectPath);

if (repositoryAuthenticationToken.isPresent()) {
return repositoryAuthenticationToken;
}
}
}

Optional<String> nextLink = linkHeaderReader.findNextLink(appConnection.getHeaderField("Link"));
if (nextLink.isPresent()) {
appInstallations.addAll(getAppInstallations(objectMapper, nextLink.get(), jwtToken));
if (nextLink.isEmpty()) {
return Optional.empty();
}

return appInstallations;
return findTokenFromAppInstallationList(nextLink.get(), jwtToken, projectPath);
}

@Override
public RepositoryAuthenticationToken getInstallationToken(String apiUrl, String appId, String apiPrivateKey,
String projectPath) throws IOException {

Instant issued = clock.instant().minus(10, ChronoUnit.SECONDS);
Instant expiry = issued.plus(2, ChronoUnit.MINUTES);
String jwtToken = new DefaultJwtBuilder().setIssuedAt(Date.from(issued)).setExpiration(Date.from(expiry))
.claim("iss", appId).signWith(createPrivateKey(apiPrivateKey), SignatureAlgorithm.RS256).compact();

ObjectMapper objectMapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

List<AppInstallation> appInstallations = getAppInstallations(objectMapper, getV3Url(apiUrl) + "/app/installations", jwtToken);
private Optional<RepositoryAuthenticationToken> findAppTokenFromAppInstallation(AppInstallation installation, String jwtToken, String projectPath) throws IOException {
URLConnection accessTokenConnection = urlProvider.createUrlConnection(installation.getAccessTokensUrl());
((HttpURLConnection) accessTokenConnection).setRequestMethod("POST");
accessTokenConnection.setRequestProperty(ACCEPT_HEADER, APP_PREVIEW_ACCEPT_HEADER);
accessTokenConnection
.setRequestProperty(AUTHORIZATION_HEADER, BEARER_AUTHORIZATION_HEADER_PREFIX + jwtToken);

for (AppInstallation installation : appInstallations) {
URLConnection accessTokenConnection = urlProvider.createUrlConnection(installation.getAccessTokensUrl());
((HttpURLConnection) accessTokenConnection).setRequestMethod("POST");
accessTokenConnection.setRequestProperty(ACCEPT_HEADER, APP_PREVIEW_ACCEPT_HEADER);
accessTokenConnection
.setRequestProperty(AUTHORIZATION_HEADER, BEARER_AUTHORIZATION_HEADER_PREFIX + jwtToken);
try (Reader reader = new InputStreamReader(accessTokenConnection.getInputStream())) {
AppToken appToken = objectMapper.readerFor(AppToken.class).readValue(reader);

String targetUrl = installation.getRepositoriesUrl();

try (Reader reader = new InputStreamReader(accessTokenConnection.getInputStream())) {
AppToken appToken = objectMapper.readerFor(AppToken.class).readValue(reader);

String targetUrl = installation.getRepositoriesUrl();

Optional<RepositoryAuthenticationToken> potentialRepositoryAuthenticationToken = findRepositoryAuthenticationToken(appToken, targetUrl, projectPath, objectMapper);

if (potentialRepositoryAuthenticationToken.isPresent()) {
return potentialRepositoryAuthenticationToken.get();
}
Optional<RepositoryAuthenticationToken> potentialRepositoryAuthenticationToken = findRepositoryAuthenticationToken(appToken, targetUrl, projectPath);

if (potentialRepositoryAuthenticationToken.isPresent()) {
return potentialRepositoryAuthenticationToken;
}

}

throw new InvalidConfigurationException(InvalidConfigurationException.Scope.PROJECT,
"No token could be found with access to the requested repository using the given application ID and key");
return Optional.empty();
}

private Optional<RepositoryAuthenticationToken> findRepositoryAuthenticationToken(AppToken appToken, String targetUrl,
String projectPath, ObjectMapper objectMapper) throws IOException {
String projectPath) throws IOException {
URLConnection installationRepositoriesConnection = urlProvider.createUrlConnection(targetUrl);
((HttpURLConnection) installationRepositoriesConnection).setRequestMethod("GET");
installationRepositoriesConnection.setRequestProperty(ACCEPT_HEADER, APP_PREVIEW_ACCEPT_HEADER);
Expand All @@ -161,7 +160,7 @@ private Optional<RepositoryAuthenticationToken> findRepositoryAuthenticationToke
return Optional.empty();
}

return findRepositoryAuthenticationToken(appToken, nextLink.get(), projectPath, objectMapper);
return findRepositoryAuthenticationToken(appToken, nextLink.get(), projectPath);
}

private static String getV3Url(String apiUrl) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ private static Branch createBranch(DbClient dbClient, String branchName, String

private static Optional<BranchDto> findBranchByUuid(String projectUuid, DbClient dbClient) {
try (DbSession dbSession = dbClient.openSession(false)) {
return dbClient.branchDao().selectByUuid(dbSession, projectUuid);
return dbClient.branchDao().selectMainBranchByProjectUuid(dbSession, projectUuid);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,24 @@
*/
package com.github.mc1arke.sonarqube.plugin.ce.pullrequest.markup;

import java.util.Set;

public final class Link extends Node {

private static final Set<Class<? extends Node>> SUPPORTED_CHILDREN = Set.of(Text.class, Image.class);
private final String url;

public Link(String url, Node... children) {
super(children);
this.url=url;
}
this.url = url;
}

public String getUrl() {
return url;
}

@Override
boolean isValidChild(Node child) {
return child instanceof Text;
return child != null && SUPPORTED_CHILDREN.contains(child.getClass());
}
}
Loading

0 comments on commit 66d786a

Please sign in to comment.