@@ -66,7 +66,22 @@ abstract class ControlCheck extends AstNode {
6666 // The check is effective against the event and category
6767 this .protectsCategoryAndEvent ( category , event .getName ( ) ) and
6868 // The check can be triggered by the event
69- this .getATriggerEvent ( ) = event
69+ this .getATriggerEvent ( ) = event and
70+ // For reusable workflows, ALL callers for this event must be protected by SOME check
71+ (
72+ not node .getEnclosingWorkflow ( ) instanceof ReusableWorkflow
73+ or
74+ forall ( ExternalJob directCaller |
75+ directCaller = node .getEnclosingWorkflow ( ) .( ReusableWorkflow ) .getACaller ( ) and
76+ directCaller .getATriggerEvent ( ) = event
77+ |
78+ exists ( ControlCheck check |
79+ check .protectsCategoryAndEvent ( category , event .getName ( ) ) and
80+ check .getATriggerEvent ( ) = event and
81+ check .dominatesViaCaller ( node , event , directCaller )
82+ )
83+ )
84+ )
7085 }
7186
7287 /**
@@ -103,35 +118,36 @@ abstract class ControlCheck extends AstNode {
103118 node .getEnclosingJob ( ) .getANeededJob ( ) .( LocalJob ) .getAStep ( ) = this
104119 )
105120 or
106- // When the node is inside a (possibly nested) reusable workflow,
107- // all direct callers for this event must be protected along their caller chain.
108- exists ( ExternalJob directCaller |
109- directCaller = node .getEnclosingWorkflow ( ) .( ReusableWorkflow ) .getACaller ( ) and
110- directCaller .getATriggerEvent ( ) = event
111- ) and
112- forall ( ExternalJob directCaller |
113- directCaller = node .getEnclosingWorkflow ( ) .( ReusableWorkflow ) .getACaller ( ) and
114- directCaller .getATriggerEvent ( ) = event
115- |
116- exists ( ExternalJob caller |
117- caller = getAnOuterCaller * ( directCaller ) and
121+ // When the node is inside a reusable workflow,
122+ // this check dominates via at least one caller chain.
123+ this .dominatesViaCaller ( node , event , _)
124+ }
125+
126+ /**
127+ * Holds if this control check dominates `node` in a reusable workflow
128+ * via the caller chain starting at `directCaller`.
129+ */
130+ predicate dominatesViaCaller ( AstNode node , Event event , ExternalJob directCaller ) {
131+ directCaller = node .getEnclosingWorkflow ( ) .( ReusableWorkflow ) .getACaller ( ) and
132+ directCaller .getATriggerEvent ( ) = event and
133+ exists ( ExternalJob caller |
134+ caller = getAnOuterCaller * ( directCaller ) and
135+ (
136+ this instanceof If and
137+ (
138+ caller .getIf ( ) = this or
139+ caller .getANeededJob ( ) .( LocalJob ) .getIf ( ) = this or
140+ caller .getANeededJob ( ) .( LocalJob ) .getAStep ( ) .getIf ( ) = this
141+ )
142+ or
143+ this instanceof Environment and
118144 (
119- this instanceof If and
120- (
121- caller .getIf ( ) = this or
122- caller .getANeededJob ( ) .( LocalJob ) .getIf ( ) = this or
123- caller .getANeededJob ( ) .( LocalJob ) .getAStep ( ) .getIf ( ) = this
124- )
125- or
126- this instanceof Environment and
127- (
128- caller .getEnvironment ( ) = this or
129- caller .getANeededJob ( ) .getEnvironment ( ) = this
130- )
131- or
132- ( this instanceof Run or this instanceof UsesStep ) and
133- caller .getANeededJob ( ) .( LocalJob ) .getAStep ( ) = this
145+ caller .getEnvironment ( ) = this or
146+ caller .getANeededJob ( ) .getEnvironment ( ) = this
134147 )
148+ or
149+ ( this instanceof Run or this instanceof UsesStep ) and
150+ caller .getANeededJob ( ) .( LocalJob ) .getAStep ( ) = this
135151 )
136152 )
137153 }
0 commit comments