@@ -381,267 +381,3 @@ describe('Integration Tests', () => {
381381 } ) ;
382382} ) ;
383383
384- // === SECURITY TESTS ===
385- describe ( 'Security Tests' , ( ) => {
386- describe ( 'Path Traversal Protection' , ( ) => {
387- test ( 'should reject path traversal attempts - relative paths' , ( ) => {
388- const maliciousInputs = [
389- '{"transcript_path":"../../../etc/passwd"}' ,
390- '{"transcript_path":"../../.ssh/id_rsa"}' ,
391- '{"transcript_path":"../../../home/user/.bashrc"}' ,
392- '{"transcript_path":"../../../../windows/system32/config/sam"}'
393- ] ;
394-
395- maliciousInputs . forEach ( input => {
396- const result = getTranscriptPathAndModel ( input ) ;
397- // Should either reject or sanitize the path
398- assert . notEqual ( result . transcriptPath , '../../../etc/passwd' ) ;
399- assert . notEqual ( result . transcriptPath , '../../.ssh/id_rsa' ) ;
400- assert . notEqual ( result . transcriptPath , '../../../home/user/.bashrc' ) ;
401- assert . notEqual ( result . transcriptPath , '../../../../windows/system32/config/sam' ) ;
402- } ) ;
403- } ) ;
404-
405- test ( 'should reject null byte injection attempts' , ( ) => {
406- const maliciousInputs = [
407- '{"transcript_path":"valid.jsonl\\u0000../../../etc/passwd"}' ,
408- '{"transcript_path":"test\\x00/../passwd"}' ,
409- '{"transcript_path":"file.jsonl\\0\\0../secret"}'
410- ] ;
411-
412- maliciousInputs . forEach ( input => {
413- const result = getTranscriptPathAndModel ( input ) ;
414- // Should not contain null bytes in the path
415- assert . ok ( ! result . transcriptPath . includes ( '\0' ) ) ;
416- assert . ok ( ! result . transcriptPath . includes ( '\\u0000' ) ) ;
417- assert . ok ( ! result . transcriptPath . includes ( '\\x00' ) ) ;
418- } ) ;
419- } ) ;
420-
421- test ( 'should handle absolute path attempts safely' , ( ) => {
422- const maliciousInputs = [
423- '{"transcript_path":"/etc/passwd"}' ,
424- '{"transcript_path":"/root/.ssh/authorized_keys"}' ,
425- '{"transcript_path":"C:\\\\Windows\\\\System32\\\\config\\\\SAM"}' ,
426- '{"transcript_path":"/proc/version"}'
427- ] ;
428-
429- maliciousInputs . forEach ( input => {
430- const result = getTranscriptPathAndModel ( input ) ;
431- // Should either reject absolute paths or handle them safely
432- // The function should not blindly accept any absolute path
433- assert . ok ( typeof result . transcriptPath === 'string' ) ;
434- } ) ;
435- } ) ;
436- } ) ;
437-
438- describe ( 'Input Validation Security' , ( ) => {
439- test ( 'should handle extremely large JSON inputs safely' , ( ) => {
440- // Test with very large input that could cause DoS
441- const largeString = 'x' . repeat ( 100000 ) ;
442- const largeInput = `{"transcript_path":"${ largeString } "}` ;
443-
444- const startMemory = process . memoryUsage ( ) . heapUsed ;
445- const result = getTranscriptPathAndModel ( largeInput ) ;
446- const endMemory = process . memoryUsage ( ) . heapUsed ;
447-
448- // Should not consume excessive memory (>50MB growth)
449- const memoryGrowth = endMemory - startMemory ;
450- assert . ok ( memoryGrowth < 50 * 1024 * 1024 , `Memory growth too high: ${ memoryGrowth } bytes` ) ;
451-
452- // Should still return a valid result
453- assert . ok ( typeof result . transcriptPath === 'string' ) ;
454- } ) ;
455-
456- test ( 'should handle malformed Unicode safely' , ( ) => {
457- const malformedInputs = [
458- '{"transcript_path":"\\uD800"}' , // Lone high surrogate
459- '{"transcript_path":"\\uDFFF"}' , // Lone low surrogate
460- '{"transcript_path":"\\uD800\\uD800"}' , // Double high surrogate
461- '{"transcript_path":"test\\uD834file.jsonl"}' // Invalid surrogate in middle
462- ] ;
463-
464- malformedInputs . forEach ( input => {
465- const result = getTranscriptPathAndModel ( input ) ;
466- // Should handle malformed Unicode gracefully
467- assert . ok ( typeof result . transcriptPath === 'string' ) ;
468- assert . ok ( result . transcriptPath !== undefined ) ;
469- } ) ;
470- } ) ;
471-
472- test ( 'should reject deeply nested JSON objects' , ( ) => {
473- // Create deeply nested object to test for stack overflow
474- let deepObject = '{"transcript_path":"test.jsonl"' ;
475- for ( let i = 0 ; i < 1000 ; i ++ ) {
476- deepObject += `,"nested":{"level":${ i } ` ;
477- }
478- for ( let i = 0 ; i < 1000 ; i ++ ) {
479- deepObject += '}' ;
480- }
481- deepObject += '}' ;
482-
483- // Should not crash or cause stack overflow
484- const result = getTranscriptPathAndModel ( deepObject ) ;
485- assert . ok ( typeof result . transcriptPath === 'string' ) ;
486- } ) ;
487-
488- test ( 'should handle invalid JSON gracefully without exposing errors' , ( ) => {
489- const invalidInputs = [
490- '{invalid json}' ,
491- '{"unclosed": "string' ,
492- 'null' ,
493- 'undefined' ,
494- '{"transcript_path":}' ,
495- '{"transcript_path":null}' ,
496- '{"transcript_path":123}' ,
497- '{"transcript_path":[]}' ,
498- '{"transcript_path":{}}'
499- ] ;
500-
501- invalidInputs . forEach ( input => {
502- const result = getTranscriptPathAndModel ( input ) ;
503- // Should return safe fallback values
504- assert . ok ( typeof result . transcriptPath === 'string' ) ;
505- assert . ok ( typeof result . modelName === 'string' ) ;
506- // Should not throw or expose internal error details
507- } ) ;
508- } ) ;
509- } ) ;
510-
511- describe ( 'Token Processing Security' , ( ) => {
512- test ( 'should handle invalid token values safely' , ( ) => {
513- const maliciousTokenData = [
514- // String tokens (should be numbers)
515- '{"message":{"usage":{"input_tokens":"malicious_string"}}}' ,
516- '{"message":{"usage":{"input_tokens":"999999999999999999999"}}}' ,
517-
518- // Null/undefined tokens
519- '{"message":{"usage":{"input_tokens":null}}}' ,
520- '{"message":{"usage":{"input_tokens":undefined}}}' ,
521-
522- // Negative tokens
523- '{"message":{"usage":{"input_tokens":-999999}}}' ,
524-
525- // Float overflow attempts
526- '{"message":{"usage":{"input_tokens":1.7976931348623157e+308}}}' ,
527-
528- // NaN and Infinity
529- '{"message":{"usage":{"input_tokens":NaN}}}' ,
530- '{"message":{"usage":{"input_tokens":Infinity}}}'
531- ] ;
532-
533- maliciousTokenData . forEach ( line => {
534- const tokens = getTotalTokens ( [ line ] ) ;
535- // Should return valid number or 0, never NaN or Infinity
536- assert . ok ( typeof tokens === 'number' ) ;
537- assert . ok ( isFinite ( tokens ) ) ;
538- assert . ok ( ! isNaN ( tokens ) ) ;
539- assert . ok ( tokens >= 0 ) ; // Should not return negative values
540- } ) ;
541- } ) ;
542-
543- test ( 'should prevent integer overflow in token calculations' , ( ) => {
544- const maxSafeInteger = Number . MAX_SAFE_INTEGER ;
545- const overflowData = [
546- `{"message":{"usage":{"input_tokens":${ maxSafeInteger } }}}` ,
547- `{"message":{"usage":{"input_tokens":${ maxSafeInteger } ,"cache_read_input_tokens":1000}}}` ,
548- '{"message":{"usage":{"input_tokens":999999999999999999999999999999}}}'
549- ] ;
550-
551- overflowData . forEach ( line => {
552- const tokens = getTotalTokens ( [ line ] ) ;
553- // Should handle overflow gracefully
554- assert . ok ( typeof tokens === 'number' ) ;
555- assert . ok ( isFinite ( tokens ) ) ;
556- assert . ok ( tokens >= 0 ) ;
557- } ) ;
558- } ) ;
559- } ) ;
560-
561- describe ( 'Resource Consumption Limits' , ( ) => {
562- test ( 'should handle very long JSONL files efficiently' , ( ) => {
563- // Create a large dataset
564- const largeDataset = [ ] ;
565- for ( let i = 0 ; i < 50000 ; i ++ ) {
566- largeDataset . push ( `{"message":{"usage":{"input_tokens":${ i % 1000 } }}}` ) ;
567- }
568-
569- const startTime = performance . now ( ) ;
570- const startMemory = process . memoryUsage ( ) . heapUsed ;
571-
572- const tokens = getTotalTokens ( largeDataset ) ;
573-
574- const endTime = performance . now ( ) ;
575- const endMemory = process . memoryUsage ( ) . heapUsed ;
576-
577- // Should complete in reasonable time (<5 seconds)
578- const processingTime = endTime - startTime ;
579- assert . ok ( processingTime < 5000 , `Processing took too long: ${ processingTime } ms` ) ;
580-
581- // Should not consume excessive memory
582- const memoryGrowth = endMemory - startMemory ;
583- assert . ok ( memoryGrowth < 100 * 1024 * 1024 , `Memory usage too high: ${ memoryGrowth } bytes` ) ;
584-
585- // Should return valid result
586- assert . ok ( typeof tokens === 'number' ) ;
587- assert . ok ( tokens >= 0 ) ;
588- } ) ;
589-
590- test ( 'should handle rapid repeated processing without memory leaks' , ( ) => {
591- const testData = [ '{"message":{"usage":{"input_tokens":1000}}}' ] ;
592- const initialMemory = process . memoryUsage ( ) . heapUsed ;
593-
594- // Process the same data many times
595- for ( let i = 0 ; i < 10000 ; i ++ ) {
596- getTotalTokens ( testData ) ;
597- }
598-
599- // Force garbage collection if available
600- if ( global . gc ) {
601- global . gc ( ) ;
602- }
603-
604- const finalMemory = process . memoryUsage ( ) . heapUsed ;
605- const memoryGrowth = finalMemory - initialMemory ;
606-
607- // Should not have significant memory growth (>10MB indicates leak)
608- assert . ok ( memoryGrowth < 10 * 1024 * 1024 , `Potential memory leak: ${ memoryGrowth } bytes growth` ) ;
609- } ) ;
610- } ) ;
611-
612- describe ( 'Integration Security' , ( ) => {
613- test ( 'should not expose sensitive information in error outputs' , ( ) => {
614- const sensitiveInputs = [
615- '{"transcript_path":"/etc/shadow","secret":"password123"}' ,
616- '{"transcript_path":"config.json","api_key":"sk-1234567890abcdef"}' ,
617- '{"transcript_path":"test.jsonl","aws_secret":"AKIAIOSFODNN7EXAMPLE"}'
618- ] ;
619-
620- sensitiveInputs . forEach ( input => {
621- const result = getTranscriptPathAndModel ( input ) ;
622- // Result should not contain the sensitive fields
623- const resultStr = JSON . stringify ( result ) ;
624- assert . ok ( ! resultStr . includes ( 'password123' ) ) ;
625- assert . ok ( ! resultStr . includes ( 'sk-1234567890abcdef' ) ) ;
626- assert . ok ( ! resultStr . includes ( 'AKIAIOSFODNN7EXAMPLE' ) ) ;
627- } ) ;
628- } ) ;
629-
630- test ( 'should handle concurrent processing safely' , async ( ) => {
631- const testData = [ '{"message":{"usage":{"input_tokens":1000}}}' ] ;
632-
633- // Create multiple concurrent processing tasks
634- const promises = [ ] ;
635- for ( let i = 0 ; i < 100 ; i ++ ) {
636- promises . push ( Promise . resolve ( getTotalTokens ( testData ) ) ) ;
637- }
638-
639- const results = await Promise . all ( promises ) ;
640-
641- // All results should be consistent
642- results . forEach ( result => {
643- assert . strictEqual ( result , 1000 ) ;
644- } ) ;
645- } ) ;
646- } ) ;
647- } ) ;
0 commit comments