zeroSteiner / rule-engine

A lightweight, optionally typed expression language with a custom grammar for matching arbitrary Python objects.
https://zerosteiner.github.io/rule-engine/
BSD 3-Clause "New" or "Revised" License
455 stars 54 forks source link

Rule Help for List in List #51

Closed bp4151 closed 1 year ago

bp4151 commented 1 year ago

Question for @zeroSteiner regarding nested lists. I have the following block of code:

datum = {
        "locations": "",
        "package": {
            "Package": {
                "pm": "npm",
                "group": None,
                "name": "minimist",
                "version": "1.2.0",
                "vendor": None,
                "fixVersions": ["[1.2.6]"],
                "impactPaths": [["npm://covert:1.0.0", "npm://minimist:1.2.0"], ["npm://some_package:1.0.0", "npm://some_dependency:1.2.0"]]
            },
            "Vulnerabilities": [{
                "id": "XRAY-256849",
                "title": "Critical vulnerability found in component temp_react_core",
                "description": "Prototype pollution vulnerability in function parseQuery in parseQuery.js in webpack loader-utils 2.0.0 via the name variable in parseQuery.js.",
                "cvssScore": "9.8",
                "cvssVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
                "cve": "CVE-2022-37601"
            }]
        }
    }

and I am having a time of it trying to create the rule that checks the impact paths at package.Package.impactPaths. I have a scratch file with the following code

complex_list = [["list1_1", "list1_2"], ["list2_1", "list2_2"]]

print('list1_1' in [val for sublist in complex_list for val in sublist])

single_list = [["list1_1", "list1_2"]]

print('list1_1' in [val for sublist in single_list for val in sublist])

Both of those print True, but if I create a rule with the same code

rule_engine.Rule("'some_dependency' in [path for subpath in package.Package.impactPaths for path in subpath]")

I get the following errors:

Traceback (most recent call last):
  File "C:\Program Files (x86)\JetBrains\PyCharm 2022.3.1\plugins\python\helpers\pydev\_pydevd_bundle\pydevd_exec2.py", line 3, in Exec
    exec(exp, global_vars, local_vars)
  File "<input>", line 1, in <module>
  File "C:\Users\bparr\.virtualenvs\cvss-rescore-04yqQuLz\lib\site-packages\rule_engine\engine.py", line 578, in __init__
    self.statement = self.parser.parse(text, context)
  File "C:\Users\bparr\.virtualenvs\cvss-rescore-04yqQuLz\lib\site-packages\rule_engine\parser.py", line 102, in parse
    result = self._parser.parse(text, **kwargs)
  File "C:\Users\bparr\.virtualenvs\cvss-rescore-04yqQuLz\lib\site-packages\ply\yacc.py", line 333, in parse
    return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
  File "C:\Users\bparr\.virtualenvs\cvss-rescore-04yqQuLz\lib\site-packages\ply\yacc.py", line 1201, in parseopt_notrack
    tok = call_errorfunc(self.errorfunc, errtoken, self)
  File "C:\Users\bparr\.virtualenvs\cvss-rescore-04yqQuLz\lib\site-packages\ply\yacc.py", line 192, in call_errorfunc
    r = errorfunc(token)
  File "C:\Users\bparr\.virtualenvs\cvss-rescore-04yqQuLz\lib\site-packages\rule_engine\parser.py", line 287, in p_error
    raise errors.RuleSyntaxError('syntax error', token)
rule_engine.errors.RuleSyntaxError: ('syntax error', LexToken(FOR,'for',1,70))

Any suggestions? Any help is greatly appreciated

zeroSteiner commented 1 year ago

I think you want something like this:

rule > [p for p in package.Package.impactPaths if [x for x in p if 'some_dependency' in x]]
result: 
(('npm://some_package:1.0.0', 'npm://some_dependency:1.2.0'),)

If you wanted the result of the expression, I think you'd have to do it twice:

rule > [[x for x in p if 'some_dependency' in x][0] for p in package.Package.impactPaths if [x for x in p if 'some_dependency' in x]]
result: 
('npm://some_dependency:1.2.0',)

FWIW, I was using the debug REPL to figure this out.

bp4151 commented 1 year ago

Thank you for the rapid response @zeroSteiner. I got around it temporarily by simply flattening the impact paths in my source data and changing the rules to go after the flattenedImpactPath instead. Definitely saving your approach for future updates.