Repository: project-origin/registry
Pull request #564: Upgrade to dotnet 9
Author: login: sahma19
Created: 2025-03-04T16:47:33Z | Merged: 2025-03-06T12:30:40Z



Diff:
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index e0f308e8..9f115584 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -2,7 +2,7 @@
 // README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
 {
     "name": "C# (.NET)",
-    "image": "mcr.microsoft.com/devcontainers/dotnet:1.3.6-8.0-jammy",
+    "image": "mcr.microsoft.com/devcontainers/dotnet:1.3.6-9.0-noble",
     // Features to add to the dev container. More info: https://containers.dev/features.
     "features": {
         "ghcr.io/devcontainers/features/docker-in-docker:2": {},
diff --git a/Directory.Build.props b/Directory.Build.props
index 69ccb6dd..1be298da 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,6 +1,6 @@
 <Project>
   <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
+    <TargetFramework>net9.0</TargetFramework>
     <Nullable>enable</Nullable>
     <ImplicitUsings>disable</ImplicitUsings>
     <WarningsAsErrors>IDE0005</WarningsAsErrors>
diff --git a/Directory.Build.targets b/Directory.Build.targets
deleted file mode 100644
index 8db34581..00000000
--- a/Directory.Build.targets
+++ /dev/null
@@ -1,22 +0,0 @@
-<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <MSBuildWarningsAsErrors>$(MSBuildWarningsAsErrors);PO1001</MSBuildWarningsAsErrors>
-  </PropertyGroup>
-
-  <Target Name="BlockUnwantedDependencies" BeforeTargets="PrepareForBuild">
-    <ItemGroup>
-      <UnwantedPackages Include="@(PackageReference)"
-                        Condition="'%(PackageReference.Version)' != '' and
-                                        $([System.Text.RegularExpressions.Regex]::IsMatch('%(PackageReference.Version)', '^(0\.\d+\.\d+.*|.*-.*)'))" />
-    </ItemGroup>
-
-    <PropertyGroup>
-      <_WarningMessage>Build blocked: Prerelease or unstable NuGet package</_WarningMessage>
-    </PropertyGroup>
-
-    <Warning File="$(MSBuildProjectFullPath)"
-             Code="PO1001"
-             Text="$(_WarningMessage): %(UnwantedPackages.Identity) (%(UnwantedPackages.Version))"
-             Condition="'@(UnwantedPackages)' != ''" />
-  </Target>
-</Project>
diff --git a/Registry.Dockerfile b/Registry.Dockerfile
index 8240db82..edf33d80 100644
--- a/Registry.Dockerfile
+++ b/Registry.Dockerfile
@@ -1,6 +1,6 @@
 ARG PROJECT=ProjectOrigin.Registry
 
-FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0.406 AS build
+FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0 AS build
 ARG PROJECT
 
 WORKDIR /builddir
@@ -14,7 +14,7 @@ RUN dotnet build ./src/${PROJECT} -c Release --no-restore -p:CustomAssemblyName=
 RUN dotnet publish ./src/${PROJECT} -c Release --no-build -p:CustomAssemblyName=Registry -o /app/publish
 
 # ------- production image -------
-FROM mcr.microsoft.com/dotnet/aspnet:8.0.13-jammy-chiseled-extra AS production
+FROM mcr.microsoft.com/dotnet/aspnet:9.0-noble AS production
 
 WORKDIR /app
 COPY --from=build /app/publish .
diff --git a/global.json b/global.json
index 8eaa52a8..b6c230e1 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
 {
     "sdk": {
-        "version": "8.0.401",
+        "version": "9.0.100",
         "rollForward": "feature"
     }
 }
diff --git a/src/ProjectOrigin.Registry/Extensions/IEnumerableMerkleExtension.cs b/src/ProjectOrigin.Registry/Extensions/IEnumerableMerkleExtension.cs
index cd7bfb3c..6903770f 100644
--- a/src/ProjectOrigin.Registry/Extensions/IEnumerableMerkleExtension.cs
+++ b/src/ProjectOrigin.Registry/Extensions/IEnumerableMerkleExtension.cs
@@ -64,24 +64,43 @@ private static IEnumerable<byte[]> RecursiveGetRequiredHashes(IEnumerable<byte[]
 
     private static byte[] RecursiveShaNodes(IEnumerable<byte[]> nodes, int balancedCount)
     {
-        if (nodes.Count() == 1)
+        var nodeList = nodes.ToList();
+        if (nodeList.Count == 0)
+            throw new ArgumentException("Nodes cannot be empty.", nameof(nodes));
+
+        if (nodeList.Count == 1)
         {
-            var data = SHA256.HashData(nodes.Single());
+            var nodeHash = SHA256.HashData(nodeList[0]);
+
             for (int i = (int)Math.Log(balancedCount, 2); i > 0; i--)
             {
-                var doubleData = data.Concat(data);
-                data = SHA256.HashData(doubleData.ToArray());
+                byte[] combinedHash = new byte[nodeHash.Length * 2];
+                Buffer.BlockCopy(nodeHash, 0, combinedHash, 0, nodeHash.Length);
+                Buffer.BlockCopy(nodeHash, 0, combinedHash, nodeHash.Length, nodeHash.Length);
+
+                nodeHash = SHA256.HashData(combinedHash);
             }
-            return data;
+            return nodeHash;
         }
         else
         {
             var halfSize = balancedCount / 2;
+            var leftNodes = nodeList.Take(halfSize).ToList();
+            var rightNodes = nodeList.Skip(halfSize).ToList();
+
+            if (rightNodes.Count == 0)
+            {
+                rightNodes.Add(leftNodes[^1]);
+            }
+
+            var leftHash = RecursiveShaNodes(leftNodes, halfSize);
+            var rightHash = RecursiveShaNodes(rightNodes, halfSize);
 
-            var left = RecursiveShaNodes(nodes.Take(halfSize), halfSize);
-            var right = RecursiveShaNodes(nodes.Skip(halfSize).DefaultIfEmpty(nodes.Last()), halfSize);
+            byte[] combinedHash = new byte[leftHash.Length + rightHash.Length];
+            Buffer.BlockCopy(leftHash, 0, combinedHash, 0, leftHash.Length);
+            Buffer.BlockCopy(rightHash, 0, combinedHash, leftHash.Length, rightHash.Length);
 
-            return SHA256.HashData(left.Concat(right).ToArray());
+            return SHA256.HashData(combinedHash);
         }
     }
 
diff --git a/src/ProjectOrigin.Registry/ProjectOrigin.Registry.csproj b/src/ProjectOrigin.Registry/ProjectOrigin.Registry.csproj
index ceeb1a43..8d388d2b 100644
--- a/src/ProjectOrigin.Registry/ProjectOrigin.Registry.csproj
+++ b/src/ProjectOrigin.Registry/ProjectOrigin.Registry.csproj
@@ -5,27 +5,27 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="ProjectOrigin.ServiceCommon" Version="1.0.0" />
-    <PackageReference Include="Grpc.AspNetCore" Version="2.65.0" />
-    <PackageReference Include="OpenTelemetry" Version="1.9.0" />
-    <PackageReference Include="Npgsql.OpenTelemetry" Version="9.0.0" />
-    <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.9.0" />
-    <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
-    <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
-    <PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
-    <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
+    <PackageReference Include="ProjectOrigin.ServiceCommon" Version="2.0.0" />
+    <PackageReference Include="Grpc.AspNetCore" Version="2.67.0" />
+    <PackageReference Include="OpenTelemetry" Version="1.11.2" />
+    <PackageReference Include="Npgsql.OpenTelemetry" Version="9.0.3" />
+    <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.11.2" />
+    <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.11.2" />
+    <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.11.2" />
+    <PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.11.1" />
+    <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.11.1" />
     <PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
     <PackageReference Include="Serilog.Enrichers.Span" Version="3.1.0" />
     <PackageReference Include="Serilog.Expressions" Version="5.0.0" />
-    <PackageReference Include="RabbitMQ.Client" Version="7.0.0" />
+    <PackageReference Include="RabbitMQ.Client" Version="7.1.1" />
     <PackageReference Include="murmurhash" Version="1.0.3" />
-    <PackageReference Include="Swashbuckle.AspNetCore" Version="7.0.0" />
+    <PackageReference Include="Swashbuckle.AspNetCore" Version="7.3.1" />
     <PackageReference Include="ConcordiumNetSdk" Version="6.0.1" />
-    <PackageReference Include="Dapper" Version="2.1.44" />
-    <PackageReference Include="dbup-postgresql" Version="5.0.40" />
+    <PackageReference Include="Dapper" Version="2.1.66" />
+    <PackageReference Include="dbup-postgresql" Version="6.0.3" />
     <PackageReference Include="NSec.Cryptography" Version="24.4.0" />
-    <PackageReference Include="Npgsql" Version="9.0.0" />
-    <PackageReference Include="StackExchange.Redis" Version="2.8.0" />
+    <PackageReference Include="Npgsql" Version="9.0.3" />
+    <PackageReference Include="StackExchange.Redis" Version="2.8.24" />
   </ItemGroup>
 
   <ItemGroup>
@@ -35,8 +35,8 @@
   </ItemGroup>
 
   <ItemGroup>
-    <Protobuf Include="..\..\protos\common.proto" GrpcServices="None"/>
-    <Protobuf Include="..\..\protos\registry.proto" GrpcServices="Both"/>
+    <Protobuf Include="..\..\protos\common.proto" GrpcServices="None" />
+    <Protobuf Include="..\..\protos\registry.proto" GrpcServices="Both" />
     <Protobuf Include="..\..\protos\verifier.proto" GrpcServices="Client" />
   </ItemGroup>
 </Project>
diff --git a/test/ProjectOrigin.Registry.ChartTests/ProjectOrigin.Registry.ChartTests.csproj b/test/ProjectOrigin.Registry.ChartTests/ProjectOrigin.Registry.ChartTests.csproj
index 0862fe7e..cc826c4c 100644
--- a/test/ProjectOrigin.Registry.ChartTests/ProjectOrigin.Registry.ChartTests.csproj
+++ b/test/ProjectOrigin.Registry.ChartTests/ProjectOrigin.Registry.ChartTests.csproj
@@ -10,12 +10,12 @@
   </Target>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
     <PackageReference Include="ProjectOrigin.PedersenCommitment" Version="1.1.1" />
-    <PackageReference Include="ProjectOrigin.HierarchicalDeterministicKeys" Version="1.0.0" />
-    <PackageReference Include="Grpc.AspNetCore" Version="2.65.0" />
-    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.1" />
-    <PackageReference Include="xunit" Version="2.9.0" />
+    <PackageReference Include="ProjectOrigin.HierarchicalDeterministicKeys" Version="1.1.0" />
+    <PackageReference Include="Grpc.AspNetCore" Version="2.67.0" />
+    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.6.0" />
+    <PackageReference Include="xunit" Version="2.9.3" />
     <PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
       <PrivateAssets>all</PrivateAssets>
@@ -23,8 +23,11 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="Google.Protobuf" Version="3.27.2" />
-    <PackageReference Include="Grpc.Tools" Version="2.65.0" />
+    <PackageReference Include="Google.Protobuf" Version="3.29.3" />
+    <PackageReference Include="Grpc.Tools" Version="2.70.0">
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+      <PrivateAssets>all</PrivateAssets>
+    </PackageReference>
     <Protobuf Include="..\..\protos\common.proto" GrpcServices="None" />
     <Protobuf Include="..\..\protos\registry.proto" GrpcServices="Client" />
     <Protobuf Include="../../protos/electricity.proto" Link="Protos\electricity.proto" GrpcServices="None">
diff --git a/test/ProjectOrigin.Registry.ConcordiumIntegrationTests/ProjectOrigin.Registry.ConcordiumIntegrationTests.csproj b/test/ProjectOrigin.Registry.ConcordiumIntegrationTests/ProjectOrigin.Registry.ConcordiumIntegrationTests.csproj
index bbd48b84..e7eb0729 100644
--- a/test/ProjectOrigin.Registry.ConcordiumIntegrationTests/ProjectOrigin.Registry.ConcordiumIntegrationTests.csproj
+++ b/test/ProjectOrigin.Registry.ConcordiumIntegrationTests/ProjectOrigin.Registry.ConcordiumIntegrationTests.csproj
@@ -6,15 +6,15 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
-    <PackageReference Include="Moq" Version="4.20.70" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
+    <PackageReference Include="Moq" Version="4.20.72" />
     <PackageReference Include="FluentAssertions" Version="7.0.0" />
-    <PackageReference Include="xunit" Version="2.9.0" />
+    <PackageReference Include="xunit" Version="2.9.3" />
     <PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
       <PrivateAssets>all</PrivateAssets>
     </PackageReference>
-    <PackageReference Include="coverlet.collector" Version="6.0.2">
+    <PackageReference Include="coverlet.collector" Version="6.0.4">
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
       <PrivateAssets>all</PrivateAssets>
     </PackageReference>
diff --git a/test/ProjectOrigin.Registry.IntegrationTests/ProjectOrigin.Registry.IntegrationTests.csproj b/test/ProjectOrigin.Registry.IntegrationTests/ProjectOrigin.Registry.IntegrationTests.csproj
index f0af5649..73c52853 100644
--- a/test/ProjectOrigin.Registry.IntegrationTests/ProjectOrigin.Registry.IntegrationTests.csproj
+++ b/test/ProjectOrigin.Registry.IntegrationTests/ProjectOrigin.Registry.IntegrationTests.csproj
@@ -10,23 +10,23 @@
   </Target>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
-    <PackageReference Include="Moq" Version="4.20.70" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
+    <PackageReference Include="Moq" Version="4.20.72" />
     <PackageReference Include="AutoFixture" Version="4.18.1" />
     <PackageReference Include="FluentAssertions" Version="7.0.0" />
-    <PackageReference Include="xunit" Version="2.9.0" />
+    <PackageReference Include="xunit" Version="2.9.3" />
     <PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
       <PrivateAssets>all</PrivateAssets>
     </PackageReference>
-    <PackageReference Include="coverlet.collector" Version="6.0.2">
+    <PackageReference Include="coverlet.collector" Version="6.0.4">
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
       <PrivateAssets>all</PrivateAssets>
     </PackageReference>
     <PackageReference Include="System.Security.Cryptography.Algorithms" Version="4.3.1" />
     <PackageReference Include="ProjectOrigin.PedersenCommitment" Version="1.1.1" />
-    <PackageReference Include="ProjectOrigin.HierarchicalDeterministicKeys" Version="1.0.0" />
-    <PackageReference Include="ProjectOrigin.TestCommon" Version="1.0.0" />
+    <PackageReference Include="ProjectOrigin.HierarchicalDeterministicKeys" Version="1.1.0" />
+    <PackageReference Include="ProjectOrigin.TestCommon" Version="2.0.0" />
   </ItemGroup>
 
   <ItemGroup>
@@ -34,8 +34,11 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="Google.Protobuf" Version="3.27.2" />
-    <PackageReference Include="Grpc.Tools" Version="2.65.0" />
+    <PackageReference Include="Google.Protobuf" Version="3.29.3" />
+    <PackageReference Include="Grpc.Tools" Version="2.70.0">
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+      <PrivateAssets>all</PrivateAssets>
+    </PackageReference>
     <Protobuf Include="../../protos/electricity.proto" Link="Protos\electricity.proto" GrpcServices="None">
       <SourceUrl>https://raw.githubusercontent.com/project-origin/verifier_electricity/v2.0.0-rc.5/protos/electricity.proto</SourceUrl>
     </Protobuf>
diff --git a/test/ProjectOrigin.Registry.Tests/ProjectOrigin.Registry.Tests.csproj b/test/ProjectOrigin.Registry.Tests/ProjectOrigin.Registry.Tests.csproj
index 7c2a6990..fc66126e 100644
--- a/test/ProjectOrigin.Registry.Tests/ProjectOrigin.Registry.Tests.csproj
+++ b/test/ProjectOrigin.Registry.Tests/ProjectOrigin.Registry.Tests.csproj
@@ -10,16 +10,16 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="ProjectOrigin.TestCommon" Version="1.0.0" />
+    <PackageReference Include="ProjectOrigin.TestCommon" Version="2.0.0" />
     <PackageReference Include="FluentAssertions" Version="7.0.0" />
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
     <PackageReference Include="AutoFixture" Version="4.18.1" />
-    <PackageReference Include="xunit" Version="2.9.0" />
+    <PackageReference Include="xunit" Version="2.9.3" />
     <PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
       <PrivateAssets>all</PrivateAssets>
     </PackageReference>
-    <PackageReference Include="coverlet.collector" Version="6.0.2">
+    <PackageReference Include="coverlet.collector" Version="6.0.4">
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
       <PrivateAssets>all</PrivateAssets>
     </PackageReference>


Reviews:
user: login: ckr123
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T19:00:30Z
user: login: sahma19
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T21:10:06Z
user: login: ckr123
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T12:30:38Z

Review comments:
diff_hunk: @@ -64,24 +64,43 @@ private static IEnumerable<byte[]> RecursiveGetRequiredHashes(IEnumerable<byte[]
 
     private static byte[] RecursiveShaNodes(IEnumerable<byte[]> nodes, int balancedCount)
     {
-        if (nodes.Count() == 1)
+        var nodeList = nodes.ToList();
+        if (nodeList.Count == 0)
+            throw new ArgumentException("Nodes cannot be empty.", nameof(nodes));
+
+        if (nodeList.Count == 1)
         {
-            var data = SHA256.HashData(nodes.Single());
+            var nodeHash = SHA256.HashData(nodeList[0]);
+
             for (int i = (int)Math.Log(balancedCount, 2); i > 0; i--)
             {
-                var doubleData = data.Concat(data);
-                data = SHA256.HashData(doubleData.ToArray());
+                byte[] combinedHash = new byte[nodeHash.Length * 2];
path: src/ProjectOrigin.Registry/Extensions/IEnumerableMerkleExtension.cs
user: login: ckr123
body: Are we sure this does the same as before? 
created_at: 2025-03-05T19:00:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -64,24 +64,43 @@ private static IEnumerable<byte[]> RecursiveGetRequiredHashes(IEnumerable<byte[]
 
     private static byte[] RecursiveShaNodes(IEnumerable<byte[]> nodes, int balancedCount)
     {
-        if (nodes.Count() == 1)
+        var nodeList = nodes.ToList();
+        if (nodeList.Count == 0)
+            throw new ArgumentException("Nodes cannot be empty.", nameof(nodes));
+
+        if (nodeList.Count == 1)
         {
-            var data = SHA256.HashData(nodes.Single());
+            var nodeHash = SHA256.HashData(nodeList[0]);
+
             for (int i = (int)Math.Log(balancedCount, 2); i > 0; i--)
             {
-                var doubleData = data.Concat(data);
-                data = SHA256.HashData(doubleData.ToArray());
+                byte[] combinedHash = new byte[nodeHash.Length * 2];
path: src/ProjectOrigin.Registry/Extensions/IEnumerableMerkleExtension.cs
user: login: sahma19
body: Yes. I tried alot of solutions, and this one is the best, that also satisfies sonarcloud. Also there are 40 unit tests, dedicated only to verifying this logic, and they all pass
created_at: 2025-03-05T21:10:06Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-03-05T21:18:08Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=project-origin_registry&pullRequest=564) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=project-origin_registry&pullRequest=564&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=project-origin_registry&pullRequest=564&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=project-origin_registry&pullRequest=564&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [95.5% Coverage on New Code](https://sonarcloud.io/component_measures?id=project-origin_registry&pullRequest=564&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=project-origin_registry&pullRequest=564&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=project-origin_registry&pullRequest=564)


author_association: NONE