Skip to main content
Glama

MCP Gemini Server

by bsmi021
FileSecurityServiceBasics.test.vitest.ts6.39 kB
// Using vitest globals - see vitest.config.ts globals: true import * as path from "node:path"; import * as fs from "node:fs/promises"; // Import the code to test import { FileSecurityService } from "../../../src/utils/FileSecurityService.js"; import { logger } from "../../../src/utils/logger.js"; describe("FileSecurityService Basic Operations", () => { // Define test constants for all tests const TEST_CONTENT = "Test file content"; // Test directories for our tests const testDir = path.resolve("./test-temp-dir"); const outsideDir = path.resolve("./outside-dir"); const ALLOWED_DIR = path.join(testDir, "allowed"); // Setup and teardown for tests beforeEach(async () => { // Setup test directories await fs.mkdir(testDir, { recursive: true }); await fs.mkdir(ALLOWED_DIR, { recursive: true }); await fs.mkdir(outsideDir, { recursive: true }); // Mock logger to prevent console spam vi.spyOn(logger, "info").mockImplementation(vi.fn()); vi.spyOn(logger, "error").mockImplementation(vi.fn()); vi.spyOn(logger, "warn").mockImplementation(vi.fn()); }); afterEach(async () => { // Clean up test directories await fs.rm(testDir, { recursive: true, force: true }); await fs.rm(outsideDir, { recursive: true, force: true }); // Restore mocks vi.restoreAllMocks(); }); describe("Basic File Security Operations", () => { it("should write to a file directly within allowed absolute directory", async () => { // Arrange const filePath = path.join(ALLOWED_DIR, "file.txt"); const allowedPaths = [ALLOWED_DIR]; const fileSecurityService = new FileSecurityService(allowedPaths); // Act await fileSecurityService.secureWriteFile(filePath, TEST_CONTENT); // Assert const fileContent = await fs.readFile(filePath, "utf8"); expect(fileContent).toBe(TEST_CONTENT); }); it("should write to a file in a nested subdirectory of allowed directory", async () => { // Arrange const nestedDir = path.join(ALLOWED_DIR, "subdir"); const filePath = path.join(nestedDir, "file.txt"); const allowedPaths = [ALLOWED_DIR]; const fileSecurityService = new FileSecurityService(allowedPaths); // Act await fileSecurityService.secureWriteFile(filePath, TEST_CONTENT); // Assert const fileContent = await fs.readFile(filePath, "utf8"); expect(fileContent).toBe(TEST_CONTENT); }); it("should allow writing when filePath is an exact match to allowed absolute file path", async () => { // Arrange const exactFilePath = path.join(ALLOWED_DIR, "exact-file.txt"); const allowedPaths = [exactFilePath]; // Allowing the exact file path const fileSecurityService = new FileSecurityService(allowedPaths); // Act await fileSecurityService.secureWriteFile(exactFilePath, TEST_CONTENT); // Assert const fileContent = await fs.readFile(exactFilePath, "utf8"); expect(fileContent).toBe(TEST_CONTENT); }); it("should throw error when filePath resolves outside allowed paths", async () => { // Arrange const unsafePath = path.join(outsideDir, "unsafe-file.txt"); const allowedPaths = [ALLOWED_DIR]; const fileSecurityService = new FileSecurityService(allowedPaths); // Act & Assert await expect( fileSecurityService.secureWriteFile(unsafePath, TEST_CONTENT) ).rejects.toThrow( /Access denied: The file path must be within the allowed directories/ ); // Additional check that logger.warn was called (FileSecurityService uses warn, not error) expect(logger.warn).toHaveBeenCalled(); // Verify file was not written await expect(fs.access(unsafePath)).rejects.toThrow(); }); it("should throw error when filePath uses directory traversal to escape allowed path", async () => { // Arrange const traversalPath = path.join( ALLOWED_DIR, "subdir", "..", "..", "outside", "file.txt" ); const allowedPaths = [ALLOWED_DIR]; const fileSecurityService = new FileSecurityService(allowedPaths); // Act & Assert await expect( fileSecurityService.secureWriteFile(traversalPath, TEST_CONTENT) ).rejects.toThrow( /Access denied: The file path must be within the allowed directories/ ); }); it("should use default path when no allowed paths are provided", async () => { // Arrange const filePath = path.join(process.cwd(), "test-file.txt"); const fileSecurityService = new FileSecurityService(); // No paths provided uses CWD as default try { // Act await fileSecurityService.secureWriteFile(filePath, TEST_CONTENT); // Assert const fileContent = await fs.readFile(filePath, "utf8"); expect(fileContent).toBe(TEST_CONTENT); } finally { // Cleanup the file created in CWD try { await fs.unlink(filePath); } catch (err) { // Ignore error if file doesn't exist } } }); it("should correctly handle path normalization and resolution", async () => { // Arrange const complexPath = path.join( ALLOWED_DIR, ".", "subdir", "..", "normalized-file.txt" ); const allowedPaths = [ALLOWED_DIR]; const fileSecurityService = new FileSecurityService(allowedPaths); // Act await fileSecurityService.secureWriteFile(complexPath, TEST_CONTENT); // Assert - check the file exists at the normalized location const expectedPath = path.join(ALLOWED_DIR, "normalized-file.txt"); const fileContent = await fs.readFile(expectedPath, "utf8"); expect(fileContent).toBe(TEST_CONTENT); }); it("should handle multiple allowed paths", async () => { // Arrange const filePath = path.join(outsideDir, "allowed-outside-file.txt"); const content = "multi-allowed content"; const fileSecurityService = new FileSecurityService([ ALLOWED_DIR, outsideDir, ]); // Act await fileSecurityService.secureWriteFile(filePath, content); // Assert const fileContent = await fs.readFile(filePath, "utf8"); expect(fileContent).toBe(content); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bsmi021/mcp-gemini-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server