diff --git a/.github/workflows/auto-merge-dependabot.yml b/.github/workflows/auto-merge-dependabot.yml index ba2243c97..62a99a480 100644 --- a/.github/workflows/auto-merge-dependabot.yml +++ b/.github/workflows/auto-merge-dependabot.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v2.5.0 + uses: dependabot/fetch-metadata@v3.0.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.release-please-manifest.json b/.release-please-manifest.json index bf0d03617..3549461d9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.5.0" + ".": "3.5.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e0cc37e18..265529627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [3.5.1](https://github.com/microsoft/OpenAPI.NET/compare/v3.5.0...v3.5.1) (2026-03-31) + + +### Bug Fixes + +* security scheme references serialization ([a5acb89](https://github.com/microsoft/OpenAPI.NET/commit/a5acb896cb46a58702c07bc742b5e114ba90f95a)) + ## [3.5.0](https://github.com/microsoft/OpenAPI.NET/compare/v3.4.0...v3.5.0) (2026-03-20) diff --git a/Directory.Build.props b/Directory.Build.props index 034c59b03..410c635e0 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,7 +12,7 @@ https://github.com/Microsoft/OpenAPI.NET © Microsoft Corporation. All rights reserved. OpenAPI .NET - 3.5.0 + 3.5.1 diff --git a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs index bb4bc58d9..6d2282b32 100644 --- a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs +++ b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs @@ -5,7 +5,6 @@ using System.Text; using System.Text.RegularExpressions; using Humanizer; -using Humanizer.Inflections; using Microsoft.OpenApi.Hidi.Extensions; namespace Microsoft.OpenApi.Hidi.Formatters diff --git a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj index 3352b5a21..d28fb038a 100644 --- a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj +++ b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs index 4a912c0de..766b73f0d 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs @@ -79,11 +79,7 @@ private void SerializeInternal(IOpenApiWriter writer, Action p.Key?.Target is not null)) + foreach (var securitySchemeAndScopesValuePair in this.Where(static p => CanSerializeSecurityScheme(p.Key))) { var securityScheme = securitySchemeAndScopesValuePair.Key; var scopes = securitySchemeAndScopesValuePair.Value; @@ -103,6 +99,25 @@ private void SerializeInternal(IOpenApiWriter writer, Action /// Serialize to Open Api v2.0 /// diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index 1acd8ce8c..7a47b8597 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Net.Http; +using System.Text.Json.Nodes; using System.Threading.Tasks; using VerifyXunit; using Xunit; @@ -2387,6 +2388,56 @@ public async Task SerializeDocumentWithSelfPropertyAsV32Works() Assert.Equal(expected.MakeLineBreaksEnvironmentNeutral(), actual.MakeLineBreaksEnvironmentNeutral()); } + [Theory] + [InlineData(OpenApiSpecVersion.OpenApi3_0)] + [InlineData(OpenApiSpecVersion.OpenApi3_1)] + [InlineData(OpenApiSpecVersion.OpenApi3_2)] + public async Task SerializeDocumentWithSecurityRequirementAsJsonWorks(OpenApiSpecVersion openApiSpecVersion) + { + // Arrange + var doc = new OpenApiDocument + { + Info = new OpenApiInfo { Title = "Test", Version = "1.0" }, + Components = new OpenApiComponents + { + SecuritySchemes = new Dictionary(StringComparer.Ordinal) + { + ["Bearer"] = new OpenApiSecurityScheme + { + Type = SecuritySchemeType.Http, + Scheme = "Bearer", + BearerFormat = "JWT", + }, + }, + }, + }; + + doc.Security = + [ + new OpenApiSecurityRequirement + { + { new OpenApiSecuritySchemeReference("Bearer", doc), [] }, + }, + ]; + + var expected = + """ + [ + { + "Bearer": [] + } + ] + """; + + // Act + var actual = await doc.SerializeAsJsonAsync(openApiSpecVersion); + + // Assert + var actualSecurity = JsonNode.Parse(actual)?["security"]; + Assert.NotNull(actualSecurity); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), actualSecurity)); + } + [Fact] public async Task SerializeDocumentWithSelfPropertyAsV31WritesAsExtension() { diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs index 4ae9aedfd..29f5af3c6 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs @@ -130,35 +130,10 @@ public async Task SerializeSecurityRequirementAsV3JsonWorksAsync(bool produceTer await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); } - [Fact] - public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsV3JsonWorks() - { - // Arrange - var expected = - """ - { - "scheme1": [ - "scope1", - "scope2", - "scope3" - ], - "scheme2": [ - "scope4", - "scope5" - ], - "scheme3": [ ] - } - """; - - // Act - var actual = await SecurityRequirementWithReferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); - - // Assert - Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); - } - - [Fact] - public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsV2JsonWorks() + [Theory] + [InlineData(OpenApiSpecVersion.OpenApi3_0)] + [InlineData(OpenApiSpecVersion.OpenApi2_0)] + public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsJsonWorks(OpenApiSpecVersion openApiSpecVersion) { // Arrange var expected = @@ -178,37 +153,16 @@ public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsV2Js """; // Act - var actual = await SecurityRequirementWithReferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0); + var actual = await SecurityRequirementWithReferencedSecurityScheme.SerializeAsJsonAsync(openApiSpecVersion); // Assert Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } - [Fact] - public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsV3JsonShouldSkipUnserializableKeyValuePair() - { - // Arrange - var expected = - """ - { - "scheme1": [ - "scope1", - "scope2", - "scope3" - ], - "scheme3": [ ] - } - """; - - // Act - var actual = await SecurityRequirementWithUnreferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); - - // Assert - Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); - } - - [Fact] - public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsV2JsonShouldSkipUnserializableKeyValuePair() + [Theory] + [InlineData(OpenApiSpecVersion.OpenApi3_0)] + [InlineData(OpenApiSpecVersion.OpenApi2_0)] + public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsJsonShouldSkipUnserializableKeyValuePair(OpenApiSpecVersion openApiSpecVersion) { // Arrange var expected = @@ -224,8 +178,7 @@ public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsV2 """; // Act - var actual = - await SecurityRequirementWithUnreferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0); + var actual = await SecurityRequirementWithUnreferencedSecurityScheme.SerializeAsJsonAsync(openApiSpecVersion); // Assert Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual)));