namespace BuildFlow.Architecture.Tests; using Xunit; /// /// RAG 高风险入口的权限和 CQRS 架构约束。 /// public class RagSecurityArchitectureTests { [Fact] public void ObsidianSyncEndpointShouldRequireKnowledgeWritePermission() { var source = ReadSource( "src/BuildFlow.Host/Endpoints/Rag/Obsidian/SyncObsidianVaultEndpoint.cs"); Assert.Contains("Permissions(\"knowledge:write\")", source); Assert.DoesNotContain("AllowAnonymous()", source); } [Theory] [InlineData("src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageEndpoint.cs")] [InlineData("src/BuildFlow.Host/Endpoints/Rag/Chat/EditMessageStreamEndpoint.cs")] public void ChatStreamEndpointsShouldUseMediatorWithoutDbContext(string relativePath) { var source = ReadSource(relativePath); Assert.Contains("IMediator mediator", source); Assert.Contains("mediator.CreateStream", source); Assert.Contains("event: done", source); Assert.DoesNotContain("RagDbContext", source); Assert.DoesNotContain("IAIChatAgent", source); Assert.DoesNotContain("IChatMessageCache", source); } private static string ReadSource(string relativePath) { return System.IO.File.ReadAllText(Path.Combine( FindRepoRoot().FullName, relativePath.Replace('/', Path.DirectorySeparatorChar))); } private static DirectoryInfo FindRepoRoot() { var current = new DirectoryInfo(AppContext.BaseDirectory); while (current is not null) { if (System.IO.File.Exists(Path.Combine(current.FullName, "BuildFlow.slnx"))) return current; current = current.Parent; } throw new InvalidOperationException("无法定位 BuildFlow.slnx,无法验证 RAG 安全边界。"); } }