/** * Credential Isolation Integration Tests * * Verifies that UserCredential data never leaks across federation boundaries. */ import { describe, it, expect, beforeEach } from "vitest"; import { Test, TestingModule } from "@nestjs/testing"; import { QueryService } from "./query.service"; import { CommandService } from "./command.service"; import { PrismaService } from "../prisma/prisma.service"; import { FederationService } from "./federation.service"; import { SignatureService } from "./signature.service"; import { HttpService } from "@nestjs/axios"; import { ConfigService } from "@nestjs/config"; import { TasksService } from "../tasks/tasks.service"; import { EventsService } from "../events/events.service"; import { ProjectsService } from "../projects/projects.service"; import { ModuleRef } from "@nestjs/core"; import { FederationConnectionStatus } from "@prisma/client"; describe("Credential Isolation (Integration)", () => { let queryService: QueryService; let commandService: CommandService; const mockPrisma = { federationConnection: { findFirst: () => Promise.resolve({ id: "connection-1", workspaceId: "workspace-1", remoteInstanceId: "remote-instance-1", status: FederationConnectionStatus.ACTIVE, }), }, }; const mockFederationService = { getInstanceIdentity: () => Promise.resolve({ instanceId: "local-instance-1", }), }; const mockSignatureService = { validateTimestamp: () => true, verifyMessage: () => Promise.resolve({ valid: true }), signMessage: () => Promise.resolve("signature"), }; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ QueryService, CommandService, { provide: PrismaService, useValue: mockPrisma }, { provide: FederationService, useValue: mockFederationService }, { provide: SignatureService, useValue: mockSignatureService }, { provide: HttpService, useValue: { post: () => Promise.resolve() } }, { provide: ConfigService, useValue: { get: () => null } }, { provide: TasksService, useValue: { findAll: () => Promise.resolve({ data: [] }) } }, { provide: EventsService, useValue: { findAll: () => Promise.resolve({ data: [] }) } }, { provide: ProjectsService, useValue: { findAll: () => Promise.resolve({ data: [] }) } }, { provide: ModuleRef, useValue: { get: () => ({}) } }, ], }).compile(); queryService = module.get(QueryService); commandService = module.get(CommandService); }); describe("Query Isolation", () => { it("should block direct credential entity queries", async () => { const queryMessage = { messageId: "msg-1", instanceId: "remote-instance-1", query: "SELECT * FROM user_credentials", context: { workspaceId: "workspace-1" }, timestamp: Date.now(), signature: "valid-signature", }; const result = await queryService.handleIncomingQuery(queryMessage); expect(result.success).toBe(false); expect(result.error).toContain("Credential queries are not allowed"); }); it("should block queries with credential keywords in different case", async () => { const queries = ["Get all CREDENTIALS", "Show API_KEYS", "List oauth TOKENS", "Find secrets"]; for (const query of queries) { const queryMessage = { messageId: `msg-${Math.random()}`, instanceId: "remote-instance-1", query, context: { workspaceId: "workspace-1" }, timestamp: Date.now(), signature: "valid-signature", }; const result = await queryService.handleIncomingQuery(queryMessage); expect(result.success).toBe(false); expect(result.error).toContain("Credential queries are not allowed"); } }); it("should allow non-credential queries", async () => { const queries = ["tasks", "events", "projects"]; for (const query of queries) { const queryMessage = { messageId: `msg-${Math.random()}`, instanceId: "remote-instance-1", query, context: { workspaceId: "workspace-1" }, timestamp: Date.now(), signature: "valid-signature", }; const result = await queryService.handleIncomingQuery(queryMessage); expect(result.success).toBe(true); } }); }); describe("Command Isolation", () => { it("should block credential.create commands", async () => { const commandMessage = { messageId: "cmd-1", instanceId: "remote-instance-1", commandType: "credential.create", payload: { name: "test", value: "secret" }, timestamp: Date.now(), signature: "valid-signature", }; const result = await commandService.handleIncomingCommand(commandMessage); expect(result.success).toBe(false); expect(result.error).toContain("Credential operations are not allowed"); }); it("should block all credential operations", async () => { const operations = [ "credential.create", "credential.update", "credential.delete", "credential.read", "credentials.sync", "credentials.list", ]; for (const commandType of operations) { const commandMessage = { messageId: `cmd-${Math.random()}`, instanceId: "remote-instance-1", commandType, payload: {}, timestamp: Date.now(), signature: "valid-signature", }; const result = await commandService.handleIncomingCommand(commandMessage); expect(result.success).toBe(false); expect(result.error).toContain("Credential operations are not allowed"); } }); it("should block credential operations with different case", async () => { const operations = ["CREDENTIAL.create", "Credentials.Update", "CrEdEnTiAl.delete"]; for (const commandType of operations) { const commandMessage = { messageId: `cmd-${Math.random()}`, instanceId: "remote-instance-1", commandType, payload: {}, timestamp: Date.now(), signature: "valid-signature", }; const result = await commandService.handleIncomingCommand(commandMessage); expect(result.success).toBe(false); expect(result.error).toContain("Credential operations are not allowed"); } }); it("should allow agent commands (existing functionality)", async () => { const commandMessage = { messageId: "cmd-1", instanceId: "remote-instance-1", commandType: "agent.spawn", payload: { agentType: "task-executor" }, timestamp: Date.now(), signature: "valid-signature", }; // Mock FederationAgentService const moduleRef = { get: () => ({ handleAgentCommand: () => Promise.resolve({ success: true, data: { agentId: "agent-123" }, }), }), }; // Inject moduleRef (commandService as never)["moduleRef"] = moduleRef; const result = await commandService.handleIncomingCommand(commandMessage); expect(result.success).toBe(true); }); }); describe("Defense-in-Depth", () => { it("should document transit key separation", () => { // This test documents the architectural isolation // TransitKey.CREDENTIALS is used for user credentials // TransitKey.FEDERATION is used for federation private keys // Each federated instance has its own OpenBao instance // Even if one Transit key is compromised, credentials remain isolated const architecture = { userCredentials: { transitKey: "mosaic-credentials", service: "VaultService", scope: "per-workspace", }, federationKeys: { transitKey: "mosaic-federation", service: "CryptoService (legacy) / VaultService (future)", scope: "per-instance", }, isolation: { cryptographic: "Separate Transit keys prevent cross-contamination", infrastructure: "Each instance has its own OpenBao", application: "Deny-lists prevent accidental exposure", }, }; expect(architecture.userCredentials.transitKey).not.toBe( architecture.federationKeys.transitKey ); expect(architecture.isolation).toBeDefined(); }); }); });