1
0
mirror of https://github.com/bitwarden/server synced 2026-02-11 22:13:24 +00:00

[deps] Billing: Update swashbuckle-aspnetcore monorepo to v10 (major) (#6729)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Derek Nance <dnance@bitwarden.com>
This commit is contained in:
renovate[bot]
2026-02-10 11:11:44 -05:00
committed by GitHub
parent cda8527c7d
commit 065d971dc4
21 changed files with 121 additions and 109 deletions

View File

@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"swashbuckle.aspnetcore.cli": {
"version": "9.0.4",
"version": "10.1.0",
"commands": ["swagger"]
},
"dotnet-ef": {

View File

@@ -38,7 +38,7 @@
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="8.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="8.0.1" />
<PackageReference Include="Azure.Messaging.EventGrid" Version="5.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.0" />
</ItemGroup>
</Project>

View File

@@ -14,7 +14,7 @@ using Bit.Api.Tools.Models.Request;
using Bit.Api.Vault.Models.Request;
using Bit.Core.Auth.Entities;
using Bit.SharedWeb.Health;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Bit.SharedWeb.Utilities;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -301,44 +301,43 @@ public class Startup
// Remove all Bitwarden cloud servers and only register the local server
config.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
{
swaggerDoc.Servers.Clear();
swaggerDoc.Servers.Add(new OpenApiServer
{
Url = globalSettings.BaseServiceUri.Api,
});
swaggerDoc.Servers =
[
new() {
Url = globalSettings.BaseServiceUri.Api,
}
];
swaggerDoc.Components.SecuritySchemes.Clear();
swaggerDoc.Components.SecuritySchemes.Add("oauth2-client-credentials", new OpenApiSecurityScheme
swaggerDoc.Components ??= new OpenApiComponents();
swaggerDoc.Components.SecuritySchemes = new Dictionary<string, IOpenApiSecurityScheme>
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
ClientCredentials = new OpenApiOAuthFlow
"oauth2-client-credentials",
new OpenApiSecurityScheme
{
TokenUrl = new Uri($"{globalSettings.BaseServiceUri.Identity}/connect/token"),
Scopes = new Dictionary<string, string>
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
ClientCredentials = new OpenApiOAuthFlow
{
TokenUrl = new Uri($"{globalSettings.BaseServiceUri.Identity}/connect/token"),
Scopes = new Dictionary<string, string>
{
{ ApiScopes.ApiOrganization, "Organization APIs" }
}
}
}
}
}
});
};
swaggerDoc.SecurityRequirements.Clear();
swaggerDoc.SecurityRequirements.Add(new OpenApiSecurityRequirement
{
swaggerDoc.Security =
[
new OpenApiSecurityRequirement
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2-client-credentials"
}
},
[ApiScopes.ApiOrganization]
}
});
[new OpenApiSecuritySchemeReference("oauth2-client-credentials")] = [ApiScopes.ApiOrganization]
},
];
});
});

View File

@@ -7,7 +7,7 @@ using Bit.SharedWeb.Health;
using Bit.SharedWeb.Swagger;
using Bit.SharedWeb.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
namespace Bit.Api.Utilities;

View File

@@ -21,7 +21,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="MarkDig" Version="0.44.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.0" />
</ItemGroup>
</Project>

View File

@@ -14,7 +14,7 @@ using Bit.SharedWeb.Swagger;
using Bit.SharedWeb.Utilities;
using Duende.IdentityServer.Services;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
namespace Bit.Identity;

View File

@@ -13,7 +13,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Version="4.23.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="9.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="10.1.0" />
</ItemGroup>
</Project>

View File

@@ -1,6 +1,5 @@
using System.Text.Json;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Bit.SharedWeb.Swagger;
@@ -18,8 +17,9 @@ public class ActionNameOperationFilter : IOperationFilter
if (!context.ApiDescription.ActionDescriptor.RouteValues.TryGetValue("action", out var action)) return;
if (string.IsNullOrEmpty(action)) return;
operation.Extensions.Add("x-action-name", new OpenApiString(action));
operation.Extensions ??= new Dictionary<string, IOpenApiExtension>();
operation.Extensions.Add("x-action-name", new JsonNodeExtension(action));
// We can't do case changes in the codegen templates, so we also add the snake_case version of the action name
operation.Extensions.Add("x-action-name-snake-case", new OpenApiString(JsonNamingPolicy.SnakeCaseLower.ConvertName(action)));
operation.Extensions.Add("x-action-name-snake-case", new JsonNodeExtension(JsonNamingPolicy.SnakeCaseLower.ConvertName(action)));
}
}

View File

