@@ -607,3 +607,164 @@ func TestAuditLogErrorCapture(t *testing.T) {
607607 assert .Equal (t , http .StatusBadRequest , entry .StatusCode )
608608 })
609609}
610+
611+ func TestAuditLogOnlyModelInteractions (t * testing.T ) {
612+ t .Run ("logs model endpoints when OnlyModelInteractions enabled" , func (t * testing.T ) {
613+ store := newMockLogStore ()
614+ cfg := auditlog.Config {
615+ Enabled : true ,
616+ LogBodies : false ,
617+ LogHeaders : false ,
618+ BufferSize : 100 ,
619+ FlushInterval : 100 * time .Millisecond ,
620+ OnlyModelInteractions : true ,
621+ }
622+
623+ serverURL , srv , logger := setupAuditLogTestServer (t , cfg , store )
624+ defer func () {
625+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
626+ defer cancel ()
627+ _ = srv .Shutdown (ctx )
628+ _ = logger .Close ()
629+ }()
630+
631+ // Make a request to a model endpoint
632+ payload := core.ChatRequest {
633+ Model : "gpt-4" ,
634+ Messages : []core.Message {{Role : "user" , Content : "Hello" }},
635+ }
636+ body , _ := json .Marshal (payload )
637+ resp , err := http .Post (serverURL + "/v1/chat/completions" , "application/json" , bytes .NewReader (body ))
638+ require .NoError (t , err )
639+ defer closeBody (resp )
640+ require .Equal (t , http .StatusOK , resp .StatusCode )
641+
642+ // Wait for log entry to be written
643+ entries := store .WaitForEntries (1 , 2 * time .Second )
644+ require .Len (t , entries , 1 , "Expected 1 log entry for model endpoint" )
645+
646+ entry := entries [0 ]
647+ assert .Equal (t , "/v1/chat/completions" , entry .Data .Path )
648+ })
649+
650+ t .Run ("skips health endpoint when OnlyModelInteractions enabled" , func (t * testing.T ) {
651+ store := newMockLogStore ()
652+ cfg := auditlog.Config {
653+ Enabled : true ,
654+ LogBodies : false ,
655+ LogHeaders : false ,
656+ BufferSize : 100 ,
657+ FlushInterval : 100 * time .Millisecond ,
658+ OnlyModelInteractions : true ,
659+ }
660+
661+ serverURL , srv , logger := setupAuditLogTestServer (t , cfg , store )
662+ defer func () {
663+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
664+ defer cancel ()
665+ _ = srv .Shutdown (ctx )
666+ _ = logger .Close ()
667+ }()
668+
669+ // Make multiple requests to health endpoint
670+ for i := 0 ; i < 3 ; i ++ {
671+ resp , err := http .Get (serverURL + "/health" )
672+ require .NoError (t , err )
673+ closeBody (resp )
674+ }
675+
676+ // Wait a bit and check that NO entries were logged
677+ time .Sleep (500 * time .Millisecond )
678+ entries := store .GetEntries ()
679+ assert .Empty (t , entries , "Expected no log entries for health endpoint when OnlyModelInteractions=true" )
680+ })
681+
682+ t .Run ("logs health endpoint when OnlyModelInteractions disabled" , func (t * testing.T ) {
683+ store := newMockLogStore ()
684+ cfg := auditlog.Config {
685+ Enabled : true ,
686+ LogBodies : false ,
687+ LogHeaders : false ,
688+ BufferSize : 100 ,
689+ FlushInterval : 100 * time .Millisecond ,
690+ OnlyModelInteractions : false ,
691+ }
692+
693+ serverURL , srv , logger := setupAuditLogTestServer (t , cfg , store )
694+ defer func () {
695+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
696+ defer cancel ()
697+ _ = srv .Shutdown (ctx )
698+ _ = logger .Close ()
699+ }()
700+
701+ // Note: setupAuditLogTestServer makes health check calls during startup
702+ // so we may already have entries. Count before making our request.
703+ time .Sleep (200 * time .Millisecond ) // Wait for any buffered entries to flush
704+ entriesBefore := len (store .GetEntries ())
705+
706+ // Make requests to health endpoint
707+ resp , err := http .Get (serverURL + "/health" )
708+ require .NoError (t , err )
709+ closeBody (resp )
710+
711+ // Wait for log entry to be written (at least 1 more than before)
712+ entries := store .WaitForEntries (entriesBefore + 1 , 2 * time .Second )
713+ require .Greater (t , len (entries ), entriesBefore , "Expected new log entry for health endpoint when OnlyModelInteractions=false" )
714+
715+ // The last entry should be our health request
716+ lastEntry := entries [len (entries )- 1 ]
717+ assert .Equal (t , "/health" , lastEntry .Data .Path )
718+ })
719+
720+ t .Run ("filters mixed requests correctly" , func (t * testing.T ) {
721+ store := newMockLogStore ()
722+ cfg := auditlog.Config {
723+ Enabled : true ,
724+ LogBodies : false ,
725+ LogHeaders : false ,
726+ BufferSize : 100 ,
727+ FlushInterval : 100 * time .Millisecond ,
728+ OnlyModelInteractions : true ,
729+ }
730+
731+ serverURL , srv , logger := setupAuditLogTestServer (t , cfg , store )
732+ defer func () {
733+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
734+ defer cancel ()
735+ _ = srv .Shutdown (ctx )
736+ _ = logger .Close ()
737+ }()
738+
739+ // Make multiple health requests (should not be logged)
740+ for i := 0 ; i < 5 ; i ++ {
741+ resp , err := http .Get (serverURL + "/health" )
742+ require .NoError (t , err )
743+ closeBody (resp )
744+ }
745+
746+ // Make a model request (should be logged)
747+ payload := core.ChatRequest {
748+ Model : "gpt-4" ,
749+ Messages : []core.Message {{Role : "user" , Content : "Hello" }},
750+ }
751+ body , _ := json .Marshal (payload )
752+ resp , err := http .Post (serverURL + "/v1/chat/completions" , "application/json" , bytes .NewReader (body ))
753+ require .NoError (t , err )
754+ closeBody (resp )
755+
756+ // Make more health requests (should not be logged)
757+ for i := 0 ; i < 3 ; i ++ {
758+ resp , err := http .Get (serverURL + "/health" )
759+ require .NoError (t , err )
760+ closeBody (resp )
761+ }
762+
763+ // Wait for log entry to be written
764+ entries := store .WaitForEntries (1 , 2 * time .Second )
765+
766+ // Should only have the model endpoint logged
767+ require .Len (t , entries , 1 , "Expected only 1 log entry (model endpoint)" )
768+ assert .Equal (t , "/v1/chat/completions" , entries [0 ].Data .Path )
769+ })
770+ }
0 commit comments