diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/IntegrationTests/FunctionInvokeTest.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/IntegrationTests/FunctionInvokeTest.cs index 67d4d38..7642f9a 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/IntegrationTests/FunctionInvokeTest.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/IntegrationTests/FunctionInvokeTest.cs @@ -1,7 +1,9 @@ using System.Threading.Tasks; +using Ahk.GitHub.Monitor.Config; using Ahk.GitHub.Monitor.Services.EventDispatch; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; @@ -18,7 +20,8 @@ public async Task NoAppConfigsReturnsError() { var log = new Mock>(); var eds = new Mock(); - var func = new GitHubMonitorFunction(eds.Object, Options.Create(new GitHubMonitorConfig()), log.Object); + var mockConfiguration = new Mock(); + var func = new GitHubMonitorFunction(eds.Object, log.Object, mockConfiguration.Object); ObjectResult resp = await func.InvokeAndGetResponseAs(req => { }); diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/IntegrationTests/Helpers/FunctionBuilder.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/IntegrationTests/Helpers/FunctionBuilder.cs index 438e480..ab6eb1e 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/IntegrationTests/Helpers/FunctionBuilder.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/IntegrationTests/Helpers/FunctionBuilder.cs @@ -1,3 +1,4 @@ +using Ahk.GitHub.Monitor.Config; using Ahk.GitHub.Monitor.Services.EventDispatch; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -13,7 +14,5 @@ internal static class FunctionBuilder }; public static GitHubMonitorFunction Create(IEventDispatchService dispatchService = null) - => new(dispatchService ?? new Mock().Object, - Options.Create(AppConfig), - new Mock>().Object); + => new(dispatchService ?? new Mock().Object, Options.Create(AppConfig), new Mock>().Object); } diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/ConfigYamlParserTest.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/ConfigYamlParserTest.cs index 51ce1a1..bf1324c 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/ConfigYamlParserTest.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/ConfigYamlParserTest.cs @@ -1,4 +1,5 @@ using Ahk.GitHub.Monitor.EventHandlers; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Ahk.GitHub.Monitor.Tests.UnitTests; diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventDispatchServiceTest.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventDispatchServiceTest.cs index 483e91f..5967f41 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventDispatchServiceTest.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventDispatchServiceTest.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Ahk.GitHub.Monitor.EventHandlers; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Services; using Ahk.GitHub.Monitor.Services.EventDispatch; using Ahk.GitHub.Monitor.Tests.UnitTests.EventHandlersTests.Helpers; diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/ActionWorkflowRunHandlerTest.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/ActionWorkflowRunHandlerTest.cs index 797bdfe..927c309 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/ActionWorkflowRunHandlerTest.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/ActionWorkflowRunHandlerTest.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Ahk.GitHub.Monitor.EventHandlers; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Services; using Ahk.GitHub.Monitor.Tests.UnitTests.EventHandlersTests.Helpers; using Microsoft.Extensions.DependencyInjection; diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/BranchProtectionRuleHandlerTest.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/BranchProtectionRuleHandlerTest.cs index e3d6494..b15ac5a 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/BranchProtectionRuleHandlerTest.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/BranchProtectionRuleHandlerTest.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Ahk.GitHub.Monitor.EventHandlers; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Tests.UnitTests.EventHandlersTests.Helpers; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/GradeCommandHandlerTest.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/GradeCommandHandlerTest.cs index a3421a3..f6bafca 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/GradeCommandHandlerTest.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/GradeCommandHandlerTest.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Threading.Tasks; using Ahk.GitHub.Monitor.EventHandlers; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.EventHandlers.GradeComment; -using Ahk.GitHub.Monitor.EventHandlers.StatusTracking; using Ahk.GitHub.Monitor.Services; using Ahk.GitHub.Monitor.Services.GradeStore; using Ahk.GitHub.Monitor.Services.StatusTrackingStore; diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/Helpers/GitHubClientMockFactory.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/Helpers/GitHubClientMockFactory.cs index 03a2153..a034fad 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/Helpers/GitHubClientMockFactory.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/Helpers/GitHubClientMockFactory.cs @@ -49,7 +49,7 @@ public static GitHubClientMockFactory CreateDefault() public IGitHubClientFactory CreateFactory() { var factoryMock = new Mock(); - factoryMock.Setup(f => f.CreateGitHubClient(It.IsAny(), NullLogger.Instance)) + factoryMock.Setup(f => f.CreateGitHubClient(It.IsAny(), It.IsAny(), NullLogger.Instance)) .ReturnsAsync(this.GitHubClientMock.Object); return factoryMock.Object; } diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/IssueCommentEditDeleteHandlerTest.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/IssueCommentEditDeleteHandlerTest.cs index 917c416..50e011f 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/IssueCommentEditDeleteHandlerTest.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/IssueCommentEditDeleteHandlerTest.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Ahk.GitHub.Monitor.EventHandlers; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Tests.UnitTests.EventHandlersTests.Helpers; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/PullRequestOpenDuplicateHandlerTest.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/PullRequestOpenDuplicateHandlerTest.cs index d12d06f..0b54455 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/PullRequestOpenDuplicateHandlerTest.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/PullRequestOpenDuplicateHandlerTest.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Ahk.GitHub.Monitor.EventHandlers; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Tests.UnitTests.EventHandlersTests.Helpers; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/PullRequestReviewToAssigneeHandlerTest.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/PullRequestReviewToAssigneeHandlerTest.cs index 70c85e2..2b85980 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/PullRequestReviewToAssigneeHandlerTest.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/PullRequestReviewToAssigneeHandlerTest.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Ahk.GitHub.Monitor.EventHandlers; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Tests.UnitTests.EventHandlersTests.Helpers; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/PullRequestStatusTrackingHandlerTest.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/PullRequestStatusTrackingHandlerTest.cs index c15c344..52e73a0 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/PullRequestStatusTrackingHandlerTest.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/PullRequestStatusTrackingHandlerTest.cs @@ -53,3 +53,4 @@ public async Task PullRequestStatusEventIssued(string actualEventName) */ + diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/RepositoryCreateStatusTrackingHandlerTest.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/RepositoryCreateStatusTrackingHandlerTest.cs index 7bb38a7..7b442eb 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/RepositoryCreateStatusTrackingHandlerTest.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/RepositoryCreateStatusTrackingHandlerTest.cs @@ -1,11 +1,10 @@ using System; using System.Threading.Tasks; using Ahk.GitHub.Monitor.EventHandlers; -using Ahk.GitHub.Monitor.EventHandlers.StatusTracking; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Services.StatusTrackingStore; using Ahk.GitHub.Monitor.Services.StatusTrackingStore.Dto; using Ahk.GitHub.Monitor.Tests.UnitTests.EventHandlersTests.Helpers; -using Microsoft.Extensions.Logging.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; diff --git a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/RepositoryEventBaseTest.cs b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/RepositoryEventBaseTest.cs index e1478bb..c0cd0cf 100644 --- a/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/RepositoryEventBaseTest.cs +++ b/github-monitor/Ahk.GitHub.Monitor.Tests/UnitTests/EventHandlersTests/RepositoryEventBaseTest.cs @@ -1,9 +1,14 @@ +using System; +using System.Net; using System.Threading.Tasks; using Ahk.GitHub.Monitor.EventHandlers; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; +using Ahk.GitHub.Monitor.Services; using Ahk.GitHub.Monitor.Tests.UnitTests.EventHandlersTests.Helpers; -using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Caching.Memory; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using Octokit; namespace Ahk.GitHub.Monitor.Tests.UnitTests.EventHandlersTests; @@ -17,7 +22,7 @@ public async Task NonJsonPayloadReturnsError() MemoryCacheMockFactory.Instance); EventHandlerResult result = await eh.Execute("invalid payload"); - Assert.IsTrue(result.Result.Contains("payload error", System.StringComparison.InvariantCultureIgnoreCase)); + Assert.IsTrue(result.Result.Contains("payload error", StringComparison.InvariantCultureIgnoreCase)); } [TestMethod] @@ -27,7 +32,7 @@ public async Task EmptyPayloadReturnsError() MemoryCacheMockFactory.Instance); EventHandlerResult result = await eh.Execute(string.Empty); - Assert.IsTrue(result.Result.Contains("payload error", System.StringComparison.InvariantCultureIgnoreCase)); + Assert.IsTrue(result.Result.Contains("payload error", StringComparison.InvariantCultureIgnoreCase)); } [TestMethod] @@ -37,7 +42,7 @@ public async Task InvalidPayloadReturnsError() MemoryCacheMockFactory.Instance); EventHandlerResult result = await eh.Execute("{a:1}"); - Assert.IsTrue(result.Result.Contains("payload error", System.StringComparison.InvariantCultureIgnoreCase)); + Assert.IsTrue(result.Result.Contains("payload error", StringComparison.InvariantCultureIgnoreCase)); } [TestMethod] @@ -45,13 +50,13 @@ public async Task NoAhkMonitorConfigYaml1() { GitHubClientMockFactory gitHubMock = GitHubClientMockFactory.CreateCustom() .WithAhkMonitorConfigYamlContent(c => - c.ThrowsAsync(new Octokit.NotFoundException(string.Empty, System.Net.HttpStatusCode.NotFound))); + c.ThrowsAsync(new NotFoundException(string.Empty, HttpStatusCode.NotFound))); var eh = new TestHandler(gitHubMock.CreateFactory(), MemoryCacheMockFactory.Instance); EventHandlerResult result = await eh.Execute(SampleData.BranchCreate.Body); Assert.IsTrue(result.Result.Contains("no ahk-monitor.yml or disabled", - System.StringComparison.InvariantCultureIgnoreCase)); + StringComparison.InvariantCultureIgnoreCase)); gitHubMock.GitHubClientMock.Verify(c => c.Repository.Content.GetAllContentsByRef(It.IsAny(), ".github/ahk-monitor.yml", It.IsAny()), @@ -62,13 +67,13 @@ public async Task NoAhkMonitorConfigYaml1() public async Task NoAhkMonitorConfigYaml2() { GitHubClientMockFactory gitHubMock = GitHubClientMockFactory.CreateCustom() - .WithAhkMonitorConfigYamlContent(c => c.ReturnsAsync(new Octokit.RepositoryContent[0])); + .WithAhkMonitorConfigYamlContent(c => c.ReturnsAsync(new RepositoryContent[0])); var eh = new TestHandler(gitHubMock.CreateFactory(), MemoryCacheMockFactory.Instance); EventHandlerResult result = await eh.Execute(SampleData.BranchCreate.Body); Assert.IsTrue(result.Result.Contains("no ahk-monitor.yml or disabled", - System.StringComparison.InvariantCultureIgnoreCase)); + StringComparison.InvariantCultureIgnoreCase)); gitHubMock.GitHubClientMock.Verify(c => c.Repository.Content.GetAllContentsByRef(It.IsAny(), ".github/ahk-monitor.yml", It.IsAny()), @@ -86,7 +91,7 @@ public async Task AhkMonitorConfigYamlInvalid() EventHandlerResult result = await eh.Execute(SampleData.BranchCreate.Body); Assert.IsTrue(result.Result.Contains("no ahk-monitor.yml or disabled", - System.StringComparison.InvariantCultureIgnoreCase)); + StringComparison.InvariantCultureIgnoreCase)); gitHubMock.GitHubClientMock.Verify(c => c.Repository.Content.GetAllContentsByRef(It.IsAny(), ".github/ahk-monitor.yml", It.IsAny()), @@ -141,22 +146,22 @@ public async Task EnabledAndHandlerCalled() var eh = new TestHandler(gitHubMock.CreateFactory(), MemoryCacheMockFactory.Instance); EventHandlerResult result = await eh.Execute(SampleData.BranchCreate.Body); - Assert.IsTrue(result.Result.Contains("TestHandler ok", System.StringComparison.InvariantCultureIgnoreCase)); + Assert.IsTrue(result.Result.Contains("TestHandler ok", StringComparison.InvariantCultureIgnoreCase)); gitHubMock.GitHubClientMock.Verify(c => c.Repository.Content.GetAllContentsByRef(It.IsAny(), ".github/ahk-monitor.yml", It.IsAny()), Times.Once()); } - private class TestHandler : RepositoryEventBase + private class TestHandler : RepositoryEventBase { - public TestHandler(Services.IGitHubClientFactory gitHubClientFactory, - Microsoft.Extensions.Caching.Memory.IMemoryCache cache) + public TestHandler(IGitHubClientFactory gitHubClientFactory, + IMemoryCache cache) : base(gitHubClientFactory, cache, ServiceProviderMock.GetMockedObject()) { } - protected override Task executeCore(Octokit.ActivityPayload webhookPayload) => + protected override Task executeCore(ActivityPayload webhookPayload) => Task.FromResult(EventHandlerResult.ActionPerformed("TestHandler ok")); } } diff --git a/github-monitor/Ahk.GitHub.Monitor/Ahk.GitHub.Monitor.csproj b/github-monitor/Ahk.GitHub.Monitor/Ahk.GitHub.Monitor.csproj index ded152c..5e01fcf 100644 --- a/github-monitor/Ahk.GitHub.Monitor/Ahk.GitHub.Monitor.csproj +++ b/github-monitor/Ahk.GitHub.Monitor/Ahk.GitHub.Monitor.csproj @@ -26,24 +26,27 @@ + + + - - + + all runtime; build; native; contentfiles; analyzers - - - - + + + + - - - + + + - - + + diff --git a/github-monitor/Ahk.GitHub.Monitor/Config/ConfigurationBuilderExtensions.cs b/github-monitor/Ahk.GitHub.Monitor/Config/ConfigurationBuilderExtensions.cs new file mode 100644 index 0000000..8cf48b1 --- /dev/null +++ b/github-monitor/Ahk.GitHub.Monitor/Config/ConfigurationBuilderExtensions.cs @@ -0,0 +1,21 @@ +using System; +using Azure.Identity; +using Microsoft.Extensions.Configuration; + +namespace Ahk.GitHub.Monitor.Config; + +public static class ConfigurationBuilderExtensions +{ + public static IConfigurationBuilder AddAzureKeyVaultIfConfigured(this IConfigurationBuilder builder) + { + var keyVaultUri = Environment.GetEnvironmentVariable("KEY_VAULT_URI"); + + if (!string.IsNullOrEmpty(keyVaultUri)) + { + var credential = new DefaultAzureCredential(); + builder.AddAzureKeyVault(new Uri(keyVaultUri), credential); + } + + return builder; + } +} diff --git a/github-monitor/Ahk.GitHub.Monitor/Config/GitHubMonitorConfig.cs b/github-monitor/Ahk.GitHub.Monitor/Config/GitHubMonitorConfig.cs new file mode 100644 index 0000000..e443dfb --- /dev/null +++ b/github-monitor/Ahk.GitHub.Monitor/Config/GitHubMonitorConfig.cs @@ -0,0 +1,12 @@ +namespace Ahk.GitHub.Monitor.Config; + +public class GitHubMonitorConfig +{ + private static string name = "GitHubMonitorConfig"; + + public string GitHubAppId { get; set; } + public string GitHubAppPrivateKey { get; set; } + public string GitHubWebhookSecret { get; set; } + + public static string GetSectionName(string gitHubOrganisationName) => name + ":" + gitHubOrganisationName; +} diff --git a/github-monitor/Ahk.GitHub.Monitor/Config/QueueConfig.cs b/github-monitor/Ahk.GitHub.Monitor/Config/QueueConfig.cs new file mode 100644 index 0000000..aee4f35 --- /dev/null +++ b/github-monitor/Ahk.GitHub.Monitor/Config/QueueConfig.cs @@ -0,0 +1,6 @@ +namespace Ahk.GitHub.Monitor.Config; + +public class QueueConfig +{ + public string EventsQueueConnectionString { get; set; } +} diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/ActionWorkflowRunHandler.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/ActionWorkflowRunHandler.cs index 0e01bc9..0b95029 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/ActionWorkflowRunHandler.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/ActionWorkflowRunHandler.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Services; using Microsoft.Extensions.Caching.Memory; using Octokit; diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/ConfigYamlParser.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/ConfigYamlParser.cs similarity index 95% rename from github-monitor/Ahk.GitHub.Monitor/EventHandlers/ConfigYamlParser.cs rename to github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/ConfigYamlParser.cs index 22fe86c..ae11585 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/ConfigYamlParser.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/ConfigYamlParser.cs @@ -1,7 +1,7 @@ using System; using System.Text.RegularExpressions; -namespace Ahk.GitHub.Monitor.EventHandlers; +namespace Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; internal static class ConfigYamlParser { diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/EventHandlerResult.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/EventHandlerResult.cs similarity index 92% rename from github-monitor/Ahk.GitHub.Monitor/EventHandlers/EventHandlerResult.cs rename to github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/EventHandlerResult.cs index c34018f..eb23bb4 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/EventHandlerResult.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/EventHandlerResult.cs @@ -1,4 +1,4 @@ -namespace Ahk.GitHub.Monitor.EventHandlers; +namespace Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; public class EventHandlerResult(string result) { diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/IGitHubEventHandler.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/IGitHubEventHandler.cs similarity index 84% rename from github-monitor/Ahk.GitHub.Monitor/EventHandlers/IGitHubEventHandler.cs rename to github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/IGitHubEventHandler.cs index 4acfc78..d6f01fd 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/IGitHubEventHandler.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/IGitHubEventHandler.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -namespace Ahk.GitHub.Monitor.EventHandlers; +namespace Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; [System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Event is a GitHub terminology in this context.")] diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/PayloadParser.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/PayloadParser.cs new file mode 100644 index 0000000..62a2f3b --- /dev/null +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/PayloadParser.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.Extensions.Logging; +using Octokit; +using Octokit.Internal; + +namespace Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; + +public class PayloadParser + where TPayload : ActivityPayload +{ + public static bool TryParsePayload(string requestBody, out TPayload payload, out EventHandlerResult errorResult, ILogger logger) + { + payload = null; + if (string.IsNullOrEmpty(requestBody)) + { + errorResult = EventHandlerResult.PayloadError("request body was empty"); + logger.LogError("request body was empty"); + return false; + } + + try + { + payload = new SimpleJsonSerializer().Deserialize(requestBody); + } + catch (Exception ex) + { + errorResult = EventHandlerResult.PayloadError($"request body deserialization failed: {ex.Message}"); + logger.LogError(ex, "request body deserialization failed"); + return false; + } + + if (payload == null) + { + errorResult = EventHandlerResult.PayloadError("parsed payload was null or empty"); + logger.LogError("parsed payload was null or empty"); + return false; + } + + if (payload.Repository == null) + { + errorResult = EventHandlerResult.PayloadError("no repository information in webhook payload"); + logger.LogError("no repository information in webhook payload"); + return false; + } + + errorResult = null; + return true; + } +} diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/RepositoryEventBase.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/RepositoryEventBase.cs similarity index 69% rename from github-monitor/Ahk.GitHub.Monitor/EventHandlers/RepositoryEventBase.cs rename to github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/RepositoryEventBase.cs index 01cdd1e..2708586 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/RepositoryEventBase.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BaseAndUtils/RepositoryEventBase.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Services; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Octokit; -using Octokit.Internal; namespace Ahk.GitHub.Monitor.EventHandlers; @@ -23,12 +23,14 @@ public abstract class RepositoryEventBase( public async Task Execute(string requestBody) { - if (!this.tryParsePayload(requestBody, out TPayload webhookPayload, out EventHandlerResult errorResult)) + if (!PayloadParser.TryParsePayload(requestBody, out TPayload webhookPayload, + out EventHandlerResult errorResult, Logger)) { return errorResult; } - this.GitHubClient = await gitHubClientFactory.CreateGitHubClient(webhookPayload.Installation.Id, Logger); + this.GitHubClient = await gitHubClientFactory.CreateGitHubClient( + webhookPayload.Repository.Owner.Login, webhookPayload.Installation.Id, Logger); if (!await this.isEnabledForRepository(webhookPayload)) { @@ -41,45 +43,6 @@ public async Task Execute(string requestBody) protected abstract Task executeCore(TPayload webhookPayload); - protected bool tryParsePayload(string requestBody, out TPayload payload, out EventHandlerResult errorResult) - { - payload = null; - if (string.IsNullOrEmpty(requestBody)) - { - errorResult = EventHandlerResult.PayloadError("request body was empty"); - Logger.LogError("request body was empty"); - return false; - } - - try - { - payload = new SimpleJsonSerializer().Deserialize(requestBody); - } - catch (Exception ex) - { - errorResult = EventHandlerResult.PayloadError($"request body deserialization failed: {ex.Message}"); - Logger.LogError(ex, "request body deserialization failed"); - return false; - } - - if (payload == null) - { - errorResult = EventHandlerResult.PayloadError("parsed payload was null or empty"); - Logger.LogError("parsed payload was null or empty"); - return false; - } - - if (payload.Repository == null) - { - errorResult = EventHandlerResult.PayloadError("no repository information in webhook payload"); - Logger.LogError("no repository information in webhook payload"); - return false; - } - - errorResult = null; - return true; - } - protected Task isUserOrganizationMember(TPayload webhookPayload, string username) { if (webhookPayload.Repository.Owner.Type != AccountType.Organization) diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BranchProtectionRuleHandler.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BranchProtectionRuleHandler.cs index 72a6daf..efe54f9 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BranchProtectionRuleHandler.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/BranchProtectionRuleHandler.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Services; using Microsoft.Extensions.Caching.Memory; using Octokit; @@ -28,8 +29,8 @@ await this.GitHubClient.Repository.Branch.UpdateBranchProtection( return EventHandlerResult.ActionPerformed("branch protection rule applied"); } - private static BranchProtectionSettingsUpdate getBranchProtectionSettingsUpdate(string branchName, - string repositoryDefaultBranch) => + private static BranchProtectionSettingsUpdate getBranchProtectionSettingsUpdate( + string branchName, string repositoryDefaultBranch) => // For default: prohibits the merge request into default to be merged // For other branches: disables force push new( diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/GradeComment/GradeCommandHandlerBase.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/GradeComment/GradeCommandHandlerBase.cs index aaac3cc..d4cfa67 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/GradeComment/GradeCommandHandlerBase.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/GradeComment/GradeCommandHandlerBase.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.EventHandlers.GradeComment.Payload; -using Ahk.GitHub.Monitor.EventHandlers.StatusTracking; using Ahk.GitHub.Monitor.Helpers; using Ahk.GitHub.Monitor.Services; using Ahk.GitHub.Monitor.Services.GradeStore; diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/GradeComment/GradeCommandIssueCommentHandler.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/GradeComment/GradeCommandIssueCommentHandler.cs index fc5cef5..51c3217 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/GradeComment/GradeCommandIssueCommentHandler.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/GradeComment/GradeCommandIssueCommentHandler.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.EventHandlers.GradeComment.Payload; -using Ahk.GitHub.Monitor.EventHandlers.StatusTracking; using Ahk.GitHub.Monitor.Services; using Ahk.GitHub.Monitor.Services.GradeStore; using Microsoft.Extensions.Caching.Memory; diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/GradeComment/GradeCommandReviewCommentHandler.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/GradeComment/GradeCommandReviewCommentHandler.cs index bfb1d3b..2c1e758 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/GradeComment/GradeCommandReviewCommentHandler.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/GradeComment/GradeCommandReviewCommentHandler.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.EventHandlers.GradeComment.Payload; -using Ahk.GitHub.Monitor.EventHandlers.StatusTracking; using Ahk.GitHub.Monitor.Services; using Ahk.GitHub.Monitor.Services.GradeStore; using Microsoft.Extensions.Caching.Memory; diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/IssueCommentEditDeleteHandler.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/IssueCommentEditDeleteHandler.cs index e68a14f..e782f79 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/IssueCommentEditDeleteHandler.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/IssueCommentEditDeleteHandler.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Services; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/PullRequestOpenDuplicateHandler.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/PullRequestOpenDuplicateHandler.cs index 14e615f..e76ae8c 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/PullRequestOpenDuplicateHandler.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/PullRequestOpenDuplicateHandler.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Services; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/PullRequestReviewToAssigneeHandler.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/PullRequestReviewToAssigneeHandler.cs index 6f575fb..c98791b 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/PullRequestReviewToAssigneeHandler.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/PullRequestReviewToAssigneeHandler.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Services; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/StatusTracking/PullRequestStatusTrackingHandler.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/PullRequestStatusTrackingHandler.cs similarity index 97% rename from github-monitor/Ahk.GitHub.Monitor/EventHandlers/StatusTracking/PullRequestStatusTrackingHandler.cs rename to github-monitor/Ahk.GitHub.Monitor/EventHandlers/PullRequestStatusTrackingHandler.cs index 8f408e7..06058f5 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/StatusTracking/PullRequestStatusTrackingHandler.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/PullRequestStatusTrackingHandler.cs @@ -1,13 +1,14 @@ using System; using System.Linq; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Services; using Ahk.GitHub.Monitor.Services.StatusTrackingStore; using Ahk.GitHub.Monitor.Services.StatusTrackingStore.Dto; using Microsoft.Extensions.Caching.Memory; using Octokit; -namespace Ahk.GitHub.Monitor.EventHandlers.StatusTracking; +namespace Ahk.GitHub.Monitor.EventHandlers; public class PullRequestStatusTrackingHandler( IGitHubClientFactory gitHubClientFactory, diff --git a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/StatusTracking/RepositoryCreateStatusTrackingHandler.cs b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/RepositoryCreateStatusTrackingHandler.cs similarity index 92% rename from github-monitor/Ahk.GitHub.Monitor/EventHandlers/StatusTracking/RepositoryCreateStatusTrackingHandler.cs rename to github-monitor/Ahk.GitHub.Monitor/EventHandlers/RepositoryCreateStatusTrackingHandler.cs index 02e264b..969b088 100644 --- a/github-monitor/Ahk.GitHub.Monitor/EventHandlers/StatusTracking/RepositoryCreateStatusTrackingHandler.cs +++ b/github-monitor/Ahk.GitHub.Monitor/EventHandlers/RepositoryCreateStatusTrackingHandler.cs @@ -1,13 +1,13 @@ using System; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Services; using Ahk.GitHub.Monitor.Services.StatusTrackingStore; using Ahk.GitHub.Monitor.Services.StatusTrackingStore.Dto; using Microsoft.Extensions.Caching.Memory; -using Microsoft.Extensions.Logging; using Octokit; -namespace Ahk.GitHub.Monitor.EventHandlers.StatusTracking; +namespace Ahk.GitHub.Monitor.EventHandlers; public class RepositoryCreateStatusTrackingHandler( IGitHubClientFactory gitHubClientFactory, @@ -21,7 +21,6 @@ public class RepositoryCreateStatusTrackingHandler( protected override async Task executeCore(CreateEventPayload webhookPayload) => await this.processRepositoryCreateEvent(webhookPayload); - private async Task processRepositoryCreateEvent(CreateEventPayload webhookPayload) { var repositoryUrl = webhookPayload.Repository.HtmlUrl; diff --git a/github-monitor/Ahk.GitHub.Monitor/GitHubMonitorConfig.cs b/github-monitor/Ahk.GitHub.Monitor/GitHubMonitorConfig.cs deleted file mode 100644 index f90daef..0000000 --- a/github-monitor/Ahk.GitHub.Monitor/GitHubMonitorConfig.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ahk.GitHub.Monitor; - -public class GitHubMonitorConfig -{ - public string GitHubAppId { get; set; } - public string GitHubAppPrivateKey { get; set; } - public string GitHubWebhookSecret { get; set; } - - public string EventsQueueConnectionString { get; set; } -} diff --git a/github-monitor/Ahk.GitHub.Monitor/GitHubMonitorFunction.cs b/github-monitor/Ahk.GitHub.Monitor/GitHubMonitorFunction.cs index 38e1e83..a65cd33 100644 --- a/github-monitor/Ahk.GitHub.Monitor/GitHubMonitorFunction.cs +++ b/github-monitor/Ahk.GitHub.Monitor/GitHubMonitorFunction.cs @@ -2,45 +2,30 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.Config; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Ahk.GitHub.Monitor.Helpers; -using Ahk.GitHub.Monitor.Services; using Ahk.GitHub.Monitor.Services.EventDispatch; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; +using Octokit; namespace Ahk.GitHub.Monitor; public class GitHubMonitorFunction( IEventDispatchService eventDispatchService, - IOptions config, - ILogger logger) + ILogger logger, + IConfiguration configuration) { [Function("github-webhook")] public async Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequestData request) { - if (string.IsNullOrEmpty(config.Value.GitHubWebhookSecret)) - { - return new ObjectResult(new { error = "GitHub secret not configured" }) - { - StatusCode = StatusCodes.Status500InternalServerError - }; - } - - if (string.IsNullOrEmpty(config.Value.GitHubAppId) || - string.IsNullOrEmpty(config.Value.GitHubAppPrivateKey)) - { - return new ObjectResult(new { error = "GitHub App ID/Token not configured" }) - { - StatusCode = StatusCodes.Status500InternalServerError - }; - } - request.Headers.TryGetValues("X-GitHub-Event", out IEnumerable eventNameValues); var eventName = eventNameValues?.FirstOrDefault(); request.Headers.TryGetValues("X-GitHub-Delivery", out IEnumerable deliveryIdValues); @@ -63,8 +48,36 @@ public async Task Run( } var requestBody = await request.ReadAsStringAsync(); + if (!PayloadParser.TryParsePayload(requestBody, out ActivityPayload parsedRequestBody, + out EventHandlerResult errorResult, logger)) + { + return new BadRequestObjectResult(new { error = errorResult.Result }); + } + + var orgName = parsedRequestBody.Repository.Owner.Login; + + var orgConfig = new GitHubMonitorConfig(); + configuration.GetSection(GitHubMonitorConfig.GetSectionName(orgName)).Bind(orgConfig); + + if (string.IsNullOrEmpty(orgConfig.GitHubWebhookSecret)) + { + return new ObjectResult(new { error = "GitHub secret not configured" }) + { + StatusCode = StatusCodes.Status500InternalServerError + }; + } + + if (string.IsNullOrEmpty(orgConfig.GitHubAppId) || + string.IsNullOrEmpty(orgConfig.GitHubAppPrivateKey)) + { + return new ObjectResult(new { error = "GitHub App ID/Token not configured" }) + { + StatusCode = StatusCodes.Status500InternalServerError + }; + } + if (!GitHubSignatureValidator.IsSignatureValid(requestBody, receivedSignature, - config.Value.GitHubWebhookSecret)) + orgConfig.GitHubWebhookSecret)) { return new BadRequestObjectResult(new { error = "Payload signature not valid" }); } diff --git a/github-monitor/Ahk.GitHub.Monitor/Program.cs b/github-monitor/Ahk.GitHub.Monitor/Program.cs index 92b7123..5f1acf7 100644 --- a/github-monitor/Ahk.GitHub.Monitor/Program.cs +++ b/github-monitor/Ahk.GitHub.Monitor/Program.cs @@ -1,9 +1,9 @@ #pragma warning disable CA1506 using System; using Ahk.GitHub.Monitor; +using Ahk.GitHub.Monitor.Config; using Ahk.GitHub.Monitor.EventHandlers; using Ahk.GitHub.Monitor.EventHandlers.GradeComment; -using Ahk.GitHub.Monitor.EventHandlers.StatusTracking; using Ahk.GitHub.Monitor.Services; using Ahk.GitHub.Monitor.Services.AzureQueues; using Ahk.GitHub.Monitor.Services.EventDispatch; @@ -11,6 +11,7 @@ using Ahk.GitHub.Monitor.Services.GradeStore; using Ahk.GitHub.Monitor.Services.StatusTrackingStore; using Azure.Core; +using Azure.Identity; using Azure.Storage.Queues; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Azure; @@ -20,18 +21,26 @@ IHost host = new HostBuilder() .ConfigureFunctionsWebApplication() + .ConfigureAppConfiguration((context, config) => + { + var builtConfig = config.Build(); // Build early to get settings + var keyVaultUrl = builtConfig["KEY_VAULT_URI"]; // Ensure you have this in env variables + + if (!string.IsNullOrEmpty(keyVaultUrl)) + { + config.AddAzureKeyVault( + new Uri(keyVaultUrl), + new DefaultAzureCredential()); + } + }) .ConfigureServices((context, services) => { // Application Insights setup services.AddApplicationInsightsTelemetryWorkerService(); services.ConfigureFunctionsApplicationInsights(); - // Load configuration from environment variables with the prefix "AHK_" - IConfigurationRoot configuration = new ConfigurationBuilder() - .AddEnvironmentVariables("AHK_") - .Build(); - - services.AddLogging(); // Register logging services + // Register logging services + services.AddLogging(); // Add memory cache with a specific expiration scan frequency services.AddMemoryCache(setup => @@ -40,17 +49,15 @@ }); // Register services - services - .AddSingleton(); + services.AddSingleton(); RegisterEventHandlers(services); - services - .AddSingleton(); + services.AddSingleton(); - // Bind configuration - services.Configure(configuration); + // Load configuration from environment variables with the prefix "AHK_" + IConfigurationRoot configuration = new ConfigurationBuilder() + .AddEnvironmentVariables("AHK_") + .Build(); // Add Azure Queue integration based on configuration AddAzureQueueIntegration(services, configuration); @@ -77,9 +84,9 @@ void RegisterEventHandlers(IServiceCollection services) void AddAzureQueueIntegration(IServiceCollection services, IConfiguration configuration) { - GitHubMonitorConfig config = configuration.Get(); + QueueConfig queueConfig = configuration.Get(); - if (!string.IsNullOrEmpty(config?.EventsQueueConnectionString)) + if (!string.IsNullOrEmpty(queueConfig?.EventsQueueConnectionString)) { services .AddSingleton(); @@ -90,7 +97,7 @@ void AddAzureQueueIntegration(IServiceCollection services, IConfiguration config services.AddAzureClients(az => { az.ConfigureDefaults(opts => opts.Diagnostics.IsLoggingEnabled = false); - az.AddQueueServiceClient(config.EventsQueueConnectionString) + az.AddQueueServiceClient(queueConfig.EventsQueueConnectionString) .WithName(QueueClientName.Name) .ConfigureOptions(options => { diff --git a/github-monitor/Ahk.GitHub.Monitor/Services/EventDispatch/EventDispatchConfigBuilder.cs b/github-monitor/Ahk.GitHub.Monitor/Services/EventDispatch/EventDispatchConfigBuilder.cs index 02ab8c1..a1357cb 100644 --- a/github-monitor/Ahk.GitHub.Monitor/Services/EventDispatch/EventDispatchConfigBuilder.cs +++ b/github-monitor/Ahk.GitHub.Monitor/Services/EventDispatch/EventDispatchConfigBuilder.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Ahk.GitHub.Monitor.EventHandlers; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Microsoft.Extensions.DependencyInjection; namespace Ahk.GitHub.Monitor.Services.EventDispatch; diff --git a/github-monitor/Ahk.GitHub.Monitor/Services/EventDispatch/EventDispatchService.cs b/github-monitor/Ahk.GitHub.Monitor/Services/EventDispatch/EventDispatchService.cs index 0dad25b..e5b5dca 100644 --- a/github-monitor/Ahk.GitHub.Monitor/Services/EventDispatch/EventDispatchService.cs +++ b/github-monitor/Ahk.GitHub.Monitor/Services/EventDispatch/EventDispatchService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Ahk.GitHub.Monitor.EventHandlers; +using Ahk.GitHub.Monitor.EventHandlers.BaseAndUtils; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -57,7 +58,7 @@ private async Task executeHandler(string requestBody, WebhookResult webhookResul { var handler = ActivatorUtilities.CreateInstance( - serviceProvider, handlerType) as EventHandlers.IGitHubEventHandler; + serviceProvider, handlerType) as IGitHubEventHandler; EventHandlerResult handlerResult = await handler.Execute(requestBody); logger.LogInformation($"{handlerType.Name} result: {handlerResult.Result}"); diff --git a/github-monitor/Ahk.GitHub.Monitor/Services/GitHubClientFactory/GitHubClientFactory.cs b/github-monitor/Ahk.GitHub.Monitor/Services/GitHubClientFactory/GitHubClientFactory.cs index d4009a1..0febb2d 100644 --- a/github-monitor/Ahk.GitHub.Monitor/Services/GitHubClientFactory/GitHubClientFactory.cs +++ b/github-monitor/Ahk.GitHub.Monitor/Services/GitHubClientFactory/GitHubClientFactory.cs @@ -1,51 +1,55 @@ using System; +using System.Globalization; using System.IdentityModel.Tokens.Jwt; using System.Net.Http; using System.Net.Http.Headers; using System.Security.Claims; using System.Security.Cryptography; using System.Threading.Tasks; +using Ahk.GitHub.Monitor.Config; using Ahk.GitHub.Monitor.Extensions; using Ahk.GitHub.Monitor.Helpers; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json.Linq; using Octokit; +using Octokit.Internal; +using ProductHeaderValue = Octokit.ProductHeaderValue; namespace Ahk.GitHub.Monitor.Services.GitHubClientFactory; /// /// Based on https://thomaslevesque.com/2018/03/30/writing-a-github-webhook-as-an-azure-function/. /// -public class GitHubClientFactory(IMemoryCache cache, IOptions config) : IGitHubClientFactory +public class GitHubClientFactory(IMemoryCache cache, IConfiguration configuration) : IGitHubClientFactory { - public async Task CreateGitHubClient(long installationId, ILogger logger) + public async Task CreateGitHubClient(string gitHubOrg, long installationId, ILogger logger) { var token = await cache.GetOrCreateAsync( $"githubtokenforinstallation_{installationId}", async cacheEntry => { - var token = await this.getInstallationToken(installationId, logger); + var token = await this.getInstallationToken(gitHubOrg, installationId, logger); cacheEntry.SetValue(token); cacheEntry.SetAbsoluteExpiration(TimeSpan.FromMinutes(5)); return token; }); #pragma warning disable CA2000 // Dispose objects before losing scope - var httpHandler = new Octokit.Internal.HttpClientAdapter(() => + var httpHandler = new HttpClientAdapter(() => new ResponseLoggerHandler( - new RetryOnServerErrorHandler(Octokit.Internal.HttpMessageHandlerFactory.CreateDefault()), logger)); + new RetryOnServerErrorHandler(HttpMessageHandlerFactory.CreateDefault()), logger)); #pragma warning restore CA2000 // Dispose objects before losing scope // Connection creation based on what the GitHubClient ctor does var githubConnection = new Connection( - new Octokit.ProductHeaderValue("Ahk"), + new ProductHeaderValue("Ahk"), GitHubClient.GitHubApiUrl, - new Octokit.Internal.InMemoryCredentialStore(new Credentials(token)), + new InMemoryCredentialStore(new Credentials(token)), httpHandler, - new Octokit.Internal.SimpleJsonSerializer()); + new SimpleJsonSerializer()); var gitHubClient = new GitHubClient(githubConnection); gitHubClient.SetRequestTimeout(TimeSpan.FromSeconds(15)); @@ -53,9 +57,9 @@ public async Task CreateGitHubClient(long installationId, ILogger return gitHubClient; } - private async Task getInstallationToken(long installationId, ILogger logger) + private async Task getInstallationToken(string gitHubOrg, long installationId, ILogger logger) { - var applicationToken = this.getApplicationToken(); + var applicationToken = this.getApplicationToken(gitHubOrg); using var client = new HttpClient(); using var request = new HttpRequestMessage(HttpMethod.Post, $"https://api.github.com/app/installations/{installationId}/access_tokens"); @@ -79,21 +83,24 @@ private async Task getInstallationToken(long installationId, ILogger log return obj["token"]?.Value(); } - private string getApplicationToken() + private string getApplicationToken(string gitHubOrg) { - RSAParameters parameters = CryptoHelper.GetRsaParameters(config.Value.GitHubAppPrivateKey); + var orgConfig = new GitHubMonitorConfig(); + configuration.GetSection(GitHubMonitorConfig.GetSectionName(gitHubOrg)).Bind(orgConfig); + + RSAParameters parameters = CryptoHelper.GetRsaParameters(orgConfig.GitHubAppPrivateKey); var key = new RsaSecurityKey(parameters); var creds = new SigningCredentials(key, SecurityAlgorithms.RsaSha256); DateTime now = DateTime.UtcNow; var token = new JwtSecurityToken( claims: [ - new Claim("iat", now.ToUnixTimeStamp().ToString(System.Globalization.CultureInfo.InvariantCulture), + new Claim("iat", now.ToUnixTimeStamp().ToString(CultureInfo.InvariantCulture), ClaimValueTypes.Integer), new Claim("exp", now.AddMinutes(10).ToUnixTimeStamp() - .ToString(System.Globalization.CultureInfo.InvariantCulture), ClaimValueTypes.Integer), - new Claim("iss", config.Value.GitHubAppId, ClaimValueTypes.Integer) + .ToString(CultureInfo.InvariantCulture), ClaimValueTypes.Integer), + new Claim("iss", orgConfig.GitHubAppId, ClaimValueTypes.Integer) ], signingCredentials: creds); diff --git a/github-monitor/Ahk.GitHub.Monitor/Services/GitHubClientFactory/IGitHubClientFactory.cs b/github-monitor/Ahk.GitHub.Monitor/Services/GitHubClientFactory/IGitHubClientFactory.cs index 0b304f9..3106ecb 100644 --- a/github-monitor/Ahk.GitHub.Monitor/Services/GitHubClientFactory/IGitHubClientFactory.cs +++ b/github-monitor/Ahk.GitHub.Monitor/Services/GitHubClientFactory/IGitHubClientFactory.cs @@ -6,5 +6,5 @@ namespace Ahk.GitHub.Monitor.Services; public interface IGitHubClientFactory { - Task CreateGitHubClient(long installationId, ILogger logger); + Task CreateGitHubClient(string gitHubOrg, long installationId, ILogger logger); }