@@ -1,4 +1,4 @@
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Bit.SharedWeb.Swagger;
@@ -15,19 +15,22 @@ public class CheckDuplicateOperationIdsDocumentFilter(bool printDuplicates = tru
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
var operationIdMap = new Dictionary<string, List<(string Path, OpenApiPathItem PathItem, OperationType Method, OpenApiOperation Operation)>>();
var operationIdMap = new Dictionary<string, List<(string Path, IOpenApiPathItem PathItem, HttpMethod Method, OpenApiOperation Operation)>>();
foreach (var (path, pathItem) in swaggerDoc.Paths)
{
foreach (var operation in pathItem.Operations)
if (pathItem.Operations is null) continue;
foreach (var (method, operation) in pathItem.Operations)
{
if (!operationIdMap.TryGetValue(operation.Value.OperationId, out var list))
var operationId = operation.OperationId ?? string.Empty;
if (!operationIdMap.TryGetValue(operationId, out var list))
{
list = [];
operationIdMap[operation.Value.OperationId] = list;
operationIdMap[operationId] = list;
}
list.Add((path, pathItem, operation.Key, operation.Value));
list.Add((path, pathItem, method, operation));
}
}
@@ -57,11 +60,15 @@ public class CheckDuplicateOperationIdsDocumentFilter(bool printDuplicates = tru
{
Console.Write($" {method.ToString().ToUpper()} {path}");
if (operation.Extensions is null) continue;
if (operation.Extensions.TryGetValue("x-source-file", out var sourceFile) && operation.Extensions.TryGetValue("x-source-line", out var sourceLine))
if (operation.Extensions.TryGetValue("x-source-file", out var sourceFile)
&& operation.Extensions.TryGetValue("x-source-line", out var sourceLine)
&& sourceFile is JsonNodeExtension sourceFileNodeExt
&& sourceLine is JsonNodeExtension sourceLineNodeExt)
{
var sourceFileString = ((Microsoft.OpenApi.Any.OpenApiString)sourceFile).Value;
var sourceLineString = ((Microsoft.OpenApi.Any.OpenApiInteger)sourceLine).Value;
var sourceFileString = sourceFileNodeExt.Node.ToString();
var sourceLineString = sourceLineNodeExt.Node.ToString();
Console.WriteLine($" {sourceFileString}:{sourceLineString}");
}

View File

@@ -2,7 +2,7 @@
using System.Text.Json;
using Bit.Core.Utilities;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Bit.SharedWeb.Swagger;
@@ -13,7 +13,7 @@ namespace Bit.SharedWeb.Swagger;
/// </summary>
public class EncryptedStringSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
public void Apply(IOpenApiSchema schema, SchemaFilterContext context)
{
if (context.Type == null || schema.Properties == null)
return;
@@ -30,9 +30,9 @@ public class EncryptedStringSchemaFilter : ISchemaFilter
// Convert prop.Name to camelCase for JSON schema property lookup
var jsonPropName = JsonNamingPolicy.CamelCase.ConvertName(prop.Name);
if (schema.Properties.TryGetValue(jsonPropName, out var value))
if (schema.Properties.TryGetValue(jsonPropName, out var value) && value is OpenApiSchema innerSchema)
{
value.Format = "x-enc-string";
innerSchema.Format = "x-enc-string";
}
}
}

View File

@@ -1,5 +1,5 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using System.Text.Json.Nodes;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Bit.SharedWeb.Swagger;
@@ -14,13 +14,15 @@ namespace Bit.SharedWeb.Swagger;
/// </remarks>
public class EnumSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
public void Apply(IOpenApiSchema schema, SchemaFilterContext context)
{
if (context.Type.IsEnum)
if (context.Type.IsEnum && schema is OpenApiSchema openApiSchema)
{
var array = new OpenApiArray();
array.AddRange(Enum.GetNames(context.Type).Select(n => new OpenApiString(n)));
schema.Extensions.Add("x-enum-varnames", array);
var array = new JsonArray();
foreach (var name in Enum.GetNames(context.Type)) array.Add(name);
openApiSchema.Extensions ??= new Dictionary<string, IOpenApiExtension>();
openApiSchema.Extensions.Add("x-enum-varnames", new JsonNodeExtension(array));
}
}
}

View File

@@ -1,7 +1,7 @@
#nullable enable
using System.Diagnostics;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Bit.SharedWeb.Swagger;
@@ -16,7 +16,8 @@ public class GitCommitDocumentFilter : IDocumentFilter
{
if (!string.IsNullOrEmpty(GitCommit))
{
swaggerDoc.Extensions.Add("x-git-commit", new Microsoft.OpenApi.Any.OpenApiString(GitCommit));
swaggerDoc.Extensions ??= new Dictionary<string, IOpenApiExtension>();
swaggerDoc.Extensions.Add("x-git-commit", new JsonNodeExtension(GitCommit));
}
}

View File

@@ -4,8 +4,7 @@ using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.CompilerServices;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Bit.SharedWeb.Swagger;
@@ -24,8 +23,9 @@ public class SourceFileLineOperationFilter : IOperationFilter
if (fileName != null && lineNumber > 0)
{
// Also add the information as extensions, so other tools can use it in the future
operation.Extensions.Add("x-source-file", new OpenApiString(fileName));
operation.Extensions.Add("x-source-line", new OpenApiInteger(lineNumber));
operation.Extensions ??= new Dictionary<string, IOpenApiExtension>();
operation.Extensions.Add("x-source-file", new JsonNodeExtension(fileName));
operation.Extensions.Add("x-source-line", new JsonNodeExtension(lineNumber));
}
}

