GT AI OS Community v2.0.33 - Add NVIDIA NIM and Nemotron agents

- Updated python_coding_microproject.csv to use NVIDIA NIM Kimi K2
- Updated kali_linux_shell_simulator.csv to use NVIDIA NIM Kimi K2
  - Made more general-purpose (flexible targets, expanded tools)
- Added nemotron-mini-agent.csv for fast local inference via Ollama
- Added nemotron-agent.csv for advanced reasoning via Ollama
- Added wiki page: Projects for NVIDIA NIMs and Nemotron
This commit is contained in:
HackWeasel
2025-12-12 17:47:14 -05:00
commit 310491a557
750 changed files with 232701 additions and 0 deletions

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,212 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Unit tests for authentication utilities
*/
const auth_1 = require("../auth");
describe('Authentication Utilities', () => {
describe('Capability Hash Functions', () => {
const testCapabilities = [
{
resource: 'tenant:test:*',
actions: ['read', 'write'],
constraints: {}
}
];
test('generateCapabilityHash creates consistent hash', () => {
const hash1 = (0, auth_1.generateCapabilityHash)(testCapabilities);
const hash2 = (0, auth_1.generateCapabilityHash)(testCapabilities);
expect(hash1).toBe(hash2);
expect(typeof hash1).toBe('string');
expect(hash1.length).toBeGreaterThan(0);
});
test('verifyCapabilityHash validates correct hash', () => {
const hash = (0, auth_1.generateCapabilityHash)(testCapabilities);
const isValid = (0, auth_1.verifyCapabilityHash)(testCapabilities, hash);
expect(isValid).toBe(true);
});
test('verifyCapabilityHash rejects incorrect hash', () => {
const isValid = (0, auth_1.verifyCapabilityHash)(testCapabilities, 'incorrect-hash');
expect(isValid).toBe(false);
});
test('capability hash changes with different capabilities', () => {
const capabilities1 = [
{ resource: 'tenant:test1:*', actions: ['read'], constraints: {} }
];
const capabilities2 = [
{ resource: 'tenant:test2:*', actions: ['write'], constraints: {} }
];
const hash1 = (0, auth_1.generateCapabilityHash)(capabilities1);
const hash2 = (0, auth_1.generateCapabilityHash)(capabilities2);
expect(hash1).not.toBe(hash2);
});
});
describe('JWT Functions', () => {
const testPayload = {
sub: 'test@example.com',
tenant_id: '123',
user_type: 'tenant_user',
capabilities: [
{
resource: 'tenant:test:*',
actions: ['read', 'write'],
constraints: {}
}
]
};
test('createJWT generates valid token', () => {
const token = (0, auth_1.createJWT)(testPayload);
expect(typeof token).toBe('string');
expect(token.split('.')).toHaveLength(3); // JWT has 3 parts
});
test('verifyJWT validates correct token', () => {
const token = (0, auth_1.createJWT)(testPayload);
const decoded = (0, auth_1.verifyJWT)(token);
expect(decoded).toBeTruthy();
expect(decoded?.sub).toBe(testPayload.sub);
expect(decoded?.tenant_id).toBe(testPayload.tenant_id);
expect(decoded?.user_type).toBe(testPayload.user_type);
});
test('verifyJWT rejects invalid token', () => {
const decoded = (0, auth_1.verifyJWT)('invalid.token.here');
expect(decoded).toBeNull();
});
test('verifyJWT rejects tampered token', () => {
const token = (0, auth_1.createJWT)(testPayload);
const tamperedToken = token.slice(0, -10) + 'tampered123';
const decoded = (0, auth_1.verifyJWT)(tamperedToken);
expect(decoded).toBeNull();
});
test('isTokenExpired detects expired tokens', () => {
const expiredPayload = {
...testPayload,
exp: Math.floor(Date.now() / 1000) - 3600, // 1 hour ago
iat: Math.floor(Date.now() / 1000) - 7200 // 2 hours ago
};
expect((0, auth_1.isTokenExpired)(expiredPayload)).toBe(true);
});
test('isTokenExpired allows valid tokens', () => {
const validPayload = {
...testPayload,
exp: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
iat: Math.floor(Date.now() / 1000) // Now
};
expect((0, auth_1.isTokenExpired)(validPayload)).toBe(false);
});
});
describe('Capability Authorization', () => {
const userCapabilities = [
{
resource: 'tenant:acme:*',
actions: ['read', 'write'],
constraints: {}
},
{
resource: 'ai_resource:*',
actions: ['use'],
constraints: {
usage_limits: {
max_requests_per_hour: 100
}
}
}
];
test('hasCapability grants access for exact match', () => {
const hasAccess = (0, auth_1.hasCapability)(userCapabilities, 'tenant:acme:conversations', 'read');
expect(hasAccess).toBe(true);
});
test('hasCapability grants access for wildcard match', () => {
const hasAccess = (0, auth_1.hasCapability)(userCapabilities, 'ai_resource:groq', 'use');
expect(hasAccess).toBe(true);
});
test('hasCapability denies access for unauthorized resource', () => {
const hasAccess = (0, auth_1.hasCapability)(userCapabilities, 'tenant:other:*', 'read');
expect(hasAccess).toBe(false);
});
test('hasCapability denies access for unauthorized action', () => {
const hasAccess = (0, auth_1.hasCapability)(userCapabilities, 'tenant:acme:*', 'admin');
expect(hasAccess).toBe(false);
});
test('hasCapability respects time constraints', () => {
const expiredCapabilities = [
{
resource: 'tenant:test:*',
actions: ['read'],
constraints: {
valid_until: new Date(Date.now() - 3600000).toISOString() // 1 hour ago
}
}
];
const hasAccess = (0, auth_1.hasCapability)(expiredCapabilities, 'tenant:test:*', 'read');
expect(hasAccess).toBe(false);
});
});
describe('Password Functions', () => {
const testPassword = 'TestPassword123!';
test('hashPassword creates valid hash', async () => {
const hash = await (0, auth_1.hashPassword)(testPassword);
expect(typeof hash).toBe('string');
expect(hash).not.toBe(testPassword);
expect(hash.startsWith('$2b$')).toBe(true); // bcrypt hash format
});
test('verifyPassword validates correct password', async () => {
const hash = await (0, auth_1.hashPassword)(testPassword);
const isValid = await (0, auth_1.verifyPassword)(testPassword, hash);
expect(isValid).toBe(true);
});
test('verifyPassword rejects incorrect password', async () => {
const hash = await (0, auth_1.hashPassword)(testPassword);
const isValid = await (0, auth_1.verifyPassword)('WrongPassword', hash);
expect(isValid).toBe(false);
});
test('different passwords create different hashes', async () => {
const hash1 = await (0, auth_1.hashPassword)('Password1');
const hash2 = await (0, auth_1.hashPassword)('Password2');
expect(hash1).not.toBe(hash2);
});
});
describe('Utility Functions', () => {
test('generateSecureToken creates token of correct length', () => {
const token = (0, auth_1.generateSecureToken)(16);
expect(typeof token).toBe('string');
expect(token.length).toBe(32); // Hex encoding doubles the length
});
test('generateSecureToken creates different tokens', () => {
const token1 = (0, auth_1.generateSecureToken)();
const token2 = (0, auth_1.generateSecureToken)();
expect(token1).not.toBe(token2);
});
test('extractBearerToken extracts token correctly', () => {
const token = (0, auth_1.extractBearerToken)('Bearer abc123token');
expect(token).toBe('abc123token');
});
test('extractBearerToken returns null for invalid format', () => {
expect((0, auth_1.extractBearerToken)('Invalid format')).toBeNull();
expect((0, auth_1.extractBearerToken)('Bearer')).toBeNull();
expect((0, auth_1.extractBearerToken)('')).toBeNull();
expect((0, auth_1.extractBearerToken)(undefined)).toBeNull();
});
});
describe('Capability Template Functions', () => {
test('createTenantCapabilities for admin user', () => {
const capabilities = (0, auth_1.createTenantCapabilities)('acme', 'tenant_admin');
expect(capabilities).toHaveLength(2);
expect(capabilities[0].resource).toBe('tenant:acme:*');
expect(capabilities[0].actions).toContain('admin');
expect(capabilities[1].resource).toBe('ai_resource:*');
});
test('createTenantCapabilities for regular user', () => {
const capabilities = (0, auth_1.createTenantCapabilities)('acme', 'tenant_user');
expect(capabilities).toHaveLength(3);
expect(capabilities[0].resource).toBe('tenant:acme:conversations');
expect(capabilities[0].actions).not.toContain('admin');
expect(capabilities[1].resource).toBe('tenant:acme:documents');
});
test('createSuperAdminCapabilities grants full access', () => {
const capabilities = (0, auth_1.createSuperAdminCapabilities)();
expect(capabilities).toHaveLength(1);
expect(capabilities[0].resource).toBe('*');
expect(capabilities[0].actions).toEqual(['*']);
});
});
});

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,204 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Unit tests for cryptographic utilities
*/
const crypto_1 = require("../crypto");
describe('Cryptographic Utilities', () => {
describe('Key Generation', () => {
test('generateEncryptionKey creates valid key', () => {
const key = (0, crypto_1.generateEncryptionKey)();
expect(typeof key).toBe('string');
expect(key.length).toBe(64); // 32 bytes * 2 for hex encoding
expect(/^[a-f0-9]+$/i.test(key)).toBe(true); // Valid hex string
});
test('generateEncryptionKey creates different keys', () => {
const key1 = (0, crypto_1.generateEncryptionKey)();
const key2 = (0, crypto_1.generateEncryptionKey)();
expect(key1).not.toBe(key2);
});
});
describe('Encryption/Decryption', () => {
const testData = 'This is test data to encrypt';
const testKey = 'a'.repeat(64); // 32-byte key in hex
test('encrypt returns encrypted data with IV and tag', () => {
const result = (0, crypto_1.encrypt)(testData, testKey);
expect(result).toHaveProperty('encrypted');
expect(result).toHaveProperty('iv');
expect(result).toHaveProperty('tag');
expect(typeof result.encrypted).toBe('string');
expect(typeof result.iv).toBe('string');
expect(typeof result.tag).toBe('string');
expect(result.encrypted).not.toBe(testData);
});
test('decrypt successfully recovers original data', () => {
const { encrypted, iv, tag } = (0, crypto_1.encrypt)(testData, testKey);
const decrypted = (0, crypto_1.decrypt)(encrypted, testKey, iv, tag);
expect(decrypted).toBe(testData);
});
test('decrypt fails with wrong key', () => {
const { encrypted, iv, tag } = (0, crypto_1.encrypt)(testData, testKey);
const wrongKey = 'b'.repeat(64);
expect(() => {
(0, crypto_1.decrypt)(encrypted, wrongKey, iv, tag);
}).toThrow();
});
test('decrypt fails with tampered data', () => {
const { encrypted, iv, tag } = (0, crypto_1.encrypt)(testData, testKey);
const tamperedData = encrypted.slice(0, -2) + 'XX';
expect(() => {
(0, crypto_1.decrypt)(tamperedData, testKey, iv, tag);
}).toThrow();
});
test('encryption produces different results for same data', () => {
const result1 = (0, crypto_1.encrypt)(testData, testKey);
const result2 = (0, crypto_1.encrypt)(testData, testKey);
// Different IVs should produce different encrypted data
expect(result1.encrypted).not.toBe(result2.encrypted);
expect(result1.iv).not.toBe(result2.iv);
// But both should decrypt to same original data
const decrypted1 = (0, crypto_1.decrypt)(result1.encrypted, testKey, result1.iv, result1.tag);
const decrypted2 = (0, crypto_1.decrypt)(result2.encrypted, testKey, result2.iv, result2.tag);
expect(decrypted1).toBe(testData);
expect(decrypted2).toBe(testData);
});
});
describe('Hashing', () => {
test('sha256Hash creates consistent hash', () => {
const data = 'test data';
const hash1 = (0, crypto_1.sha256Hash)(data);
const hash2 = (0, crypto_1.sha256Hash)(data);
expect(hash1).toBe(hash2);
expect(typeof hash1).toBe('string');
expect(hash1.length).toBe(64); // SHA-256 produces 32 bytes = 64 hex chars
});
test('sha256Hash creates different hashes for different data', () => {
const hash1 = (0, crypto_1.sha256Hash)('data 1');
const hash2 = (0, crypto_1.sha256Hash)('data 2');
expect(hash1).not.toBe(hash2);
});
});
describe('HMAC', () => {
const testData = 'test data';
const testSecret = 'test secret';
test('generateHMAC creates valid signature', () => {
const signature = (0, crypto_1.generateHMAC)(testData, testSecret);
expect(typeof signature).toBe('string');
expect(signature.length).toBe(64); // HMAC-SHA256 = 64 hex chars
expect(/^[a-f0-9]+$/i.test(signature)).toBe(true);
});
test('verifyHMAC validates correct signature', () => {
const signature = (0, crypto_1.generateHMAC)(testData, testSecret);
const isValid = (0, crypto_1.verifyHMAC)(testData, signature, testSecret);
expect(isValid).toBe(true);
});
test('verifyHMAC rejects incorrect signature', () => {
const signature = (0, crypto_1.generateHMAC)(testData, testSecret);
const isValid = (0, crypto_1.verifyHMAC)(testData, signature + 'tampered', testSecret);
expect(isValid).toBe(false);
});
test('verifyHMAC rejects signature with wrong secret', () => {
const signature = (0, crypto_1.generateHMAC)(testData, testSecret);
const isValid = (0, crypto_1.verifyHMAC)(testData, signature, 'wrong secret');
expect(isValid).toBe(false);
});
test('HMAC is consistent for same inputs', () => {
const signature1 = (0, crypto_1.generateHMAC)(testData, testSecret);
const signature2 = (0, crypto_1.generateHMAC)(testData, testSecret);
expect(signature1).toBe(signature2);
});
});
describe('Key Derivation', () => {
const masterKey = 'a'.repeat(64); // 32-byte master key
const tenantId = 'tenant-123';
test('deriveTenantKey creates consistent key for tenant', () => {
const key1 = (0, crypto_1.deriveTenantKey)(masterKey, tenantId);
const key2 = (0, crypto_1.deriveTenantKey)(masterKey, tenantId);
expect(key1).toBe(key2);
expect(typeof key1).toBe('string');
expect(key1.length).toBe(64); // 32 bytes in hex
});
test('deriveTenantKey creates different keys for different tenants', () => {
const key1 = (0, crypto_1.deriveTenantKey)(masterKey, 'tenant-1');
const key2 = (0, crypto_1.deriveTenantKey)(masterKey, 'tenant-2');
expect(key1).not.toBe(key2);
});
test('deriveTenantKey creates different keys for different master keys', () => {
const masterKey2 = 'b'.repeat(64);
const key1 = (0, crypto_1.deriveTenantKey)(masterKey, tenantId);
const key2 = (0, crypto_1.deriveTenantKey)(masterKey2, tenantId);
expect(key1).not.toBe(key2);
});
});
describe('Database Encryption', () => {
const testData = { id: 1, name: 'test', data: [1, 2, 3] };
const testKey = 'a'.repeat(64);
test('encryptForDatabase encrypts JSON data', () => {
const encrypted = (0, crypto_1.encryptForDatabase)(testData, testKey);
expect(typeof encrypted).toBe('string');
expect(encrypted.split(':')).toHaveLength(3); // iv:tag:encrypted format
expect(encrypted).not.toContain('test'); // Should not contain original data
});
test('decryptFromDatabase recovers original JSON data', () => {
const encrypted = (0, crypto_1.encryptForDatabase)(testData, testKey);
const decrypted = (0, crypto_1.decryptFromDatabase)(encrypted, testKey);
expect(decrypted).toEqual(testData);
});
test('decryptFromDatabase fails with wrong key', () => {
const encrypted = (0, crypto_1.encryptForDatabase)(testData, testKey);
const wrongKey = 'b'.repeat(64);
expect(() => {
(0, crypto_1.decryptFromDatabase)(encrypted, wrongKey);
}).toThrow();
});
test('decryptFromDatabase fails with invalid format', () => {
expect(() => {
(0, crypto_1.decryptFromDatabase)('invalid-format', testKey);
}).toThrow('Invalid encrypted data format');
});
test('database encryption handles complex objects', () => {
const complexData = {
user: { id: 1, name: 'John Doe' },
preferences: { theme: 'dark', lang: 'en' },
timestamps: { created: new Date().toISOString() },
numbers: [1, 2.5, -3],
boolean: true,
null_value: null
};
const encrypted = (0, crypto_1.encryptForDatabase)(complexData, testKey);
const decrypted = (0, crypto_1.decryptFromDatabase)(encrypted, testKey);
expect(decrypted).toEqual(complexData);
});
});
describe('Password Generation', () => {
test('generateSecurePassword creates password of correct length', () => {
const password = (0, crypto_1.generateSecurePassword)(16);
expect(typeof password).toBe('string');
expect(password.length).toBe(16);
});
test('generateSecurePassword uses default length', () => {
const password = (0, crypto_1.generateSecurePassword)();
expect(password.length).toBe(16); // Default length
});
test('generateSecurePassword creates different passwords', () => {
const password1 = (0, crypto_1.generateSecurePassword)();
const password2 = (0, crypto_1.generateSecurePassword)();
expect(password1).not.toBe(password2);
});
test('generateSecurePassword includes variety of characters', () => {
const password = (0, crypto_1.generateSecurePassword)(50); // Longer for better test
expect(/[a-z]/.test(password)).toBe(true); // Lowercase
expect(/[A-Z]/.test(password)).toBe(true); // Uppercase
expect(/[0-9]/.test(password)).toBe(true); // Numbers
expect(/[!@#$%^&*]/.test(password)).toBe(true); // Special chars
});
test('generateSecurePassword creates strong passwords', () => {
// Test multiple passwords to ensure consistency
for (let i = 0; i < 10; i++) {
const password = (0, crypto_1.generateSecurePassword)(12);
expect(password.length).toBe(12);
expect(/[a-zA-Z0-9!@#$%^&*]/.test(password)).toBe(true);
}
});
});
});

View File

@@ -0,0 +1,3 @@
/**
* Test setup for utility functions
*/

20
packages/utils/dist/__tests__/setup.js vendored Normal file
View File

@@ -0,0 +1,20 @@
"use strict";
/**
* Test setup for utility functions
*/
// Mock environment variables for testing
process.env.JWT_SECRET = 'test-jwt-secret-for-testing-only';
process.env.MASTER_ENCRYPTION_KEY = 'test-master-key-32-bytes-long-test';
// Mock crypto for consistent testing
jest.mock('crypto', () => {
const originalCrypto = jest.requireActual('crypto');
return {
...originalCrypto,
randomBytes: jest.fn().mockImplementation((size) => {
return Buffer.alloc(size, 'a'); // Return consistent fake random bytes
}),
randomInt: jest.fn().mockReturnValue(5), // Return consistent fake random int
};
});
// Global test timeout
jest.setTimeout(10000);

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,279 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Unit tests for validation utilities
*/
const validation_1 = require("../validation");
describe('Validation Utilities', () => {
describe('Email Validation', () => {
test('validates correct email formats', () => {
const validEmails = [
'test@example.com',
'user.name@domain.co.uk',
'user+tag@example.org',
'user123@sub.domain.com'
];
validEmails.forEach(email => {
expect((0, validation_1.isValidEmail)(email)).toBe(true);
});
});
test('rejects invalid email formats', () => {
const invalidEmails = [
'invalid-email',
'@domain.com',
'user@',
'user@domain',
'user space@domain.com',
'',
'user@@domain.com'
];
invalidEmails.forEach(email => {
expect((0, validation_1.isValidEmail)(email)).toBe(false);
});
});
});
describe('Domain Validation', () => {
test('validates correct domain formats', () => {
const validDomains = [
'acme',
'test-company',
'company123',
'a1b2c3',
'long-domain-name-with-dashes'
];
validDomains.forEach(domain => {
expect((0, validation_1.isValidDomain)(domain)).toBe(true);
});
});
test('rejects invalid domain formats', () => {
const invalidDomains = [
'AB', // Too short
'a', // Too short
'domain-', // Ends with dash
'-domain', // Starts with dash
'domain.com', // Contains dot
'domain_name', // Contains underscore
'UPPERCASE', // Contains uppercase
'domain with spaces', // Contains spaces
'a'.repeat(51), // Too long
'' // Empty
];
invalidDomains.forEach(domain => {
expect((0, validation_1.isValidDomain)(domain)).toBe(false);
});
});
});
describe('Password Validation', () => {
test('validates strong passwords', () => {
const strongPasswords = [
'StrongPass123!',
'MySecure#Password1',
'Complex$Password99'
];
strongPasswords.forEach(password => {
const result = (0, validation_1.isValidPassword)(password);
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
});
test('rejects weak passwords with specific errors', () => {
const weakPasswords = [
{ password: 'short', expectedErrors: 5 }, // All criteria failed
{ password: 'toolongbutnothing', expectedErrors: 4 }, // No upper, digit, special
{ password: 'NoNumbers!', expectedErrors: 1 }, // No numbers
{ password: 'nonumbers123', expectedErrors: 2 }, // No upper, special
{ password: 'NOLOWER123!', expectedErrors: 1 }, // No lower
];
weakPasswords.forEach(({ password, expectedErrors }) => {
const result = (0, validation_1.isValidPassword)(password);
expect(result.valid).toBe(false);
expect(result.errors.length).toBeGreaterThanOrEqual(1);
});
});
});
describe('Tenant Create Request Validation', () => {
const validTenantRequest = {
name: 'Test Company',
domain: 'test-company',
template: 'basic',
max_users: 50,
resource_limits: {
cpu: '1000m',
memory: '2Gi',
storage: '10Gi'
}
};
test('validates correct tenant request', () => {
const result = (0, validation_1.validateTenantCreateRequest)(validTenantRequest);
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
test('rejects request with missing name', () => {
const request = { ...validTenantRequest, name: '' };
const result = (0, validation_1.validateTenantCreateRequest)(request);
expect(result.valid).toBe(false);
expect(result.errors).toContain('Tenant name is required');
});
test('rejects request with invalid domain', () => {
const request = { ...validTenantRequest, domain: 'invalid_domain' };
const result = (0, validation_1.validateTenantCreateRequest)(request);
expect(result.valid).toBe(false);
expect(result.errors[0]).toContain('Domain must be');
});
test('rejects request with invalid template', () => {
const request = { ...validTenantRequest, template: 'invalid' };
const result = (0, validation_1.validateTenantCreateRequest)(request);
expect(result.valid).toBe(false);
expect(result.errors[0]).toContain('Template must be one of');
});
test('rejects request with invalid max_users', () => {
const request = { ...validTenantRequest, max_users: -1 };
const result = (0, validation_1.validateTenantCreateRequest)(request);
expect(result.valid).toBe(false);
expect(result.errors[0]).toContain('Max users must be between');
});
test('validates resource limits format', () => {
const invalidRequests = [
{ ...validTenantRequest, resource_limits: { cpu: 'invalid' } },
{ ...validTenantRequest, resource_limits: { memory: '2Tb' } }, // Invalid unit
{ ...validTenantRequest, resource_limits: { storage: '10' } } // Missing unit
];
invalidRequests.forEach(request => {
const result = (0, validation_1.validateTenantCreateRequest)(request);
expect(result.valid).toBe(false);
expect(result.errors.length).toBeGreaterThan(0);
});
});
});
describe('Chat Request Validation', () => {
const validChatRequest = {
message: 'Hello, how can I help you?',
conversation_id: 1,
model_id: 'gpt-4',
system_prompt: 'You are a helpful assistant.',
context_sources: ['doc1', 'doc2']
};
test('validates correct chat request', () => {
const result = (0, validation_1.validateChatRequest)(validChatRequest);
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
test('rejects request with empty message', () => {
const request = { ...validChatRequest, message: '' };
const result = (0, validation_1.validateChatRequest)(request);
expect(result.valid).toBe(false);
expect(result.errors).toContain('Message is required');
});
test('rejects request with too long message', () => {
const request = { ...validChatRequest, message: 'a'.repeat(10001) };
const result = (0, validation_1.validateChatRequest)(request);
expect(result.valid).toBe(false);
expect(result.errors[0]).toContain('10000 characters or less');
});
test('rejects request with invalid conversation_id', () => {
const request = { ...validChatRequest, conversation_id: 0 };
const result = (0, validation_1.validateChatRequest)(request);
expect(result.valid).toBe(false);
expect(result.errors).toContain('Invalid conversation ID');
});
test('rejects request with too long system_prompt', () => {
const request = { ...validChatRequest, system_prompt: 'a'.repeat(2001) };
const result = (0, validation_1.validateChatRequest)(request);
expect(result.valid).toBe(false);
expect(result.errors[0]).toContain('2000 characters or less');
});
});
describe('Document Upload Validation', () => {
const createMockFile = (size, type, name) => ({
file: Buffer.alloc(size),
filename: name,
file_type: type
});
test('validates correct document upload', () => {
const upload = createMockFile(1000, 'text/plain', 'test.txt');
const result = (0, validation_1.validateDocumentUpload)(upload);
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
test('rejects upload with empty filename', () => {
const upload = createMockFile(1000, 'text/plain', '');
const result = (0, validation_1.validateDocumentUpload)(upload);
expect(result.valid).toBe(false);
expect(result.errors).toContain('Filename is required');
});
test('rejects upload with unsupported file type', () => {
const upload = createMockFile(1000, 'image/jpeg', 'image.jpg');
const result = (0, validation_1.validateDocumentUpload)(upload);
expect(result.valid).toBe(false);
expect(result.errors[0]).toContain('not supported');
});
test('rejects upload with file too large', () => {
const upload = createMockFile(51 * 1024 * 1024, 'text/plain', 'large.txt');
const result = (0, validation_1.validateDocumentUpload)(upload);
expect(result.valid).toBe(false);
expect(result.errors).toContain('File size must be 50MB or less');
});
test('validates supported file types', () => {
const supportedTypes = [
'text/plain',
'text/markdown',
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'text/csv'
];
supportedTypes.forEach(type => {
const upload = createMockFile(1000, type, 'test.file');
const result = (0, validation_1.validateDocumentUpload)(upload);
expect(result.valid).toBe(true);
});
});
});
describe('Utility Validations', () => {
test('sanitizeString removes dangerous content', () => {
const dangerous = '<script>alert("xss")</script><p onclick="alert()">Click me</p>';
const sanitized = (0, validation_1.sanitizeString)(dangerous);
expect(sanitized).not.toContain('<script>');
expect(sanitized).not.toContain('onclick');
expect(sanitized).not.toContain('javascript:');
});
test('isValidUUID validates correct UUIDs', () => {
const validUUIDs = [
'123e4567-e89b-12d3-a456-426614174000',
'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
'6ba7b810-9dad-11d1-80b4-00c04fd430c8'
];
validUUIDs.forEach(uuid => {
expect((0, validation_1.isValidUUID)(uuid)).toBe(true);
});
});
test('isValidUUID rejects invalid UUIDs', () => {
const invalidUUIDs = [
'not-a-uuid',
'123e4567-e89b-12d3-a456', // Too short
'123e4567-e89b-12d3-a456-426614174000-extra', // Too long
'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', // Invalid characters
''
];
invalidUUIDs.forEach(uuid => {
expect((0, validation_1.isValidUUID)(uuid)).toBe(false);
});
});
test('validatePagination normalizes and validates parameters', () => {
// Test valid parameters
const result1 = (0, validation_1.validatePagination)(2, 50);
expect(result1.page).toBe(2);
expect(result1.limit).toBe(50);
expect(result1.errors).toHaveLength(0);
// Test defaults
const result2 = (0, validation_1.validatePagination)();
expect(result2.page).toBe(1);
expect(result2.limit).toBe(20);
// Test invalid parameters
const result3 = (0, validation_1.validatePagination)(-1, 150);
expect(result3.page).toBe(1); // Corrected
expect(result3.limit).toBe(100); // Corrected to max
expect(result3.errors.length).toBeGreaterThan(0);
});
});
});