diff --git a/.github/workflows/docker-ci.yml b/.github/workflows/docker-ci.txt similarity index 81% rename from .github/workflows/docker-ci.yml rename to .github/workflows/docker-ci.txt index fb6c23d..768c58a 100644 --- a/.github/workflows/docker-ci.yml +++ b/.github/workflows/docker-ci.txt @@ -11,6 +11,8 @@ jobs: steps: - name: 'Checkout' uses: actions/checkout@v4 + with: + persist-credentials: false - name: 'Setup .NET' uses: actions/setup-dotnet@v4 @@ -32,6 +34,8 @@ jobs: steps: - name: 'Checkout' uses: actions/checkout@v4 + with: + persist-credentials: false - name: 'Login via Azure CLI' uses: azure/login@v1 @@ -53,9 +57,12 @@ jobs: - run: | docker build . \ - --build-arg GIT_SHA=${{ steps.commit.outputs.sha }} \ - --build-arg "GIT_COMMIT_MSG=${{ steps.commit.outputs.msg }}" \ + --build-arg GIT_SHA=${STEPS_COMMIT_OUTPUTS_SHA} \ + --build-arg "GIT_COMMIT_MSG=${STEPS_COMMIT_OUTPUTS_MSG}" \ -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/thesexy6bot:${{ github.sha }} \ -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/thesexy6bot:latest docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}/thesexy6bot:${{ github.sha }} docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}/thesexy6bot:latest + env: + STEPS_COMMIT_OUTPUTS_SHA: ${{ steps.commit.outputs.sha }} + STEPS_COMMIT_OUTPUTS_MSG: ${{ steps.commit.outputs.msg }} diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml index 9f49726..4d6c8c4 100644 --- a/.github/workflows/pr-validation.yml +++ b/.github/workflows/pr-validation.yml @@ -1,26 +1,146 @@ name: PR Validation +permissions: {} + on: pull_request: branches: [main] jobs: - test: + changes: + permissions: + pull-requests: read + runs-on: ubuntu-latest + outputs: + terraform: ${{ steps.filter.outputs.terraform }} + github: ${{ steps.filter.outputs.github }} + steps: + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d + id: filter + with: + filters: | + terraform: + - 'src/terraform/**' + github: + - '.github/**' + + + zizmor-scan: + runs-on: ubuntu-latest + permissions: + contents: read + needs: changes + if: needs.changes.outputs.github == 'true' + steps: + - name: Sparse Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 1 + sparse-checkout: | + .github + sparse-checkout-cone-mode: true + persist-credentials: false + + - name: Zizmor Scan + uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 + with: + advanced-security: false + inputs: + .github + fail-on-no-inputs: true + + + terraform-plan: + permissions: + id-token: write + contents: read + environment: stg + runs-on: ubuntu-latest + needs: changes + if: needs.changes.outputs.terraform == 'true' + env: + ARM_USE_OIDC: true + ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + steps: + - name: Checkout Terraform files only + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 1 + sparse-checkout: | + src/terraform + sparse-checkout-cone-mode: true + persist-credentials: false + + - name: Token replace Terraform env vars + env: + ENVIRONMENT: ${{ vars.NAME_PREFIX }} + run: | + sed "s|__ENVIRONMENT__|${ENVIRONMENT}|g" \ + src/terraform/environment.tfvars \ + > src/terraform/environment.auto.tfvars + + - name: Azure Login + uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + enable-AzPSSession: true + - name: Setup Terraform + uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd + with: + terraform_version: 1.9.8 + - name: Terraform Init + run: | + terraform -chdir=src/terraform init -input=false \ + -backend-config="resource_group_name=${VARS_TFSTATE_RESOURCE_GROUP}" \ + -backend-config="storage_account_name=${VARS_TFSTATE_STORAGE_ACCOUNT}" \ + -backend-config="container_name=${VARS_TFSTATE_CONTAINER}" \ + -backend-config="key=${VARS_TFSTATE_KEY}" \ + env: + VARS_TFSTATE_RESOURCE_GROUP: ${{ vars.TFSTATE_RESOURCE_GROUP}} + VARS_TFSTATE_STORAGE_ACCOUNT: ${{ vars.TFSTATE_STORAGE_ACCOUNT}} + VARS_TFSTATE_CONTAINER: ${{ vars.TFSTATE_CONTAINER}} + VARS_TFSTATE_KEY: ${{ vars.TFSTATE_KEY}} + + - name: Terraform Plan + run: terraform -chdir=src/terraform plan -input=false -no-color + + + test-dotnet: + permissions: + contents: read runs-on: ubuntu-latest steps: - name: 'Checkout' - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: 'Setup .NET' - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: dotnet-version: '9.0.x' - name: 'Restore dependencies' - run: dotnet restore TheSexy6BotWorker.sln + run: dotnet restore TheSexy6BotWorker.slnx - name: 'Build' - run: dotnet build TheSexy6BotWorker.sln --no-restore + run: dotnet build TheSexy6BotWorker.slnx --no-restore - name: 'Test' - run: dotnet test TheSexy6BotWorker.sln --no-build --verbosity normal --filter "Category!=Integration" + run: dotnet test TheSexy6BotWorker.slnx --no-build --verbosity normal --filter "Category!=Integration" + + status-check: + if: ${{ always() }} + needs: [test-dotnet, terraform-plan, zizmor-scan] + runs-on: ubuntu-latest + steps: + - name: Fail if required jobs failed + run: | + echo "dotnet=${{ needs.test-dotnet.result }}" + echo "terraform=${{ needs.terraform-plan.result }}" + echo "zizmor=${{ needs.zizmor-scan.result }}" + test "${{ needs.test-dotnet.result }}" = "success" + test "${{ needs.terraform-plan.result }}" = "success" -o "${{ needs.terraform-plan.result }}" = "skipped" + test "${{ needs.zizmor-scan.result }}" = "success" -o "${{ needs.zizmor-scan.result }}" = "skipped" diff --git a/.github/workflows/uks-discordbot-capp-AutoDeployTrigger-1d9d2bc7-25ca-4498-aade-a6f0d0ff776e.yml b/.github/workflows/uks-discordbot-capp-AutoDeployTrigger-1d9d2bc7-25ca-4498-aade-a6f0d0ff776e.yml index 38e626c..311907b 100644 --- a/.github/workflows/uks-discordbot-capp-AutoDeployTrigger-1d9d2bc7-25ca-4498-aade-a6f0d0ff776e.yml +++ b/.github/workflows/uks-discordbot-capp-AutoDeployTrigger-1d9d2bc7-25ca-4498-aade-a6f0d0ff776e.yml @@ -45,7 +45,7 @@ jobs: COMMIT_MSG_SAFE="$(git log -1 --pretty=%s | tr -cs '[:alnum:]._+-' '-')" echo "msg_safe=${COMMIT_MSG_SAFE}" >> $GITHUB_OUTPUT - - name: Azure Login + - name : Azure Login uses: azure/login@v2 with: client-id: ${{ secrets.UKSDISCORDBOTCAPP_AZURE_CLIENT_ID }} diff --git a/.gitignore b/.gitignore index 74a6897..a14dd53 100644 --- a/.gitignore +++ b/.gitignore @@ -363,4 +363,11 @@ MigrationBackup/ FodyWeavers.xsd # TheSexy6BotWorker -.env \ No newline at end of file +.env + +#terraform + +src/terraform/.terraform* +.terraform.lock.hcl + +*terraform.tfstate* \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..54a23de --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "chat.tools.terminal.autoApprove": { + "terraform": true + } +} \ No newline at end of file diff --git a/TheSexy6BotWorker.sln b/TheSexy6BotWorker.sln deleted file mode 100644 index 8a7ecbf..0000000 --- a/TheSexy6BotWorker.sln +++ /dev/null @@ -1,51 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.2.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheSexy6BotWorker", "TheSexy6BotWorker\TheSexy6BotWorker.csproj", "{277B9C4A-C549-A038-445C-2F6BB26DE6D6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheSexy6BotWorker.Tests", "TheSexy6BotWorker.Tests\TheSexy6BotWorker.Tests.csproj", "{3B1E557F-5E60-4E4B-8917-3BBAAA998C93}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {277B9C4A-C549-A038-445C-2F6BB26DE6D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {277B9C4A-C549-A038-445C-2F6BB26DE6D6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {277B9C4A-C549-A038-445C-2F6BB26DE6D6}.Debug|x64.ActiveCfg = Debug|Any CPU - {277B9C4A-C549-A038-445C-2F6BB26DE6D6}.Debug|x64.Build.0 = Debug|Any CPU - {277B9C4A-C549-A038-445C-2F6BB26DE6D6}.Debug|x86.ActiveCfg = Debug|Any CPU - {277B9C4A-C549-A038-445C-2F6BB26DE6D6}.Debug|x86.Build.0 = Debug|Any CPU - {277B9C4A-C549-A038-445C-2F6BB26DE6D6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {277B9C4A-C549-A038-445C-2F6BB26DE6D6}.Release|Any CPU.Build.0 = Release|Any CPU - {277B9C4A-C549-A038-445C-2F6BB26DE6D6}.Release|x64.ActiveCfg = Release|Any CPU - {277B9C4A-C549-A038-445C-2F6BB26DE6D6}.Release|x64.Build.0 = Release|Any CPU - {277B9C4A-C549-A038-445C-2F6BB26DE6D6}.Release|x86.ActiveCfg = Release|Any CPU - {277B9C4A-C549-A038-445C-2F6BB26DE6D6}.Release|x86.Build.0 = Release|Any CPU - {3B1E557F-5E60-4E4B-8917-3BBAAA998C93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3B1E557F-5E60-4E4B-8917-3BBAAA998C93}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3B1E557F-5E60-4E4B-8917-3BBAAA998C93}.Debug|x64.ActiveCfg = Debug|Any CPU - {3B1E557F-5E60-4E4B-8917-3BBAAA998C93}.Debug|x64.Build.0 = Debug|Any CPU - {3B1E557F-5E60-4E4B-8917-3BBAAA998C93}.Debug|x86.ActiveCfg = Debug|Any CPU - {3B1E557F-5E60-4E4B-8917-3BBAAA998C93}.Debug|x86.Build.0 = Debug|Any CPU - {3B1E557F-5E60-4E4B-8917-3BBAAA998C93}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3B1E557F-5E60-4E4B-8917-3BBAAA998C93}.Release|Any CPU.Build.0 = Release|Any CPU - {3B1E557F-5E60-4E4B-8917-3BBAAA998C93}.Release|x64.ActiveCfg = Release|Any CPU - {3B1E557F-5E60-4E4B-8917-3BBAAA998C93}.Release|x64.Build.0 = Release|Any CPU - {3B1E557F-5E60-4E4B-8917-3BBAAA998C93}.Release|x86.ActiveCfg = Release|Any CPU - {3B1E557F-5E60-4E4B-8917-3BBAAA998C93}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {ACBB3BA7-8E81-466A-A1B4-73747E78639C} - EndGlobalSection -EndGlobal diff --git a/TheSexy6BotWorker.slnx b/TheSexy6BotWorker.slnx index 47fab7f..f2e9aeb 100644 --- a/TheSexy6BotWorker.slnx +++ b/TheSexy6BotWorker.slnx @@ -1,4 +1,4 @@ - + diff --git a/TheSexy6BotWorker.Tests/Configuration/BotConfigurationExtensionsTests.cs b/src/dotnet/TheSexy6BotWorker.Tests/Configuration/BotConfigurationExtensionsTests.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Configuration/BotConfigurationExtensionsTests.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Configuration/BotConfigurationExtensionsTests.cs diff --git a/TheSexy6BotWorker.Tests/Configuration/BotConfigurationIntegrationTests.cs b/src/dotnet/TheSexy6BotWorker.Tests/Configuration/BotConfigurationIntegrationTests.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Configuration/BotConfigurationIntegrationTests.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Configuration/BotConfigurationIntegrationTests.cs diff --git a/TheSexy6BotWorker.Tests/Configuration/GeminiBotConfigurationTests.cs b/src/dotnet/TheSexy6BotWorker.Tests/Configuration/GeminiBotConfigurationTests.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Configuration/GeminiBotConfigurationTests.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Configuration/GeminiBotConfigurationTests.cs diff --git a/TheSexy6BotWorker.Tests/Configuration/GrokBotConfigurationTests.cs b/src/dotnet/TheSexy6BotWorker.Tests/Configuration/GrokBotConfigurationTests.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Configuration/GrokBotConfigurationTests.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Configuration/GrokBotConfigurationTests.cs diff --git a/TheSexy6BotWorker.Tests/Integration/MarkdownIntegrationTests.cs b/src/dotnet/TheSexy6BotWorker.Tests/Integration/MarkdownIntegrationTests.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Integration/MarkdownIntegrationTests.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Integration/MarkdownIntegrationTests.cs diff --git a/TheSexy6BotWorker.Tests/Markdown/MarkdownBuilderTests.cs b/src/dotnet/TheSexy6BotWorker.Tests/Markdown/MarkdownBuilderTests.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Markdown/MarkdownBuilderTests.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Markdown/MarkdownBuilderTests.cs diff --git a/TheSexy6BotWorker.Tests/Markdown/MarkdownGeneratorTests.cs b/src/dotnet/TheSexy6BotWorker.Tests/Markdown/MarkdownGeneratorTests.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Markdown/MarkdownGeneratorTests.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Markdown/MarkdownGeneratorTests.cs diff --git a/TheSexy6BotWorker.Tests/Services/BotRegistryTests.cs b/src/dotnet/TheSexy6BotWorker.Tests/Services/BotRegistryTests.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Services/BotRegistryTests.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Services/BotRegistryTests.cs diff --git a/TheSexy6BotWorker.Tests/Services/ConversationSessionManagerTests.cs b/src/dotnet/TheSexy6BotWorker.Tests/Services/ConversationSessionManagerTests.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Services/ConversationSessionManagerTests.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Services/ConversationSessionManagerTests.cs diff --git a/TheSexy6BotWorker.Tests/Services/PerplexityApiIntegrationTest.cs b/src/dotnet/TheSexy6BotWorker.Tests/Services/PerplexityApiIntegrationTest.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Services/PerplexityApiIntegrationTest.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Services/PerplexityApiIntegrationTest.cs diff --git a/TheSexy6BotWorker.Tests/Services/PerplexityKernelIntegrationTest.cs b/src/dotnet/TheSexy6BotWorker.Tests/Services/PerplexityKernelIntegrationTest.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Services/PerplexityKernelIntegrationTest.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Services/PerplexityKernelIntegrationTest.cs diff --git a/TheSexy6BotWorker.Tests/Services/WeatherApiIntegrationTests.cs b/src/dotnet/TheSexy6BotWorker.Tests/Services/WeatherApiIntegrationTests.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Services/WeatherApiIntegrationTests.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Services/WeatherApiIntegrationTests.cs diff --git a/TheSexy6BotWorker.Tests/Services/WeatherKernelIntegrationTest.cs b/src/dotnet/TheSexy6BotWorker.Tests/Services/WeatherKernelIntegrationTest.cs similarity index 100% rename from TheSexy6BotWorker.Tests/Services/WeatherKernelIntegrationTest.cs rename to src/dotnet/TheSexy6BotWorker.Tests/Services/WeatherKernelIntegrationTest.cs diff --git a/TheSexy6BotWorker.Tests/TheSexy6BotWorker.Tests.csproj b/src/dotnet/TheSexy6BotWorker.Tests/TheSexy6BotWorker.Tests.csproj similarity index 100% rename from TheSexy6BotWorker.Tests/TheSexy6BotWorker.Tests.csproj rename to src/dotnet/TheSexy6BotWorker.Tests/TheSexy6BotWorker.Tests.csproj diff --git a/TheSexy6BotWorker/Commands/PingCommand.cs b/src/dotnet/TheSexy6BotWorker/Commands/PingCommand.cs similarity index 100% rename from TheSexy6BotWorker/Commands/PingCommand.cs rename to src/dotnet/TheSexy6BotWorker/Commands/PingCommand.cs diff --git a/TheSexy6BotWorker/Configuration/BotConfigurationExtensions.cs b/src/dotnet/TheSexy6BotWorker/Configuration/BotConfigurationExtensions.cs similarity index 100% rename from TheSexy6BotWorker/Configuration/BotConfigurationExtensions.cs rename to src/dotnet/TheSexy6BotWorker/Configuration/BotConfigurationExtensions.cs diff --git a/TheSexy6BotWorker/Configuration/GeminiBotConfiguration.cs b/src/dotnet/TheSexy6BotWorker/Configuration/GeminiBotConfiguration.cs similarity index 100% rename from TheSexy6BotWorker/Configuration/GeminiBotConfiguration.cs rename to src/dotnet/TheSexy6BotWorker/Configuration/GeminiBotConfiguration.cs diff --git a/TheSexy6BotWorker/Configuration/GrokBotConfiguration.cs b/src/dotnet/TheSexy6BotWorker/Configuration/GrokBotConfiguration.cs similarity index 100% rename from TheSexy6BotWorker/Configuration/GrokBotConfiguration.cs rename to src/dotnet/TheSexy6BotWorker/Configuration/GrokBotConfiguration.cs diff --git a/TheSexy6BotWorker/Configuration/README.md b/src/dotnet/TheSexy6BotWorker/Configuration/README.md similarity index 100% rename from TheSexy6BotWorker/Configuration/README.md rename to src/dotnet/TheSexy6BotWorker/Configuration/README.md diff --git a/TheSexy6BotWorker/Contracts/IBotConfiguration.cs b/src/dotnet/TheSexy6BotWorker/Contracts/IBotConfiguration.cs similarity index 100% rename from TheSexy6BotWorker/Contracts/IBotConfiguration.cs rename to src/dotnet/TheSexy6BotWorker/Contracts/IBotConfiguration.cs diff --git a/TheSexy6BotWorker/Contracts/IConversationSessionManager.cs b/src/dotnet/TheSexy6BotWorker/Contracts/IConversationSessionManager.cs similarity index 100% rename from TheSexy6BotWorker/Contracts/IConversationSessionManager.cs rename to src/dotnet/TheSexy6BotWorker/Contracts/IConversationSessionManager.cs diff --git a/TheSexy6BotWorker/DTOs/PerplexitySearchRequest.cs b/src/dotnet/TheSexy6BotWorker/DTOs/PerplexitySearchRequest.cs similarity index 100% rename from TheSexy6BotWorker/DTOs/PerplexitySearchRequest.cs rename to src/dotnet/TheSexy6BotWorker/DTOs/PerplexitySearchRequest.cs diff --git a/TheSexy6BotWorker/DTOs/PerplexitySearchResult.cs b/src/dotnet/TheSexy6BotWorker/DTOs/PerplexitySearchResult.cs similarity index 100% rename from TheSexy6BotWorker/DTOs/PerplexitySearchResult.cs rename to src/dotnet/TheSexy6BotWorker/DTOs/PerplexitySearchResult.cs diff --git a/TheSexy6BotWorker/DTOs/WeatherRequest.cs b/src/dotnet/TheSexy6BotWorker/DTOs/WeatherRequest.cs similarity index 100% rename from TheSexy6BotWorker/DTOs/WeatherRequest.cs rename to src/dotnet/TheSexy6BotWorker/DTOs/WeatherRequest.cs diff --git a/TheSexy6BotWorker/DTOs/WeatherResponse.cs b/src/dotnet/TheSexy6BotWorker/DTOs/WeatherResponse.cs similarity index 100% rename from TheSexy6BotWorker/DTOs/WeatherResponse.cs rename to src/dotnet/TheSexy6BotWorker/DTOs/WeatherResponse.cs diff --git a/TheSexy6BotWorker/DiscordWorker.cs b/src/dotnet/TheSexy6BotWorker/DiscordWorker.cs similarity index 100% rename from TheSexy6BotWorker/DiscordWorker.cs rename to src/dotnet/TheSexy6BotWorker/DiscordWorker.cs diff --git a/TheSexy6BotWorker/Handlers/MessageCreatedHandler.cs b/src/dotnet/TheSexy6BotWorker/Handlers/MessageCreatedHandler.cs similarity index 100% rename from TheSexy6BotWorker/Handlers/MessageCreatedHandler.cs rename to src/dotnet/TheSexy6BotWorker/Handlers/MessageCreatedHandler.cs diff --git a/TheSexy6BotWorker/Helpers/DiscordMessageFormatter.cs b/src/dotnet/TheSexy6BotWorker/Helpers/DiscordMessageFormatter.cs similarity index 100% rename from TheSexy6BotWorker/Helpers/DiscordMessageFormatter.cs rename to src/dotnet/TheSexy6BotWorker/Helpers/DiscordMessageFormatter.cs diff --git a/TheSexy6BotWorker/Helpers/DiscordMessageSender.cs b/src/dotnet/TheSexy6BotWorker/Helpers/DiscordMessageSender.cs similarity index 100% rename from TheSexy6BotWorker/Helpers/DiscordMessageSender.cs rename to src/dotnet/TheSexy6BotWorker/Helpers/DiscordMessageSender.cs diff --git a/TheSexy6BotWorker/Helpers/DiscordReplyChainHelper.cs b/src/dotnet/TheSexy6BotWorker/Helpers/DiscordReplyChainHelper.cs similarity index 100% rename from TheSexy6BotWorker/Helpers/DiscordReplyChainHelper.cs rename to src/dotnet/TheSexy6BotWorker/Helpers/DiscordReplyChainHelper.cs diff --git a/TheSexy6BotWorker/Markdown/MarkdownBuilder.cs b/src/dotnet/TheSexy6BotWorker/Markdown/MarkdownBuilder.cs similarity index 100% rename from TheSexy6BotWorker/Markdown/MarkdownBuilder.cs rename to src/dotnet/TheSexy6BotWorker/Markdown/MarkdownBuilder.cs diff --git a/TheSexy6BotWorker/Markdown/MarkdownGenerator.cs b/src/dotnet/TheSexy6BotWorker/Markdown/MarkdownGenerator.cs similarity index 100% rename from TheSexy6BotWorker/Markdown/MarkdownGenerator.cs rename to src/dotnet/TheSexy6BotWorker/Markdown/MarkdownGenerator.cs diff --git a/TheSexy6BotWorker/Markdown/MarkdownIgnoreAttribute.cs b/src/dotnet/TheSexy6BotWorker/Markdown/MarkdownIgnoreAttribute.cs similarity index 100% rename from TheSexy6BotWorker/Markdown/MarkdownIgnoreAttribute.cs rename to src/dotnet/TheSexy6BotWorker/Markdown/MarkdownIgnoreAttribute.cs diff --git a/TheSexy6BotWorker/Markdown/MarkdownPropertyAttribute.cs b/src/dotnet/TheSexy6BotWorker/Markdown/MarkdownPropertyAttribute.cs similarity index 100% rename from TheSexy6BotWorker/Markdown/MarkdownPropertyAttribute.cs rename to src/dotnet/TheSexy6BotWorker/Markdown/MarkdownPropertyAttribute.cs diff --git a/TheSexy6BotWorker/Markdown/MarkdownSectionAttribute.cs b/src/dotnet/TheSexy6BotWorker/Markdown/MarkdownSectionAttribute.cs similarity index 100% rename from TheSexy6BotWorker/Markdown/MarkdownSectionAttribute.cs rename to src/dotnet/TheSexy6BotWorker/Markdown/MarkdownSectionAttribute.cs diff --git a/TheSexy6BotWorker/Markdown/README.md b/src/dotnet/TheSexy6BotWorker/Markdown/README.md similarity index 100% rename from TheSexy6BotWorker/Markdown/README.md rename to src/dotnet/TheSexy6BotWorker/Markdown/README.md diff --git a/TheSexy6BotWorker/Models/BotConfigurationModel.cs b/src/dotnet/TheSexy6BotWorker/Models/BotConfigurationModel.cs similarity index 100% rename from TheSexy6BotWorker/Models/BotConfigurationModel.cs rename to src/dotnet/TheSexy6BotWorker/Models/BotConfigurationModel.cs diff --git a/TheSexy6BotWorker/Models/ConversationSession.cs b/src/dotnet/TheSexy6BotWorker/Models/ConversationSession.cs similarity index 100% rename from TheSexy6BotWorker/Models/ConversationSession.cs rename to src/dotnet/TheSexy6BotWorker/Models/ConversationSession.cs diff --git a/TheSexy6BotWorker/Models/EngagementDecision.cs b/src/dotnet/TheSexy6BotWorker/Models/EngagementDecision.cs similarity index 100% rename from TheSexy6BotWorker/Models/EngagementDecision.cs rename to src/dotnet/TheSexy6BotWorker/Models/EngagementDecision.cs diff --git a/TheSexy6BotWorker/Program.cs b/src/dotnet/TheSexy6BotWorker/Program.cs similarity index 100% rename from TheSexy6BotWorker/Program.cs rename to src/dotnet/TheSexy6BotWorker/Program.cs diff --git a/TheSexy6BotWorker/Properties/launchSettings.json b/src/dotnet/TheSexy6BotWorker/Properties/launchSettings.json similarity index 100% rename from TheSexy6BotWorker/Properties/launchSettings.json rename to src/dotnet/TheSexy6BotWorker/Properties/launchSettings.json diff --git a/TheSexy6BotWorker/Services/BotRegistry.cs b/src/dotnet/TheSexy6BotWorker/Services/BotRegistry.cs similarity index 100% rename from TheSexy6BotWorker/Services/BotRegistry.cs rename to src/dotnet/TheSexy6BotWorker/Services/BotRegistry.cs diff --git a/TheSexy6BotWorker/Services/ConversationSessionManager.cs b/src/dotnet/TheSexy6BotWorker/Services/ConversationSessionManager.cs similarity index 100% rename from TheSexy6BotWorker/Services/ConversationSessionManager.cs rename to src/dotnet/TheSexy6BotWorker/Services/ConversationSessionManager.cs diff --git a/TheSexy6BotWorker/Services/DynamicStatusService.cs b/src/dotnet/TheSexy6BotWorker/Services/DynamicStatusService.cs similarity index 100% rename from TheSexy6BotWorker/Services/DynamicStatusService.cs rename to src/dotnet/TheSexy6BotWorker/Services/DynamicStatusService.cs diff --git a/TheSexy6BotWorker/Services/PerplexitySearchService.cs b/src/dotnet/TheSexy6BotWorker/Services/PerplexitySearchService.cs similarity index 100% rename from TheSexy6BotWorker/Services/PerplexitySearchService.cs rename to src/dotnet/TheSexy6BotWorker/Services/PerplexitySearchService.cs diff --git a/TheSexy6BotWorker/Services/WeatherService.cs b/src/dotnet/TheSexy6BotWorker/Services/WeatherService.cs similarity index 100% rename from TheSexy6BotWorker/Services/WeatherService.cs rename to src/dotnet/TheSexy6BotWorker/Services/WeatherService.cs diff --git a/TheSexy6BotWorker/TheSexy6BotWorker.csproj b/src/dotnet/TheSexy6BotWorker/TheSexy6BotWorker.csproj similarity index 100% rename from TheSexy6BotWorker/TheSexy6BotWorker.csproj rename to src/dotnet/TheSexy6BotWorker/TheSexy6BotWorker.csproj diff --git a/TheSexy6BotWorker/appsettings.Development.json b/src/dotnet/TheSexy6BotWorker/appsettings.Development.json similarity index 100% rename from TheSexy6BotWorker/appsettings.Development.json rename to src/dotnet/TheSexy6BotWorker/appsettings.Development.json diff --git a/TheSexy6BotWorker/appsettings.json b/src/dotnet/TheSexy6BotWorker/appsettings.json similarity index 100% rename from TheSexy6BotWorker/appsettings.json rename to src/dotnet/TheSexy6BotWorker/appsettings.json diff --git a/src/terraform/README.md b/src/terraform/README.md new file mode 100644 index 0000000..490d094 --- /dev/null +++ b/src/terraform/README.md @@ -0,0 +1,6 @@ + + + +Before running tf plan: +1. Set environment subscription +run `export ARM_SUBSCRIPTION_ID=your-subscription-id` \ No newline at end of file diff --git a/src/terraform/container_app.tf b/src/terraform/container_app.tf new file mode 100644 index 0000000..f2fd04c --- /dev/null +++ b/src/terraform/container_app.tf @@ -0,0 +1,42 @@ +resource "azurerm_container_app_environment" "this" { + name = "${local.name_prefix}-cae" + location = azurerm_resource_group.this.location + resource_group_name = azurerm_resource_group.this.name + log_analytics_workspace_id = azurerm_log_analytics_workspace.this.id + tags = local.common_tags +} + +resource "azurerm_container_app" "this" { + name = "${local.name_prefix}-app" + container_app_environment_id = azurerm_container_app_environment.this.id + resource_group_name = azurerm_resource_group.this.name + revision_mode = "Single" + tags = local.common_tags + + // bootstrap - pipeline owns image + template { + container { + name = "${local.name_prefix}" + image = "mcr.microsoft.com/k8se/quickstart:latest" + cpu = 0.25 + memory = "0.5Gi" + } + } + + lifecycle { + ignore_changes = [ + template[0].container[0].image, + ] + } + + identity { + type = "SystemAssigned" + } +} + +// rbac +resource "azurerm_role_assignment" "container_app_acr_pull" { + scope = azurerm_container_app.this.id + role_definition_name = "Contributor" + principal_id = data.azurerm_client_config.this.object_id +} \ No newline at end of file diff --git a/src/terraform/container_registry.tf b/src/terraform/container_registry.tf new file mode 100644 index 0000000..3c9a4f5 --- /dev/null +++ b/src/terraform/container_registry.tf @@ -0,0 +1,25 @@ +resource "azurerm_container_registry" "this" { + name = "${local.name_prefix_no_dash}acr" + resource_group_name = azurerm_resource_group.this.name + location = var.location + sku = "Basic" + admin_enabled = false + tags = local.common_tags + + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_role_assignment" "acr_push" { + scope = azurerm_container_registry.this.id + role_definition_name = "AcrPush" + principal_id = data.azurerm_client_config.this.object_id +} + +resource "azurerm_role_assignment" "acr_pull" { + scope = azurerm_container_registry.this.id + role_definition_name = "AcrPull" + principal_id = azurerm_container_app.this.identity[0].principal_id +} + diff --git a/src/terraform/data.tf b/src/terraform/data.tf new file mode 100644 index 0000000..012126a --- /dev/null +++ b/src/terraform/data.tf @@ -0,0 +1 @@ +data "azurerm_client_config" "this" {} \ No newline at end of file diff --git a/src/terraform/environment.tfvars b/src/terraform/environment.tfvars new file mode 100644 index 0000000..f9b95fb --- /dev/null +++ b/src/terraform/environment.tfvars @@ -0,0 +1,9 @@ +application = "discordbot" +location = "uksouth" +location_short = "uks" +environment = "__ENVIRONMENT__" + +#these populate: +# name_prefix in format "${var.environment}-${var.application}" +# name_prefix_no_dash in format "${var.environment}${var.application}" +# e.g. stg-uks-discordbot \ No newline at end of file diff --git a/src/terraform/key_vault.tf b/src/terraform/key_vault.tf new file mode 100644 index 0000000..d9797ef --- /dev/null +++ b/src/terraform/key_vault.tf @@ -0,0 +1,17 @@ +resource "azurerm_key_vault" "this" { + name = "${local.name_prefix}-kv" + resource_group_name = azurerm_resource_group.this.name + location = var.location + tenant_id = data.azurerm_client_config.this.tenant_id + purge_protection_enabled = false + sku_name = "standard" + enable_rbac_authorization = true + + tags = local.common_tags +} + +resource "azurerm_role_assignment" "kv_pipeline_access" { + scope = azurerm_key_vault.this.id + role_definition_name = "Key Vault Secrets User" + principal_id = data.azurerm_client_config.this.client_id +} \ No newline at end of file diff --git a/src/terraform/law.tf b/src/terraform/law.tf new file mode 100644 index 0000000..23edc9c --- /dev/null +++ b/src/terraform/law.tf @@ -0,0 +1,10 @@ +resource "azurerm_log_analytics_workspace" "this" { + name = "${local.name_prefix}-law" + location = azurerm_resource_group.this.location + resource_group_name = azurerm_resource_group.this.name + sku = "PerGB2018" + retention_in_days = 30 + daily_quota_gb = 1 + + tags = local.common_tags +} \ No newline at end of file diff --git a/src/terraform/locals.tf b/src/terraform/locals.tf new file mode 100644 index 0000000..17f1154 --- /dev/null +++ b/src/terraform/locals.tf @@ -0,0 +1,9 @@ +locals { + common_tags = { + Environment = var.environment + Application = var.application + Location = var.location + } + name_prefix = "${var.environment}-${var.location_short}-${var.application}" + name_prefix_no_dash = "${var.environment}${var.location_short}${var.application}" +} \ No newline at end of file diff --git a/src/terraform/main.tf b/src/terraform/main.tf new file mode 100644 index 0000000..90317a4 --- /dev/null +++ b/src/terraform/main.tf @@ -0,0 +1,5 @@ +resource "azurerm_resource_group" "this" { + name = "${local.name_prefix}-rg" + location = var.location + tags = local.common_tags +} \ No newline at end of file diff --git a/src/terraform/outputs.tf b/src/terraform/outputs.tf new file mode 100644 index 0000000..c7ac54b --- /dev/null +++ b/src/terraform/outputs.tf @@ -0,0 +1,23 @@ +output "resource_group_name" { + value = azurerm_resource_group.this.name +} + +output "container_app_name" { + value = azurerm_container_app.this.name +} + +output "container_app_environment_name" { + value = azurerm_container_app_environment.this.name +} + +output "container_registry_login_server" { + value = azurerm_container_registry.this.login_server +} + +output "container_app_id" { + value = azurerm_container_app.this.id +} + +output "container_registry_id" { + value = azurerm_container_registry.this.id +} diff --git a/src/terraform/policies.tf b/src/terraform/policies.tf new file mode 100644 index 0000000..e69de29 diff --git a/src/terraform/providers.tf b/src/terraform/providers.tf new file mode 100644 index 0000000..0f995d9 --- /dev/null +++ b/src/terraform/providers.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 4.1.0" + } + } +} + +provider "azurerm" { + use_oidc = true + features {} +} diff --git a/src/terraform/storage.tf b/src/terraform/storage.tf new file mode 100644 index 0000000..dc0db2a --- /dev/null +++ b/src/terraform/storage.tf @@ -0,0 +1,11 @@ +resource "azurerm_storage_account" "this" { + name = "${local.name_prefix_no_dash}sa" + resource_group_name = azurerm_resource_group.this.name + location = var.location + account_tier = "Standard" + account_replication_type = "LRS" + tags = local.common_tags + shared_access_key_enabled = false + https_traffic_only_enabled = true + +} \ No newline at end of file diff --git a/src/terraform/terraform.tfvars b/src/terraform/terraform.tfvars new file mode 100644 index 0000000..d8e04f9 --- /dev/null +++ b/src/terraform/terraform.tfvars @@ -0,0 +1,6 @@ +application = "discordbot" +location = "uksouth" +location_short = "uks" +environment = "stg" + +# populate these for local tf plan \ No newline at end of file diff --git a/src/terraform/variables.tf b/src/terraform/variables.tf new file mode 100644 index 0000000..666effa --- /dev/null +++ b/src/terraform/variables.tf @@ -0,0 +1,19 @@ +variable "application" { + type = string + description = "Application name" +} + +variable "location_short" { + type = string + description = "Short name for the Azure region to deploy to" +} + +variable "location" { + type = string + description = "Azure region to deploy to" +} + +variable "environment" { + type = string + description = "Environment (staging / prd)" +} \ No newline at end of file