View File

@@ -80,7 +80,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using StackExchange.Redis;
using Swashbuckle.AspNetCore.SwaggerGen;
using NoopRepos = Bit.Core.Repositories.Noop;
@@ -847,19 +847,9 @@ public static class ServiceCollectionExtensions
});
// Add security requirement
config.AddSecurityRequirement(new OpenApiSecurityRequirement
config.AddSecurityRequirement((document) => new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = serverId
},
},
[ApiScopes.ApiOrganization]
}
[new OpenApiSecuritySchemeReference(serverId, document)] = [ApiScopes.ApiOrganization]
});
}
}

View File

@@ -1,8 +1,7 @@
using Bit.SharedWeb.Swagger;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace SharedWeb.Test;
@@ -13,7 +12,10 @@ public class ActionNameOperationFilterTest
public void WithValidActionNameAddsActionNameExtensions()
{
// Arrange
var operation = new OpenApiOperation();
var operation = new OpenApiOperation
{
Extensions = new Dictionary<string, IOpenApiExtension>()
};
var actionDescriptor = new ActionDescriptor();
actionDescriptor.RouteValues["action"] = "GetUsers";
@@ -22,7 +24,7 @@ public class ActionNameOperationFilterTest
ActionDescriptor = actionDescriptor
};
var context = new OperationFilterContext(apiDescription, null, null, null);
var context = new OperationFilterContext(apiDescription, null, null, null, null);
var filter = new ActionNameOperationFilter();
// Act
@@ -32,20 +34,23 @@ public class ActionNameOperationFilterTest
Assert.True(operation.Extensions.ContainsKey("x-action-name"));
Assert.True(operation.Extensions.ContainsKey("x-action-name-snake-case"));
var actionNameExt = operation.Extensions["x-action-name"] as OpenApiString;
var actionNameSnakeCaseExt = operation.Extensions["x-action-name-snake-case"] as OpenApiString;
var actionNameExt = operation.Extensions["x-action-name"] as JsonNodeExtension;
var actionNameSnakeCaseExt = operation.Extensions["x-action-name-snake-case"] as JsonNodeExtension;
Assert.NotNull(actionNameExt);
Assert.NotNull(actionNameSnakeCaseExt);
Assert.Equal("GetUsers", actionNameExt.Value);
Assert.Equal("get_users", actionNameSnakeCaseExt.Value);
Assert.Equal("GetUsers", actionNameExt.Node.ToString());
Assert.Equal("get_users", actionNameSnakeCaseExt.Node.ToString());
}
[Fact]
public void WithMissingActionRouteValueDoesNotAddExtensions()
{
// Arrange
var operation = new OpenApiOperation();
var operation = new OpenApiOperation
{
Extensions = new Dictionary<string, IOpenApiExtension>()
};
var actionDescriptor = new ActionDescriptor();
// Not setting the "action" route value at all
@@ -54,7 +59,7 @@ public class ActionNameOperationFilterTest
ActionDescriptor = actionDescriptor
};
var context = new OperationFilterContext(apiDescription, null, null, null);
var context = new OperationFilterContext(apiDescription, null, null, null, null);
var filter = new ActionNameOperationFilter();
// Act

View File

@@ -1,6 +1,6 @@
using Bit.SharedWeb.Swagger;
using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace SharedWeb.Test;

View File

