@@ -169,6 +169,7 @@ describe('TaskIntegrationsController', () => {
169169 complete : jest . fn ( ) ,
170170 addResults : jest . fn ( ) ,
171171 findLatestPerConnectionAndCheckByTask : jest . fn ( ) ,
172+ countExceptedFailures : jest . fn ( ) ,
172173 } ;
173174 const mockCredentialVaultService = { getDecryptedCredentials : jest . fn ( ) } ;
174175 const mockOAuthCredentialsService = {
@@ -229,6 +230,9 @@ describe('TaskIntegrationsController', () => {
229230 ) ;
230231 mockCheckRunRepository . complete . mockResolvedValue ( { } ) ;
231232 mockCheckRunRepository . addResults . mockResolvedValue ( { } ) ;
233+ // Default: nothing excepted (no count query needed). Exception tests
234+ // override this to the exact excepted-failure count for the run.
235+ mockCheckRunRepository . countExceptedFailures . mockResolvedValue ( 0 ) ;
232236 mockCredentialVaultService . getDecryptedCredentials . mockResolvedValue (
233237 VALID_CREDS ,
234238 ) ;
@@ -564,13 +568,23 @@ describe('TaskIntegrationsController', () => {
564568 resourceId : 'reports-bucket' ,
565569 } ,
566570 ] ) ;
571+ // The excepted-failure count is now computed via a targeted query (the
572+ // full result set is no longer loaded). reports-bucket is the one
573+ // excepted failing result for this run.
574+ mockCheckRunRepository . countExceptedFailures . mockResolvedValue ( 1 ) ;
567575
568576 const { runs } = await controller . getTaskCheckRuns ( 'task_1' , 'org_1' ) ;
569577
570578 expect ( runs [ 0 ] . failedCount ) . toBe ( 0 ) ;
571579 expect ( runs [ 0 ] . exceptedCount ) . toBe ( 1 ) ;
572580 expect ( runs [ 0 ] . status ) . toBe ( 'success' ) ;
573581 expect ( runs [ 0 ] . results [ 0 ] . excepted ) . toBe ( true ) ;
582+ // Exact count is computed via the targeted query, scoped to this run's
583+ // excepted resourceIds (not by loading + filtering every result).
584+ expect ( mockCheckRunRepository . countExceptedFailures ) . toHaveBeenCalledWith (
585+ 'icr_1' ,
586+ [ 'reports-bucket' ] ,
587+ ) ;
574588 } ) ;
575589
576590 it ( 'keeps an execution-error run as failed (no findings, not excepted)' , async ( ) => {
@@ -621,5 +635,108 @@ describe('TaskIntegrationsController', () => {
621635 mockCheckRunRepository . findLatestPerConnectionAndCheckByTask ,
622636 ) . not . toHaveBeenCalled ( ) ;
623637 } ) ;
638+
639+ it ( 'bounds a run with a huge result set + logs so the payload stays small (CS-588)' , async ( ) => {
640+ // Defense-in-depth response cap: even if a run somehow carries a large
641+ // result/log set, the serialized response is bounded (results per
642+ // category, evidence size, log count) while the run's summary counts stay
643+ // accurate. The PRIMARY fix — never LOADING all result rows from the DB —
644+ // lives in CheckRunRepository.findLatestPerConnectionAndCheckByTask and is
645+ // covered in check-run.repository.spec.ts.
646+ const HUGE = 5000 ;
647+ const results = [
648+ // First finding carries an oversized evidence blob.
649+ {
650+ id : 'icx_finding_0' ,
651+ passed : false ,
652+ resourceType : 'firebase-user' ,
653+ resourceId : 'user_0' ,
654+ title : 'finding 0' ,
655+ description : 'd' ,
656+ severity : 'high' ,
657+ remediation : 'fix' ,
658+ evidence : { blob : 'x' . repeat ( 30_000 ) } ,
659+ collectedAt : new Date ( ) ,
660+ } ,
661+ ...Array . from ( { length : HUGE - 1 } , ( _ , i ) => ( {
662+ id : `icx_finding_${ i + 1 } ` ,
663+ passed : false ,
664+ resourceType : 'firebase-user' ,
665+ resourceId : `user_f_${ i + 1 } ` ,
666+ title : 'finding' ,
667+ description : 'd' ,
668+ severity : 'high' ,
669+ remediation : 'fix' ,
670+ evidence : { ok : true } ,
671+ collectedAt : new Date ( ) ,
672+ } ) ) ,
673+ ...Array . from ( { length : HUGE } , ( _ , i ) => ( {
674+ id : `icx_pass_${ i } ` ,
675+ passed : true ,
676+ resourceType : 'firebase-user' ,
677+ resourceId : `user_p_${ i } ` ,
678+ title : 'passing' ,
679+ description : 'd' ,
680+ evidence : { ok : true } ,
681+ collectedAt : new Date ( ) ,
682+ } ) ) ,
683+ ] ;
684+ const logs = Array . from ( { length : HUGE } , ( _ , i ) => ( {
685+ level : 'info' ,
686+ message : `log ${ i } ` ,
687+ timestamp : new Date ( ) . toISOString ( ) ,
688+ } ) ) ;
689+
690+ mockCheckRunRepository . findLatestPerConnectionAndCheckByTask . mockResolvedValue (
691+ [
692+ {
693+ id : 'icr_huge' ,
694+ checkId : 'firebase-employee-access' ,
695+ checkName : 'Employee Access' ,
696+ status : 'failed' ,
697+ startedAt : new Date ( ) ,
698+ completedAt : new Date ( ) ,
699+ durationMs : 10 ,
700+ totalChecked : HUGE * 2 ,
701+ passedCount : HUGE ,
702+ failedCount : HUGE ,
703+ errorMessage : null ,
704+ logs,
705+ connectionId : 'conn_1' ,
706+ createdAt : new Date ( ) ,
707+ results,
708+ connection : {
709+ id : 'conn_1' ,
710+ metadata : { connectionName : 'Firebase' } ,
711+ provider : { slug : 'firebase' , name : 'Firebase' } ,
712+ } ,
713+ } ,
714+ ] ,
715+ ) ;
716+
717+ const { runs } = await controller . getTaskCheckRuns ( 'task_1' , 'org_1' ) ;
718+
719+ // Result detail is bounded (a few findings + a few passing), NOT 10000.
720+ expect ( runs [ 0 ] . results . length ) . toBeLessThanOrEqual ( 15 ) ;
721+ expect ( runs [ 0 ] . results . length ) . toBeLessThan ( results . length ) ;
722+ // Logs are bounded too.
723+ expect ( Array . isArray ( runs [ 0 ] . logs ) ) . toBe ( true ) ;
724+ if ( Array . isArray ( runs [ 0 ] . logs ) ) {
725+ expect ( runs [ 0 ] . logs . length ) . toBeLessThanOrEqual ( 100 ) ;
726+ }
727+ // Summary counts remain authoritative (computed from the full set).
728+ expect ( runs [ 0 ] . passedCount ) . toBe ( HUGE ) ;
729+ expect ( runs [ 0 ] . failedCount ) . toBe ( HUGE ) ;
730+ expect ( runs [ 0 ] . exceptedCount ) . toBe ( 0 ) ;
731+ // The oversized evidence blob is replaced with a compact placeholder.
732+ const shippedFinding = runs [ 0 ] . results . find (
733+ ( r ) => r . id === 'icx_finding_0' ,
734+ ) ;
735+ expect ( shippedFinding ) . toBeDefined ( ) ;
736+ expect ( shippedFinding ?. evidence ) . toMatchObject ( { truncated : true } ) ;
737+ // Normal small evidence is left intact.
738+ const shippedPass = runs [ 0 ] . results . find ( ( r ) => r . passed ) ;
739+ expect ( shippedPass ?. evidence ) . toEqual ( { ok : true } ) ;
740+ } ) ;
624741 } ) ;
625742} ) ;
0 commit comments