Skip to content

Commit 3e100a6

Browse files
Merge pull request #133 from leanix/feature/CID-3890/Only-support-configured-Webhook-Events
CID-3890: Only support configured Webhook Events
2 parents d24127c + 8c28b44 commit 3e100a6

File tree

9 files changed

+137
-14
lines changed

9 files changed

+137
-14
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package net.leanix.githubagent.dto
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
4+
5+
@JsonIgnoreProperties(ignoreUnknown = true)
6+
class GenericWebhookEvent(
7+
val action: String? = null
8+
)

src/main/kotlin/net/leanix/githubagent/handler/BrokerStompSessionHandler.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class BrokerStompSessionHandler(
1818
private val repositoryGetHandler: RepositoryGetHandler,
1919
private val installationGetHandler: InstallationGetHandler,
2020
private val fullScanHandler: FullScanHandler,
21+
private val configurationSetHandler: ConfigurationSetHandler,
2122
private val eventPublisher: ApplicationEventPublisher
2223
) : StompSessionHandlerAdapter() {
2324
@Lazy
@@ -35,6 +36,7 @@ class BrokerStompSessionHandler(
3536
session.subscribe("/user/queue/message/repository", repositoryGetHandler)
3637
session.subscribe("/user/queue/message/installation", installationGetHandler)
3738
session.subscribe("/user/queue/message/fullScan", fullScanHandler)
39+
session.subscribe("/user/queue/message/configurationSet", configurationSetHandler)
3840
eventPublisher.publishEvent(ConnectionEstablishedEvent())
3941
}
4042

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package net.leanix.githubagent.handler
2+
3+
import net.leanix.githubagent.services.GitHubWebhookService
4+
import org.slf4j.LoggerFactory
5+
import org.springframework.messaging.simp.stomp.StompFrameHandler
6+
import org.springframework.messaging.simp.stomp.StompHeaders
7+
import org.springframework.stereotype.Component
8+
import java.lang.reflect.Type
9+
10+
@Component
11+
class ConfigurationSetHandler : StompFrameHandler {
12+
13+
private val logger = LoggerFactory.getLogger(ConfigurationSetHandler::class.java)
14+
15+
override fun getPayloadType(headers: StompHeaders): Type {
16+
return AgentConfigurationRequest::class.java
17+
}
18+
19+
override fun handleFrame(headers: StompHeaders, payload: Any?) {
20+
payload?.let {
21+
val config = payload as AgentConfigurationRequest
22+
logger.info("Received configuration set message from server")
23+
runCatching {
24+
config.supportedWebhookEvents?.let { supportedEvents ->
25+
GitHubWebhookService.updateSupportedWebhookEvents(supportedEvents)
26+
logger.info(
27+
"Supported webhook events updated: ${GitHubWebhookService.getSupportedWebhookEvents()}"
28+
)
29+
}
30+
}
31+
}
32+
}
33+
}
34+
35+
data class SupportedWebhookEvent(val eventType: String, val actions: List<String>)
36+
data class AgentConfigurationRequest(val supportedWebhookEvents: List<SupportedWebhookEvent>?)

src/main/kotlin/net/leanix/githubagent/services/GitHubWebhookService.kt

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package net.leanix.githubagent.services
22

3+
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
34
import net.leanix.githubagent.config.GitHubEnterpriseProperties
5+
import net.leanix.githubagent.dto.GenericWebhookEvent
46
import net.leanix.githubagent.exceptions.InvalidEventSignatureException
57
import net.leanix.githubagent.exceptions.WebhookSecretNotSetException
6-
import net.leanix.githubagent.shared.SUPPORTED_EVENT_TYPES
8+
import net.leanix.githubagent.handler.SupportedWebhookEvent
79
import net.leanix.githubagent.shared.hmacSHA256
810
import net.leanix.githubagent.shared.timingSafeEqual
911
import org.slf4j.LoggerFactory
@@ -17,6 +19,17 @@ class GitHubWebhookService(
1719
private val cachingService: CachingService,
1820
) {
1921

22+
companion object {
23+
private var supportedWebhookEvents = listOf<SupportedWebhookEvent>()
24+
25+
fun updateSupportedWebhookEvents(events: List<SupportedWebhookEvent>) {
26+
supportedWebhookEvents = events
27+
}
28+
29+
fun getSupportedWebhookEvents(): List<SupportedWebhookEvent> = supportedWebhookEvents
30+
}
31+
32+
private val objectMapper = jacksonObjectMapper()
2033
private val logger = LoggerFactory.getLogger(GitHubWebhookService::class.java)
2134

2235
@Async
@@ -26,7 +39,10 @@ class GitHubWebhookService(
2639
logger.debug("Received a webhook event while a full sync is in progress, ignoring the event.")
2740
return
2841
}
29-
if (SUPPORTED_EVENT_TYPES.contains(eventType.uppercase())) {
42+
43+
val eventAction = extractEventAction(payload)
44+
val supportedWebhookEvent = findSupportedWebhookEvent(eventType)
45+
if (isEventSupported(supportedWebhookEvent, eventAction)) {
3046
if (!gitHubEnterpriseProperties.baseUrl.contains(host)) {
3147
logger.error("Received a webhook event from an unknown host: $host")
3248
return
@@ -49,7 +65,19 @@ class GitHubWebhookService(
4965
logger.info("Received a webhook event of type: $eventType")
5066
webhookEventService.consumeWebhookEvent(eventType, payload)
5167
} else {
52-
logger.warn("Received an unsupported event of type: $eventType")
68+
logger.warn("Received an unsupported event of type: $eventType with action: $eventAction")
5369
}
5470
}
71+
72+
private fun findSupportedWebhookEvent(eventType: String): SupportedWebhookEvent? {
73+
return getSupportedWebhookEvents().find { it.eventType.equals(eventType, ignoreCase = true) }
74+
}
75+
76+
private fun extractEventAction(payload: String): String? {
77+
return objectMapper.readValue(payload, GenericWebhookEvent::class.java).action
78+
}
79+
80+
private fun isEventSupported(event: SupportedWebhookEvent?, action: String?): Boolean {
81+
return event != null && (event.actions.isEmpty() || (action != null && action in event.actions))
82+
}
5583
}

src/main/kotlin/net/leanix/githubagent/shared/Constants.kt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,6 @@ const val TOPIC_PREFIX = "/app/ghe/"
44
const val APP_NAME_TOPIC = "appName"
55
const val LOGS_TOPIC = "logs"
66
const val MANIFEST_FILE_NAME = "leanix.yaml"
7-
const val WORKFLOW_RUN_EVENT = "WORKFLOW_RUN"
8-
const val INSTALLATION_REPOSITORIES = "INSTALLATION_REPOSITORIES"
9-
10-
val SUPPORTED_EVENT_TYPES = listOf(
11-
"REPOSITORY",
12-
"PUSH",
13-
"ORGANIZATION",
14-
"INSTALLATION",
15-
WORKFLOW_RUN_EVENT,
16-
INSTALLATION_REPOSITORIES
17-
)
187

198
val fileNameMatchRegex = Regex("/?$MANIFEST_FILE_NAME\$", RegexOption.IGNORE_CASE)
209

src/test/kotlin/net/leanix/githubagent/controllers/GitHubWebhookControllerTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.ninjasquad.springmockk.SpykBean
55
import io.mockk.every
66
import io.mockk.verify
77
import net.leanix.githubagent.exceptions.WebhookSecretNotSetException
8+
import net.leanix.githubagent.helper.defaultSupportedWebhookEvents
89
import net.leanix.githubagent.services.CachingService
910
import net.leanix.githubagent.services.GitHubWebhookService
1011
import net.leanix.githubagent.services.SyncLogService
@@ -40,6 +41,7 @@ class GitHubWebhookControllerTest {
4041
every { syncLogService.sendErrorLog(any()) } returns Unit
4142
every { cachingService.get(any()) } returns Unit
4243
every { cachingService.set(any(), any(), any()) } returns Unit
44+
GitHubWebhookService.updateSupportedWebhookEvents(defaultSupportedWebhookEvents())
4345
}
4446

4547
@Test
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package net.leanix.githubagent.handler
2+
3+
import io.mockk.mockkObject
4+
import io.mockk.verify
5+
import net.leanix.githubagent.services.GitHubWebhookService
6+
import org.junit.jupiter.api.Assertions.assertEquals
7+
import org.junit.jupiter.api.BeforeEach
8+
import org.junit.jupiter.api.Test
9+
import org.springframework.messaging.simp.stomp.StompHeaders
10+
11+
class ConfigurationSetHandlerTest {
12+
13+
private val configurationSetHandler = ConfigurationSetHandler()
14+
15+
@BeforeEach
16+
fun setUp() {
17+
mockkObject(GitHubWebhookService.Companion)
18+
}
19+
20+
@Test
21+
fun `should update supported webhook events when payload is valid`() {
22+
val headers = StompHeaders()
23+
val supportedEvents = listOf(
24+
SupportedWebhookEvent("PUSH", listOf("created", "updated")),
25+
SupportedWebhookEvent("PULL_REQUEST", listOf("opened", "closed"))
26+
)
27+
val payload = AgentConfigurationRequest(supportedWebhookEvents = supportedEvents)
28+
29+
configurationSetHandler.handleFrame(headers, payload)
30+
31+
verify { GitHubWebhookService.updateSupportedWebhookEvents(supportedEvents) }
32+
assertEquals(GitHubWebhookService.getSupportedWebhookEvents().size, supportedEvents.size)
33+
}
34+
35+
@Test
36+
fun `should not update supported webhook events when payload is null`() {
37+
val headers = StompHeaders()
38+
39+
configurationSetHandler.handleFrame(headers, null)
40+
41+
verify(exactly = 0) { GitHubWebhookService.updateSupportedWebhookEvents(any()) }
42+
}
43+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package net.leanix.githubagent.helper
2+
3+
import net.leanix.githubagent.handler.SupportedWebhookEvent
4+
5+
fun defaultSupportedWebhookEvents() =
6+
listOf(
7+
SupportedWebhookEvent("WORKFLOW_RUN", listOf("completed")),
8+
SupportedWebhookEvent("REPOSITORY", listOf("archived", "unarchived", "renamed", "edited")),
9+
SupportedWebhookEvent("INSTALLATION_REPOSITORIES", listOf("removed", "added")),
10+
SupportedWebhookEvent("PUSH", emptyList()),
11+
SupportedWebhookEvent("INSTALLATION", listOf("created")),
12+
SupportedWebhookEvent("ORGANIZATION", listOf("created"))
13+
)

src/test/kotlin/net/leanix/githubagent/services/GitHubWebhookServiceTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import io.mockk.verify
66
import net.leanix.githubagent.config.GitHubEnterpriseProperties
77
import net.leanix.githubagent.exceptions.InvalidEventSignatureException
88
import net.leanix.githubagent.exceptions.WebhookSecretNotSetException
9+
import net.leanix.githubagent.helper.defaultSupportedWebhookEvents
910
import org.junit.jupiter.api.BeforeEach
1011
import org.junit.jupiter.api.Test
1112
import org.junit.jupiter.api.assertThrows
@@ -24,6 +25,7 @@ class GitHubWebhookServiceTest {
2425
@BeforeEach
2526
fun setUp() {
2627
every { cachingService.get("runId") } returns null
28+
GitHubWebhookService.updateSupportedWebhookEvents(defaultSupportedWebhookEvents())
2729
}
2830

2931
@Test

0 commit comments

Comments
 (0)