From: Klaudio Sinani Date: Thu, 15 Sep 2022 11:11:10 +0000 (+0200) Subject: SONAR-17279 - Add ITs for scanning alerts in GitHub enterprise X-Git-Tag: 9.7.0.61563~144 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=8de417f3fd99a81942ff925434d5aca77f639421;p=sonarqube.git SONAR-17279 - Add ITs for scanning alerts in GitHub enterprise --- diff --git a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationHttpClientImpl.java b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationHttpClientImpl.java index 96045882a0b..11845309142 100644 --- a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationHttpClientImpl.java +++ b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubApplicationHttpClientImpl.java @@ -79,7 +79,6 @@ public class GithubApplicationHttpClientImpl implements GithubApplicationHttpCli private GetResponse get(String appUrl, AccessToken token, String endPoint, boolean withLog) throws IOException { validateEndPoint(endPoint); - try (okhttp3.Response response = client.newCall(newGetRequest(appUrl, token, endPoint)).execute()) { int responseCode = response.code(); if (responseCode != HTTP_OK) { diff --git a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/SonarQubeIssueKeyFormatter.java b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/SonarQubeIssueKeyFormatter.java new file mode 100644 index 00000000000..f14ca04af0b --- /dev/null +++ b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/SonarQubeIssueKeyFormatter.java @@ -0,0 +1,41 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.alm.client.github; + +import java.util.Optional; + +import static org.apache.commons.lang.StringUtils.substringBetween; + + +public final class SonarQubeIssueKeyFormatter { + static final String SONAR_ISSUE_KEY_PREFIX = ""; + + private SonarQubeIssueKeyFormatter() { + } + + public static String serialize(String key) { + return SONAR_ISSUE_KEY_PREFIX + key + SONAR_ISSUE_KEY_SUFFIX; + } + + public static Optional deserialize(String messageText) { + return Optional.ofNullable(substringBetween(messageText, SONAR_ISSUE_KEY_PREFIX, SONAR_ISSUE_KEY_SUFFIX)); + } +} diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/SonarQubeIssueKeyFormatterTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/SonarQubeIssueKeyFormatterTest.java new file mode 100644 index 00000000000..04bcaa3a5d3 --- /dev/null +++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/github/SonarQubeIssueKeyFormatterTest.java @@ -0,0 +1,66 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.alm.client.github; + +import java.util.Optional; +import org.apache.commons.lang.RandomStringUtils; +import org.junit.Test; + +import static java.lang.String.join; +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.alm.client.github.SonarQubeIssueKeyFormatter.SONAR_ISSUE_KEY_PREFIX; +import static org.sonar.alm.client.github.SonarQubeIssueKeyFormatter.SONAR_ISSUE_KEY_SUFFIX; + +public class SonarQubeIssueKeyFormatterTest { + + @Test + public void should_serializeIssueKey() { + String issueKey = RandomStringUtils.randomAlphanumeric(20); + + String serialized = SonarQubeIssueKeyFormatter.serialize(issueKey); + + String expectedSerializedKey = join("", SONAR_ISSUE_KEY_PREFIX, issueKey, SONAR_ISSUE_KEY_SUFFIX); + assertThat(serialized).isEqualTo(expectedSerializedKey); + } + + @Test + public void should_deserializeIssueKey() { + String issueKey = RandomStringUtils.randomAlphanumeric(20); + String message = join("", SONAR_ISSUE_KEY_PREFIX, issueKey, SONAR_ISSUE_KEY_SUFFIX, "a message"); + + Optional deserialized = SonarQubeIssueKeyFormatter.deserialize(message); + + assertThat(deserialized).hasValue(issueKey); + } + + @Test + public void should_notDeserializeIssueKey_when_messageHasWrongFormat() { + String issueKey = RandomStringUtils.randomAlphanumeric(20); + String messageWithoutSuffix = join("", SONAR_ISSUE_KEY_PREFIX, issueKey, "a message"); + String messageWithoutPrefix = join("", issueKey, SONAR_ISSUE_KEY_SUFFIX, "a message"); + String messageWithPrefixSuffixReversed = join("", SONAR_ISSUE_KEY_SUFFIX, issueKey, SONAR_ISSUE_KEY_PREFIX, "a message"); + String messageWithNoPrefixSuffix = join("", issueKey, "a message"); + + assertThat(SonarQubeIssueKeyFormatter.deserialize(messageWithoutSuffix)).isEmpty(); + assertThat(SonarQubeIssueKeyFormatter.deserialize(messageWithoutPrefix)).isEmpty(); + assertThat(SonarQubeIssueKeyFormatter.deserialize(messageWithPrefixSuffixReversed)).isEmpty(); + assertThat(SonarQubeIssueKeyFormatter.deserialize(messageWithNoPrefixSuffix)).isEmpty(); + } +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java index 9ce4db76bc8..9442cf30f33 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java @@ -55,6 +55,7 @@ public class HttpConnector implements WsConnector { public static final int DEFAULT_CONNECT_TIMEOUT_MILLISECONDS = 30_000; public static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = 60_000; + private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); /** * Base URL with trailing slash, for instance "https://localhost/sonarqube/". @@ -129,7 +130,9 @@ public class HttpConnector implements WsConnector { RequestBody body; Map parts = postRequest.getParts(); - if (parts.isEmpty()) { + if (postRequest.hasBody()) { + body = RequestBody.create(JSON, postRequest.getBody()); + } else if (parts.isEmpty()) { // parameters are defined in the body (application/x-www-form-urlencoded) FormBody.Builder formBody = new FormBody.Builder(); postRequest.getParameters().getKeys() diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/PostRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/PostRequest.java index 0ca67861385..fd807e333fc 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/PostRequest.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/PostRequest.java @@ -28,6 +28,7 @@ import java.util.Map; */ public class PostRequest extends BaseRequest { + private String body; private final Map parts = new LinkedHashMap<>(); public PostRequest(String path) { @@ -39,6 +40,19 @@ public class PostRequest extends BaseRequest { return Method.POST; } + public PostRequest setBody(String body) { + this.body = body; + return this; + } + + public String getBody() { + return body; + } + + public boolean hasBody() { + return this.body != null; + } + public PostRequest setPart(String name, Part part) { this.parts.put(name, part); return this; diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/almintegrations/AlmIntegrationsService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/almintegrations/AlmIntegrationsService.java index a1ff8fffbb6..96a4230bcf1 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/almintegrations/AlmIntegrationsService.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/almintegrations/AlmIntegrationsService.java @@ -197,6 +197,24 @@ public class AlmIntegrationsService extends BaseService { AlmIntegrations.SearchBitbucketcloudReposWsResponse.parser()); } + /** + * This is part of the internal API. + * This is a POST request. + * + * @see Further information about this action online (including a response example) + * @since 9.7 + */ + public void sendGitubCodeScanningAlertWebhookPayload(SendGithubCodeScanningAlertWebhookPayloadRequest request) { + call( + new PostRequest(path("webhook_github")) + .setHeader("X-GitHub-Event", request.getGithubEventHeader()) + .setHeader("X-Hub-Signature", request.getGithubSignatureHeader()) + .setHeader("X-Hub-Signature-256", request.getGithubSignature256Header()) + .setBody(request.getPayload()) + .setMediaType(MediaTypes.JSON) + ).content(); + } + /** * This is part of the internal API. * This is a POST request. diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/almintegrations/SendGithubCodeScanningAlertWebhookPayloadRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/almintegrations/SendGithubCodeScanningAlertWebhookPayloadRequest.java new file mode 100644 index 00000000000..e7ce6ce181a --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/almintegrations/SendGithubCodeScanningAlertWebhookPayloadRequest.java @@ -0,0 +1,84 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonarqube.ws.client.almintegrations; + +import javax.annotation.Generated; + +/** + * This is part of the internal API. + * This is a POST request. + * @see Further information about this action online (including a response example) + * @since 9.7 + */ +@Generated("sonar-ws-generator") +public class SendGithubCodeScanningAlertWebhookPayloadRequest { + private String payload; + private String githubEventHeader; + private String githubSignatureHeader; + private String githubSignature256Header; + + /** + * This is a mandatory parameter. + */ + public SendGithubCodeScanningAlertWebhookPayloadRequest setPayload(String payload) { + this.payload = payload; + return this; + } + + public String getPayload() { + return payload; + } + + /** + * This is a mandatory parameter. + */ + public SendGithubCodeScanningAlertWebhookPayloadRequest setGithubEventHeader(String header) { + this.githubEventHeader = header; + return this; + } + + public String getGithubEventHeader() { + return githubEventHeader; + } + + /** + * This is a mandatory parameter. + */ + public SendGithubCodeScanningAlertWebhookPayloadRequest setGithubSignatureHeader(String header) { + this.githubSignatureHeader = header; + return this; + } + + public String getGithubSignatureHeader() { + return this.githubSignatureHeader; + } + + /** + * This is a mandatory parameter. + */ + public SendGithubCodeScanningAlertWebhookPayloadRequest setGithubSignature256Header(String header) { + this.githubSignature256Header = header; + return this; + } + + public String getGithubSignature256Header() { + return githubSignature256Header; + } +} diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/HttpConnectorTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/HttpConnectorTest.java index cbaae7969d5..31786be64cf 100644 --- a/sonar-ws/src/test/java/org/sonarqube/ws/client/HttpConnectorTest.java +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/HttpConnectorTest.java @@ -365,6 +365,32 @@ public class HttpConnectorTest { assertThat(recordedRequest.getHeader("X-Bar")).isEqualTo("barz"); } + @Test + public void setBody_shouldAddCorrectlyBodyPayloadToPostRequest_whenComposingAndSendingPostRequest() throws Exception { + answerHelloWorld(); + + String xGithubEventHeader = "code_scanning_alert"; + String xHubSignatureHeader = "x-hub-signature"; + String xHubSignature256Header = "x-hub-signature-256"; + String bodyRaw = "{\"state\":\"open\"}"; + + PostRequest request = new PostRequest("api/alm_integrations/webhook_github") + .setHeader("X-GitHub-Event", xGithubEventHeader) + .setHeader("X-Hub-Signature", xHubSignatureHeader) + .setHeader("X-Hub-Signature-256", xHubSignature256Header) + .setBody(bodyRaw) + .setMediaType(MediaTypes.JSON); + + underTest = HttpConnector.newBuilder().url(serverUrl).build(); + underTest.call(request); + + RecordedRequest recordedRequest = server.takeRequest(); + assertThat(recordedRequest.getHeader("X-GitHub-Event")).isEqualTo(xGithubEventHeader); + assertThat(recordedRequest.getHeader("X-Hub-Signature")).isEqualTo(xHubSignatureHeader); + assertThat(recordedRequest.getHeader("X-Hub-Signature-256")).isEqualTo(xHubSignature256Header); + assertThat(recordedRequest.getBody().readUtf8()).isEqualTo(bodyRaw); + } + @Test public void upload_file() throws Exception { answerHelloWorld(); diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/PostRequestTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/PostRequestTest.java index 43845dc4b60..62dcd8c7c59 100644 --- a/sonar-ws/src/test/java/org/sonarqube/ws/client/PostRequestTest.java +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/PostRequestTest.java @@ -57,4 +57,14 @@ public class PostRequestTest { assertThat(part.getMediaType()).isEqualTo(MediaTypes.JSON); assertThat(part.getFile()).isSameAs(reportFile); } + + @Test + public void setBody_shouldCorrectlyAddRawBodyToPostRequest() throws IOException { + String bodyRaw = "{\"state\":\"open\"}"; + PostRequest request = new PostRequest("api/alm_integrations/webhook_github"); + request.setBody(bodyRaw); + + assertThat(request.getBody()).isEqualTo(bodyRaw); + assertThat(request.hasBody()).isTrue(); + } }