@@ -1,6 +1,6 @@
using Bit.Core.Utilities;
using Bit.SharedWeb.Swagger;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
@@ -24,7 +24,7 @@ public class EncryptedStringSchemaFilterTest
{
var schema = new OpenApiSchema
{
Properties = new Dictionary<string, OpenApiSchema> { { "secretKey", new() } }
Properties = new Dictionary<string, IOpenApiSchema> { { "secretKey", new OpenApiSchema() } }
};
var context = new SchemaFilterContext(typeof(TestClass), null, null, null);
var filter = new EncryptedStringSchemaFilter();
@@ -37,7 +37,7 @@ public class EncryptedStringSchemaFilterTest
{
var schema = new OpenApiSchema
{
Properties = new Dictionary<string, OpenApiSchema> { { "username", new() } }
Properties = new Dictionary<string, IOpenApiSchema> { { "username", new OpenApiSchema() } }
};
var context = new SchemaFilterContext(typeof(TestClass), null, null, null);
var filter = new EncryptedStringSchemaFilter();
@@ -50,7 +50,7 @@ public class EncryptedStringSchemaFilterTest
{
var schema = new OpenApiSchema
{
Properties = new Dictionary<string, OpenApiSchema> { { "wrong", new() } }
Properties = new Dictionary<string, IOpenApiSchema> { { "wrong", new OpenApiSchema() } }
};
var context = new SchemaFilterContext(typeof(TestClass), null, null, null);
var filter = new EncryptedStringSchemaFilter();

View File

@@ -1,6 +1,5 @@
using Bit.SharedWeb.Swagger;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace SharedWeb.Test;
@@ -17,21 +16,27 @@ public class EnumSchemaFilterTest
[Fact]
public void SetsEnumVarNamesExtension()
{
var schema = new OpenApiSchema();
var schema = new OpenApiSchema
{
Extensions = new Dictionary<string, IOpenApiExtension>()
};
var context = new SchemaFilterContext(typeof(TestEnum), null, null, null);
var filter = new EnumSchemaFilter();
filter.Apply(schema, context);
Assert.True(schema.Extensions.ContainsKey("x-enum-varnames"));
var extensions = schema.Extensions["x-enum-varnames"] as OpenApiArray;
var extensions = (schema.Extensions["x-enum-varnames"] as JsonNodeExtension).Node.AsArray();
Assert.NotNull(extensions);
Assert.Equal(["First", "Second", "Third"], extensions.Select(x => ((OpenApiString)x).Value));
Assert.Equal(["First", "Second", "Third"], extensions.GetValues<string>().Select(x => x));
}
[Fact]
public void DoesNotSetExtensionForNonEnum()
{
var schema = new OpenApiSchema();
var schema = new OpenApiSchema
{
Extensions = new Dictionary<string, IOpenApiExtension>()
};
var context = new SchemaFilterContext(typeof(string), null, null, null);
var filter = new EnumSchemaFilter();
filter.Apply(schema, context);

View File

@@ -1,5 +1,5 @@
using Bit.SharedWeb.Swagger;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace SharedWeb.Test;
@@ -9,15 +9,18 @@ public class GitCommitDocumentFilterTest
[Fact]
public void AddsGitCommitExtensionIfAvailable()
{
var doc = new OpenApiDocument();
var doc = new OpenApiDocument
{
Extensions = new Dictionary<string, IOpenApiExtension>()
};
var context = new DocumentFilterContext(null, null, null);
var filter = new GitCommitDocumentFilter();
filter.Apply(doc, context);
Assert.True(doc.Extensions.ContainsKey("x-git-commit"));
var ext = doc.Extensions["x-git-commit"] as Microsoft.OpenApi.Any.OpenApiString;
var ext = doc.Extensions["x-git-commit"] as JsonNodeExtension;
Assert.NotNull(ext);
Assert.False(string.IsNullOrEmpty(ext.Value));
Assert.False(string.IsNullOrEmpty(ext.Node.ToString()));
}
}

View File

@@ -1,5 +1,5 @@
using Bit.SharedWeb.Swagger;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace SharedWeb.Test;
@@ -16,18 +16,18 @@ public class SourceFileLineOperationFilterTest
{
var methodInfo = typeof(DummyController).GetMethod(nameof(DummyController.DummyMethod));
var operation = new OpenApiOperation();
var context = new OperationFilterContext(null, null, null, methodInfo);
var context = new OperationFilterContext(null, null, null, null, methodInfo);
var filter = new SourceFileLineOperationFilter();
filter.Apply(operation, context);
Assert.True(operation.Extensions.ContainsKey("x-source-file"));
Assert.True(operation.Extensions.ContainsKey("x-source-line"));
var fileExt = operation.Extensions["x-source-file"] as Microsoft.OpenApi.Any.OpenApiString;
var lineExt = operation.Extensions["x-source-line"] as Microsoft.OpenApi.Any.OpenApiInteger;
var fileExt = operation.Extensions["x-source-file"] as JsonNodeExtension;
var lineExt = operation.Extensions["x-source-line"] as JsonNodeExtension;
Assert.NotNull(fileExt);
Assert.NotNull(lineExt);
Assert.Equal(11, lineExt.Value);
Assert.StartsWith("test/SharedWeb.Test/", fileExt.Value);
Assert.Equal(11, (int)lineExt.Node);
Assert.StartsWith("test/SharedWeb.Test/", fileExt.Node.ToString());
}
}

View File

@@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using NSubstitute;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;