From 3892e342b3fa63e37fc05fa5586241f32475e66f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 09:24:04 +0100 Subject: [PATCH 01/30] chore(deps): update nginx docker tag to v1.27.3 (#1581) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Update | Change | |---|---|---| | nginx | patch | `1.27.2` -> `1.27.3` | --- ### Configuration πŸ“… **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f8b605880..f2a7ec59f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ include: services: dialogporten-webapi-ingress: - image: nginx:1.27.2 + image: nginx:1.27.3 ports: - "7214:80" volumes: @@ -38,7 +38,7 @@ services: - ./.aspnet/https:/https dialogporten-graphql-ingress: - image: nginx:1.27.2 + image: nginx:1.27.3 ports: - "7215:80" volumes: From bd02745edd4914f82bd3be6e2639183ce66ae3fe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 09:24:25 +0100 Subject: [PATCH 02/30] chore(deps): update dependency bouncycastle.cryptography to 2.5.0 (#1582) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [BouncyCastle.Cryptography](https://www.bouncycastle.org/stable/nuget/csharp/website) ([source](https://redirect.github.com/bcgit/bc-csharp)) | `2.4.0` -> `2.5.0` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/BouncyCastle.Cryptography/2.5.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/BouncyCastle.Cryptography/2.5.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/BouncyCastle.Cryptography/2.4.0/2.5.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/BouncyCastle.Cryptography/2.4.0/2.5.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
bcgit/bc-csharp (BouncyCastle.Cryptography) ### [`v2.5.0`](https://redirect.github.com/bcgit/bc-csharp/compare/release-2.4.0...release-2.5.0) [Compare Source](https://redirect.github.com/bcgit/bc-csharp/compare/release-2.4.0...release-2.5.0)
--- ### Configuration πŸ“… **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../Digdir.Tool.Dialogporten.Benchmarks.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Digdir.Tool.Dialogporten.Benchmarks/Digdir.Tool.Dialogporten.Benchmarks.csproj b/src/Digdir.Tool.Dialogporten.Benchmarks/Digdir.Tool.Dialogporten.Benchmarks.csproj index 7a3ea8bd5..291f1a9dc 100644 --- a/src/Digdir.Tool.Dialogporten.Benchmarks/Digdir.Tool.Dialogporten.Benchmarks.csproj +++ b/src/Digdir.Tool.Dialogporten.Benchmarks/Digdir.Tool.Dialogporten.Benchmarks.csproj @@ -6,7 +6,7 @@ - + From f9c2c9d57bdcdbfeae7c984bb783f94db2048c29 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 09:24:52 +0100 Subject: [PATCH 03/30] chore(deps): update dependency fluentassertions to v7 (#1584) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [FluentAssertions](https://www.fluentassertions.com/) ([source](https://redirect.github.com/fluentassertions/fluentassertions)) | `6.12.2` -> `7.0.0` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/FluentAssertions/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/FluentAssertions/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/FluentAssertions/6.12.2/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/FluentAssertions/6.12.2/7.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
fluentassertions/fluentassertions (FluentAssertions) ### [`v7.0.0`](https://redirect.github.com/fluentassertions/fluentassertions/releases/tag/7.0.0) [Compare Source](https://redirect.github.com/fluentassertions/fluentassertions/compare/6.12.2...7.0.0) ##### What's Changed ##### Breaking Changes - Drop support for .NET Core 2.1, 3.0 and NSpec by [@​dennisdoomen](https://redirect.github.com/dennisdoomen) in [https://github.com/fluentassertions/fluentassertions/pull/2835](https://redirect.github.com/fluentassertions/fluentassertions/pull/2835) ##### Fixes - The expectation node identified as a cyclic reference is still compared to the subject node using simple equality. by [@​dennisdoomen](https://redirect.github.com/dennisdoomen) in [https://github.com/fluentassertions/fluentassertions/pull/2819](https://redirect.github.com/fluentassertions/fluentassertions/pull/2819) - Fix support for write-only properties in BeEquivalentTo by [@​dennisdoomen](https://redirect.github.com/dennisdoomen) in [https://github.com/fluentassertions/fluentassertions/pull/2836](https://redirect.github.com/fluentassertions/fluentassertions/pull/2836) ##### Documentation - Fix minor syntax error in objectgraphs.md by [@​rklec](https://redirect.github.com/rklec) in [https://github.com/fluentassertions/fluentassertions/pull/2847](https://redirect.github.com/fluentassertions/fluentassertions/pull/2847) ##### Others - Use the same Qodana build pipeline as develop is using by [@​dennisdoomen](https://redirect.github.com/dennisdoomen) in [https://github.com/fluentassertions/fluentassertions/pull/2809](https://redirect.github.com/fluentassertions/fluentassertions/pull/2809) - Add section highlighting for better navigation by [@​sentemon](https://redirect.github.com/sentemon) in [https://github.com/fluentassertions/fluentassertions/pull/2807](https://redirect.github.com/fluentassertions/fluentassertions/pull/2807) - Bump all relevant dependencies by [@​dennisdoomen](https://redirect.github.com/dennisdoomen) in [https://github.com/fluentassertions/fluentassertions/pull/2834](https://redirect.github.com/fluentassertions/fluentassertions/pull/2834) - Changed references to the master branch to main by [@​dennisdoomen](https://redirect.github.com/dennisdoomen) in [https://github.com/fluentassertions/fluentassertions/pull/2848](https://redirect.github.com/fluentassertions/fluentassertions/pull/2848) - Missed two more references to master by [@​dennisdoomen](https://redirect.github.com/dennisdoomen) in [https://github.com/fluentassertions/fluentassertions/pull/2849](https://redirect.github.com/fluentassertions/fluentassertions/pull/2849) - Backport bump of `System.Configuration.ConfigurationManager` and `System.Threading.Tasks.Extensions` by [@​jnyrup](https://redirect.github.com/jnyrup) in [https://github.com/fluentassertions/fluentassertions/pull/2856](https://redirect.github.com/fluentassertions/fluentassertions/pull/2856) ##### New Contributors - [@​sentemon](https://redirect.github.com/sentemon) made their first contribution in [https://github.com/fluentassertions/fluentassertions/pull/2807](https://redirect.github.com/fluentassertions/fluentassertions/pull/2807) - [@​rklec](https://redirect.github.com/rklec) made their first contribution in [https://github.com/fluentassertions/fluentassertions/pull/2847](https://redirect.github.com/fluentassertions/fluentassertions/pull/2847) **Full Changelog**: https://github.com/fluentassertions/fluentassertions/compare/6.12.2...7.0.0
--- ### Configuration πŸ“… **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- ...dir.Domain.Dialogporten.Application.Integration.Tests.csproj | 2 +- .../Digdir.Domain.Dialogporten.Application.Unit.Tests.csproj | 2 +- .../Digdir.Domain.Dialogporten.Architecture.Tests.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Digdir.Domain.Dialogporten.Application.Integration.Tests.csproj b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Digdir.Domain.Dialogporten.Application.Integration.Tests.csproj index 8907b1cf5..06df06b6c 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Digdir.Domain.Dialogporten.Application.Integration.Tests.csproj +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Digdir.Domain.Dialogporten.Application.Integration.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Digdir.Domain.Dialogporten.Application.Unit.Tests.csproj b/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Digdir.Domain.Dialogporten.Application.Unit.Tests.csproj index f01c3c17c..002f7ea39 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Digdir.Domain.Dialogporten.Application.Unit.Tests.csproj +++ b/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/Digdir.Domain.Dialogporten.Application.Unit.Tests.csproj @@ -10,7 +10,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/tests/Digdir.Domain.Dialogporten.Architecture.Tests/Digdir.Domain.Dialogporten.Architecture.Tests.csproj b/tests/Digdir.Domain.Dialogporten.Architecture.Tests/Digdir.Domain.Dialogporten.Architecture.Tests.csproj index d400b3da9..c7b365548 100644 --- a/tests/Digdir.Domain.Dialogporten.Architecture.Tests/Digdir.Domain.Dialogporten.Architecture.Tests.csproj +++ b/tests/Digdir.Domain.Dialogporten.Architecture.Tests/Digdir.Domain.Dialogporten.Architecture.Tests.csproj @@ -7,7 +7,7 @@ - + From 40dc4fb20eccbe866bef76522956c9cc0a984735 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 09:59:46 +0100 Subject: [PATCH 04/30] chore(deps): update dependency fastendpoints.swagger to 5.32.0 (#1583) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [FastEndpoints.Swagger](https://fast-endpoints.com/) ([source](https://redirect.github.com/FastEndpoints/FastEndpoints)) | `5.31.0` -> `5.32.0` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/FastEndpoints.Swagger/5.32.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/FastEndpoints.Swagger/5.32.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/FastEndpoints.Swagger/5.31.0/5.32.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/FastEndpoints.Swagger/5.31.0/5.32.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Configuration πŸ“… **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Ole JΓΈrgen Skogstad --- docs/schema/V1/swagger.verified.json | 9 +++++++++ .../Digdir.Domain.Dialogporten.WebApi.csproj | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/schema/V1/swagger.verified.json b/docs/schema/V1/swagger.verified.json index 01348f6fd..a58e21b95 100644 --- a/docs/schema/V1/swagger.verified.json +++ b/docs/schema/V1/swagger.verified.json @@ -5853,6 +5853,9 @@ }, "description": "The UUID of the created the dialog aggregate. A relative URL to the newly created activity is set in the \u0022Location\u0022 header." }, + "204": { + "description": "No Content" + }, "400": { "content": { "application/problem\u002Bjson": { @@ -6468,6 +6471,9 @@ }, "description": "The UUID of the created the dialog activity. A relative URL to the newly created activity is set in the \u0022Location\u0022 header." }, + "204": { + "description": "No Content" + }, "400": { "content": { "application/problem\u002Bjson": { @@ -6825,6 +6831,9 @@ }, "description": "The UUID of the created the dialog transmission. A relative URL to the newly created activity is set in the \u0022Location\u0022 header." }, + "204": { + "description": "No Content" + }, "400": { "content": { "application/problem\u002Bjson": { diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj b/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj index 6216ac381..2641131ac 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj +++ b/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj @@ -8,7 +8,7 @@ - + From e624fef167899b2997e3ac2ac85c253c3fa8786f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Wed, 11 Dec 2024 10:33:12 +0100 Subject: [PATCH 05/30] chore: Use correct database name for local Docker setup (#1587) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `dialogporten != Dialogporten` Had some confusing moments in pgAdmin with dual databases πŸ˜‡ --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index cbd2e3101..8300930d6 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ # ENV variables for docker-compose POSTGRES_USER=postgres POSTGRES_PASSWORD=supersecret -POSTGRES_DB=Dialogporten +POSTGRES_DB=dialogporten DB_CONNECTION_STRING=Server=dialogporten-postgres;Port=5432;Database=${POSTGRES_DB};User ID=${POSTGRES_USER};Password=${POSTGRES_PASSWORD}; COMPOSE_PROJECT_NAME=digdir From 6e88e0c13c089d0f4871be2ee95a7f74fb21a51c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Wed, 11 Dec 2024 13:44:32 +0100 Subject: [PATCH 06/30] fix(webapi): Set correct swagger return type for transmission list (#1590) ## Description ## Related Issue(s) - #1589 ## Verification - [ ] **Your** code builds clean without any errors or warnings - [ ] Manual testing done (required) - [ ] Relevant automated test added (if you find this hard, leave it and we'll help out) ## Documentation - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable) --- docs/schema/V1/swagger.verified.json | 5 ++++- .../Search/SearchDialogTransmissionEndpoint.cs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/schema/V1/swagger.verified.json b/docs/schema/V1/swagger.verified.json index a58e21b95..e617e216e 100644 --- a/docs/schema/V1/swagger.verified.json +++ b/docs/schema/V1/swagger.verified.json @@ -6747,7 +6747,10 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/V1ServiceOwnerDialogTransmissionsQueriesSearch_Transmission" + "items": { + "$ref": "#/components/schemas/V1ServiceOwnerDialogTransmissionsQueriesSearch_Transmission" + }, + "type": "array" } } }, diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogTransmissions/Search/SearchDialogTransmissionEndpoint.cs b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogTransmissions/Search/SearchDialogTransmissionEndpoint.cs index 06fb1aede..5af04f663 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogTransmissions/Search/SearchDialogTransmissionEndpoint.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Endpoints/V1/ServiceOwner/DialogTransmissions/Search/SearchDialogTransmissionEndpoint.cs @@ -22,7 +22,7 @@ public override void Configure() Policies(AuthorizationPolicy.ServiceProvider); Group(); - Description(b => b.ProducesOneOf( + Description(b => b.ProducesOneOf>( StatusCodes.Status200OK, StatusCodes.Status404NotFound, StatusCodes.Status410Gone)); From bb4433bec905b4e95b46e72186c7250bb79ef646 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Wed, 11 Dec 2024 15:12:28 +0100 Subject: [PATCH 07/30] ci: ensure bicep is upgraded (#1593) ## Description ## Related Issue(s) - #{issue number} ## Verification - [ ] **Your** code builds clean without any errors or warnings - [ ] Manual testing done (required) - [ ] Relevant automated test added (if you find this hard, leave it and we'll help out) ## Documentation - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable) --- .azure/modules/redis/main.bicep | 3 --- .azure/modules/serviceBus/main.bicep | 3 --- .github/actions/azure-login/action.yml | 28 +++++++++++++++++++++ .github/workflows/workflow-deploy-apps.yml | 18 ++++++------- .github/workflows/workflow-deploy-infra.yml | 9 ++----- 5 files changed, 37 insertions(+), 24 deletions(-) create mode 100644 .github/actions/azure-login/action.yml diff --git a/.azure/modules/redis/main.bicep b/.azure/modules/redis/main.bicep index d6e873b18..80aa92885 100644 --- a/.azure/modules/redis/main.bicep +++ b/.azure/modules/redis/main.bicep @@ -97,9 +97,6 @@ module privateDnsZone '../privateDnsZone/main.bicep' = { module privateDnsZoneGroup '../privateDnsZoneGroup/main.bicep' = { name: '${namePrefix}-redis-privateDnsZoneGroup' - dependsOn: [ - privateDnsZone - ] params: { name: 'default' dnsZoneGroupName: 'privatelink-redis-cache-windows-net' diff --git a/.azure/modules/serviceBus/main.bicep b/.azure/modules/serviceBus/main.bicep index 4c34d3a56..50ad8883b 100644 --- a/.azure/modules/serviceBus/main.bicep +++ b/.azure/modules/serviceBus/main.bicep @@ -83,9 +83,6 @@ module privateDnsZone '../privateDnsZone/main.bicep' = { module privateDnsZoneGroup '../privateDnsZoneGroup/main.bicep' = { name: '${namePrefix}-service-bus-privateDnsZoneGroup' - dependsOn: [ - privateDnsZone - ] params: { name: 'default' dnsZoneGroupName: 'privatelink-servicebus-windows-net' diff --git a/.github/actions/azure-login/action.yml b/.github/actions/azure-login/action.yml new file mode 100644 index 000000000..5b8772979 --- /dev/null +++ b/.github/actions/azure-login/action.yml @@ -0,0 +1,28 @@ +name: 'Azure Login with Bicep Upgrade' +description: 'Login to Azure and upgrade Bicep CLI' + +inputs: + client-id: + description: 'Azure Client ID' + required: true + tenant-id: + description: 'Azure Tenant ID' + required: true + subscription-id: + description: 'Azure Subscription ID' + required: true +env: + AZ_CLI_VERSION: 2.67.0 +runs: + using: "composite" + steps: + - name: OIDC Login to Azure Public Cloud + uses: azure/login@v2 + with: + client-id: ${{ inputs.client-id }} + tenant-id: ${{ inputs.tenant-id }} + subscription-id: ${{ inputs.subscription-id }} + + - name: Upgrade Azure Bicep + shell: bash + run: az bicep upgrade \ No newline at end of file diff --git a/.github/workflows/workflow-deploy-apps.yml b/.github/workflows/workflow-deploy-apps.yml index a45653ef2..26d66c2e8 100644 --- a/.github/workflows/workflow-deploy-apps.yml +++ b/.github/workflows/workflow-deploy-apps.yml @@ -1,6 +1,4 @@ ο»Ώname: Deploy apps -env: - AZ_CLI_VERSION: 2.67.0 on: workflow_call: outputs: @@ -67,8 +65,8 @@ jobs: - name: "Checkout GitHub Action" uses: actions/checkout@v4 - - name: OIDC Login to Azure Public Cloud - uses: azure/login@v2 + - name: Azure Login + uses: ./.github/actions/azure-login with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} @@ -119,7 +117,6 @@ jobs: uses: azure/CLI@v2 if: ${{!inputs.dryRun}} with: - azcliversion: ${{ env.AZ_CLI_VERSION }} inlineScript: | az containerapp job start -n ${{ steps.deploy.outputs.name }} -g ${{ secrets.AZURE_RESOURCE_GROUP_NAME }} @@ -129,7 +126,6 @@ jobs: id: verify-migration timeout-minutes: 3 with: - azcliversion: ${{ env.AZ_CLI_VERSION }} inlineScript: | ./.github/tools/containerAppJobVerifier.sh ${{ steps.deploy.outputs.name }} ${{ secrets.AZURE_RESOURCE_GROUP_NAME }} ${{ inputs.version }} @@ -162,12 +158,13 @@ jobs: - name: "Checkout GitHub Action" uses: actions/checkout@v4 - - name: OIDC Login to Azure Public Cloud - uses: azure/login@v2 + - name: Azure Login + uses: ./.github/actions/azure-login with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + - name: Dryrun Deploy app ${{ matrix.name }}(${{ inputs.environment }}) uses: azure/arm-deploy@v2 if: ${{ inputs.dryRun }} @@ -223,7 +220,6 @@ jobs: id: verify-deployment timeout-minutes: 3 with: - azcliversion: ${{ env.AZ_CLI_VERSION }} inlineScript: | ./.github/tools/revisionVerifier.sh ${{ steps.deploy.outputs.revisionName }} ${{ secrets.AZURE_RESOURCE_GROUP_NAME }} @@ -252,8 +248,8 @@ jobs: - name: "Checkout GitHub Action" uses: actions/checkout@v4 - - name: OIDC Login to Azure Public Cloud - uses: azure/login@v2 + - name: Azure Login + uses: ./.github/actions/azure-login with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} diff --git a/.github/workflows/workflow-deploy-infra.yml b/.github/workflows/workflow-deploy-infra.yml index cbc7ebca3..014a0db79 100644 --- a/.github/workflows/workflow-deploy-infra.yml +++ b/.github/workflows/workflow-deploy-infra.yml @@ -1,8 +1,4 @@ name: Deploy infrastructure - -env: - AZ_CLI_VERSION: 2.67.0 - on: workflow_call: secrets: @@ -63,8 +59,8 @@ jobs: with: ref: ${{ inputs.ref }} - - name: OIDC Login to Azure Public Cloud - uses: azure/login@v2 + - name: Azure Login + uses: ./.github/actions/azure-login with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} @@ -74,7 +70,6 @@ jobs: uses: azure/CLI@v2 id: keyvault-keys with: - azcliversion: ${{ env.AZ_CLI_VERSION }} inlineScript: | KEY_VAULT_KEYS=$(az keyvault secret list --vault-name ${{ secrets.AZURE_SOURCE_KEY_VAULT_NAME }} --subscription ${{ secrets.AZURE_SOURCE_KEY_VAULT_SUBSCRIPTION_ID }} --query "[].name" -o json | tr -d '\n') echo "::set-output name=key-vault-keys::$KEY_VAULT_KEYS" From 828851ec5682aac7b2f5efb5abca6b3e950339ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Thu, 12 Dec 2024 13:47:05 +0100 Subject: [PATCH 08/30] chore: Disable all Sonar duplicate detections (#1596) Co-authored-by: Are Almaas --- sonar-project.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonar-project.properties b/sonar-project.properties index 5dc15fea4..dc4fd23e1 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,5 +1,5 @@ -# Disable code duplication detection for C# files -sonar.cpd.exclusions=**/*.cs +# Disable code duplication detection for C# and k6 files +sonar.cpd.exclusions=**/*.cs,**/k6/**/* # Disable all rules for auto-generated migration files sonar.exclusions=**/Migrations/**/* From f6f33d806b85f13476b4eb3a8a136c24b21947fa Mon Sep 17 00:00:00 2001 From: Dagfinn Olsen Date: Thu, 12 Dec 2024 14:02:03 +0100 Subject: [PATCH 09/30] chore: add performance tests to ci-cd-yt01 workflow (#1595) Add performance tests and run these tests in ci-cd-yt01 workflow ## Description ## Related Issue(s) #1540 - #{issue number} ## Verification - [ ] **Your** code builds clean without any errors or warnings - [x] Manual testing done (required) - [ ] Relevant automated test added (if you find this hard, leave it and we'll help out) ## Documentation - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable) --------- Co-authored-by: Are Almaas --- .github/workflows/ci-cd-yt01.yml | 33 +++++++++++++++++++ .../workflows/workflow-run-k6-performance.yml | 13 ++++++-- .../enduser/enduserSearchWithThresholds.js | 28 ++++++++++++++++ .../enduser/performance/enduser-search.js | 16 ++++----- tests/k6/tests/scripts/generate_tokens.sh | 23 +++++++++++-- .../createDialogWithThresholds.js | 12 +++++++ .../serviceOwnerSearchWithThresholds.js | 24 ++++++++++++++ 7 files changed, 136 insertions(+), 13 deletions(-) create mode 100644 tests/k6/tests/enduser/enduserSearchWithThresholds.js create mode 100644 tests/k6/tests/serviceowner/createDialogWithThresholds.js create mode 100644 tests/k6/tests/serviceowner/serviceOwnerSearchWithThresholds.js diff --git a/.github/workflows/ci-cd-yt01.yml b/.github/workflows/ci-cd-yt01.yml index 734ff03ed..af94c7f8f 100644 --- a/.github/workflows/ci-cd-yt01.yml +++ b/.github/workflows/ci-cd-yt01.yml @@ -140,6 +140,39 @@ jobs: checks: write pull-requests: write + run-performance: + name: "Run K6 performance tests" + # we want the performance tests to be dependent on deployment of infrastructure and apps, but if infrastructure is skipped, we still want to run the tests + if: ${{ always() && !failure() && !cancelled() && (github.event_name == 'workflow_dispatch' || needs.check-for-changes.outputs.hasBackendChanges == 'true' || needs.check-for-changes.outputs.hasInfraChanges == 'true') }} + needs: [deploy-apps, deploy-infra, check-for-changes] + #needs: [deploy-apps, check-for-changes] + uses: ./.github/workflows/workflow-run-k6-performance.yml + secrets: + TOKEN_GENERATOR_USERNAME: ${{ secrets.TOKEN_GENERATOR_USERNAME }} + TOKEN_GENERATOR_PASSWORD: ${{ secrets.TOKEN_GENERATOR_PASSWORD }} + K6_CLOUD_TOKEN: ${{ secrets.K6_CLOUD_TOKEN }} + K6_CLOUD_PROJECT_ID: ${{ secrets.K6_CLOUD_PROJECT_ID }} + + strategy: + max-parallel: 1 + matrix: + files: + - tests/k6/tests/serviceowner/serviceOwnerSearchWithThresholds.js + - tests/k6/tests/serviceowner/createDialogWithThresholds.js + - tests/k6/tests/enduser/enduserSearchWithThresholds.js + fail-fast: false + with: + environment: yt01 + apiVersion: v1 + vus: 1 + duration: 30s + tokens: both + numberOfTokens: 100 + testSuitePath: ${{ matrix.files }} + permissions: + checks: write + pull-requests: write + send-slack-message-on-failure: name: Send Slack message on failure needs: [deploy-infra, deploy-apps, deploy-slack-notifier, run-e2e-tests, publish] diff --git a/.github/workflows/workflow-run-k6-performance.yml b/.github/workflows/workflow-run-k6-performance.yml index 17ddcadf5..88a839e6c 100644 --- a/.github/workflows/workflow-run-k6-performance.yml +++ b/.github/workflows/workflow-run-k6-performance.yml @@ -21,6 +21,14 @@ on: tokens: required: true type: string + numberOfTokens: + required: false + type: number + default: 0 + ttl: + required: false + type: number + default: 3600 secrets: TOKEN_GENERATOR_USERNAME: required: true @@ -45,9 +53,10 @@ jobs: uses: grafana/setup-k6-action@v1 - name: Run K6 tests (${{ inputs.testSuitePath }}) run: | - ./tests/k6/tests/scripts/generate_tokens.sh ./tests/k6/tests/performancetest_data ${{ inputs.tokens }} + ./tests/k6/tests/scripts/generate_tokens.sh ./tests/k6/tests/performancetest_data ${{ inputs.tokens }} ${{ inputs.numberOfTokens }} ${{ inputs.ttl }} + echo "Running k6 test suite ${{ inputs.testSuitePath }} with ${{ inputs.vus }} VUs for ${{ inputs.duration }}" k6 run ${{ inputs.testSuitePath }} --quiet --log-output=stdout --include-system-env-vars \ - --vus=${{ inputs.vus }} --duration=${{ inputs.duration }} --out=cloud --out csv=./results.csv + --vus=${{ inputs.vus }} --duration=${{ inputs.duration }} --out csv=./results.csv grep http_req_duration ./results.csv | sort --field-separator=',' --key=3 -nr | head -10 env: API_ENVIRONMENT: ${{ inputs.environment }} diff --git a/tests/k6/tests/enduser/enduserSearchWithThresholds.js b/tests/k6/tests/enduser/enduserSearchWithThresholds.js new file mode 100644 index 000000000..eb2d3b6c1 --- /dev/null +++ b/tests/k6/tests/enduser/enduserSearchWithThresholds.js @@ -0,0 +1,28 @@ +import { default as run } from "./performance/enduser-search.js"; + +export let options = { + summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.5)', 'p(99.9)', 'count'], + vus: 1, + duration: "30s", + thresholds: { + "http_req_duration{name:enduser search}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:enduser get dialog}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:enduser get dialog activities}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:enduser get dialog activity}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:enduser get seenlogs}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:enduser get transmissions}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:enduser get transmission}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:enduser get labellog}": ["p(95)<300", "p(99)<500"], + "http_reqs{name:enduser search}": [], + "http_reqs{name:enduser get dialog activities}": [], + "http_reqs{name:enduser get dialog activity}": [], + "http_reqs{name:enduser get seenlogs}": [], + "http_reqs{name:enduser get transmissions}": [], + "http_reqs{name:enduser get transmission}": [], + "http_reqs{name:enduser get dialog}": [], + "http_reqs{name:enduser get labellog}": [], + } +} + +export default function (data) { run(data); } + diff --git a/tests/k6/tests/enduser/performance/enduser-search.js b/tests/k6/tests/enduser/performance/enduser-search.js index 41f1b0d7c..90fd03737 100644 --- a/tests/k6/tests/enduser/performance/enduser-search.js +++ b/tests/k6/tests/enduser/performance/enduser-search.js @@ -8,14 +8,14 @@ const traceCalls = (__ENV.traceCalls ?? 'false') === 'true'; export let options = { summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.5)', 'p(99.9)', 'count'], thresholds: getDefaultThresholds(['http_req_duration', 'http_reqs'],['enduser search', - 'get dialog', - 'get dialog activities', - 'get dialog activity', - 'get seenlogs', - 'get seenlog', - 'get transmissions', - 'get transmission', - 'get labellog' + 'enduser get dialog', + 'enduser get dialog activities', + 'enduser get dialog activity', + 'enduser get seenlogs', + 'enduser get seenlog', + 'enduser get transmissions', + 'enduser get transmission', + 'enduser get labellog' ]) }; diff --git a/tests/k6/tests/scripts/generate_tokens.sh b/tests/k6/tests/scripts/generate_tokens.sh index 4373de459..f9d39ab9a 100755 --- a/tests/k6/tests/scripts/generate_tokens.sh +++ b/tests/k6/tests/scripts/generate_tokens.sh @@ -11,11 +11,14 @@ usage() { echo "Usage: $0 " echo " : Path to the test data files" echo " : Type of tokens to generate (both, enterprise, or personal)" + echo " : limit number of tokens to generate. 0 means generate all" + echo " : Time to live in seconds for the generated tokens" + echo "Example: $0 /path/to/testdata both 10 3600" exit 1 } # Validate arguments -if [ $# -ne 2 ]; then +if [ $# -ne 4 ]; then usage fi @@ -37,6 +40,8 @@ esac testdatafilepath=$1 tokens=$2 +limit=$3 +ttl=$4 # Validate tokens argument if [[ ! "$tokens" =~ ^(both|enterprise|personal)$ ]]; then @@ -55,9 +60,13 @@ if [ "$tokens" = "both" ] || [ "$tokens" = "enterprise" ]; then exit 1 fi echo "org,orgno,scopes,resource,token" > $serviceowner_tokenfile + generated=0 while IFS=, read -r org orgno scopes resource do - url="https://altinn-testtools-token-generator.azurewebsites.net/api/GetEnterpriseToken?org=$org&env=$env&orgno=$orgno&ttl=3600" + if [ $limit -gt 0 ] && [ $generated -ge $limit ]; then + break + fi + url="https://altinn-testtools-token-generator.azurewebsites.net/api/GetEnterpriseToken?org=$org&env=$env&orgno=$orgno&ttl=$ttl" token=$(curl -s -f --get --data-urlencode "scopes=$scopes" $url -u "$tokengenuser:$tokengenpasswd" ) if [ $? -ne 0 ]; then echo "Error: Failed to generate enterprise token for: $env, $org, $orgno, $scopes " @@ -67,6 +76,8 @@ if [ "$tokens" = "both" ] || [ "$tokens" = "enterprise" ]; then status=$? if [ $status -ne 0 ]; then echo "Error: Failed to write enterprise token to file for: $env, $org, $orgno, $scopes" + else + ((generated++)) fi done < <(tail -n +2 $serviceowner_datafile) fi @@ -77,9 +88,13 @@ if [ "$tokens" = "both" ] || [ "$tokens" = "personal" ]; then exit 1 fi echo "ssn,resource,scopes,token" > $enduser_tokenfile + generated=0 while IFS=, read -r ssn resource scopes do - url="https://altinn-testtools-token-generator.azurewebsites.net/api/GetPersonalToken?env=$env&scopes=$scopes&pid=$ssn&ttl=3600" + if [ $limit -gt 0 ] && [ $generated -ge $limit ]; then + break + fi + url="https://altinn-testtools-token-generator.azurewebsites.net/api/GetPersonalToken?env=$env&scopes=$scopes&pid=$ssn&ttl=$ttl" token=$(curl -s -f $url -u "$tokengenuser:$tokengenpasswd" ) if [ $? -ne 0 ]; then echo "Error: Failed to generate personal token for: $ssn, $scopes " @@ -89,6 +104,8 @@ if [ "$tokens" = "both" ] || [ "$tokens" = "personal" ]; then status=$? if [ $status -ne 0 ]; then echo "Error: Failed to write personal token to file for: $ssn, $scopes" + else + ((generated++)) fi done < <(tail -n +2 $enduser_datafile) fi diff --git a/tests/k6/tests/serviceowner/createDialogWithThresholds.js b/tests/k6/tests/serviceowner/createDialogWithThresholds.js new file mode 100644 index 000000000..56b473244 --- /dev/null +++ b/tests/k6/tests/serviceowner/createDialogWithThresholds.js @@ -0,0 +1,12 @@ +import { default as run } from "./performance/create-dialog.js"; + +export let options = { + summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.5)', 'p(99.9)', 'count'], + vus: 1, + duration: "30s", + thresholds: { + "http_req_duration": ["p(95)<300", "p(99)<500"], + } +} + +export default function (data) { run(data); } \ No newline at end of file diff --git a/tests/k6/tests/serviceowner/serviceOwnerSearchWithThresholds.js b/tests/k6/tests/serviceowner/serviceOwnerSearchWithThresholds.js new file mode 100644 index 000000000..ed0fac469 --- /dev/null +++ b/tests/k6/tests/serviceowner/serviceOwnerSearchWithThresholds.js @@ -0,0 +1,24 @@ +import { default as run } from "./performance/serviceowner-search.js"; + +export let options = { + summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.5)', 'p(99.9)', 'count'], + vus: 1, + duration: "30s", + thresholds: { + "http_req_duration{name:serviceowner search}": ["p(95)<100", "p(99)<300"], + "http_req_duration{name:get dialog activities}": ["p(95)<100", "p(99)<300"], + "http_req_duration{name:get dialog activity}": ["p(95)<100", "p(99)<300"], + "http_req_duration{name:get seenlogs}": ["p(95)<100", "p(99)<300"], + "http_req_duration{name:get transmissions}": ["p(95)<100", "p(99)<300"], + "http_req_duration{name:get transmission}": ["p(95)<100", "p(99)<300"], + "http_reqs{name:get dialog activities}": [], + "http_reqs{name:get dialog activity}": [], + "http_reqs{name:get seenlogs}": [], + "http_reqs{name:get transmissions}": [], + "http_reqs{name:get transmission}": [], + "http_reqs{name:serviceowner search}": [], + } +} + +export default function (data) { run(data); } + From b5133d7498aea30e65a3d978c0c6b8256675e8ea Mon Sep 17 00:00:00 2001 From: Dialogporten Automation Bot <164321870+dialogporten-bot@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:06:51 +0100 Subject: [PATCH 10/30] chore(main): release 1.41.2 (#1591) :robot: I have created a release *beep* *boop* --- ## [1.41.2](https://github.com/digdir/dialogporten/compare/v1.41.1...v1.41.2) (2024-12-12) ### Bug Fixes * **webapi:** Set correct swagger return type for transmission list ([#1590](https://github.com/digdir/dialogporten/issues/1590)) ([6e88e0c](https://github.com/digdir/dialogporten/commit/6e88e0c13c089d0f4871be2ee95a7f74fb21a51c)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- CHANGELOG.md | 7 +++++++ version.txt | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 393e7b6a7..e051daf4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.41.2](https://github.com/digdir/dialogporten/compare/v1.41.1...v1.41.2) (2024-12-12) + + +### Bug Fixes + +* **webapi:** Set correct swagger return type for transmission list ([#1590](https://github.com/digdir/dialogporten/issues/1590)) ([6e88e0c](https://github.com/digdir/dialogporten/commit/6e88e0c13c089d0f4871be2ee95a7f74fb21a51c)) + ## [1.41.1](https://github.com/digdir/dialogporten/compare/v1.41.0...v1.41.1) (2024-12-09) diff --git a/version.txt b/version.txt index f86fb9cbc..5f2441072 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.41.1 +1.41.2 From b4440ca001c35e2c872ff02a43aa74ac0225e280 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 12 Dec 2024 14:53:08 +0100 Subject: [PATCH 11/30] ci: send slack message on failed performance tests (#1598) ## Description ## Related Issue(s) - #1540 ## Verification - [ ] **Your** code builds clean without any errors or warnings - [ ] Manual testing done (required) - [ ] Relevant automated test added (if you find this hard, leave it and we'll help out) ## Documentation - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable) --- .github/slack-templates/pipeline-failed.json | 2 +- .github/workflows/ci-cd-yt01.yml | 5 +++-- .../workflows/workflow-send-ci-cd-status-slack-message.yml | 6 ++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/slack-templates/pipeline-failed.json b/.github/slack-templates/pipeline-failed.json index d08909a3a..cd02b10a0 100644 --- a/.github/slack-templates/pipeline-failed.json +++ b/.github/slack-templates/pipeline-failed.json @@ -23,7 +23,7 @@ "type": "section", "text": { "type": "mrkdwn", - "text": "*Job Status:*\nβ€’ Infrastructure: ${{ env.INFRA_STATUS }}\nβ€’ Apps: ${{ env.APPS_STATUS }}\nβ€’ Slack Notifier: ${{ env.SLACK_NOTIFIER_STATUS }}\nβ€’ E2E Tests: ${{ env.E2E_TESTS_STATUS }}\nβ€’ Schema NPM: ${{ env.SCHEMA_NPM_STATUS }}\nβ€’ Publish: ${{ env.PUBLISH_STATUS }}" + "text": "*Job Status:*\nβ€’ Infrastructure: ${{ env.INFRA_STATUS }}\nβ€’ Apps: ${{ env.APPS_STATUS }}\nβ€’ Slack Notifier: ${{ env.SLACK_NOTIFIER_STATUS }}\nβ€’ E2E Tests: ${{ env.E2E_TESTS_STATUS }}\nβ€’ Performance Tests: ${{ env.PERFORMANCE_TESTS_STATUS }}\nβ€’ Schema NPM: ${{ env.SCHEMA_NPM_STATUS }}\nβ€’ Publish: ${{ env.PUBLISH_STATUS }}" } }, { diff --git a/.github/workflows/ci-cd-yt01.yml b/.github/workflows/ci-cd-yt01.yml index af94c7f8f..a047d1a68 100644 --- a/.github/workflows/ci-cd-yt01.yml +++ b/.github/workflows/ci-cd-yt01.yml @@ -140,7 +140,7 @@ jobs: checks: write pull-requests: write - run-performance: + run-performance-tests: name: "Run K6 performance tests" # we want the performance tests to be dependent on deployment of infrastructure and apps, but if infrastructure is skipped, we still want to run the tests if: ${{ always() && !failure() && !cancelled() && (github.event_name == 'workflow_dispatch' || needs.check-for-changes.outputs.hasBackendChanges == 'true' || needs.check-for-changes.outputs.hasInfraChanges == 'true') }} @@ -175,7 +175,7 @@ jobs: send-slack-message-on-failure: name: Send Slack message on failure - needs: [deploy-infra, deploy-apps, deploy-slack-notifier, run-e2e-tests, publish] + needs: [deploy-infra, deploy-apps, deploy-slack-notifier, run-e2e-tests, publish, run-performance-tests] if: ${{ always() && failure() && !cancelled() }} uses: ./.github/workflows/workflow-send-ci-cd-status-slack-message.yml with: @@ -184,6 +184,7 @@ jobs: apps_status: ${{ needs.deploy-apps.result }} slack_notifier_status: ${{ needs.deploy-slack-notifier.result }} e2e_tests_status: ${{ needs.run-e2e-tests.result }} + performance_tests_status: ${{ needs.run-performance-tests.result }} publish_status: ${{ needs.publish.result }} secrets: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} diff --git a/.github/workflows/workflow-send-ci-cd-status-slack-message.yml b/.github/workflows/workflow-send-ci-cd-status-slack-message.yml index 451814205..557f5d1e6 100644 --- a/.github/workflows/workflow-send-ci-cd-status-slack-message.yml +++ b/.github/workflows/workflow-send-ci-cd-status-slack-message.yml @@ -22,6 +22,10 @@ on: type: string description: "Status of the end-to-end tests job" default: "skipped" + performance_tests_status: + type: string + description: "Status of the performance tests job" + default: "skipped" schema_npm_status: type: string description: "Status of the schema npm publishing job" @@ -69,6 +73,7 @@ jobs: echo "SCHEMA_NPM_EMOJI=$(determine_emoji "${{ inputs.schema_npm_status }}")" echo "PUBLISH_EMOJI=$(determine_emoji "${{ inputs.publish_status }}")" echo "BUILD_AND_TEST_EMOJI=$(determine_emoji "${{ inputs.build_and_test_status }}")" + echo "PERFORMANCE_TESTS_EMOJI=$(determine_emoji "${{ inputs.performance_tests_status }}")" } >> "$GITHUB_OUTPUT" - name: Send GitHub slack message @@ -85,6 +90,7 @@ jobs: SCHEMA_NPM_STATUS: "${{ steps.status-emojis.outputs.SCHEMA_NPM_EMOJI }}" PUBLISH_STATUS: "${{ steps.status-emojis.outputs.PUBLISH_EMOJI }}" BUILD_AND_TEST_STATUS: "${{ steps.status-emojis.outputs.BUILD_AND_TEST_EMOJI }}" + PERFORMANCE_TESTS_STATUS: "${{ steps.status-emojis.outputs.PERFORMANCE_TESTS_EMOJI }}" uses: slackapi/slack-github-action@v2.0.0 with: errors: true From b39c37662f61361b083d7addc60b26ad4e06fab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Dybvik=20Langfors?= Date: Thu, 12 Dec 2024 15:43:19 +0100 Subject: [PATCH 12/30] fix: Collapse subject resource mappings before building sql query (#1579) ## Description This implements a few optimizations for search authorization, which particularly improves performance for users with access to a large number of parties. - SubjectsByParties gets collapsed and merged into ResourcesByParties. This lets us avoid doing subselects in the OR-clauses added to the search SQL - The entire SubjectResources-table is cached, which lets us do the above without an additional database hit. - When constructing the SQL, parties with identical resource lists are grouped, further collapsing multiple OR clauses into single ones with two ANY checks. This vastly reduces the number of clauses for large number of reportees, which in turn reduces the number of (identical) query parameters being sent over the network. - Minor improvements to data structures (mostly replacing List with HashSet) ## Related Issue(s) - N/A ## Verification - [x] **Your** code builds clean without any errors or warnings - [x] Manual testing done (required) - [x] Relevant automated test added --- .../Common/Extensions/DbSetExtensions.cs | 59 ++++++++------ .../DialogSearchAuthorizationResult.cs | 6 +- .../AltinnAuthorizationClient.cs | 39 ++++++---- .../Authorization/AuthorizationHelper.cs | 52 +++++++++++++ .../LocalDevelopmentAltinnAuthorization.cs | 6 +- .../InfrastructureExtensions.cs | 5 ++ .../DbSetExtensionsTests.cs | 72 +++++++++++++++++ .../AuthorizationHelperTests.cs | 78 +++++++++++++++++++ 8 files changed, 271 insertions(+), 46 deletions(-) create mode 100644 src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AuthorizationHelper.cs create mode 100644 tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/DbSetExtensionsTests.cs create mode 100644 tests/Digdir.Domain.Dialogporten.Infrastructure.Unit.Tests/AuthorizationHelperTests.cs diff --git a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/DbSetExtensions.cs b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/DbSetExtensions.cs index a15186323..8d207682d 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/DbSetExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Common/Extensions/DbSetExtensions.cs @@ -2,18 +2,15 @@ using System.Text; using Digdir.Domain.Dialogporten.Application.Externals.AltinnAuthorization; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities; -using Digdir.Domain.Dialogporten.Domain.SubjectResources; using Microsoft.EntityFrameworkCore; namespace Digdir.Domain.Dialogporten.Application.Common.Extensions; public static class DbSetExtensions { - public static IQueryable PrefilterAuthorizedDialogs(this DbSet dialogs, DialogSearchAuthorizationResult authorizedResources) + public static (string sql, object[] parameters) GeneratePrefilterAuthorizedDialogsSql(DialogSearchAuthorizationResult authorizedResources) { var parameters = new List(); - - // lang=sql var sb = new StringBuilder() .AppendLine(CultureInfo.InvariantCulture, $""" SELECT * @@ -22,36 +19,50 @@ public static IQueryable PrefilterAuthorizedDialogs(this DbSet kv.Value, new HashSetEqualityComparer()) + .ToDictionary( + g => g.Key, + g => new HashSet(g.Select(kv => kv.Key)) + ); + + foreach (var (resources, parties) in groupedResult) { - // lang=sql sb.AppendLine(CultureInfo.InvariantCulture, $""" OR ( - "{nameof(DialogEntity.Party)}" = @p{parameters.Count} + "{nameof(DialogEntity.Party)}" = ANY(@p{parameters.Count}) AND "{nameof(DialogEntity.ServiceResource)}" = ANY(@p{parameters.Count + 1}) ) """); - parameters.Add(party); + parameters.Add(parties); parameters.Add(resources); } - foreach (var (party, subjects) in authorizedResources.SubjectsByParties) + return (sb.ToString(), parameters.ToArray()); + } + + public static IQueryable PrefilterAuthorizedDialogs(this DbSet dialogs, DialogSearchAuthorizationResult authorizedResources) + { + var (sql, parameters) = GeneratePrefilterAuthorizedDialogsSql(authorizedResources); + return dialogs.FromSqlRaw(sql, parameters); + } +} + + +public sealed class HashSetEqualityComparer : IEqualityComparer> +{ + public bool Equals(HashSet? x, HashSet? y) + { + return ReferenceEquals(x, y) || (x is not null && y is not null && x.SetEquals(y)); + } + + public int GetHashCode(HashSet obj) + { + ArgumentNullException.ThrowIfNull(obj); + unchecked { - // lang=sql - sb.AppendLine(CultureInfo.InvariantCulture, $""" - OR ( - "{nameof(DialogEntity.Party)}" = @p{parameters.Count} - AND "{nameof(DialogEntity.ServiceResource)}" = ANY( - SELECT "{nameof(SubjectResource.Resource)}" - FROM "{nameof(SubjectResource)}" - WHERE "{nameof(SubjectResource.Subject)}" = ANY(@p{parameters.Count + 1}) - ) - ) - """); - parameters.Add(party); - parameters.Add(subjects); + return obj.Aggregate(0, (hash, item) => hash ^ (item?.GetHashCode() ?? 0)); } - - return dialogs.FromSqlRaw(sb.ToString(), parameters.ToArray()); } } diff --git a/src/Digdir.Domain.Dialogporten.Application/Externals/AltinnAuthorization/DialogSearchAuthorizationResult.cs b/src/Digdir.Domain.Dialogporten.Application/Externals/AltinnAuthorization/DialogSearchAuthorizationResult.cs index 838b979c4..4945413e7 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Externals/AltinnAuthorization/DialogSearchAuthorizationResult.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Externals/AltinnAuthorization/DialogSearchAuthorizationResult.cs @@ -4,12 +4,10 @@ public sealed class DialogSearchAuthorizationResult { // Resources here are "main" resources, eg. something that represents an entry in the Resource Registry // eg. "urn:altinn:resource:some-service" and referred to by "ServiceResource" in DialogEntity - public Dictionary> ResourcesByParties { get; init; } = new(); - public Dictionary> SubjectsByParties { get; init; } = new(); + public Dictionary> ResourcesByParties { get; init; } = new(); public List DialogIds { get; init; } = []; public bool HasNoAuthorizations => ResourcesByParties.Count == 0 - && DialogIds.Count == 0 - && SubjectsByParties.Count == 0; + && DialogIds.Count == 0; } diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AltinnAuthorizationClient.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AltinnAuthorizationClient.cs index 22465274a..4ae95cb71 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AltinnAuthorizationClient.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AltinnAuthorizationClient.cs @@ -3,11 +3,14 @@ using System.Text.Json.Serialization; using Altinn.Authorization.ABAC.Xacml.JsonProfile; using Digdir.Domain.Dialogporten.Application.Common.Extensions; +using Digdir.Domain.Dialogporten.Application.Externals; using Digdir.Domain.Dialogporten.Application.Externals.AltinnAuthorization; using Digdir.Domain.Dialogporten.Application.Externals.Presentation; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities; using Digdir.Domain.Dialogporten.Domain.Parties.Abstractions; +using Digdir.Domain.Dialogporten.Domain.SubjectResources; using Digdir.Domain.Dialogporten.Infrastructure.Common.Exceptions; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using ZiggyCreatures.Caching.Fusion; @@ -20,7 +23,9 @@ internal sealed class AltinnAuthorizationClient : IAltinnAuthorization private readonly HttpClient _httpClient; private readonly IFusionCache _pdpCache; private readonly IFusionCache _partiesCache; + private readonly IFusionCache _subjectResourcesCache; private readonly IUser _user; + private readonly IDialogDbContext _dialogDbContext; private readonly ILogger _logger; private static readonly JsonSerializerOptions SerializerOptions = new() @@ -33,12 +38,15 @@ public AltinnAuthorizationClient( HttpClient client, IFusionCacheProvider cacheProvider, IUser user, + IDialogDbContext dialogDbContext, ILogger logger) { _httpClient = client ?? throw new ArgumentNullException(nameof(client)); _pdpCache = cacheProvider.GetCache(nameof(Authorization)) ?? throw new ArgumentNullException(nameof(cacheProvider)); _partiesCache = cacheProvider.GetCache(nameof(AuthorizedPartiesResult)) ?? throw new ArgumentNullException(nameof(cacheProvider)); + _subjectResourcesCache = cacheProvider.GetCache(nameof(SubjectResource)) ?? throw new ArgumentNullException(nameof(cacheProvider)); _user = user ?? throw new ArgumentNullException(nameof(user)); + _dialogDbContext = dialogDbContext ?? throw new ArgumentNullException(nameof(dialogDbContext)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } @@ -94,7 +102,6 @@ public async Task HasListAuthorizationForDialog(DialogEntity dialog, Cance [dialog.Party], [dialog.ServiceResource], cancellationToken); return authorizedResourcesForSearch.ResourcesByParties.Count > 0 - || authorizedResourcesForSearch.SubjectsByParties.Count > 0 || authorizedResourcesForSearch.DialogIds.Contains(dialog.Id); } @@ -128,9 +135,9 @@ void Flatten(AuthorizedParty party, AuthorizedParty? parent = null) } private async Task PerformAuthorizedPartiesRequest(AuthorizedPartiesRequest authorizedPartiesRequest, - CancellationToken token) + CancellationToken cancellationToken) { - var authorizedPartiesDto = await SendAuthorizedPartiesRequest(authorizedPartiesRequest, token); + var authorizedPartiesDto = await SendAuthorizedPartiesRequest(authorizedPartiesRequest, cancellationToken); if (authorizedPartiesDto is null || authorizedPartiesDto.Count == 0) { throw new UpstreamServiceException("access-management returned no authorized parties, missing Altinn profile?"); @@ -139,10 +146,10 @@ private async Task PerformAuthorizedPartiesRequest(Auth return AuthorizedPartiesHelper.CreateAuthorizedPartiesResult(authorizedPartiesDto, authorizedPartiesRequest); } - private async Task PerformDialogSearchAuthorization(DialogSearchAuthorizationRequest request, CancellationToken token) + private async Task PerformDialogSearchAuthorization(DialogSearchAuthorizationRequest request, CancellationToken cancellationToken) { var partyIdentifier = request.Claims.GetEndUserPartyIdentifier() ?? throw new UnreachableException(); - var authorizedParties = await GetAuthorizedParties(partyIdentifier, flatten: true, cancellationToken: token); + var authorizedParties = await GetAuthorizedParties(partyIdentifier, flatten: true, cancellationToken: cancellationToken); if (request.ConstraintParties.Count > 0) { @@ -158,23 +165,27 @@ private async Task PerformDialogSearchAuthoriza p => p.Party, p => p.AuthorizedResources .Where(r => request.ConstraintServiceResources.Count == 0 || request.ConstraintServiceResources.Contains(r)) - .ToList()) + .ToHashSet()) // Skip parties with no authorized resources .Where(kv => kv.Value.Count != 0) .ToDictionary(kv => kv.Key, kv => kv.Value), - - SubjectsByParties = authorizedParties.AuthorizedParties - .ToDictionary( - p => p.Party, - p => p.AuthorizedRoles) - // Skip parties with no authorized roles - .Where(kv => kv.Value.Count != 0) - .ToDictionary(kv => kv.Key, kv => kv.Value) }; + await AuthorizationHelper.CollapseSubjectResources( + dialogSearchAuthorizationResult, + authorizedParties, + request.ConstraintServiceResources, + GetAllSubjectResources, + cancellationToken); + return dialogSearchAuthorizationResult; } + private async Task> GetAllSubjectResources(CancellationToken cancellationToken) => + await _subjectResourcesCache.GetOrSetAsync(nameof(SubjectResource), async ct + => await _dialogDbContext.SubjectResources.ToListAsync(cancellationToken: ct), + token: cancellationToken); + private async Task PerformDialogDetailsAuthorization( DialogDetailsAuthorizationRequest request, CancellationToken cancellationToken) { diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AuthorizationHelper.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AuthorizationHelper.cs new file mode 100644 index 000000000..5eb395399 --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AuthorizationHelper.cs @@ -0,0 +1,52 @@ +using Digdir.Domain.Dialogporten.Application.Externals.AltinnAuthorization; +using Digdir.Domain.Dialogporten.Domain.SubjectResources; + +namespace Digdir.Domain.Dialogporten.Infrastructure.Altinn.Authorization; + +internal static class AuthorizationHelper +{ + public static async Task CollapseSubjectResources( + DialogSearchAuthorizationResult dialogSearchAuthorizationResult, + AuthorizedPartiesResult authorizedParties, + List constraintResources, + Func>> getAllSubjectResources, + CancellationToken cancellationToken) + { + var authorizedPartiesWithRoles = authorizedParties.AuthorizedParties + .Where(p => p.AuthorizedRoles.Count != 0) + .ToList(); + + var uniqueSubjects = authorizedPartiesWithRoles + .SelectMany(p => p.AuthorizedRoles) + .ToHashSet(); + + var subjectResources = (await getAllSubjectResources(cancellationToken)) + .Where(x => uniqueSubjects.Contains(x.Subject) && (constraintResources.Count == 0 || constraintResources.Contains(x.Resource))).ToList(); + + var subjectToResources = subjectResources + .GroupBy(sr => sr.Subject) + .ToDictionary(g => g.Key, g => g.Select(sr => sr.Resource).ToHashSet()); + + foreach (var partyEntry in authorizedPartiesWithRoles) + { + if (!dialogSearchAuthorizationResult.ResourcesByParties.TryGetValue(partyEntry.Party, out var resourceList)) + { + resourceList = new HashSet(); + dialogSearchAuthorizationResult.ResourcesByParties[partyEntry.Party] = resourceList; + } + + foreach (var subject in partyEntry.AuthorizedRoles) + { + if (subjectToResources.TryGetValue(subject, out var subjectResourceSet)) + { + resourceList.UnionWith(subjectResourceSet); + } + } + + if (resourceList.Count == 0) + { + dialogSearchAuthorizationResult.ResourcesByParties.Remove(partyEntry.Party); + } + } + } +} diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/LocalDevelopmentAltinnAuthorization.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/LocalDevelopmentAltinnAuthorization.cs index 6f7f5c07c..7102db5e5 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/LocalDevelopmentAltinnAuthorization.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/LocalDevelopmentAltinnAuthorization.cs @@ -40,13 +40,11 @@ public async Task GetAuthorizedResourcesForSear // Keep the number of parties and resources reasonable var allParties = dialogData.Select(x => x.Party).Distinct().Take(1000).ToList(); - var allResources = dialogData.Select(x => x.ServiceResource).Distinct().Take(1000).ToList(); - var allRoles = await _db.SubjectResources.Select(x => x.Subject).Distinct().Take(30).ToListAsync(cancellationToken); + var allResources = dialogData.Select(x => x.ServiceResource).Distinct().Take(1000).ToHashSet(); var authorizedResources = new DialogSearchAuthorizationResult { - ResourcesByParties = allParties.ToDictionary(party => party, _ => allResources), - SubjectsByParties = allParties.ToDictionary(party => party, _ => allRoles) + ResourcesByParties = allParties.ToDictionary(party => party, _ => allResources) }; return authorizedResources; diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 23289ef81..d0947c3dc 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -16,6 +16,7 @@ using Digdir.Domain.Dialogporten.Application; using Digdir.Domain.Dialogporten.Application.Common.Extensions; using Digdir.Domain.Dialogporten.Application.Externals.AltinnAuthorization; +using Digdir.Domain.Dialogporten.Domain.SubjectResources; using Digdir.Domain.Dialogporten.Infrastructure.Altinn.Authorization; using Digdir.Domain.Dialogporten.Infrastructure.Altinn.Events; using Digdir.Domain.Dialogporten.Infrastructure.Altinn.NameRegistry; @@ -160,6 +161,10 @@ internal static void AddInfrastructure_Internal(InfrastructureBuilderContext bui // Timeout for the cache to wait for the factory to complete, which when reached without fail-safe data // will cause an exception to be thrown FactoryHardTimeout = TimeSpan.FromSeconds(10) + }) + .ConfigureFusionCache(nameof(SubjectResource), new() + { + Duration = TimeSpan.FromMinutes(20) }); if (!environment.IsDevelopment()) diff --git a/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/DbSetExtensionsTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/DbSetExtensionsTests.cs new file mode 100644 index 000000000..9438ea885 --- /dev/null +++ b/tests/Digdir.Domain.Dialogporten.Application.Unit.Tests/DbSetExtensionsTests.cs @@ -0,0 +1,72 @@ +using Digdir.Domain.Dialogporten.Application.Common.Extensions; +using Digdir.Domain.Dialogporten.Application.Externals.AltinnAuthorization; +using FluentAssertions; + +namespace Digdir.Domain.Dialogporten.Application.Unit.Tests; + +public class DbSetExtensionsTests +{ + [Fact] + public void PrefilterAuthorizedDialogs_GeneratesExpectedSql_ForGroupedParties() + { + // Arrange + var authorizedResources = new DialogSearchAuthorizationResult + { + DialogIds = [Guid.CreateVersion7()], + ResourcesByParties = new Dictionary> + { + { "Party1", ["Resource1", "Resource2"] }, + { "Party2", ["Resource1", "Resource2"] }, + { "Party3", ["Resource1", "Resource2", "Resource3"] }, + { "Party4", ["Resource3"] }, + { "Party5", ["Resource4"] } + } + }; + + var expectedSql = """ + SELECT * + FROM "Dialog" + WHERE "Id" = ANY(@p0) + OR ( + "Party" = ANY(@p1) + AND "ServiceResource" = ANY(@p2) + ) + OR ( + "Party" = ANY(@p3) + AND "ServiceResource" = ANY(@p4) + ) + OR ( + "Party" = ANY(@p5) + AND "ServiceResource" = ANY(@p6) + ) + OR ( + "Party" = ANY(@p7) + AND "ServiceResource" = ANY(@p8) + ) + """; + var expectedParameters = new object[] + { + authorizedResources.DialogIds, + new HashSet { "Party1", "Party2" }, + new HashSet { "Resource1", "Resource2" }, + new HashSet { "Party3" }, + new HashSet { "Resource1", "Resource2", "Resource3" }, + new HashSet { "Party4" }, + new HashSet { "Resource3" }, + new HashSet { "Party5" }, + new HashSet { "Resource4" } + }; + + // Act + var (actualSql, actualParameters) = DbSetExtensions.GeneratePrefilterAuthorizedDialogsSql(authorizedResources); + + // Assert + RemoveWhitespace(actualSql).Should().Be(RemoveWhitespace(expectedSql)); + actualParameters.Should().BeEquivalentTo(expectedParameters); + } + + private static string RemoveWhitespace(string input) + { + return string.Concat(input.Where(c => !char.IsWhiteSpace(c))); + } +} diff --git a/tests/Digdir.Domain.Dialogporten.Infrastructure.Unit.Tests/AuthorizationHelperTests.cs b/tests/Digdir.Domain.Dialogporten.Infrastructure.Unit.Tests/AuthorizationHelperTests.cs new file mode 100644 index 000000000..7559b83c3 --- /dev/null +++ b/tests/Digdir.Domain.Dialogporten.Infrastructure.Unit.Tests/AuthorizationHelperTests.cs @@ -0,0 +1,78 @@ +using Digdir.Domain.Dialogporten.Application.Externals.AltinnAuthorization; +using Digdir.Domain.Dialogporten.Domain.SubjectResources; +using Digdir.Domain.Dialogporten.Infrastructure.Altinn.Authorization; +using Xunit; + +namespace Digdir.Domain.Dialogporten.Infrastructure.Unit.Tests; + +public class AuthorizationHelperTests +{ + [Fact] + public async Task CollapseSubjectResources_ShouldCollapseCorrectly() + { + // Arrange + var dialogSearchAuthorizationResult = new DialogSearchAuthorizationResult + { + ResourcesByParties = new Dictionary>() + }; + var authorizedParties = new AuthorizedPartiesResult + { + AuthorizedParties = new List + { + new() + { + Party = "party1", + AuthorizedRoles = new List { "role1", "role2" } + }, + new() + { + Party = "party2", + AuthorizedRoles = new List { "role2" } + }, + new() + { + Party = "party3", + AuthorizedRoles = new List { "role3" } + } + } + }; + var constraintResources = new List { "resource1", "resource2", "resource4" }; + + // Simulate subject resources + var subjectResources = new List + { + new() { Subject = "role1", Resource = "resource1" }, + new() { Subject = "role1", Resource = "resource2" }, + new() { Subject = "role2", Resource = "resource2" }, + new() { Subject = "role2", Resource = "resource3" }, + new() { Subject = "role2", Resource = "resource4" }, + new() { Subject = "role3", Resource = "resource5" }, // Note: not in constraintResources + }; + + Task> GetSubjectResources(CancellationToken token) + { + return Task.FromResult(subjectResources); + } + + // Act + await AuthorizationHelper.CollapseSubjectResources( + dialogSearchAuthorizationResult, + authorizedParties, + constraintResources, + GetSubjectResources, + CancellationToken.None); + + // Assert + Assert.Equal(2, dialogSearchAuthorizationResult.ResourcesByParties.Count); + Assert.Contains("party1", dialogSearchAuthorizationResult.ResourcesByParties.Keys); + Assert.Contains("resource1", dialogSearchAuthorizationResult.ResourcesByParties["party1"]); + Assert.Contains("resource2", dialogSearchAuthorizationResult.ResourcesByParties["party1"]); + Assert.Contains("resource4", dialogSearchAuthorizationResult.ResourcesByParties["party1"]); + Assert.Equal(3, dialogSearchAuthorizationResult.ResourcesByParties["party1"].Count); + + Assert.Contains("party2", dialogSearchAuthorizationResult.ResourcesByParties.Keys); + Assert.Contains("resource2", dialogSearchAuthorizationResult.ResourcesByParties["party2"]); + Assert.Contains("resource4", dialogSearchAuthorizationResult.ResourcesByParties["party2"]); + Assert.Equal(2, dialogSearchAuthorizationResult.ResourcesByParties["party2"].Count); + } +} From 3fb9f9501b4db97847aa1ebc0b77efe722811f0a Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Fri, 13 Dec 2024 11:15:47 +0100 Subject: [PATCH 13/30] fix(azure): adjust SKU and storage for staging (#1601) ## Description Related to https://digdir.slack.com/archives/C079D6PAGDS/p1734018202302459 Experiencing heavy CPU usage on the postgresql server in staging. After some investigations, it was hard to pin down the cause. Being on a burstable tier may be too fragile, and perhaps contribute to the high CPU usage, so upgrading. Staging will be used by many test environments moving forward so making it more stable with GeneralPurpose machines makes sense. ## Related Issue(s) - #N/A ## Verification - [ ] **Your** code builds clean without any errors or warnings - [ ] Manual testing done (required) - [ ] Relevant automated test added (if you find this hard, leave it and we'll help out) ## Documentation - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable) --- .azure/infrastructure/staging.bicepparam | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.azure/infrastructure/staging.bicepparam b/.azure/infrastructure/staging.bicepparam index 83ad22b43..c434a5469 100644 --- a/.azure/infrastructure/staging.bicepparam +++ b/.azure/infrastructure/staging.bicepparam @@ -31,15 +31,15 @@ param slackNotifierSku = { } param postgresConfiguration = { sku: { - name: 'Standard_B1ms' - tier: 'Burstable' + name: 'Standard_D4ads_v5' + tier: 'GeneralPurpose' } storage: { - storageSizeGB: 32 + storageSizeGB: 256 autoGrow: 'Enabled' type: 'Premium_LRS' } - enableIndexTuning: false + enableIndexTuning: true enableQueryPerformanceInsight: true } From 2e8b3e6db507efd195245ad829dd7d5a96f272ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Fri, 13 Dec 2024 12:58:50 +0100 Subject: [PATCH 14/30] fix(webapi): Explicit null on non-nullable lists no longer causes 500 INTERNAL SERVER ERROR (#1602) ## Description Setting `RespectNullableAnnotations = true` makes it so that explicit null on non-nullable list results in a 400 BAD REQUEST across the whole API. ```json { "type": "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "instance": "/api/v1/serviceowner/dialogs", "errors": { "searchTags": [ "The property or field 'searchTags' on type 'Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Commands.Create.CreateDialogCommand' doesn't allow setting null values. Consider updating its nullability annotation. Path: $.searchTags | LineNumber: 169 | BytePositionInLine: 22." ] }, "traceId": "00-958361cdc8411eee6b3e7f32f19d1acc-119627bfbb3b75f6-01" } ``` ## Related Issue(s) - #1597 ## Verification - [x] **Your** code builds clean without any errors or warnings - [x] Manual testing done (required) - [ ] Relevant automated test added (if you find this hard, leave it and we'll help out) ## Documentation - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable) --- src/Digdir.Domain.Dialogporten.WebApi/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index 21433a66e..c02e9f007 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -173,6 +173,7 @@ static void BuildAndRun(string[] args, TelemetryConfiguration telemetryConfigura new EndpointNameMetadata( TypeNameConverter.ToShortName(endpointDefinition.EndpointType))))); }; + x.Serializer.Options.RespectNullableAnnotations = true; x.Serializer.Options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; // Do not serialize empty collections x.Serializer.Options.TypeInfoResolver = new DefaultJsonTypeInfoResolver From 2aa1a2ab1f52ae6f3afbf6d6ff79fce76f5b9e23 Mon Sep 17 00:00:00 2001 From: Dialogporten Automation Bot <164321870+dialogporten-bot@users.noreply.github.com> Date: Fri, 13 Dec 2024 13:22:22 +0100 Subject: [PATCH 15/30] chore(main): release 1.41.3 (#1600) :robot: I have created a release *beep* *boop* --- ## [1.41.3](https://github.com/digdir/dialogporten/compare/v1.41.2...v1.41.3) (2024-12-13) ### Bug Fixes * **azure:** adjust SKU and storage for staging ([#1601](https://github.com/digdir/dialogporten/issues/1601)) ([3fb9f95](https://github.com/digdir/dialogporten/commit/3fb9f9501b4db97847aa1ebc0b77efe722811f0a)) * Collapse subject resource mappings before building sql query ([#1579](https://github.com/digdir/dialogporten/issues/1579)) ([b39c376](https://github.com/digdir/dialogporten/commit/b39c37662f61361b083d7addc60b26ad4e06fab6)) * **webapi:** Explicit null on non-nullable lists no longer causes 500 INTERNAL SERVER ERROR ([#1602](https://github.com/digdir/dialogporten/issues/1602)) ([2e8b3e6](https://github.com/digdir/dialogporten/commit/2e8b3e6db507efd195245ad829dd7d5a96f272ef)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- CHANGELOG.md | 9 +++++++++ version.txt | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e051daf4b..f1c23c3bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [1.41.3](https://github.com/digdir/dialogporten/compare/v1.41.2...v1.41.3) (2024-12-13) + + +### Bug Fixes + +* **azure:** adjust SKU and storage for staging ([#1601](https://github.com/digdir/dialogporten/issues/1601)) ([3fb9f95](https://github.com/digdir/dialogporten/commit/3fb9f9501b4db97847aa1ebc0b77efe722811f0a)) +* Collapse subject resource mappings before building sql query ([#1579](https://github.com/digdir/dialogporten/issues/1579)) ([b39c376](https://github.com/digdir/dialogporten/commit/b39c37662f61361b083d7addc60b26ad4e06fab6)) +* **webapi:** Explicit null on non-nullable lists no longer causes 500 INTERNAL SERVER ERROR ([#1602](https://github.com/digdir/dialogporten/issues/1602)) ([2e8b3e6](https://github.com/digdir/dialogporten/commit/2e8b3e6db507efd195245ad829dd7d5a96f272ef)) + ## [1.41.2](https://github.com/digdir/dialogporten/compare/v1.41.1...v1.41.2) (2024-12-12) diff --git a/version.txt b/version.txt index 5f2441072..021b2b85f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.41.2 +1.41.3 From 86a8680064b1914a9e41991bc0767a406c573f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Fri, 13 Dec 2024 13:23:59 +0100 Subject: [PATCH 16/30] chore: Warning/suppression cleanup in LocalDevelopmentAltinnAuthorization (#1592) --- .../Authorization/LocalDevelopmentAltinnAuthorization.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/LocalDevelopmentAltinnAuthorization.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/LocalDevelopmentAltinnAuthorization.cs index 7102db5e5..7e6b0593e 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/LocalDevelopmentAltinnAuthorization.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/LocalDevelopmentAltinnAuthorization.cs @@ -50,7 +50,6 @@ public async Task GetAuthorizedResourcesForSear return authorizedResources; } - [SuppressMessage("Performance", "CA1822:Mark members as static")] public async Task GetAuthorizedParties(IPartyIdentifier authenticatedParty, bool _ = false, CancellationToken __ = default) => await Task.FromResult(new AuthorizedPartiesResult { @@ -70,5 +69,5 @@ public async Task GetAuthorizedParties(IPartyIdentifier }] }); - public Task HasListAuthorizationForDialog(DialogEntity dialog, CancellationToken cancellationToken) => Task.FromResult(true); + public Task HasListAuthorizationForDialog(DialogEntity _, CancellationToken __) => Task.FromResult(true); } From 3e232878a2dcf1e0b416d57cc1217978bc635c6a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 15 Dec 2024 01:51:22 +0100 Subject: [PATCH 17/30] chore(deps): update dependency npgsql to 9.0.2 (#1603) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [Npgsql](https://redirect.github.com/npgsql/npgsql) | `9.0.1` -> `9.0.2` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/Npgsql/9.0.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/Npgsql/9.0.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/Npgsql/9.0.1/9.0.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Npgsql/9.0.1/9.0.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
npgsql/npgsql (Npgsql) ### [`v9.0.2`](https://redirect.github.com/npgsql/npgsql/releases/tag/v9.0.2) 9.0.2 was released to fix SSL certificate validation ([#​5942](https://redirect.github.com/npgsql/npgsql/issues/5942)). [Milestone issues](https://redirect.github.com/npgsql/npgsql/milestone/125?closed=1) **Full Changelog**: https://github.com/npgsql/npgsql/compare/v9.0.1...v9.0.2
--- ### Configuration πŸ“… **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Ole JΓΈrgen Skogstad --- .../Digdir.Domain.Dialogporten.Application.csproj | 4 ++-- .../Digdir.Domain.Dialogporten.ChangeDataCapture.csproj | 2 +- .../Digdir.Domain.Dialogporten.Infrastructure.csproj | 4 ++-- .../Digdir.Library.Utils.AspNet.csproj | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Application/Digdir.Domain.Dialogporten.Application.csproj b/src/Digdir.Domain.Dialogporten.Application/Digdir.Domain.Dialogporten.Application.csproj index 5a4988c7f..55cec0c47 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Digdir.Domain.Dialogporten.Application.csproj +++ b/src/Digdir.Domain.Dialogporten.Application/Digdir.Domain.Dialogporten.Application.csproj @@ -12,9 +12,9 @@ - + - + diff --git a/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Digdir.Domain.Dialogporten.ChangeDataCapture.csproj b/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Digdir.Domain.Dialogporten.ChangeDataCapture.csproj index f5a137b9b..0b174c305 100644 --- a/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Digdir.Domain.Dialogporten.ChangeDataCapture.csproj +++ b/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Digdir.Domain.Dialogporten.ChangeDataCapture.csproj @@ -3,7 +3,7 @@ - + diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj b/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj index 41f872f47..dba5240fb 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj @@ -13,8 +13,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj index 807c8851a..1c7b8d5e4 100644 --- a/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj +++ b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj @@ -14,7 +14,7 @@ - + From c8056b9062360cc60661b7b8f87ba8f79e6d7111 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 15 Dec 2024 14:39:34 +0100 Subject: [PATCH 18/30] chore(deps): update masstransit monorepo to 8.3.3 (#1605) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [MassTransit](https://masstransit.io/) ([source](https://redirect.github.com/MassTransit/MassTransit)) | `8.3.2` -> `8.3.3` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/MassTransit/8.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/MassTransit/8.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/MassTransit/8.3.2/8.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/MassTransit/8.3.2/8.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [MassTransit.Azure.ServiceBus.Core](https://masstransit.io/) ([source](https://redirect.github.com/MassTransit/MassTransit)) | `8.3.2` -> `8.3.3` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/MassTransit.Azure.ServiceBus.Core/8.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/MassTransit.Azure.ServiceBus.Core/8.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/MassTransit.Azure.ServiceBus.Core/8.3.2/8.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/MassTransit.Azure.ServiceBus.Core/8.3.2/8.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [MassTransit.EntityFrameworkCore](https://masstransit.io/) ([source](https://redirect.github.com/MassTransit/MassTransit)) | `8.3.2` -> `8.3.3` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/MassTransit.EntityFrameworkCore/8.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/MassTransit.EntityFrameworkCore/8.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/MassTransit.EntityFrameworkCore/8.3.2/8.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/MassTransit.EntityFrameworkCore/8.3.2/8.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Configuration πŸ“… **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../Digdir.Domain.Dialogporten.ChangeDataCapture.csproj | 2 +- .../Digdir.Domain.Dialogporten.Infrastructure.csproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Digdir.Domain.Dialogporten.ChangeDataCapture.csproj b/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Digdir.Domain.Dialogporten.ChangeDataCapture.csproj index 0b174c305..824248115 100644 --- a/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Digdir.Domain.Dialogporten.ChangeDataCapture.csproj +++ b/src/Digdir.Domain.Dialogporten.ChangeDataCapture/Digdir.Domain.Dialogporten.ChangeDataCapture.csproj @@ -2,7 +2,7 @@ - + diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj b/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj index dba5240fb..6a28c8b85 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj @@ -3,8 +3,8 @@ - - + + From ac4b6448b4ceb518f0606a5fbada28da3d15744a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 15 Dec 2024 17:46:14 +0100 Subject: [PATCH 19/30] chore(deps): update dotnet-azure-ad-identitymodel-extensions monorepo to 8.3.0 (#1607) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [Microsoft.IdentityModel.JsonWebTokens](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) | `8.2.1` -> `8.3.0` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/Microsoft.IdentityModel.JsonWebTokens/8.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/Microsoft.IdentityModel.JsonWebTokens/8.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/Microsoft.IdentityModel.JsonWebTokens/8.2.1/8.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Microsoft.IdentityModel.JsonWebTokens/8.2.1/8.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [System.IdentityModel.Tokens.Jwt](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) | `8.2.1` -> `8.3.0` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/System.IdentityModel.Tokens.Jwt/8.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/System.IdentityModel.Tokens.Jwt/8.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/System.IdentityModel.Tokens.Jwt/8.2.1/8.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/System.IdentityModel.Tokens.Jwt/8.2.1/8.3.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet (Microsoft.IdentityModel.JsonWebTokens) ### [`v8.3.0`](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/HEAD/CHANGELOG.md#830) [Compare Source](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/8.2.1...8.3.0) \===== #### New features ##### Work related to redesign of IdentityModel's token validation logic [#​2711](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/2711) - SAML and SAML2 new model validation: Token Replay. See [#​2994](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/2994) - Extensibility tests: Token Type - JWT ([#​3030](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3030)), Issuer - SAML and SAML2 ([#​3026](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3026)), Algorithm and Signature - JWT, SAML and SAML2 ([#​3034](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3034)), Token Replay - JWT, SAML and SAML2 ([#​3032](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3032)), Issuer signing key - JWT, SAML and SAML2 ([#​3029](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/302)) - Avoid code duplication in extensibility testing. See [#​3041](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3041) - Extensibility Testing: Refactor. See [https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3011](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3011) - Remove duplicate code in extensibility tests. See [https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3044](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3044) #### Bug fixes - Fix bug with AadIssuerValidator. See [https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3042](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3042) - Fixed SignedHttpRequest flaky test. See [#​3037](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3037) #### Fundamentals - Install all .NET versions in pipeline to fix run tests task. See [https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3018](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3018) - Changelog for 8.2.1. See [https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3009](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3009) - Remove unnecessary AoT test project. See in [https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3045](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3045) - Fix powershell script for nuget update. See [https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3046](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3046) - Update to next version. See [https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3010](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3010) - Disable Coverage PR comments. See [https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3048](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3048) - Updates GitHub Action to support long paths, See [https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3049](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3049) - Stack parameters to improve reading of code. by [@​brentschmaltz](https://redirect.github.com/brentschmaltz) in [https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3031](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3031) #### New Contributors - [@​ssmelov](https://redirect.github.com/ssmelov) made their first contribution in [https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3042](https://redirect.github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3042)
--- ### Configuration πŸ“… **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../Digdir.Domain.Dialogporten.GraphQL.csproj | 4 ++-- .../Digdir.Domain.Dialogporten.Infrastructure.csproj | 4 ++-- .../Digdir.Domain.Dialogporten.WebApi.csproj | 4 ++-- ...r.Domain.Dialogporten.Application.Integration.Tests.csproj | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.GraphQL/Digdir.Domain.Dialogporten.GraphQL.csproj b/src/Digdir.Domain.Dialogporten.GraphQL/Digdir.Domain.Dialogporten.GraphQL.csproj index 7410002e9..47b62ee5d 100644 --- a/src/Digdir.Domain.Dialogporten.GraphQL/Digdir.Domain.Dialogporten.GraphQL.csproj +++ b/src/Digdir.Domain.Dialogporten.GraphQL/Digdir.Domain.Dialogporten.GraphQL.csproj @@ -10,9 +10,9 @@ - + - +
diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj b/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj index 6a28c8b85..847c03471 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj @@ -6,9 +6,9 @@ - + - + diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj b/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj index 2641131ac..590d00b8d 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj +++ b/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj @@ -12,8 +12,8 @@ - - + + diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Digdir.Domain.Dialogporten.Application.Integration.Tests.csproj b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Digdir.Domain.Dialogporten.Application.Integration.Tests.csproj index 06df06b6c..942a0cc2e 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Digdir.Domain.Dialogporten.Application.Integration.Tests.csproj +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Digdir.Domain.Dialogporten.Application.Integration.Tests.csproj @@ -7,8 +7,8 @@ - - + + From 695f4dc723941bdb213b153e5e847c9d4b3727d5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 15 Dec 2024 19:09:33 +0100 Subject: [PATCH 20/30] chore(deps): update dependency opentelemetry.instrumentation.runtime to 1.10.0 (#1606) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [OpenTelemetry.Instrumentation.Runtime](https://opentelemetry.io/) ([source](https://redirect.github.com/open-telemetry/opentelemetry-dotnet-contrib)) | `1.9.0` -> `1.10.0` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/OpenTelemetry.Instrumentation.Runtime/1.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/OpenTelemetry.Instrumentation.Runtime/1.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/OpenTelemetry.Instrumentation.Runtime/1.9.0/1.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/OpenTelemetry.Instrumentation.Runtime/1.9.0/1.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Configuration πŸ“… **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../Digdir.Library.Utils.AspNet.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj index 1c7b8d5e4..cab4e5a23 100644 --- a/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj +++ b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj @@ -16,7 +16,7 @@ - + From ab0222ea4ee8578f5e3fcf0e97bc8bd1458154db Mon Sep 17 00:00:00 2001 From: Dagfinn Olsen Date: Mon, 16 Dec 2024 08:16:02 +0100 Subject: [PATCH 21/30] chore: fix labels in k6 reports (#1599) The labels in k6 reports for enduser search was wrong, showing nothing ## Description ## Related Issue(s) - #{issue number} ## Verification - [ ] **Your** code builds clean without any errors or warnings - [ ] Manual testing done (required) - [ ] Relevant automated test added (if you find this hard, leave it and we'll help out) ## Documentation - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable) --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../enduser/enduserSearchWithThresholds.js | 28 +++++++++---------- .../enduser/performance/enduser-search.js | 16 +++++------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/k6/tests/enduser/enduserSearchWithThresholds.js b/tests/k6/tests/enduser/enduserSearchWithThresholds.js index eb2d3b6c1..8855cb07a 100644 --- a/tests/k6/tests/enduser/enduserSearchWithThresholds.js +++ b/tests/k6/tests/enduser/enduserSearchWithThresholds.js @@ -6,21 +6,21 @@ export let options = { duration: "30s", thresholds: { "http_req_duration{name:enduser search}": ["p(95)<300", "p(99)<500"], - "http_req_duration{name:enduser get dialog}": ["p(95)<300", "p(99)<500"], - "http_req_duration{name:enduser get dialog activities}": ["p(95)<300", "p(99)<500"], - "http_req_duration{name:enduser get dialog activity}": ["p(95)<300", "p(99)<500"], - "http_req_duration{name:enduser get seenlogs}": ["p(95)<300", "p(99)<500"], - "http_req_duration{name:enduser get transmissions}": ["p(95)<300", "p(99)<500"], - "http_req_duration{name:enduser get transmission}": ["p(95)<300", "p(99)<500"], - "http_req_duration{name:enduser get labellog}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:get dialog}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:get dialog activities}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:get dialog activity}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:get seenlogs}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:get transmissions}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:get transmission}": ["p(95)<300", "p(99)<500"], + "http_req_duration{name:get labellog}": ["p(95)<300", "p(99)<500"], "http_reqs{name:enduser search}": [], - "http_reqs{name:enduser get dialog activities}": [], - "http_reqs{name:enduser get dialog activity}": [], - "http_reqs{name:enduser get seenlogs}": [], - "http_reqs{name:enduser get transmissions}": [], - "http_reqs{name:enduser get transmission}": [], - "http_reqs{name:enduser get dialog}": [], - "http_reqs{name:enduser get labellog}": [], + "http_reqs{name:get dialog activities}": [], + "http_reqs{name:get dialog activity}": [], + "http_reqs{name:get seenlogs}": [], + "http_reqs{name:get transmissions}": [], + "http_reqs{name:get transmission}": [], + "http_reqs{name:get dialog}": [], + "http_reqs{name:get labellog}": [], } } diff --git a/tests/k6/tests/enduser/performance/enduser-search.js b/tests/k6/tests/enduser/performance/enduser-search.js index 90fd03737..41f1b0d7c 100644 --- a/tests/k6/tests/enduser/performance/enduser-search.js +++ b/tests/k6/tests/enduser/performance/enduser-search.js @@ -8,14 +8,14 @@ const traceCalls = (__ENV.traceCalls ?? 'false') === 'true'; export let options = { summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.5)', 'p(99.9)', 'count'], thresholds: getDefaultThresholds(['http_req_duration', 'http_reqs'],['enduser search', - 'enduser get dialog', - 'enduser get dialog activities', - 'enduser get dialog activity', - 'enduser get seenlogs', - 'enduser get seenlog', - 'enduser get transmissions', - 'enduser get transmission', - 'enduser get labellog' + 'get dialog', + 'get dialog activities', + 'get dialog activity', + 'get seenlogs', + 'get seenlog', + 'get transmissions', + 'get transmission', + 'get labellog' ]) }; From c41b2582c741e0285f0c2a1e81b7bfadd049e42e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:38:50 +0100 Subject: [PATCH 22/30] chore(deps): update dependency medo.uuid7 to v3 (#1608) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [Medo.Uuid7](https://redirect.github.com/medo64/Medo.Uuid7) | `2.1.1` -> `3.0.0` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/Medo.Uuid7/3.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/Medo.Uuid7/3.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/Medo.Uuid7/2.1.1/3.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Medo.Uuid7/2.1.1/3.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Configuration πŸ“… **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Ole JΓΈrgen Skogstad --- .../Digdir.Library.Entity.Abstractions.csproj | 2 +- .../Identifiable/IdentifiableExtensions.cs | 14 +++++++++----- .../DialogGenerator.cs | 4 ++-- .../V1/Common/Events/DomainEventsTests.cs | 8 ++++---- .../Dialogs/Commands/CreateDialogTests.cs | 18 +++++++++--------- .../Dialogs/Commands/PurgeDialogTests.cs | 8 ++++---- .../Dialogs/Queries/GetDialogTests.cs | 6 +++--- .../Commands/CreateTransmissionTests.cs | 8 ++++---- .../Commands/UpdateTransmissionTests.cs | 4 ++-- .../UUIDv7Utils.cs | 10 ---------- ...main.Dialogporten.Architecture.Tests.csproj | 2 +- 11 files changed, 39 insertions(+), 45 deletions(-) delete mode 100644 tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/UUIDv7Utils.cs diff --git a/src/Digdir.Library.Entity.Abstractions/Digdir.Library.Entity.Abstractions.csproj b/src/Digdir.Library.Entity.Abstractions/Digdir.Library.Entity.Abstractions.csproj index cb9c284f0..d9961bfe5 100644 --- a/src/Digdir.Library.Entity.Abstractions/Digdir.Library.Entity.Abstractions.csproj +++ b/src/Digdir.Library.Entity.Abstractions/Digdir.Library.Entity.Abstractions.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/Digdir.Library.Entity.Abstractions/Features/Identifiable/IdentifiableExtensions.cs b/src/Digdir.Library.Entity.Abstractions/Features/Identifiable/IdentifiableExtensions.cs index 51db679dd..5c647cc26 100644 --- a/src/Digdir.Library.Entity.Abstractions/Features/Identifiable/IdentifiableExtensions.cs +++ b/src/Digdir.Library.Entity.Abstractions/Features/Identifiable/IdentifiableExtensions.cs @@ -32,11 +32,15 @@ public static Guid CreateVersion7IfDefault(this Guid value) => /// /// Creates a new version 7 UUID. + /// /// /// A new version 7 UUID in big endian format. - public static Guid CreateVersion7() => - // We want Guids in big endian format. The default behavior of Medo is big endian, - // however, the implicit conversion from Medo.Uuid7 to Guid is little endian. - // "matchGuidEndianness" is set to true to ensure big endian. - Uuid7.NewUuid7().ToGuid(matchGuidEndianness: true); + // We want Guids in big endian text representation. + // The default behavior of Medo is bigEndian text representation, + // Setting bigEndian to false for two reasons: + // 1. Use the parameter name explicitly in case the Medo API changes + // 2. Make it clear that we want big endian text representation, which means little endian byte order + public static Guid CreateVersion7(DateTimeOffset? timeStamp = null) => timeStamp is null + ? Uuid7.NewUuid7().ToGuid(bigEndian: false) + : Uuid7.NewUuid7(timeStamp.Value).ToGuid(bigEndian: false); } diff --git a/src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs b/src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs index 7b0af6a26..4cbd05a9d 100644 --- a/src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs +++ b/src/Digdir.Tool.Dialogporten.GenerateFakeData/DialogGenerator.cs @@ -242,7 +242,7 @@ public static List GenerateFakeDialogTransmissions(int? count = DialogTransmissionType.Values? type = null) { return new Faker() - .RuleFor(o => o.Id, _ => Uuid7.NewUuid7().ToGuid(true)) + .RuleFor(o => o.Id, _ => IdentifiableExtensions.CreateVersion7()) .RuleFor(o => o.CreatedAt, f => f.Date.Past()) .RuleFor(o => o.Type, f => type ?? f.PickRandom()) .RuleFor(o => o.Sender, _ => new() { ActorType = ActorType.Values.ServiceOwner }) @@ -262,7 +262,7 @@ public static List GenerateFakeDialogActivities(int? count = null, .Where(x => x != DialogActivityType.Values.TransmissionOpened).ToList(); return new Faker() - .RuleFor(o => o.Id, () => Uuid7.NewUuid7().ToGuid(true)) + .RuleFor(o => o.Id, () => IdentifiableExtensions.CreateVersion7()) .RuleFor(o => o.CreatedAt, f => f.Date.Past()) .RuleFor(o => o.ExtendedType, f => new Uri(f.Internet.UrlWithPath(Uri.UriSchemeHttps))) .RuleFor(o => o.Type, f => type ?? f.PickRandom(activityTypes)) diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/Common/Events/DomainEventsTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/Common/Events/DomainEventsTests.cs index 115184cb9..306d3100a 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/Common/Events/DomainEventsTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/Common/Events/DomainEventsTests.cs @@ -11,9 +11,9 @@ using Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Commands.Delete; using Digdir.Domain.Dialogporten.Domain.Attachments; using Digdir.Domain.Dialogporten.Domain.Dialogs.Events.Activities; +using Digdir.Library.Entity.Abstractions.Features.Identifiable; using MassTransit.Internals; using MassTransit.Testing; -using static Digdir.Domain.Dialogporten.Application.Integration.Tests.UuiDv7Utils; namespace Digdir.Domain.Dialogporten.Application.Integration.Tests.Features.V1.Common.Events; @@ -126,7 +126,7 @@ public async Task Creates_CloudEvent_When_Attachments_Updates() { // Arrange var harness = await Application.ConfigureServicesWithMassTransitTestHarness(); - var dialogId = GenerateBigEndianUuidV7(); + var dialogId = IdentifiableExtensions.CreateVersion7(); var createDialogCommand = DialogGenerator.GenerateFakeDialog( id: dialogId, attachments: []); @@ -174,7 +174,7 @@ public async Task Creates_CloudEvents_When_Dialog_Deleted() { // Arrange var harness = await Application.ConfigureServicesWithMassTransitTestHarness(); - var dialogId = GenerateBigEndianUuidV7(); + var dialogId = IdentifiableExtensions.CreateVersion7(); var createDialogCommand = DialogGenerator.GenerateFakeDialog(id: dialogId, attachments: [], activities: []); await Application.Send(createDialogCommand); @@ -204,7 +204,7 @@ public async Task Creates_DialogDeletedEvent_When_Dialog_Purged() { // Arrange var harness = await Application.ConfigureServicesWithMassTransitTestHarness(); - var dialogId = GenerateBigEndianUuidV7(); + var dialogId = IdentifiableExtensions.CreateVersion7(); var createDialogCommand = DialogGenerator.GenerateFakeDialog(id: dialogId, attachments: [], activities: []); await Application.Send(createDialogCommand); diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/CreateDialogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/CreateDialogTests.cs index 9e7323f2c..ef91ba303 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/CreateDialogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/CreateDialogTests.cs @@ -5,11 +5,11 @@ using Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Get; using Digdir.Domain.Dialogporten.Application.Integration.Tests.Common; using Digdir.Domain.Dialogporten.Domain; +using Digdir.Library.Entity.Abstractions.Features.Identifiable; using Digdir.Tool.Dialogporten.GenerateFakeData; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -using static Digdir.Domain.Dialogporten.Application.Integration.Tests.UuiDv7Utils; namespace Digdir.Domain.Dialogporten.Application.Integration.Tests.Features.V1.ServiceOwner.Dialogs.Commands; @@ -38,8 +38,8 @@ public async Task Cant_Create_Dialog_With_UUIDv4_format() public async Task Cant_Create_Dialog_With_UUIDv7_In_Little_Endian_Format() { // Arrange - // Guid created with Medo, Uuid7.NewUuid7().ToGuid() - var invalidDialogId = Guid.Parse("638e9101-6bc7-7975-b392-ba5c5a528c23"); + // Guid created with Medo, Uuid7.NewUuid7().ToGuid(bigEndian: true) + var invalidDialogId = Guid.Parse("b2ca9301-c371-ab74-a87b-4ee1416b9655"); var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(id: invalidDialogId); @@ -56,7 +56,7 @@ public async Task Cant_Create_Dialog_With_ID_With_Timestamp_In_The_Future() { // Arrange var timestamp = DateTimeOffset.UtcNow.AddSeconds(1); - var invalidDialogId = GenerateBigEndianUuidV7(timestamp); + var invalidDialogId = IdentifiableExtensions.CreateVersion7(timestamp); var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(id: invalidDialogId); @@ -73,7 +73,7 @@ public async Task Create_Dialog_With_ID_With_Timestamp_In_The_Past() { // Arrange var timestamp = DateTimeOffset.UtcNow.AddSeconds(-1); - var validDialogId = GenerateBigEndianUuidV7(timestamp); + var validDialogId = IdentifiableExtensions.CreateVersion7(timestamp); var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(id: validDialogId); @@ -90,7 +90,7 @@ public async Task Create_Dialog_With_ID_With_Timestamp_In_The_Past() public async Task Create_CreatesDialog_WhenDialogIsSimple() { // Arrange - var expectedDialogId = GenerateBigEndianUuidV7(); + var expectedDialogId = IdentifiableExtensions.CreateVersion7(); var createCommand = DialogGenerator.GenerateSimpleFakeDialog(id: expectedDialogId); // Act @@ -105,7 +105,7 @@ public async Task Create_CreatesDialog_WhenDialogIsSimple() public async Task Create_CreateDialog_WhenDialogIsComplex() { // Arrange - var expectedDialogId = GenerateBigEndianUuidV7(); + var expectedDialogId = IdentifiableExtensions.CreateVersion7(); var createDialogCommand = DialogGenerator.GenerateFakeDialog(id: expectedDialogId); // Act @@ -120,7 +120,7 @@ public async Task Create_CreateDialog_WhenDialogIsComplex() public async Task Can_Create_Dialog_With_UpdatedAt_Supplied() { // Arrange - var dialogId = GenerateBigEndianUuidV7(); + var dialogId = IdentifiableExtensions.CreateVersion7(); var createdAt = DateTimeOffset.UtcNow.AddYears(-20); var updatedAt = DateTimeOffset.UtcNow.AddYears(-15); var createDialogCommand = DialogGenerator.GenerateFakeDialog(id: dialogId, updatedAt: updatedAt, createdAt: createdAt); @@ -387,7 +387,7 @@ public async Task Cannot_Create_Title_Content_With_Embeddable_Html_MediaType_Wit public async Task Can_Create_MainContentRef_Content_With_Embeddable_Html_MediaType_With_Correct_Scope() { // Arrange - var expectedDialogId = GenerateBigEndianUuidV7(); + var expectedDialogId = IdentifiableExtensions.CreateVersion7(); var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(id: expectedDialogId); createDialogCommand.Content.MainContentReference = new ContentValueDto { diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/PurgeDialogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/PurgeDialogTests.cs index f1da5c248..22adc5938 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/PurgeDialogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Commands/PurgeDialogTests.cs @@ -2,9 +2,9 @@ using Digdir.Domain.Dialogporten.Application.Integration.Tests.Common; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Activities; +using Digdir.Library.Entity.Abstractions.Features.Identifiable; using Digdir.Tool.Dialogporten.GenerateFakeData; using FluentAssertions; -using static Digdir.Domain.Dialogporten.Application.Integration.Tests.UuiDv7Utils; namespace Digdir.Domain.Dialogporten.Application.Integration.Tests.Features.V1.ServiceOwner.Dialogs.Commands; @@ -15,7 +15,7 @@ public class PurgeDialogTests(DialogApplication application) : ApplicationCollec public async Task Purge_RemovesDialog_FromDatabase() { // Arrange - var expectedDialogId = GenerateBigEndianUuidV7(); + var expectedDialogId = IdentifiableExtensions.CreateVersion7(); var createCommand = DialogGenerator.GenerateFakeDialog(id: expectedDialogId); var createResponse = await Application.Send(createCommand); createResponse.TryPickT0(out _, out _).Should().BeTrue(); @@ -41,7 +41,7 @@ public async Task Purge_RemovesDialog_FromDatabase() public async Task Purge_ReturnsConcurrencyError_OnIfMatchDialogRevisionMismatch() { // Arrange - var expectedDialogId = GenerateBigEndianUuidV7(); + var expectedDialogId = IdentifiableExtensions.CreateVersion7(); var createCommand = DialogGenerator.GenerateFakeDialog(id: expectedDialogId); var createResponse = await Application.Send(createCommand); createResponse.TryPickT0(out _, out _).Should().BeTrue(); @@ -58,7 +58,7 @@ public async Task Purge_ReturnsConcurrencyError_OnIfMatchDialogRevisionMismatch( public async Task Purge_ReturnsNotFound_OnNonExistingDialog() { // Arrange - var expectedDialogId = GenerateBigEndianUuidV7(); + var expectedDialogId = IdentifiableExtensions.CreateVersion7(); var createCommand = DialogGenerator.GenerateFakeDialog(id: expectedDialogId); await Application.Send(createCommand); var purgeCommand = new PurgeDialogCommand { DialogId = expectedDialogId }; diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/GetDialogTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/GetDialogTests.cs index 2493b064f..cadeb8a92 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/GetDialogTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Dialogs/Queries/GetDialogTests.cs @@ -1,8 +1,8 @@ ο»Ώusing Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialogs.Queries.Get; using Digdir.Domain.Dialogporten.Application.Integration.Tests.Common; +using Digdir.Library.Entity.Abstractions.Features.Identifiable; using Digdir.Tool.Dialogporten.GenerateFakeData; using FluentAssertions; -using static Digdir.Domain.Dialogporten.Application.Integration.Tests.UuiDv7Utils; namespace Digdir.Domain.Dialogporten.Application.Integration.Tests.Features.V1.ServiceOwner.Dialogs.Queries; @@ -15,7 +15,7 @@ public GetDialogTests(DialogApplication application) : base(application) { } public async Task Get_ReturnsSimpleDialog_WhenDialogExists() { // Arrange - var expectedDialogId = GenerateBigEndianUuidV7(); + var expectedDialogId = IdentifiableExtensions.CreateVersion7(); var createDialogCommand = DialogGenerator.GenerateSimpleFakeDialog(id: expectedDialogId); var createCommandResponse = await Application.Send(createDialogCommand); @@ -36,7 +36,7 @@ public async Task Get_ReturnsSimpleDialog_WhenDialogExists() public async Task Get_ReturnsDialog_WhenDialogExists() { // Arrange - var expectedDialogId = GenerateBigEndianUuidV7(); + var expectedDialogId = IdentifiableExtensions.CreateVersion7(); var createCommand = DialogGenerator.GenerateFakeDialog(id: expectedDialogId); var createCommandResponse = await Application.Send(createCommand); diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/CreateTransmissionTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/CreateTransmissionTests.cs index 27cfeb4a9..e0cd3e275 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/CreateTransmissionTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/CreateTransmissionTests.cs @@ -4,9 +4,9 @@ using Digdir.Domain.Dialogporten.Domain; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions.Contents; +using Digdir.Library.Entity.Abstractions.Features.Identifiable; using Digdir.Tool.Dialogporten.GenerateFakeData; using FluentAssertions; -using static Digdir.Domain.Dialogporten.Application.Integration.Tests.UuiDv7Utils; namespace Digdir.Domain.Dialogporten.Application.Integration.Tests.Features.V1.ServiceOwner.Transmissions.Commands; @@ -19,7 +19,7 @@ public CreateTransmissionTests(DialogApplication application) : base(application public async Task Can_Create_Simple_Transmission() { // Arrange - var dialogId = GenerateBigEndianUuidV7(); + var dialogId = IdentifiableExtensions.CreateVersion7(); var createCommand = DialogGenerator.GenerateSimpleFakeDialog(id: dialogId); var transmission = DialogGenerator.GenerateFakeDialogTransmissions(1)[0]; @@ -41,10 +41,10 @@ public async Task Can_Create_Simple_Transmission() public async Task Can_Create_Transmission_With_Embeddable_Content() { // Arrange - var dialogId = GenerateBigEndianUuidV7(); + var dialogId = IdentifiableExtensions.CreateVersion7(); var createCommand = DialogGenerator.GenerateSimpleFakeDialog(id: dialogId); - var transmissionId = GenerateBigEndianUuidV7(); + var transmissionId = IdentifiableExtensions.CreateVersion7(); var transmission = DialogGenerator.GenerateFakeDialogTransmissions(1)[0]; const string contentUrl = "https://example.com/transmission"; diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/UpdateTransmissionTests.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/UpdateTransmissionTests.cs index 261e36056..a7e57c4d9 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/UpdateTransmissionTests.cs +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Features/V1/ServiceOwner/Transmissions/Commands/UpdateTransmissionTests.cs @@ -3,9 +3,9 @@ using Digdir.Domain.Dialogporten.Application.Integration.Tests.Common; using Digdir.Domain.Dialogporten.Domain.Actors; using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities.Transmissions; +using Digdir.Library.Entity.Abstractions.Features.Identifiable; using Digdir.Tool.Dialogporten.GenerateFakeData; using FluentAssertions; -using static Digdir.Domain.Dialogporten.Application.Integration.Tests.UuiDv7Utils; namespace Digdir.Domain.Dialogporten.Application.Integration.Tests.Features.V1.ServiceOwner.Transmissions.Commands; @@ -122,7 +122,7 @@ public async Task Cannot_Include_Old_Transmissions_In_UpdateCommand() private static TransmissionDto UpdateDialogDialogTransmissionDto() => new() { - Id = GenerateBigEndianUuidV7(), + Id = IdentifiableExtensions.CreateVersion7(), Type = DialogTransmissionType.Values.Information, Sender = new() { ActorType = ActorType.Values.ServiceOwner }, Content = new() diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/UUIDv7Utils.cs b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/UUIDv7Utils.cs deleted file mode 100644 index 040fac197..000000000 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/UUIDv7Utils.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Medo; - -namespace Digdir.Domain.Dialogporten.Application.Integration.Tests; - -public static class UuiDv7Utils -{ - public static Guid GenerateBigEndianUuidV7(DateTimeOffset? timeStamp = null) => timeStamp is null ? - Uuid7.NewUuid7().ToGuid(matchGuidEndianness: true) - : Uuid7.NewUuid7(timeStamp.Value).ToGuid(matchGuidEndianness: true); -} diff --git a/tests/Digdir.Domain.Dialogporten.Architecture.Tests/Digdir.Domain.Dialogporten.Architecture.Tests.csproj b/tests/Digdir.Domain.Dialogporten.Architecture.Tests/Digdir.Domain.Dialogporten.Architecture.Tests.csproj index c7b365548..2d86c1eb2 100644 --- a/tests/Digdir.Domain.Dialogporten.Architecture.Tests/Digdir.Domain.Dialogporten.Architecture.Tests.csproj +++ b/tests/Digdir.Domain.Dialogporten.Architecture.Tests/Digdir.Domain.Dialogporten.Architecture.Tests.csproj @@ -8,7 +8,7 @@ - + From e375225fe081d72d1da536f0ec1dfaa0753a25bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Mon, 16 Dec 2024 12:51:55 +0100 Subject: [PATCH 23/30] chore: Group NuGet upgrades in RenovateBot PRs (#1609) Grouping by Microsoft, Npgsql, and Serillog to begin with --- renovate.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/renovate.json b/renovate.json index 74b545b9a..026d030e0 100644 --- a/renovate.json +++ b/renovate.json @@ -17,6 +17,24 @@ "schedule": [ "every 3 months" ] + }, + { + "packagePatterns": [ + "^Npgsql" + ], + "groupName": "Npgsql dependencies" + }, + { + "packagePatterns": [ + "^Microsoft" + ], + "groupName": "Microsoft dependencies" + }, + { + "packagePatterns": [ + "^Serilog" + ], + "groupName": "Serilog dependencies" } ] } From 1f69b9bc0144650197444d5a93de519949943893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Mon, 16 Dec 2024 13:37:53 +0100 Subject: [PATCH 24/30] chore(webapi): Remove specific mediatypes on ContentValueDto (#1614) ## Description ## Related Issue(s) - #1613 ## Verification - [ ] **Your** code builds clean without any errors or warnings - [ ] Manual testing done (required) - [ ] Relevant automated test added (if you find this hard, leave it and we'll help out) ## Documentation - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable) --- docs/schema/V1/swagger.verified.json | 4 ++-- .../Features/V1/Common/Content/ContentValueDto.cs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/schema/V1/swagger.verified.json b/docs/schema/V1/swagger.verified.json index e617e216e..51d6c547a 100644 --- a/docs/schema/V1/swagger.verified.json +++ b/docs/schema/V1/swagger.verified.json @@ -315,7 +315,7 @@ "additionalProperties": false, "properties": { "mediaType": { - "description": "Media type of the content (plaintext, Markdown). Can also indicate that the content is embeddable.", + "description": "Media type of the content, this can also indicate that the content is embeddable.\nFor a list of supported media types, see (link TBD).", "type": "string" }, "value": { @@ -6970,4 +6970,4 @@ "url": "https://altinn-dev-api.azure-api.net/dialogporten" } ] -} +} \ No newline at end of file diff --git a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDto.cs b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDto.cs index c3db7d6a5..58f5bf96c 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDto.cs +++ b/src/Digdir.Domain.Dialogporten.Application/Features/V1/Common/Content/ContentValueDto.cs @@ -11,7 +11,8 @@ public sealed class ContentValueDto public List Value { get; set; } = []; /// - /// Media type of the content (plaintext, Markdown). Can also indicate that the content is embeddable. + /// Media type of the content, this can also indicate that the content is embeddable. + /// For a list of supported media types, see (link TBD). /// public string MediaType { get; set; } = MediaTypes.PlainText; } From 198f73594149c6eca9e28ec339352e24eab43e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Mon, 16 Dec 2024 14:08:29 +0100 Subject: [PATCH 25/30] chore: Temp. disable automatic deploy to yt01 (#1610) --- .github/workflows/ci-cd-yt01.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-cd-yt01.yml b/.github/workflows/ci-cd-yt01.yml index a047d1a68..5be411d67 100644 --- a/.github/workflows/ci-cd-yt01.yml +++ b/.github/workflows/ci-cd-yt01.yml @@ -2,9 +2,9 @@ on: workflow_dispatch: - push: - tags: - - "v*.*.*" +# push: +# tags: +# - "v*.*.*" concurrency: group: ${{ github.workflow }}-${{ github.ref_name }} @@ -152,15 +152,15 @@ jobs: TOKEN_GENERATOR_PASSWORD: ${{ secrets.TOKEN_GENERATOR_PASSWORD }} K6_CLOUD_TOKEN: ${{ secrets.K6_CLOUD_TOKEN }} K6_CLOUD_PROJECT_ID: ${{ secrets.K6_CLOUD_PROJECT_ID }} - + strategy: max-parallel: 1 matrix: - files: + files: - tests/k6/tests/serviceowner/serviceOwnerSearchWithThresholds.js - tests/k6/tests/serviceowner/createDialogWithThresholds.js - tests/k6/tests/enduser/enduserSearchWithThresholds.js - fail-fast: false + fail-fast: false with: environment: yt01 apiVersion: v1 From cb9238ef76188b4dde371e08b7ce597645bcd8b7 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Mon, 16 Dec 2024 16:38:12 +0100 Subject: [PATCH 26/30] feat(apps): add otel exporter for graphql, service and web-api (#1528) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description - Sets up local OTEL setup that match the OTEL configuration in Azure Container Apps - Added fusioncache telemetry - Added Entity Framework telemetry - Missing liveMetrics if we want that. Needs to be considered. Other than that, the most relevant traces are pulled out from the AzureMonitor package. - Metrics are only visible locally for now. Turns out that the Azure Monitor Workspace has a Prometheus instance, but it does not allow for us sending metrics to it, as it does not have an OTEL endpoint πŸ™ƒ Solution here was adding the MetricsMonitor to send metrics directly to app insights for now..! - Will add logging in the next PR To see your metrics, spin up the OTEL services by running `docker-compose-otel.yml`. The service should start sending to the OTLP collector automatically. Example of a trace in the local Jaeger: ![CleanShot 2024-12-09 at 17 52 11@2x](https://github.com/user-attachments/assets/295eba27-84e8-4735-9a0e-be4f2fcfed9c) ## Related Issue(s) - #1465 ## Verification - [ ] **Your** code builds clean without any errors or warnings - [ ] Manual testing done (required) - [ ] Relevant automated test added (if you find this hard, leave it and we'll help out) ## Documentation - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable) --------- Co-authored-by: Ole JΓΈrgen Skogstad --- .env | 5 + README.md | 62 +++ docker-compose-otel.yml | 45 ++ docker-compose.yml | 11 +- .../dashboards/aspnet-core-metrics.json | 176 ++++++++ .../dashboards/dashboards.yml | 0 .../dashboards/http-client-metrics.json | 296 +++++++++++++ .../dashboards/runtime-metrics.json | 390 ++++++++++++++++++ .../grafana-dashboards.yml | 11 + .../grafana-datasources.yml | 8 + .../otel-collector-config.yaml | 52 +++ local-otel-configuration/prometheus.yml | 8 + .../OpenTelemetryEventListener.cs | 1 - .../Program.cs | 15 +- .../Program.cs | 9 +- .../Digdir.Domain.Dialogporten.WebApi.csproj | 10 +- .../OpenApiDocumentExtensions.cs | 1 - .../Program.cs | 9 +- .../appsettings.json | 2 +- .../AspNetUtilitiesExtensions.cs | 126 ++++-- .../AspNetUtilitiesSettings.cs | 18 + .../Digdir.Library.Utils.AspNet.csproj | 5 +- 22 files changed, 1217 insertions(+), 43 deletions(-) create mode 100644 docker-compose-otel.yml create mode 100644 local-otel-configuration/dashboards/aspnet-core-metrics.json create mode 100755 local-otel-configuration/dashboards/dashboards.yml create mode 100644 local-otel-configuration/dashboards/http-client-metrics.json create mode 100644 local-otel-configuration/dashboards/runtime-metrics.json create mode 100644 local-otel-configuration/grafana-dashboards.yml create mode 100644 local-otel-configuration/grafana-datasources.yml create mode 100644 local-otel-configuration/otel-collector-config.yaml create mode 100644 local-otel-configuration/prometheus.yml diff --git a/.env b/.env index 8300930d6..2309e6938 100644 --- a/.env +++ b/.env @@ -5,3 +5,8 @@ POSTGRES_DB=dialogporten DB_CONNECTION_STRING=Server=dialogporten-postgres;Port=5432;Database=${POSTGRES_DB};User ID=${POSTGRES_USER};Password=${POSTGRES_PASSWORD}; COMPOSE_PROJECT_NAME=digdir + +# OTEL +OTEL_NAMESPACE=dialogporten-local +OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 +OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \ No newline at end of file diff --git a/README.md b/README.md index 0135ecec0..f258d0634 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,68 @@ Besides ordinary unit and integration tests, there are test suites for both func See `tests/k6/README.md` for more information. +## Health Checks + +The project includes integrated health checks that are exposed through standard endpoints: +- `/health/startup` - Dependency checks +- `/health/liveness` - Self checks +- `/health/readiness` - Critical service checks +- `/health` - General health status +- `/health/deep` - Comprehensive health check including external services + +These health checks are integrated with Azure Container Apps' health probe system and are used to monitor the application's health status. + +## Observability with OpenTelemetry + +This project uses OpenTelemetry for distributed tracing and metrics collection. The setup includes: + +### Core Features +- Distributed tracing across services +- Runtime and application metrics +- Integration with Azure Monitor/Application Insights +- Support for both OTLP and Azure Monitor exporters +- Automatic instrumentation for: + - ASP.NET Core + - HTTP clients + - Entity Framework Core + - PostgreSQL + - FusionCache + +### Configuration + +OpenTelemetry is configured through environment variables that are automatically provided by Azure Container Apps in production environments: + +```json +{ + "OTEL_SERVICE_NAME": "your-service-name", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://your-collector:4317", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_RESOURCE_ATTRIBUTES": "key1=value1,key2=value2", + "APPLICATIONINSIGHTS_CONNECTION_STRING": "your-connection-string" +} +``` + +### Local Development + +For local development, the project includes a docker-compose setup with: +- OpenTelemetry Collector +- Grafana +- Other supporting services + +To run the local observability stack: +```bash +podman compose -f docker-compose-otel.yml up +``` + +### Request Filtering + +The telemetry setup includes smart filtering to: +- Exclude health check endpoints from tracing +- Filter out duplicate traces from Azure SDK clients +- Only record relevant HTTP client calls + +For more details about the OpenTelemetry setup, see the `ConfigureTelemetry` method in `AspNetUtilitiesExtensions.cs`. + ## Updating the SDK in global.json When RenovateBot updates `global.json` or base image versions in Dockerfiles, make sure they match. The `global.json` file should always have the same SDK version as the base image in the Dockerfiles. diff --git a/docker-compose-otel.yml b/docker-compose-otel.yml new file mode 100644 index 000000000..befa24e5b --- /dev/null +++ b/docker-compose-otel.yml @@ -0,0 +1,45 @@ +services: + # OpenTelemetry Collector + otel-collector: + image: otel/opentelemetry-collector-contrib:0.114.0 + command: ["--config=/etc/otel-collector-config.yaml"] + volumes: + - ./local-otel-configuration/otel-collector-config.yaml:/etc/otel-collector-config.yaml + ports: + - "4317:4317" # OTLP gRPC receiver + - "4318:4318" # OTLP http receiver + - "8888:8888" # Prometheus metrics exposed by the collector + - "8889:8889" # Prometheus exporter metrics + depends_on: + jaeger: + condition: service_healthy + + # Jaeger for trace visualization + jaeger: + image: jaegertracing/all-in-one:1.64.0 + ports: + - "16686:16686" # Jaeger UI + - "14250:14250" # Model used by collector + environment: + - COLLECTOR_OTLP_ENABLED=true + + # Prometheus for metrics + prometheus: + image: prom/prometheus:v3.0.1 + volumes: + - ./local-otel-configuration/prometheus.yml:/etc/prometheus/prometheus.yml + ports: + - "9090:9090" + + # Grafana for metrics visualization + grafana: + image: grafana/grafana:11.4.0 + ports: + - "3000:3000" + environment: + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + volumes: + - ./local-otel-configuration/grafana-datasources.yml:/etc/grafana/provisioning/datasources/datasources.yml + - ./local-otel-configuration/grafana-dashboards.yml:/etc/grafana/provisioning/dashboards/dashboards.yml + - ./local-otel-configuration/dashboards:/etc/grafana/provisioning/dashboards diff --git a/docker-compose.yml b/docker-compose.yml index f2a7ec59f..4519148b5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,7 @@ include: - docker-compose-db-redis.yml - docker-compose-cdc.yml + - docker-compose-otel.yml services: dialogporten-webapi-ingress: @@ -14,7 +15,7 @@ services: restart: always dialogporten-webapi: - scale: 2 + scale: 1 build: context: . dockerfile: src/Digdir.Domain.Dialogporten.WebApi/Dockerfile @@ -34,6 +35,10 @@ services: - Serilog__MinimumLevel__Default=Debug - ASPNETCORE_URLS=http://+:8080 - ASPNETCORE_ENVIRONMENT=Development + - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT} + - OTEL_EXPORTER_OTLP_PROTOCOL=${OTEL_EXPORTER_OTLP_PROTOCOL} + - OTEL_SERVICE_NAME=dialogporten-webapi + - OTEL_RESOURCE_ATTRIBUTES=service.instance.id=dialogporten-webapi,service.namespace=${OTEL_NAMESPACE} volumes: - ./.aspnet/https:/https @@ -70,5 +75,9 @@ services: - Serilog__WriteTo__0__Name=Console - Serilog__MinimumLevel__Default=Debug - ASPNETCORE_ENVIRONMENT=Development + - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT} + - OTEL_EXPORTER_OTLP_PROTOCOL=${OTEL_EXPORTER_OTLP_PROTOCOL} + - OTEL_SERVICE_NAME=dialogporten-graphql + - OTEL_RESOURCE_ATTRIBUTES=service.instance.id=dialogporten-graphql,service.namespace=${OTEL_NAMESPACE} volumes: - ./.aspnet/https:/https diff --git a/local-otel-configuration/dashboards/aspnet-core-metrics.json b/local-otel-configuration/dashboards/aspnet-core-metrics.json new file mode 100644 index 000000000..f60749a2f --- /dev/null +++ b/local-otel-configuration/dashboards/aspnet-core-metrics.json @@ -0,0 +1,176 @@ +{ + "annotations": { + "list": [] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "title": "HTTP Request Duration", + "type": "timeseries", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "sum(rate(dialogporten_http_server_request_duration_seconds_bucket[$__rate_interval])) by (le)", + "legendFormat": "{{le}}", + "refId": "A" + } + ] + }, + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.2.0", + "title": "Active Requests", + "type": "gauge", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "dialogporten_http_server_active_requests", + "refId": "A" + } + ] + } + ], + "refresh": "5s", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "ASP.NET Core Metrics", + "uid": "aspnet-core-metrics", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/local-otel-configuration/dashboards/dashboards.yml b/local-otel-configuration/dashboards/dashboards.yml new file mode 100755 index 000000000..e69de29bb diff --git a/local-otel-configuration/dashboards/http-client-metrics.json b/local-otel-configuration/dashboards/http-client-metrics.json new file mode 100644 index 000000000..56e2f687e --- /dev/null +++ b/local-otel-configuration/dashboards/http-client-metrics.json @@ -0,0 +1,296 @@ +{ + "annotations": { + "list": [] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "title": "HTTP Client Active Requests & Connections", + "type": "timeseries", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "dialogporten_http_client_active_requests", + "legendFormat": "Active Requests", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "dialogporten_http_client_open_connections", + "legendFormat": "Open Connections", + "refId": "B" + } + ] + }, + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "title": "Request Queue Time", + "type": "timeseries", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "rate(dialogporten_http_client_request_time_in_queue_seconds_sum[$__rate_interval]) / rate(dialogporten_http_client_request_time_in_queue_seconds_count[$__rate_interval])", + "legendFormat": "Average Queue Time", + "refId": "A" + } + ] + }, + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "title": "DNS Lookup Duration", + "type": "timeseries", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "rate(dialogporten_dns_lookup_duration_seconds_sum[$__rate_interval]) / rate(dialogporten_dns_lookup_duration_seconds_count[$__rate_interval])", + "legendFormat": "Average DNS Lookup Time", + "refId": "A" + } + ] + } + ], + "refresh": "5s", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "title": "HTTP Client Metrics", + "uid": "http-client-metrics", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/local-otel-configuration/dashboards/runtime-metrics.json b/local-otel-configuration/dashboards/runtime-metrics.json new file mode 100644 index 000000000..eed1ef0c6 --- /dev/null +++ b/local-otel-configuration/dashboards/runtime-metrics.json @@ -0,0 +1,390 @@ +{ + "annotations": { + "list": [] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "title": "Memory Usage", + "type": "timeseries", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "dialogporten_process_runtime_dotnet_gc_heap_size_bytes", + "legendFormat": "Heap Size", + "refId": "A" + } + ] + }, + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "title": "GC Collections", + "type": "timeseries", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "rate(dialogporten_process_runtime_dotnet_gc_collections_count_total[5m])", + "legendFormat": "Gen {{generation}}", + "refId": "A" + } + ] + }, + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "title": "Thread Pool", + "type": "timeseries", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "dialogporten_process_runtime_dotnet_thread_pool_queue_length", + "legendFormat": "Queue Length", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "dialogporten_process_runtime_dotnet_thread_pool_threads_count", + "legendFormat": "Thread Count", + "refId": "B" + } + ] + }, + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "title": "Exceptions & Lock Contentions", + "type": "timeseries", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "rate(dialogporten_process_runtime_dotnet_exceptions_count_total[$__rate_interval])", + "legendFormat": "Exceptions/sec", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "rate(dialogporten_process_runtime_dotnet_monitor_lock_contention_count_total[$__rate_interval])", + "legendFormat": "Lock Contentions/sec", + "refId": "B" + } + ] + } + ], + "refresh": "5s", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "title": "Runtime Metrics", + "uid": "runtime-metrics", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/local-otel-configuration/grafana-dashboards.yml b/local-otel-configuration/grafana-dashboards.yml new file mode 100644 index 000000000..3712f1164 --- /dev/null +++ b/local-otel-configuration/grafana-dashboards.yml @@ -0,0 +1,11 @@ +apiVersion: 1 + +providers: + - name: 'Default' + orgId: 1 + folder: '' + type: file + disableDeletion: false + editable: true + options: + path: /etc/grafana/provisioning/dashboards \ No newline at end of file diff --git a/local-otel-configuration/grafana-datasources.yml b/local-otel-configuration/grafana-datasources.yml new file mode 100644 index 000000000..4139ccba6 --- /dev/null +++ b/local-otel-configuration/grafana-datasources.yml @@ -0,0 +1,8 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true \ No newline at end of file diff --git a/local-otel-configuration/otel-collector-config.yaml b/local-otel-configuration/otel-collector-config.yaml new file mode 100644 index 000000000..97bc0c2b6 --- /dev/null +++ b/local-otel-configuration/otel-collector-config.yaml @@ -0,0 +1,52 @@ +receivers: + otlp: + protocols: + http: + endpoint: 0.0.0.0:4318 + cors: + allowed_origins: ["*"] + allowed_headers: ["*"] + include_metadata: true + +processors: + batch: + timeout: 1s + send_batch_size: 1024 + +exporters: + prometheus: + endpoint: "0.0.0.0:8889" + namespace: "dialogporten" + otlp: + endpoint: "jaeger:4317" + tls: + insecure: true + debug: + verbosity: detailed + sampling_initial: 5 + sampling_thereafter: 200 + +extensions: + health_check: + pprof: + zpages: + +service: + extensions: [health_check, pprof, zpages] + telemetry: + logs: + level: debug + development: true + pipelines: + traces: + receivers: [otlp] + processors: [batch] + exporters: [otlp, debug] + metrics: + receivers: [otlp] + processors: [batch] + exporters: [prometheus, debug] + logs: + receivers: [otlp] + processors: [batch] + exporters: [debug] diff --git a/local-otel-configuration/prometheus.yml b/local-otel-configuration/prometheus.yml new file mode 100644 index 000000000..58650dae4 --- /dev/null +++ b/local-otel-configuration/prometheus.yml @@ -0,0 +1,8 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + +scrape_configs: + - job_name: 'otel-collector' + static_configs: + - targets: ['otel-collector:8889'] \ No newline at end of file diff --git a/src/Digdir.Domain.Dialogporten.GraphQL/OpenTelemetryEventListener.cs b/src/Digdir.Domain.Dialogporten.GraphQL/OpenTelemetryEventListener.cs index 67beed8bb..b851f63f6 100644 --- a/src/Digdir.Domain.Dialogporten.GraphQL/OpenTelemetryEventListener.cs +++ b/src/Digdir.Domain.Dialogporten.GraphQL/OpenTelemetryEventListener.cs @@ -2,7 +2,6 @@ using HotChocolate.Execution; using HotChocolate.Execution.Instrumentation; using Microsoft.AspNetCore.Http.Extensions; -using OpenTelemetry.Trace; namespace Digdir.Domain.Dialogporten.GraphQL; diff --git a/src/Digdir.Domain.Dialogporten.GraphQL/Program.cs b/src/Digdir.Domain.Dialogporten.GraphQL/Program.cs index 7753936ac..5808a8408 100644 --- a/src/Digdir.Domain.Dialogporten.GraphQL/Program.cs +++ b/src/Digdir.Domain.Dialogporten.GraphQL/Program.cs @@ -68,12 +68,15 @@ static void BuildAndRun(string[] args, TelemetryConfiguration telemetryConfigura var thisAssembly = Assembly.GetExecutingAssembly(); - builder.ConfigureTelemetry(); - builder.Services.AddOpenTelemetry() - .WithTracing(tracerProviderBuilder => - { - tracerProviderBuilder.AddSource(DialogportenGraphQLSource); - }); + builder.ConfigureTelemetry((settings, configuration) => + { + settings.ServiceName = configuration["OTEL_SERVICE_NAME"] ?? builder.Environment.ApplicationName; + settings.Endpoint = configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]; + settings.Protocol = configuration["OTEL_EXPORTER_OTLP_PROTOCOL"]; + settings.AppInsightsConnectionString = configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]; + settings.ResourceAttributes = configuration["OTEL_RESOURCE_ATTRIBUTES"]; + settings.TraceSources.Add(DialogportenGraphQLSource); + }); builder.Services // Options setup diff --git a/src/Digdir.Domain.Dialogporten.Service/Program.cs b/src/Digdir.Domain.Dialogporten.Service/Program.cs index 3fffde09d..28a1c3a39 100644 --- a/src/Digdir.Domain.Dialogporten.Service/Program.cs +++ b/src/Digdir.Domain.Dialogporten.Service/Program.cs @@ -51,7 +51,14 @@ static void BuildAndRun(string[] args, TelemetryConfiguration telemetryConfigura .AddAzureConfiguration(builder.Environment.EnvironmentName) .AddLocalConfiguration(builder.Environment); - builder.ConfigureTelemetry(); + builder.ConfigureTelemetry((settings, configuration) => + { + settings.ServiceName = configuration["OTEL_SERVICE_NAME"] ?? builder.Environment.ApplicationName; + settings.Endpoint = configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]; + settings.Protocol = configuration["OTEL_EXPORTER_OTLP_PROTOCOL"]; + settings.AppInsightsConnectionString = configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]; + settings.ResourceAttributes = configuration["OTEL_RESOURCE_ATTRIBUTES"]; + }); builder.Services .AddAzureAppConfiguration() diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj b/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj index 590d00b8d..5b7f96d8b 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj +++ b/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj @@ -17,14 +17,14 @@ - + - - - - + + + + diff --git a/src/Digdir.Domain.Dialogporten.WebApi/OpenApiDocumentExtensions.cs b/src/Digdir.Domain.Dialogporten.WebApi/OpenApiDocumentExtensions.cs index 9dc187e41..a9d53de3f 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/OpenApiDocumentExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/OpenApiDocumentExtensions.cs @@ -1,4 +1,3 @@ -using Digdir.Domain.Dialogporten.WebApi.Endpoints.V1.ServiceOwner.Dialogs.Update; using NJsonSchema; using NSwag; diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index c02e9f007..6b58f6b5a 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -78,7 +78,14 @@ static void BuildAndRun(string[] args, TelemetryConfiguration telemetryConfigura var thisAssembly = Assembly.GetExecutingAssembly(); - builder.ConfigureTelemetry(); + builder.ConfigureTelemetry((settings, configuration) => + { + settings.ServiceName = configuration["OTEL_SERVICE_NAME"] ?? builder.Environment.ApplicationName; + settings.Endpoint = configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]; + settings.Protocol = configuration["OTEL_EXPORTER_OTLP_PROTOCOL"]; + settings.AppInsightsConnectionString = configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]; + settings.ResourceAttributes = configuration["OTEL_RESOURCE_ATTRIBUTES"]; + }); builder.Services // Options setup diff --git a/src/Digdir.Domain.Dialogporten.WebApi/appsettings.json b/src/Digdir.Domain.Dialogporten.WebApi/appsettings.json index ffd6358a4..938115f5a 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/appsettings.json +++ b/src/Digdir.Domain.Dialogporten.WebApi/appsettings.json @@ -19,4 +19,4 @@ } }, "AllowedHosts": "*" -} +} \ No newline at end of file diff --git a/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesExtensions.cs b/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesExtensions.cs index c47413c8f..c1388ec0d 100644 --- a/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesExtensions.cs +++ b/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesExtensions.cs @@ -1,8 +1,8 @@ -using Azure.Monitor.OpenTelemetry.AspNetCore; using Digdir.Library.Utils.AspNet.HealthChecks; using HealthChecks.UI.Client; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; @@ -10,13 +10,15 @@ using OpenTelemetry.Trace; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; +using OpenTelemetry; +using OpenTelemetry.Exporter; +using System.Diagnostics; +using Azure.Monitor.OpenTelemetry.Exporter; namespace Digdir.Library.Utils.AspNet; public static class AspNetUtilitiesExtensions { - private const string MassTransitSource = "MassTransit"; - public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection services, Action? configure = null) { var optionsBuilder = services.AddOptions(); @@ -49,41 +51,115 @@ private static WebApplication MapHealthCheckEndpoint(this WebApplication app, st return app; } - public static WebApplicationBuilder ConfigureTelemetry(this WebApplicationBuilder builder) + public static WebApplicationBuilder ConfigureTelemetry( + this WebApplicationBuilder builder, + Action? configure = null) { - builder.Services.AddOpenTelemetry() - .ConfigureResource(resource => resource - .AddService(serviceName: builder.Environment.ApplicationName)) - .WithTracing(tracing => + var settings = new TelemetrySettings(); + configure?.Invoke(settings, builder.Configuration); + + Console.WriteLine($"[OpenTelemetry] Configuring telemetry for service: {settings.ServiceName}"); + + var telemetryBuilder = builder.Services.AddOpenTelemetry() + .ConfigureResource(resource => { - if (builder.Environment.IsDevelopment()) + var resourceBuilder = resource.AddService(serviceName: settings.ServiceName ?? builder.Environment.ApplicationName); + + var resourceAttributes = settings.ResourceAttributes; + if (string.IsNullOrEmpty(resourceAttributes)) return; + + try { - tracing.SetSampler(new AlwaysOnSampler()); + var attributes = resourceAttributes + .Split(',', StringSplitOptions.RemoveEmptyEntries) + .Select(pair => pair.Split('=', 2)) + .Where(parts => parts.Length == 2 && !string.IsNullOrEmpty(parts[0])) + .Select(parts => new KeyValuePair(parts[0].Trim(), parts[1].Trim())); + + foreach (var attribute in attributes) + { + resourceBuilder.AddAttributes([attribute]); + } } + catch (Exception ex) + { + throw new InvalidOperationException( + "Failed to parse OTEL_RESOURCE_ATTRIBUTES. Expected format: key1=value1,key2=value2", + ex + ); + } + }); + + if (!string.IsNullOrEmpty(settings.Endpoint) && !string.IsNullOrEmpty(settings.Protocol)) + { + Console.WriteLine($"[OpenTelemetry] Using endpoint: {settings.Endpoint}"); + Console.WriteLine($"[OpenTelemetry] Using protocol: {settings.Protocol}"); - tracing.AddAspNetCoreInstrumentation(options => + var otlpProtocol = settings.Protocol.ToLowerInvariant() switch + { + "grpc" => OtlpExportProtocol.Grpc, + "http/protobuf" => OtlpExportProtocol.HttpProtobuf, + "http" => OtlpExportProtocol.HttpProtobuf, + _ => throw new ArgumentException($"Unsupported protocol: {settings.Protocol}") + }; + + telemetryBuilder.UseOtlpExporter(otlpProtocol, new Uri(settings.Endpoint)); + + telemetryBuilder + .WithTracing(tracing => { - options.Filter = httpContext => - !httpContext.Request.Path.StartsWithSegments("/health"); + if (builder.Environment.IsDevelopment()) + { + tracing.SetSampler(new AlwaysOnSampler()); + } + + foreach (var source in settings.TraceSources) + { + tracing.AddSource(source); + } + + tracing + .AddAspNetCoreInstrumentation(opts => + { + opts.RecordException = true; + opts.Filter = httpContext => !httpContext.Request.Path.StartsWithSegments("/health"); + }) + .AddHttpClientInstrumentation(o => + { + o.RecordException = true; + o.FilterHttpRequestMessage = _ => + { + var parentActivity = Activity.Current?.Parent; + if (parentActivity != null && parentActivity.Source.Name.Equals("Azure.Core.Http", StringComparison.Ordinal)) + { + return false; + } + return true; + }; + }) + .AddEntityFrameworkCoreInstrumentation() + .AddNpgsql() + .AddFusionCacheInstrumentation(); }); - tracing.AddHttpClientInstrumentation(); - tracing.AddNpgsql(); - tracing.AddSource(MassTransitSource); // MassTransit ActivitySource - }) - .WithMetrics(metrics => + telemetryBuilder.WithMetrics(metrics => { - metrics.AddRuntimeInstrumentation(); - }); + metrics.AddRuntimeInstrumentation() + .AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation(); - if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING"))) - { - builder.Services.AddOpenTelemetry().UseAzureMonitor(); + if (!string.IsNullOrEmpty(settings.AppInsightsConnectionString)) + { + metrics.AddAzureMonitorMetricExporter(options => + { + options.ConnectionString = settings.AppInsightsConnectionString; + }); + } + }); } else { - // Use Application Insights SDK for local development - builder.Services.AddApplicationInsightsTelemetry(); + Console.WriteLine("[OpenTelemetry] OTLP exporter not configured - skipping"); } return builder; diff --git a/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesSettings.cs b/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesSettings.cs index f8e2f7fdb..7cb14248c 100644 --- a/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesSettings.cs +++ b/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesSettings.cs @@ -9,3 +9,21 @@ public sealed class HealthCheckSettings { public List HttpGetEndpointsToCheck { get; set; } = []; } + +public sealed class TelemetrySettings +{ + private const string MassTransitSource = "MassTransit"; + private const string AzureSource = "Azure.*"; + + public string? ServiceName { get; set; } + public string? Endpoint { get; set; } + public string? Protocol { get; set; } + public string? AppInsightsConnectionString { get; set; } + // Expected format: key1=value1,key2=value2 + public string? ResourceAttributes { get; set; } + public HashSet TraceSources { get; set; } = new() + { + AzureSource, + MassTransitSource + }; +} \ No newline at end of file diff --git a/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj index cab4e5a23..5a6f2bd3b 100644 --- a/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj +++ b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj @@ -11,12 +11,15 @@ + + - + +
From a7c4aa620c00a67b9bbac865171c58d18db75aa1 Mon Sep 17 00:00:00 2001 From: Dialogporten Automation Bot <164321870+dialogporten-bot@users.noreply.github.com> Date: Tue, 17 Dec 2024 13:53:41 +0100 Subject: [PATCH 27/30] chore(main): release 1.42.0 (#1615) :robot: I have created a release *beep* *boop* --- ## [1.42.0](https://github.com/digdir/dialogporten/compare/v1.41.3...v1.42.0) (2024-12-16) ### Features * **apps:** add otel exporter for graphql, service and web-api ([#1528](https://github.com/digdir/dialogporten/issues/1528)) ([cb9238e](https://github.com/digdir/dialogporten/commit/cb9238ef76188b4dde371e08b7ce597645bcd8b7)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- CHANGELOG.md | 7 +++++++ version.txt | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1c23c3bb..7c4199ee3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.42.0](https://github.com/digdir/dialogporten/compare/v1.41.3...v1.42.0) (2024-12-16) + + +### Features + +* **apps:** add otel exporter for graphql, service and web-api ([#1528](https://github.com/digdir/dialogporten/issues/1528)) ([cb9238e](https://github.com/digdir/dialogporten/commit/cb9238ef76188b4dde371e08b7ce597645bcd8b7)) + ## [1.41.3](https://github.com/digdir/dialogporten/compare/v1.41.2...v1.41.3) (2024-12-13) diff --git a/version.txt b/version.txt index 021b2b85f..a50908ca3 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.41.3 +1.42.0 From b20c6909ab55d9d3cf0bffe85b9961b5fbd96e25 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:21:08 +0100 Subject: [PATCH 28/30] chore(deps): update otel/opentelemetry-collector-contrib docker tag to v0.115.1 (#1620) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Update | Change | Pending | |---|---|---|---| | [otel/opentelemetry-collector-contrib](https://redirect.github.com/open-telemetry/opentelemetry-collector-releases) | minor | `0.114.0` -> `0.115.1` | `0.116.1` (+1) | --- ### Release Notes
open-telemetry/opentelemetry-collector-releases (otel/opentelemetry-collector-contrib) ### [`v0.115.1`](https://redirect.github.com/open-telemetry/opentelemetry-collector-releases/releases/tag/v0.115.1) [Compare Source](https://redirect.github.com/open-telemetry/opentelemetry-collector-releases/compare/v0.114.0...v0.115.1) Check the [v0.115.0 contrib changelog](https://redirect.github.com/open-telemetry/opentelemetry-collector-contrib/releases/tag/v0.115.0) and the [v0.115.0 core changelog](https://redirect.github.com/open-telemetry/opentelemetry-collector/releases/tag/v0.115.0) for changelogs on specific components. #### Changelog - [`a61f843`](https://redirect.github.com/open-telemetry/opentelemetry-collector-releases/commit/a61f84368047532bce8de2753b236e3bc47e3e26) Revert "test: run linux package tests nightly against latest contrib main ([#​666](https://redirect.github.com/open-telemetry/opentelemetry-collector-releases/issues/666))" ([#​761](https://redirect.github.com/open-telemetry/opentelemetry-collector-releases/issues/761))
--- ### Configuration πŸ“… **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose-otel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose-otel.yml b/docker-compose-otel.yml index befa24e5b..09e80c394 100644 --- a/docker-compose-otel.yml +++ b/docker-compose-otel.yml @@ -1,7 +1,7 @@ services: # OpenTelemetry Collector otel-collector: - image: otel/opentelemetry-collector-contrib:0.114.0 + image: otel/opentelemetry-collector-contrib:0.115.1 command: ["--config=/etc/otel-collector-config.yaml"] volumes: - ./local-otel-configuration/otel-collector-config.yaml:/etc/otel-collector-config.yaml From e72e498da8557e1c883d18b076af40a7e6025a0f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 02:21:47 +0100 Subject: [PATCH 29/30] chore(deps): update dependency opentelemetry.instrumentation.runtime to 1.10.0 (#1618) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [OpenTelemetry.Instrumentation.Runtime](https://opentelemetry.io/) ([source](https://redirect.github.com/open-telemetry/opentelemetry-dotnet-contrib)) | `1.9.0` -> `1.10.0` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/OpenTelemetry.Instrumentation.Runtime/1.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/OpenTelemetry.Instrumentation.Runtime/1.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/OpenTelemetry.Instrumentation.Runtime/1.9.0/1.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/OpenTelemetry.Instrumentation.Runtime/1.9.0/1.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Configuration πŸ“… **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../Digdir.Library.Utils.AspNet.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj index 5a6f2bd3b..aeb88adaa 100644 --- a/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj +++ b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj @@ -18,7 +18,7 @@ - + From 25283d2b3822010bbce5e8495f5fd99b5af8cd88 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 02:29:00 +0100 Subject: [PATCH 30/30] chore(deps): update dependency testcontainers.postgresql to 4.1.0 (#1619) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [Testcontainers.PostgreSql](https://dotnet.testcontainers.org/) ([source](https://redirect.github.com/testcontainers/testcontainers-dotnet)) | `4.0.0` -> `4.1.0` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/Testcontainers.PostgreSql/4.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/Testcontainers.PostgreSql/4.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/Testcontainers.PostgreSql/4.0.0/4.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Testcontainers.PostgreSql/4.0.0/4.1.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
testcontainers/testcontainers-dotnet (Testcontainers.PostgreSql) ### [`v4.1.0`](https://redirect.github.com/testcontainers/testcontainers-dotnet/releases/tag/4.1.0) [Compare Source](https://redirect.github.com/testcontainers/testcontainers-dotnet/compare/4.0.0...4.1.0) ##### What's Changed This is likely the last release for this year, unless urgent fixes become necessary. I want to mention a change introduced in the last major release, where we refactored the `IImage` interface. As part of this update, we removed obsolete properties and overloaded constructors. If you previously used an overload other than `DockerImage(string)`, please ensure you pass the correct values to the constructor. Additionally, we replaced [Docker.DotNet](https://redirect.github.com/testcontainers/Docker.DotNet) with our own fork to keep the Docker Engine API up to date. Our goal is to improve reliability and performance while offering a more developer-friendly and convenient client. If you depend on a Docker client for .NET, we encourage you to contribute to this project ❀️. On a personal note, I wish everyone a peaceful and lovely holiday season. Take this time to rest, connect with loved ones, and recharge for the new year. Take care. ##### πŸš€ Features - feat: Add Azure Service Bus module ([#​1309](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1309)) [@​HofmeisterAn](https://redirect.github.com/HofmeisterAn) - feat: Set ryuk.container.privileged default value to true ([#​1313](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1313)) [@​HofmeisterAn](https://redirect.github.com/HofmeisterAn) - feat: Remove `net6.0` and add `net9.0` TFM ([#​1311](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1311)) [@​HofmeisterAn](https://redirect.github.com/HofmeisterAn) - feat: Introduce a new Testcontainers.Xunit package ([#​1165](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1165)) [@​0xced](https://redirect.github.com/0xced) ##### πŸ› Bug Fixes - fix: Postpone exception in `DbContainerFixture` to match the behavior of `ContainerFixture` ([#​1310](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1310)) [@​0xced](https://redirect.github.com/0xced) - fix: Do not pre-pull scratch image ([#​1304](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1304)) [@​HofmeisterAn](https://redirect.github.com/HofmeisterAn) - fix: Add HTTP wait strategy to prevent race-condition in WaitUntilHttpRequestIsSucceededTest ([#​1299](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1299)) [@​HofmeisterAn](https://redirect.github.com/HofmeisterAn) - fix: Add HTTP wait strategy to prevent race-condition in TarOutputMemoryStreamTest ([#​1297](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1297)) [@​HofmeisterAn](https://redirect.github.com/HofmeisterAn) - fix: Prepend Docker Hub namespace to repository ([#​1287](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1287)) [@​HofmeisterAn](https://redirect.github.com/HofmeisterAn) ##### πŸ“– Documentation - docs: Add low level API access ([#​1300](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1300)) [@​HofmeisterAn](https://redirect.github.com/HofmeisterAn) ##### 🧹 Housekeeping - feat: Add Respawn example ([#​1307](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1307)) [@​HofmeisterAn](https://redirect.github.com/HofmeisterAn) - chore: Add test to ensure that all test projects are configured for CI ([#​1305](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1305)) [@​0xced](https://redirect.github.com/0xced) - chore: Run each test project on a separate runner ([#​1295](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1295)) [@​HofmeisterAn](https://redirect.github.com/HofmeisterAn) - chore: Replace Docker.DotNet with the Testcontainers organization's build ([#​1292](https://redirect.github.com/testcontainers/testcontainers-dotnet/issues/1292)) [@​HofmeisterAn](https://redirect.github.com/HofmeisterAn)
--- ### Configuration πŸ“… **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- ...dir.Domain.Dialogporten.Application.Integration.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Digdir.Domain.Dialogporten.Application.Integration.Tests.csproj b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Digdir.Domain.Dialogporten.Application.Integration.Tests.csproj index 942a0cc2e..8f8d3faa2 100644 --- a/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Digdir.Domain.Dialogporten.Application.Integration.Tests.csproj +++ b/tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Digdir.Domain.Dialogporten.Application.Integration.Tests.csproj @@ -14,7 +14,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive