in scripts/compare_pysa_models_to_json.py [0:0]
def get_models_from_pysa_file(path: str) -> Dict[str, TargetModel]:
"""
Process a .pysa file with models in the form of:
def foo.bar(x: TaintSource[A], b) -> TaintSink[B]: ...
and return a dictionary of callables and their models in the form:
{
'parameters': {'x': {'sources': {'A', ...}, 'sinks': ... }, ...},
'return_model': {'sources': {}, 'sinks': {'B'}, 'tito': {}}
}
IMPORTANT: Note that this only works on .pysa files where:
1. All the models are self-contained on a single line.
2. Models do not contain ViaTag[...], AppliesTo[...] syntax
This script was originally intended to compare models that were generated
by the existing Python model generators, so it should be noted that
this will likely not work with most user-defined .pysa files.
"""
pysa_models: Dict[str, TargetModel] = defaultdict(make_default_target_model)
skipped = 0
with Path(path).open() as pysa_file:
for line in pysa_file:
# This is a quick hack/heuristic to skip lines with no models in them
# since regex matching can be more costly.
if "[" not in line:
skipped += 1
continue
if "def " in line:
result = get_callable_model_from_line(line)
else:
result = get_attribute_model_from_line(line)
if result:
name, model = result
for parameter in model["parameters"]:
for model_type in model["parameters"][parameter]:
# pyre-fixme[26]: TypedDict key must be a string literal.
pysa_models[name]["parameters"][parameter][model_type].update(
# pyre-fixme[26]: TypedDict key must be a string literal.
model["parameters"][parameter][model_type]
)
pysa_models[name]["parameters"].update(model["parameters"])
for model_type in model["return_model"]:
# pyre-fixme[26]: TypedDict key must be a string literal.
pysa_models[name]["return_model"][model_type].update(
# pyre-fixme[26]: TypedDict key must be a string literal.
model["return_model"][model_type]
)
else:
skipped += 1
LOG.warning(f"Skipped {skipped} lines in .pysa (no models found or were invalid).")
return pysa_models