54 lines
1.8 KiB
C#
54 lines
1.8 KiB
C#
namespace BuildFlow.Architecture.Tests;
|
||
|
||
using Xunit;
|
||
|
||
/// <summary>
|
||
/// RAG 高风险入口的权限和 CQRS 架构约束。
|
||
/// </summary>
|
||
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 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 (File.Exists(Path.Combine(current.FullName, "BuildFlow.slnx"))) return current;
|
||
current = current.Parent;
|
||
}
|
||
|
||
throw new InvalidOperationException("无法定位 BuildFlow.slnx,无法验证 RAG 安全边界。");
|
||
}
|
||
}
|