Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package net.leanix.githubagent.dto

data class InstallationRequestDTO(
val id: Long,
val account: Account,
)
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import java.util.concurrent.CountDownLatch
class BrokerStompSessionHandler(
private val artifactDownloadHandler: ArtifactDownloadHandler,
private val repositoryGetHandler: RepositoryGetHandler,
private val installationGetHandler: InstallationGetHandler,
) : StompSessionHandlerAdapter() {
@Lazy
@Autowired
Expand All @@ -32,6 +33,7 @@ class BrokerStompSessionHandler(
latch.countDown()
session.subscribe("/user/queue/message/artifact", artifactDownloadHandler)
session.subscribe("/user/queue/message/repository", repositoryGetHandler)
session.subscribe("/user/queue/message/installation", installationGetHandler)
}

override fun handleException(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package net.leanix.githubagent.handler

import net.leanix.githubagent.client.GitHubClient
import net.leanix.githubagent.dto.InstallationRequestDTO
import net.leanix.githubagent.exceptions.JwtTokenNotFound
import net.leanix.githubagent.services.CachingService
import net.leanix.githubagent.services.GitHubAuthenticationService
import net.leanix.githubagent.services.GitHubEnterpriseService
import net.leanix.githubagent.services.GitHubScanningService
import net.leanix.githubagent.services.SyncLogService
import net.leanix.githubagent.shared.INSTALLATION_LABEL
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Lazy
import org.springframework.messaging.simp.stomp.StompFrameHandler
import org.springframework.messaging.simp.stomp.StompHeaders
import org.springframework.stereotype.Component
import java.lang.reflect.Type

@Component
class InstallationGetHandler(
@Lazy @Autowired
private val gitHubAuthenticationService: GitHubAuthenticationService,
@Lazy @Autowired
private val gitHubScanningService: GitHubScanningService,
@Lazy @Autowired
private val gitHubEnterpriseService: GitHubEnterpriseService,
@Lazy @Autowired
private val cachingService: CachingService,
@Lazy @Autowired
private val syncLogService: SyncLogService,
@Lazy @Autowired
private val gitHubClient: GitHubClient,
@Value("\${webhookEventService.waitingTime}") private val waitingTime: Long,
) : StompFrameHandler {

private val logger = LoggerFactory.getLogger(InstallationGetHandler::class.java)

override fun getPayloadType(headers: StompHeaders): Type {
return InstallationRequestDTO::class.java
}

override fun handleFrame(headers: StompHeaders, payload: Any?) {
payload?.let {
val dto = payload as InstallationRequestDTO
logger.info("Received installation get message from server for organisation: ${dto.account.login}")
runCatching {
fetchAndSendOrganisationData(dto)
}
}
}

fun fetchAndSendOrganisationData(installationRequestDTO: InstallationRequestDTO) {
while (cachingService.get("runId") != null) {
logger.info("A full scan is already in progress, waiting for it to finish.")
Thread.sleep(waitingTime)
}
syncLogService.sendFullScanStart(installationRequestDTO.account.login)
kotlin.runCatching {
val jwtToken = cachingService.get("jwtToken") ?: throw JwtTokenNotFound()
val installation = gitHubClient.getInstallation(
installationRequestDTO.id,
"Bearer $jwtToken"
)
gitHubEnterpriseService.validateEnabledPermissionsAndEvents(
INSTALLATION_LABEL,
installation.permissions,
installation.events
)
gitHubAuthenticationService.refreshTokens()
gitHubScanningService.fetchAndSendOrganisationsData(listOf(installation))
gitHubScanningService.fetchAndSendRepositoriesData(installation).forEach { repository ->
gitHubScanningService.fetchManifestFilesAndSend(installation, repository)
}
}.onSuccess {
syncLogService.sendFullScanSuccess()
}.onFailure {
syncLogService.sendFullScanFailure(it.message)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,22 @@ package net.leanix.githubagent.services

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import net.leanix.githubagent.client.GitHubClient
import net.leanix.githubagent.dto.InstallationEventPayload
import net.leanix.githubagent.dto.ManifestFileAction
import net.leanix.githubagent.dto.ManifestFileUpdateDto
import net.leanix.githubagent.dto.PushEventCommit
import net.leanix.githubagent.dto.PushEventPayload
import net.leanix.githubagent.exceptions.JwtTokenNotFound
import net.leanix.githubagent.shared.INSTALLATION_LABEL
import net.leanix.githubagent.shared.MANIFEST_FILE_NAME
import net.leanix.githubagent.shared.fileNameMatchRegex
import net.leanix.githubagent.shared.generateFullPath
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service

@SuppressWarnings("TooManyFunctions")
@Service
class WebhookEventService(
private val webSocketService: WebSocketService,
private val gitHubGraphQLService: GitHubGraphQLService,
private val cachingService: CachingService,
private val gitHubAuthenticationService: GitHubAuthenticationService,
private val gitHubScanningService: GitHubScanningService,
private val syncLogService: SyncLogService,
@Value("\${webhookEventService.waitingTime}") private val waitingTime: Long,
private val gitHubClient: GitHubClient,
private val gitHubEnterpriseService: GitHubEnterpriseService
) {

private val logger = LoggerFactory.getLogger(WebhookEventService::class.java)
Expand All @@ -37,7 +26,6 @@ class WebhookEventService(
fun consumeWebhookEvent(eventType: String, payload: String) {
when (eventType.uppercase()) {
"PUSH" -> handlePushEvent(payload)
"INSTALLATION" -> handleInstallationEvent(payload)
else -> {
logger.info("Sending event of type: $eventType")
webSocketService.sendMessage("/events/other/$eventType", payload)
Expand Down Expand Up @@ -67,42 +55,6 @@ class WebhookEventService(
}
}

private fun handleInstallationEvent(payload: String) {
val installationEventPayload: InstallationEventPayload = objectMapper.readValue(payload)
if (installationEventPayload.action == "created") {
handleInstallationCreated(installationEventPayload)
}
}

private fun handleInstallationCreated(installationEventPayload: InstallationEventPayload) {
while (cachingService.get("runId") != null) {
logger.info("A full scan is already in progress, waiting for it to finish.")
Thread.sleep(waitingTime)
}
syncLogService.sendFullScanStart(installationEventPayload.installation.account.login)
kotlin.runCatching {
val jwtToken = cachingService.get("jwtToken") ?: throw JwtTokenNotFound()
val installation = gitHubClient.getInstallation(
installationEventPayload.installation.id.toLong(),
"Bearer $jwtToken"
)
gitHubEnterpriseService.validateEnabledPermissionsAndEvents(
INSTALLATION_LABEL,
installation.permissions,
installation.events
)
gitHubAuthenticationService.refreshTokens()
gitHubScanningService.fetchAndSendOrganisationsData(listOf(installation))
gitHubScanningService.fetchAndSendRepositoriesData(installation).forEach { repository ->
gitHubScanningService.fetchManifestFilesAndSend(installation, repository)
}
}.onSuccess {
syncLogService.sendFullScanSuccess()
}.onFailure {
syncLogService.sendFullScanFailure(it.message)
}
}

private fun handleManifestFileChanges(
defaultBranch: String,
headCommit: PushEventCommit,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package net.leanix.githubagent.services

import com.ninjasquad.springmockk.MockkBean
import com.ninjasquad.springmockk.SpykBean
import io.mockk.every
import io.mockk.just
import io.mockk.runs
import io.mockk.verify
import net.leanix.githubagent.dto.Account
import net.leanix.githubagent.dto.InstallationRequestDTO
import net.leanix.githubagent.handler.InstallationGetHandler
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ActiveProfiles

@SpringBootTest
@ActiveProfiles("test")
class InstallationGetHandlerTest {

@MockkBean
private lateinit var webSocketService: WebSocketService

@MockkBean
private lateinit var cachingService: CachingService

@SpykBean
private lateinit var installationGetHandler: InstallationGetHandler

@Test
fun `should wait for active scan to finish before starting scanning new org`() {
every { cachingService.get("runId") } returnsMany listOf("value", "value", "value", null)
every { cachingService.set("runId", any(), any()) } just runs
every { cachingService.remove("runId") } just runs
every { webSocketService.sendMessage(any(), any()) } returns Unit

val installationRequestDTO = InstallationRequestDTO(
30,
Account("test-org")
)

installationGetHandler.fetchAndSendOrganisationData(installationRequestDTO)

verify(exactly = 6) { cachingService.get("runId") }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,20 @@ package net.leanix.githubagent.services

import com.ninjasquad.springmockk.MockkBean
import io.mockk.every
import io.mockk.just
import io.mockk.runs
import io.mockk.verify
import net.leanix.githubagent.client.GitHubClient
import net.leanix.githubagent.dto.Account
import net.leanix.githubagent.dto.Installation
import net.leanix.githubagent.dto.ItemResponse
import net.leanix.githubagent.dto.ManifestFileAction
import net.leanix.githubagent.dto.ManifestFileUpdateDto
import net.leanix.githubagent.dto.Organization
import net.leanix.githubagent.dto.RepositoryItemResponse
import net.leanix.githubagent.shared.MANIFEST_FILE_NAME
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ActiveProfiles
import java.util.UUID

const val UNSUPPORTED_MANIFEST_EXTENSION = "leanix.yml"

Expand Down Expand Up @@ -413,29 +409,6 @@ class WebhookEventServiceTest {
}
}

@Test
fun `should wait for active scan to finish before starting scanning new org`() {
every { cachingService.get("runId") } returnsMany listOf("value", "value", "value", null)
every { cachingService.set("runId", any(), any()) } just runs
every { cachingService.remove("runId") } just runs

val eventType = "INSTALLATION"
val payload = """{
"action": "created",
"installation": {
"id": 30,
"account": {
"login": "test-org",
"id": 20
}
}
}"""

webhookEventService.consumeWebhookEvent(eventType, payload)

verify(exactly = 6) { cachingService.get("runId") }
}

@Test
fun `should ignore push events without a head commit`() {
val payload = """{
Expand All @@ -456,37 +429,6 @@ class WebhookEventServiceTest {
}
}

@Test
fun `should send the org to the backend when an new installation is created`() {
val runId = UUID.randomUUID()
every { cachingService.get("runId") } returnsMany listOf("value", null, runId)
every { cachingService.set("runId", any(), any()) } just runs
every { cachingService.remove("runId") } just runs
every { gitHubAPIService.getPaginatedOrganizations(any()) } returns
listOf(Organization("testOrganization", 1))

val eventType = "INSTALLATION"
val payload = """{
"action": "created",
"installation": {
"id": 30,
"account": {
"login": "test-org",
"id": 20
}
}
}"""

webhookEventService.consumeWebhookEvent(eventType, payload)

verify {
webSocketService.sendMessage(
"$runId/organizations",
any()
)
}
}

fun createItemResponse(repoName: String, organization: String): ItemResponse {
return ItemResponse(
MANIFEST_FILE_NAME,
Expand Down
Loading