@@ -200,6 +200,40 @@ function modifyResponseForOneRule(rule, responseHolder, mergeTagValues) {
200200 return responseHolder ;
201201}
202202
203+ // Internal helper to compute applicable rules based only on cohort membership and applied_to.
204+ // Logic (ignoring regex):
205+ // - If entity (user/company) is in rule cohort and rule.applied_to !== 'not_matching' -> include.
206+ // - If entity NOT in rule cohort and rule.applied_to === 'not_matching' -> include.
207+ function getApplicableRulesByCohortOnly ( configRuleValues , rulesHashByRuleId , logger ) {
208+ const rulesEntityInCohortHash = { } ;
209+ const applicable = [ ] ;
210+
211+ if ( Array . isArray ( configRuleValues ) && configRuleValues . length > 0 ) {
212+ configRuleValues . forEach ( function ( entry ) {
213+ const ruleId = entry . rules ;
214+ rulesEntityInCohortHash [ ruleId ] = true ;
215+ const rule = rulesHashByRuleId [ ruleId ] ;
216+ if ( ! rule ) {
217+ if ( logger ) logger ( 'rule not found for rule id from config: ' + ruleId + '. It could be deleted.' ) ;
218+ return ;
219+ }
220+ if ( rule . applied_to === 'not_matching' ) {
221+ // entity is in cohort; rule applies only to those NOT in cohort -> skip
222+ return ;
223+ }
224+ applicable . push ( rule ) ;
225+ } ) ;
226+ }
227+
228+ Object . values ( rulesHashByRuleId ) . forEach ( function ( rule ) {
229+ if ( rule . applied_to === 'not_matching' && ! rulesEntityInCohortHash [ rule . _id ] ) {
230+ applicable . push ( rule ) ;
231+ }
232+ } ) ;
233+
234+ return applicable ;
235+ }
236+
203237/**
204238 *
205239 * @type Class
@@ -352,66 +386,16 @@ GovernanceRulesManager.prototype._getApplicableUserRules = function (
352386 requestBody ,
353387 requestHeaders
354388) {
355- const self = this ;
356-
357- const applicableRules = [ ] ;
358- const rulesThatUserIsInCohortHash = { } ;
359-
360- const userRulesHashByRuleId = this . userRulesHashByRuleId ;
361-
362- // handle if user is in cohort.
363- // if user is in a rule's cohort, the data is from config_rule_rules_values
364- if ( Array . isArray ( configUserRulesValues ) && configUserRulesValues . length > 0 ) {
365- configUserRulesValues . forEach ( function ( entry ) {
366- const ruleId = entry . rules ;
367-
368- // cache the fact current user is in the cohort of this rule.
369- rulesThatUserIsInCohortHash [ ruleId ] = true ;
370-
371- const foundRule = userRulesHashByRuleId [ ruleId ] ;
372- if ( ! foundRule ) {
373- // skip not found, but shouldn't be the case here.
374- self . log ( 'rule not found for rule id from config' + ruleId ) ;
375- return ;
376- }
377-
378- const regexMatched = doesRegexConfigMatch (
379- foundRule . regex_config ,
380- requestFields ,
381- requestBody ,
382- requestHeaders
383- ) ;
384-
385- if ( ! regexMatched ) {
386- // skipping because regex didn't not match.
387- return ;
388- }
389-
390- if ( foundRule . applied_to === 'not_matching' ) {
391- // skipping because rule is apply to those not in cohort.
392- return ;
393- } else {
394- applicableRules . push ( foundRule ) ;
395- }
396- } ) ;
397- }
398-
399- // handle if rule is not matching and user is not in the cohort.
400- Object . values ( userRulesHashByRuleId ) . forEach ( ( rule ) => {
401- if ( rule . applied_to === 'not_matching' && ! rulesThatUserIsInCohortHash [ rule . _id ] ) {
402- const regexMatched = doesRegexConfigMatch (
403- rule . regex_config ,
404- requestFields ,
405- requestBody ,
406- requestHeaders
407- ) ;
408- if ( regexMatched ) {
409- applicableRules . push ( rule ) ;
410- }
411- }
412- } ) ;
413-
414- return applicableRules ;
389+ // Use cohort-only helper then apply regex filtering identical to original behavior.
390+ const userRulesHashByRuleId = this . userRulesHashByRuleId || { } ;
391+ const cohortCandidates = getApplicableRulesByCohortOnly (
392+ configUserRulesValues ,
393+ userRulesHashByRuleId ,
394+ ( msg ) => this . log ( msg )
395+ ) ;
396+ return cohortCandidates . filter ( ( rule ) =>
397+ doesRegexConfigMatch ( rule . regex_config , requestFields , requestBody , requestHeaders )
398+ ) ;
415399} ;
416400
417401GovernanceRulesManager . prototype . _getApplicableCompanyRules = function (
@@ -420,65 +404,15 @@ GovernanceRulesManager.prototype._getApplicableCompanyRules = function (
420404 requestBody ,
421405 requestHeaders
422406) {
423- const applicableRules = [ ] ;
424- const rulesThatCompanyIsInCohortHash = { } ;
425- const self = this ;
426-
427- const rulesHashByRuleId = this . companyRulesHashByRuleId ;
428-
429- // handle if company is in cohort.
430- // if company is in a rule's cohort, the data is from config_rules_values
431- if ( Array . isArray ( configCompanyRulesValues ) && configCompanyRulesValues . length > 0 ) {
432- configCompanyRulesValues . forEach ( function ( entry ) {
433- const ruleId = entry . rules ;
434-
435- // cache the fact current company is in the cohort of this rule.
436- rulesThatCompanyIsInCohortHash [ ruleId ] = true ;
437-
438- const foundRule = rulesHashByRuleId [ ruleId ] ;
439- if ( ! foundRule ) {
440- // skip not found, but shouldn't be the case here.
441- self . log ( 'rule not found for rule id from config' + ruleId ) ;
442- return ;
443- }
444-
445- const regexMatched = doesRegexConfigMatch (
446- foundRule . regex_config ,
447- requestFields ,
448- requestBody ,
449- requestHeaders
450- ) ;
451-
452- if ( ! regexMatched ) {
453- // skipping because regex didn't not match.
454- return ;
455- }
456-
457- if ( foundRule . applied_to === 'not_matching' ) {
458- // skipping because rule is apply to those not in cohort.
459- return ;
460- } else {
461- applicableRules . push ( foundRule ) ;
462- }
463- } ) ;
464- }
465-
466- // company is not in cohort, and if rule is not matching we apply the rule.
467- Object . values ( rulesHashByRuleId ) . forEach ( ( rule ) => {
468- if ( rule . applied_to === 'not_matching' && ! rulesThatCompanyIsInCohortHash [ rule . _id ] ) {
469- const regexMatched = doesRegexConfigMatch (
470- rule . regex_config ,
471- requestFields ,
472- requestBody ,
473- requestHeaders
474- ) ;
475- if ( regexMatched ) {
476- applicableRules . push ( rule ) ;
477- }
478- }
479- } ) ;
480-
481- return applicableRules ;
407+ const companyRulesHashByRuleId = this . companyRulesHashByRuleId || { } ;
408+ const cohortCandidates = getApplicableRulesByCohortOnly (
409+ configCompanyRulesValues ,
410+ companyRulesHashByRuleId ,
411+ ( msg ) => this . log ( msg )
412+ ) ;
413+ return cohortCandidates . filter ( ( rule ) =>
414+ doesRegexConfigMatch ( rule . regex_config , requestFields , requestBody , requestHeaders )
415+ ) ;
482416} ;
483417
484418GovernanceRulesManager . prototype . applyRuleList = function (
@@ -552,11 +486,10 @@ GovernanceRulesManager.prototype.governInternal = function (
552486 responseHolder = this . applyRuleList ( anonCompanyRules , responseHolder ) ;
553487 } else {
554488 const configCompanyRulesValues = safeGet ( safeGet ( config , 'company_rules' ) , companyId ) ;
555- const idCompanyRules = this . _getApplicableCompanyRules (
556- configCompanyRulesValues ,
557- requestFields ,
558- requestBody ,
559- requestHeaders
489+ // Get cohort-based list using new public helper then filter by regex for current request context.
490+ const companyCohortCandidates = this . getApplicableRulesForCompanyId ( companyId , config ) ;
491+ const idCompanyRules = companyCohortCandidates . filter ( ( rule ) =>
492+ doesRegexConfigMatch ( rule . regex_config , requestFields , requestBody , requestHeaders )
560493 ) ;
561494 responseHolder = this . applyRuleList ( idCompanyRules , responseHolder , configCompanyRulesValues ) ;
562495 }
@@ -570,11 +503,10 @@ GovernanceRulesManager.prototype.governInternal = function (
570503 responseHolder = this . applyRuleList ( anonUserRules , responseHolder ) ;
571504 } else {
572505 const configUserRulesValues = safeGet ( safeGet ( config , 'user_rules' ) , userId ) ;
573- const idUserRules = this . _getApplicableUserRules (
574- configUserRulesValues ,
575- requestFields ,
576- requestBody ,
577- requestHeaders
506+ // Cohort-only then regex filter for current request context.
507+ const userCohortCandidates = this . getApplicableRulesForUserId ( userId , config ) ;
508+ const idUserRules = userCohortCandidates . filter ( ( rule ) =>
509+ doesRegexConfigMatch ( rule . regex_config , requestFields , requestBody , requestHeaders )
578510 ) ;
579511 responseHolder = this . applyRuleList ( idUserRules , responseHolder , configUserRulesValues ) ;
580512 }
@@ -641,4 +573,50 @@ GovernanceRulesManager.prototype.governRequest = function (config, userId, compa
641573 ) ;
642574} ;
643575
576+ /**
577+ * Return all user rules applicable for the given userId based solely on cohort membership
578+ * (config user_rules values) and the rule's applied_to property. Ignores request fields,
579+ * body, headers, and regex matching. Logic:
580+ * - If user is in a rule cohort and rule.applied_to !== 'not_matching' -> include.
581+ * - If user is NOT in a rule cohort and rule.applied_to === 'not_matching' -> include.
582+ * @param {String } userId
583+ * @param {Object } config Full config object containing user_rules hash
584+ * @returns {Array<Object> } array of rule objects applicable to the userId
585+ */
586+ GovernanceRulesManager . prototype . getApplicableRulesForUserId = function ( userId , config ) {
587+ if ( isNil ( userId ) ) {
588+ return [ ] ;
589+ }
590+ const userRulesHashByRuleId = this . userRulesHashByRuleId || { } ;
591+ const configUserRulesValues = safeGet ( safeGet ( config , 'user_rules' ) , userId ) ;
592+ return getApplicableRulesByCohortOnly (
593+ configUserRulesValues ,
594+ userRulesHashByRuleId ,
595+ ( msg ) => this . log ( msg )
596+ ) ;
597+ } ;
598+
599+ /**
600+ * Return all company rules applicable for the given companyId based solely on cohort membership
601+ * (config company_rules values) and the rule's applied_to property. Ignores request fields,
602+ * body, headers, and regex matching. Logic:
603+ * - If company is in a rule cohort and rule.applied_to !== 'not_matching' -> include.
604+ * - If company is NOT in a rule cohort and rule.applied_to === 'not_matching' -> include.
605+ * @param {String } companyId
606+ * @param {Object } config Full config object containing company_rules hash
607+ * @returns {Array<Object> } array of rule objects applicable to the companyId
608+ */
609+ GovernanceRulesManager . prototype . getApplicableRulesForCompanyId = function ( companyId , config ) {
610+ if ( isNil ( companyId ) ) {
611+ return [ ] ;
612+ }
613+ const companyRulesHashByRuleId = this . companyRulesHashByRuleId || { } ;
614+ const configCompanyRulesValues = safeGet ( safeGet ( config , 'company_rules' ) , companyId ) ;
615+ return getApplicableRulesByCohortOnly (
616+ configCompanyRulesValues ,
617+ companyRulesHashByRuleId ,
618+ ( msg ) => this . log ( msg )
619+ ) ;
620+ } ;
621+
644622module . exports = new GovernanceRulesManager ( ) ;
0 commit comments