1818 */
1919package org .dependencytrack .policy .cel ;
2020
21- import alpine .common .logging .Logger ;
2221import com .google .api .expr .v1alpha1 .Expr ;
2322import com .google .api .expr .v1alpha1 .Type ;
2423import org .apache .commons .collections4 .MultiValuedMap ;
2524import org .apache .commons .collections4 .multimap .HashSetValuedHashMap ;
2625
27- import java .util .ArrayDeque ;
28- import java .util .Deque ;
2926import java .util .HashSet ;
3027import java .util .List ;
3128import java .util .Map ;
3229import java .util .Set ;
3330
34- class CelPolicyScriptVisitor {
35-
36- private static final Logger LOGGER = Logger .getLogger (CelPolicyScriptVisitor .class );
31+ final class CelPolicyScriptVisitor {
3732
3833 record FunctionSignature (String function , Type targetType , List <Type > argumentTypes ) {
3934 }
4035
41- private final Map <Long , Type > types ;
36+ private final Map <Long , Type > typeByExpressionId ;
4237 private final MultiValuedMap <Type , String > accessedFieldsByType ;
4338 private final Set <FunctionSignature > usedFunctionSignatures ;
44- private final Deque <String > callFunctionStack ;
45- private final Deque <String > selectFieldStack ;
46- private final Deque <Type > selectOperandTypeStack ;
4739
48- CelPolicyScriptVisitor (final Map <Long , Type > types ) {
49- this .types = types ;
40+ CelPolicyScriptVisitor (Map <Long , Type > typeByExpressionId ) {
41+ this .typeByExpressionId = typeByExpressionId ;
5042 this .accessedFieldsByType = new HashSetValuedHashMap <>();
5143 this .usedFunctionSignatures = new HashSet <>();
52- this .callFunctionStack = new ArrayDeque <>();
53- this .selectFieldStack = new ArrayDeque <>();
54- this .selectOperandTypeStack = new ArrayDeque <>();
5544 }
5645
57- void visit (final Expr expr ) {
46+ void visit (Expr expr ) {
5847 switch (expr .getExprKindCase ()) {
5948 case CALL_EXPR -> visitCall (expr );
6049 case COMPREHENSION_EXPR -> visitComprehension (expr );
61- case CONST_EXPR -> visitConst (expr );
62- case IDENT_EXPR -> visitIdent (expr );
6350 case LIST_EXPR -> visitList (expr );
6451 case SELECT_EXPR -> visitSelect (expr );
6552 case STRUCT_EXPR -> visitStruct (expr );
66- case EXPRKIND_NOT_SET -> LOGGER .debug ("Unknown expression: %s" .formatted (expr ));
53+ case CONST_EXPR , EXPRKIND_NOT_SET , IDENT_EXPR -> {
54+ }
6755 }
6856 }
6957
70- private void visitCall (final Expr expr ) {
71- logExpr (expr );
58+ private void visitCall (Expr expr ) {
7259 final Expr .Call callExpr = expr .getCallExpr ();
7360
74- final Type targetType = types .get (callExpr .getTarget ().getId ());
61+ final Type targetType = typeByExpressionId .get (callExpr .getTarget ().getId ());
7562 final List <Type > argumentTypes = callExpr .getArgsList ().stream ()
7663 .map (Expr ::getId )
77- .map (types ::get )
64+ .map (typeByExpressionId ::get )
7865 .toList ();
7966 usedFunctionSignatures .add (new FunctionSignature (callExpr .getFunction (), targetType , argumentTypes ));
8067
81- callFunctionStack .push (callExpr .getFunction ());
8268 visit (callExpr .getTarget ());
83- for (final Expr argExpr : callExpr .getArgsList ()) {
84- visit (argExpr );
85- }
86- callFunctionStack .pop ();
69+ callExpr .getArgsList ().forEach (this ::visit );
8770 }
8871
89- private void visitComprehension (final Expr expr ) {
90- logExpr (expr );
72+ private void visitComprehension (Expr expr ) {
9173 final Expr .Comprehension comprehensionExpr = expr .getComprehensionExpr ();
9274
9375 visit (comprehensionExpr .getAccuInit ());
@@ -97,40 +79,26 @@ private void visitComprehension(final Expr expr) {
9779 visit (comprehensionExpr .getResult ());
9880 }
9981
100- private void visitConst (final Expr expr ) {
101- logExpr (expr );
102- }
103-
104- private void visitIdent (final Expr expr ) {
105- logExpr (expr );
106- selectOperandTypeStack .push (types .get (expr .getId ()));
107- }
108-
109- private void visitList (final Expr expr ) {
110- logExpr (expr );
82+ private void visitList (Expr expr ) {
83+ expr .getListExpr ().getElementsList ().forEach (this ::visit );
11184 }
11285
113- private void visitSelect (final Expr expr ) {
114- logExpr (expr );
86+ private void visitSelect (Expr expr ) {
11587 final Expr .Select selectExpr = expr .getSelectExpr ();
116-
117- selectFieldStack .push (selectExpr .getField ());
118- selectOperandTypeStack .push (types .get (expr .getId ()));
88+ final Type operandType = typeByExpressionId .get (selectExpr .getOperand ().getId ());
89+ if (operandType != null ) {
90+ accessedFieldsByType .put (operandType , selectExpr .getField ());
91+ }
11992 visit (selectExpr .getOperand ());
120- accessedFieldsByType .put (selectOperandTypeStack .pop (), selectFieldStack .pop ());
121- }
122-
123- private void visitStruct (final Expr expr ) {
124- logExpr (expr );
12593 }
12694
127- private void logExpr ( final Expr expr ) {
128- if (! LOGGER . isDebugEnabled ()) {
129- return ;
130- }
131-
132- LOGGER . debug ( "Visiting %s (id=%d, fieldStack=%s, fieldTypeStack=%s, functionStack=%s)"
133- . formatted ( expr . getExprKindCase (), expr . getId (), selectFieldStack , selectOperandTypeStack , callFunctionStack ) );
95+ private void visitStruct ( Expr expr ) {
96+ expr . getStructExpr (). getEntriesList (). forEach ( entry -> {
97+ if ( entry . hasMapKey ()) {
98+ visit ( entry . getMapKey ());
99+ }
100+ visit ( entry . getValue ());
101+ } );
134102 }
135103
136104 MultiValuedMap <Type , String > getAccessedFieldsByType () {
0 commit comments