using BuildFlow.Platform.Domain.Entities.Role; using BuildFlow.Platform.Infrastructure.Configuration; using BuildFlow.Platform.Infrastructure.Persistence; using FluentAssertions; using Microsoft.EntityFrameworkCore; using Xunit; namespace BuildFlow.Platform.Tests.Auth; /// /// 首次部署管理员初始化安全边界测试。 /// public class BootstrapAdminSeederTests { private static BootstrapAdminOptions ValidOptions(string password = "BootstrapAdmin1") => new() { Enabled = true, Username = "bootstrap-admin", Email = "bootstrap-admin@test.local", Password = password, }; private static async Task SeedAdminRoleAsync(PlatformDbContext db) { db.Roles.Add(PlatformTestDb.WithAudit(new RoleEntity { Id = BootstrapAdminSeeder.AdminRoleId, Name = "Admin", Description = "管理员", })); await db.SaveChangesAsync(); } [Fact] public async Task DisabledShouldNotCreateAUser() { await using var db = PlatformTestDb.CreateDbContext(); var created = await BootstrapAdminSeeder.SeedAsync( db, new BootstrapAdminOptions()); created.Should().BeFalse(); db.Users.Should().BeEmpty(); } [Fact] public async Task EnabledWithoutPasswordShouldFailClearly() { await using var db = PlatformTestDb.CreateDbContext(); var options = ValidOptions(""); var act = () => BootstrapAdminSeeder.SeedAsync(db, options); await act.Should().ThrowAsync() .WithMessage("*密码不能为空*"); } [Fact] public async Task WeakPasswordShouldFailClearly() { await using var db = PlatformTestDb.CreateDbContext(); var act = () => BootstrapAdminSeeder.SeedAsync(db, ValidOptions("weakpass")); await act.Should().ThrowAsync() .WithMessage("*大写字母*"); } [Fact] public async Task FirstRunShouldCreateAnAdminWithTheConfiguredPassword() { await using var db = PlatformTestDb.CreateDbContext(); await SeedAdminRoleAsync(db); var options = ValidOptions(); var created = await BootstrapAdminSeeder.SeedAsync(db, options); created.Should().BeTrue(); var user = await db.Users.SingleAsync(); user.Username.Should().Be(options.Username); BCrypt.Net.BCrypt.Verify(options.Password, user.PasswordHash).Should().BeTrue(); (await db.UserRoles.CountAsync(x => x.UserId == user.Id && x.RoleId == BootstrapAdminSeeder.AdminRoleId)) .Should().Be(1); } [Fact] public async Task RepeatedRunShouldNotResetTheExistingAdminPassword() { await using var db = PlatformTestDb.CreateDbContext(); await SeedAdminRoleAsync(db); await BootstrapAdminSeeder.SeedAsync(db, ValidOptions("BootstrapAdmin1")); var originalHash = await db.Users.Select(x => x.PasswordHash).SingleAsync(); var created = await BootstrapAdminSeeder.SeedAsync( db, ValidOptions("DifferentAdmin2")); created.Should().BeFalse(); (await db.Users.Select(x => x.PasswordHash).SingleAsync()).Should().Be(originalHash); BCrypt.Net.BCrypt.Verify("BootstrapAdmin1", originalHash).Should().BeTrue(); } }