1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-19 08:30:59 -05:00

[PM-22103] Exclude default collections from admin apis (#6021)

* feat: exclude DefaultUserCollection from GetManyByOrganizationIdWithPermissionsAsync

Updated EF implementation, SQL procedure, and unit test to verify that default user collections are filtered from results

* Update the public CollectionsController.Get method to return a NotFoundResult for collections of type DefaultUserCollection.

* Add unit tests for the public CollectionsController

* Update ICollectionRepository.GetManyByOrganizationIdAsync to exclude results of the type DefaultUserCollection

Modified the SQL stored procedure and the EF query to reflect this change and added a new integration test to ensure the functionality works as expected.

* Refactor CollectionsController to remove unused IApplicationCacheService dependency

* Update IOrganizationUserRepository.GetDetailsByIdWithCollectionsAsync to exclude DefaultUserCollections

* Update IOrganizationUserRepository.GetManyDetailsByOrganizationAsync to exclude DefaultUserCollections

* Undo change to GetByIdWithCollectionsAsync

* Update integration test to verify exclusion of DefaultUserCollection in OrganizationUserRepository.GetDetailsByIdWithCollectionsAsync

* Clarify documentation in ICollectionRepository to specify that GetManyByOrganizationIdWithAccessAsync returns only shared collections belonging to the organization.

* Add Arrange, Act, and Assert comments to CollectionsControllerTests
This commit is contained in:
Rui Tomé
2025-07-18 13:00:54 +01:00
committed by GitHub
parent 828003f101
commit 30300bc59b
14 changed files with 500 additions and 15 deletions

View File

@ -0,0 +1,122 @@
using Bit.Api.Models.Public.Response;
using Bit.Api.Public.Controllers;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.AspNetCore.Mvc;
using NSubstitute;
using Xunit;
namespace Bit.Api.Test.Public.Controllers;
[ControllerCustomize(typeof(CollectionsController))]
[SutProviderCustomize]
public class CollectionsControllerTests
{
[Theory, BitAutoData]
public async Task Get_WithDefaultUserCollection_ReturnsNotFound(
Collection collection, SutProvider<CollectionsController> sutProvider)
{
// Arrange
collection.Type = CollectionType.DefaultUserCollection;
var access = new CollectionAccessDetails
{
Groups = new List<CollectionAccessSelection>(),
Users = new List<CollectionAccessSelection>()
};
sutProvider.GetDependency<ICurrentContext>()
.OrganizationId.Returns(collection.OrganizationId);
sutProvider.GetDependency<ICollectionRepository>()
.GetByIdWithAccessAsync(collection.Id)
.Returns(new Tuple<Collection?, CollectionAccessDetails>(collection, access));
// Act
var result = await sutProvider.Sut.Get(collection.Id);
// Assert
Assert.IsType<NotFoundResult>(result);
}
[Theory, BitAutoData]
public async Task Get_WithSharedCollection_ReturnsCollection(
Collection collection, SutProvider<CollectionsController> sutProvider)
{
// Arrange
collection.Type = CollectionType.SharedCollection;
var access = new CollectionAccessDetails
{
Groups = [],
Users = []
};
sutProvider.GetDependency<ICurrentContext>()
.OrganizationId.Returns(collection.OrganizationId);
sutProvider.GetDependency<ICollectionRepository>()
.GetByIdWithAccessAsync(collection.Id)
.Returns(new Tuple<Collection?, CollectionAccessDetails>(collection, access));
// Act
var result = await sutProvider.Sut.Get(collection.Id);
// Assert
var jsonResult = Assert.IsType<JsonResult>(result);
var response = Assert.IsType<CollectionResponseModel>(jsonResult.Value);
Assert.Equal(collection.Id, response.Id);
Assert.Equal(collection.Type, response.Type);
}
[Theory, BitAutoData]
public async Task Delete_WithDefaultUserCollection_ReturnsBadRequest(
Collection collection, SutProvider<CollectionsController> sutProvider)
{
// Arrange
collection.Type = CollectionType.DefaultUserCollection;
sutProvider.GetDependency<ICurrentContext>()
.OrganizationId.Returns(collection.OrganizationId);
sutProvider.GetDependency<ICollectionRepository>()
.GetByIdAsync(collection.Id)
.Returns(collection);
// Act
var result = await sutProvider.Sut.Delete(collection.Id);
// Assert
var badRequestResult = Assert.IsType<BadRequestObjectResult>(result);
var errorResponse = Assert.IsType<ErrorResponseModel>(badRequestResult.Value);
Assert.Contains("You cannot delete a collection with the type as DefaultUserCollection", errorResponse.Message);
await sutProvider.GetDependency<ICollectionRepository>()
.DidNotReceive()
.DeleteAsync(Arg.Any<Collection>());
}
[Theory, BitAutoData]
public async Task Delete_WithSharedCollection_ReturnsOk(
Collection collection, SutProvider<CollectionsController> sutProvider)
{
// Arrange
collection.Type = CollectionType.SharedCollection;
sutProvider.GetDependency<ICurrentContext>()
.OrganizationId.Returns(collection.OrganizationId);
sutProvider.GetDependency<ICollectionRepository>()
.GetByIdAsync(collection.Id)
.Returns(collection);
// Act
var result = await sutProvider.Sut.Delete(collection.Id);
// Assert
Assert.IsType<OkResult>(result);
await sutProvider.GetDependency<ICollectionRepository>()
.Received(1)
.DeleteAsync(collection);
}
}