From 842f871232656688690f5aeec5644175de1e071d Mon Sep 17 00:00:00 2001 From: Samriddhi Singh Date: Mon, 26 Aug 2024 10:41:07 +0530 Subject: [PATCH 1/6] Add support for parameterizing Tirith policies --- src/tirith/core/policy_parameterization.py | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/tirith/core/policy_parameterization.py diff --git a/src/tirith/core/policy_parameterization.py b/src/tirith/core/policy_parameterization.py new file mode 100644 index 0000000..c61d87f --- /dev/null +++ b/src/tirith/core/policy_parameterization.py @@ -0,0 +1,34 @@ +import re + + +def check_match(string: str, pattern: re.Pattern) -> re.Match: + match_ = re.fullmatch(pattern, string) + return match_ + + +# traversing var_dict (esp for nested cases) +def get_var(data: dict, path: str): + keys = path.split(".") + value = data + for key in keys: + value = value[key] + return value + + +def replace_vars(policy_dict: dict, var_dict: dict) -> dict: + var_pattern = re.compile(r"\$\{var::(\w+(\.\w+)*)\}") + + evaluators = policy_dict["evaluators"] # looking into the evaluators only: + + for i in range(len(evaluators)): + for key, value in evaluators[i]["provider_args"].items(): + match = check_match(value, var_pattern) + if bool(match): + evaluators[i]["provider_args"][key] = get_var(var_dict, match.group(1)) + + for key, value in evaluators[i]["condition"].items(): + match = check_match(value, var_pattern) + if bool(match): + evaluators[i]["condition"][key] = get_var(var_dict, match.group(1)) + + return policy_dict From ac871eab15ca90b3d9b85dcd3f3bb60da5bc3be9 Mon Sep 17 00:00:00 2001 From: Samriddhi Singh Date: Wed, 28 Aug 2024 14:29:02 +0530 Subject: [PATCH 2/6] Use pydash.get() and check for match only if the value is of type str --- src/tirith/core/policy_parameterization.py | 24 ++++++++-------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/tirith/core/policy_parameterization.py b/src/tirith/core/policy_parameterization.py index c61d87f..3632523 100644 --- a/src/tirith/core/policy_parameterization.py +++ b/src/tirith/core/policy_parameterization.py @@ -1,4 +1,5 @@ import re +import pydash def check_match(string: str, pattern: re.Pattern) -> re.Match: @@ -6,15 +7,6 @@ def check_match(string: str, pattern: re.Pattern) -> re.Match: return match_ -# traversing var_dict (esp for nested cases) -def get_var(data: dict, path: str): - keys = path.split(".") - value = data - for key in keys: - value = value[key] - return value - - def replace_vars(policy_dict: dict, var_dict: dict) -> dict: var_pattern = re.compile(r"\$\{var::(\w+(\.\w+)*)\}") @@ -22,13 +14,15 @@ def replace_vars(policy_dict: dict, var_dict: dict) -> dict: for i in range(len(evaluators)): for key, value in evaluators[i]["provider_args"].items(): - match = check_match(value, var_pattern) - if bool(match): - evaluators[i]["provider_args"][key] = get_var(var_dict, match.group(1)) + if isinstance(value, str): + match = check_match(value, var_pattern) + if bool(match): + evaluators[i]["provider_args"][key] = pydash.get(var_dict, match.group(1)) for key, value in evaluators[i]["condition"].items(): - match = check_match(value, var_pattern) - if bool(match): - evaluators[i]["condition"][key] = get_var(var_dict, match.group(1)) + if isinstance(value, str): + match = check_match(value, var_pattern) + if bool(match): + evaluators[i]["condition"][key] = pydash.get(var_dict, match.group(1)) return policy_dict From 8ac52e554724da99938bf0a5d3640e2d78e6b75c Mon Sep 17 00:00:00 2001 From: Samriddhi Singh Date: Thu, 29 Aug 2024 23:14:55 +0530 Subject: [PATCH 3/6] Add variable replacement for meta and eval_expression in a policy --- src/tirith/core/policy_parameterization.py | 33 +++++++++++++--------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/tirith/core/policy_parameterization.py b/src/tirith/core/policy_parameterization.py index 3632523..74b7e38 100644 --- a/src/tirith/core/policy_parameterization.py +++ b/src/tirith/core/policy_parameterization.py @@ -7,22 +7,29 @@ def check_match(string: str, pattern: re.Pattern) -> re.Match: return match_ +def helper(dictionary: dict, var_pattern: re.Pattern, var_dict: dict): + for key, value in dictionary.items(): + if isinstance(value, str): + match = check_match(value, var_pattern) + if bool(match): + dictionary[key] = pydash.get(var_dict, match.group(1)) + + def replace_vars(policy_dict: dict, var_dict: dict) -> dict: var_pattern = re.compile(r"\$\{var::(\w+(\.\w+)*)\}") - evaluators = policy_dict["evaluators"] # looking into the evaluators only: - + evaluators = policy_dict["evaluators"] + helper(policy_dict["meta"], var_pattern, var_dict) for i in range(len(evaluators)): - for key, value in evaluators[i]["provider_args"].items(): - if isinstance(value, str): - match = check_match(value, var_pattern) - if bool(match): - evaluators[i]["provider_args"][key] = pydash.get(var_dict, match.group(1)) - - for key, value in evaluators[i]["condition"].items(): - if isinstance(value, str): - match = check_match(value, var_pattern) - if bool(match): - evaluators[i]["condition"][key] = pydash.get(var_dict, match.group(1)) + match = check_match(evaluators[i]["id"], var_pattern) + if bool(match): + evaluators[i]["id"] = pydash.get(var_dict, match.group(1)) + + helper(evaluators[i]["condition"], var_pattern, var_dict) + helper(evaluators[i]["provider_args"], var_pattern, var_dict) + + match = check_match(policy_dict["eval_expression"], var_pattern) + if bool(match): + policy_dict["eval_expression"] = pydash.get(var_dict, match.group(1)) return policy_dict From 791df635780fed5885ad16abc4a814f07277732a Mon Sep 17 00:00:00 2001 From: Samriddhi Singh Date: Sun, 1 Sep 2024 19:22:11 +0530 Subject: [PATCH 4/6] Add unit tests for policy parameterization, change return type for cases where the path was not found, and change syntax of entering the variable names --- src/tirith/core/policy_parameterization.py | 12 +++--- tests/core/test_policy_parameterization.py | 45 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 tests/core/test_policy_parameterization.py diff --git a/src/tirith/core/policy_parameterization.py b/src/tirith/core/policy_parameterization.py index 74b7e38..022251e 100644 --- a/src/tirith/core/policy_parameterization.py +++ b/src/tirith/core/policy_parameterization.py @@ -1,6 +1,8 @@ import re import pydash +class PydashPathNotFound: + pass def check_match(string: str, pattern: re.Pattern) -> re.Match: match_ = re.fullmatch(pattern, string) @@ -12,24 +14,24 @@ def helper(dictionary: dict, var_pattern: re.Pattern, var_dict: dict): if isinstance(value, str): match = check_match(value, var_pattern) if bool(match): - dictionary[key] = pydash.get(var_dict, match.group(1)) + dictionary[key] = pydash.get(var_dict, match.group(1),default=PydashPathNotFound) def replace_vars(policy_dict: dict, var_dict: dict) -> dict: - var_pattern = re.compile(r"\$\{var::(\w+(\.\w+)*)\}") + var_pattern = re.compile(r"{{var\.([\w\.]+)}}") evaluators = policy_dict["evaluators"] helper(policy_dict["meta"], var_pattern, var_dict) for i in range(len(evaluators)): match = check_match(evaluators[i]["id"], var_pattern) if bool(match): - evaluators[i]["id"] = pydash.get(var_dict, match.group(1)) + evaluators[i]["id"] = pydash.get(var_dict, match.group(1),default=PydashPathNotFound) helper(evaluators[i]["condition"], var_pattern, var_dict) helper(evaluators[i]["provider_args"], var_pattern, var_dict) match = check_match(policy_dict["eval_expression"], var_pattern) if bool(match): - policy_dict["eval_expression"] = pydash.get(var_dict, match.group(1)) + policy_dict["eval_expression"] = pydash.get(var_dict, match.group(1),default=PydashPathNotFound) - return policy_dict + return policy_dict \ No newline at end of file diff --git a/tests/core/test_policy_parameterization.py b/tests/core/test_policy_parameterization.py new file mode 100644 index 0000000..2ba1af7 --- /dev/null +++ b/tests/core/test_policy_parameterization.py @@ -0,0 +1,45 @@ +import pytest + +from tirith.core.policy_parameterization import replace_vars, PydashPathNotFound + +@pytest.fixture +def processed_policy(): + var_dict = { + "var_1": {"A": [1, 2, 3, 4, 5, 6]}, + "var_2": "check0", + "providers": {"json": "stackguardian/json", "infracost": "stackguardian/infracost"}, + } + + input_dict = { + "meta": {"version": "", "required_provider": "{{var.providers.json}}"}, + "evaluators": [ + { + "id": "check0", + "provider_args": { + "operation_type": "get_value", + "key_path": "{{var.key_path}}", + }, + "condition": {"type": "Equals", "value": "{{var.var_1.A.1}}"}, + } + ], + "eval_expression": "{{var.var_2}}", + } + + # Run the function once and return the result + return replace_vars(input_dict, var_dict) + + +def test_nested_dict(processed_policy): + assert processed_policy["meta"]["required_provider"] == "stackguardian/json" + + +def test_path_not_found(processed_policy): + assert processed_policy["evaluators"][0]["provider_args"]["key_path"] == PydashPathNotFound + + +def test_var_value_in_list(processed_policy): + assert processed_policy["evaluators"][0]["condition"]["value"] == 2 + + +def test_eval_expression_parameterization(processed_policy): + assert processed_policy["eval_expression"] == "check0" From 56d83f83d3a6aff52634656fef26f1024eeb27d4 Mon Sep 17 00:00:00 2001 From: Samriddhi Singh Date: Sun, 1 Sep 2024 19:32:27 +0530 Subject: [PATCH 5/6] Fix linting --- src/tirith/core/policy_parameterization.py | 10 ++++++---- tests/core/test_policy_parameterization.py | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tirith/core/policy_parameterization.py b/src/tirith/core/policy_parameterization.py index 022251e..df0e52b 100644 --- a/src/tirith/core/policy_parameterization.py +++ b/src/tirith/core/policy_parameterization.py @@ -1,9 +1,11 @@ import re import pydash + class PydashPathNotFound: pass + def check_match(string: str, pattern: re.Pattern) -> re.Match: match_ = re.fullmatch(pattern, string) return match_ @@ -14,7 +16,7 @@ def helper(dictionary: dict, var_pattern: re.Pattern, var_dict: dict): if isinstance(value, str): match = check_match(value, var_pattern) if bool(match): - dictionary[key] = pydash.get(var_dict, match.group(1),default=PydashPathNotFound) + dictionary[key] = pydash.get(var_dict, match.group(1), default=PydashPathNotFound) def replace_vars(policy_dict: dict, var_dict: dict) -> dict: @@ -25,13 +27,13 @@ def replace_vars(policy_dict: dict, var_dict: dict) -> dict: for i in range(len(evaluators)): match = check_match(evaluators[i]["id"], var_pattern) if bool(match): - evaluators[i]["id"] = pydash.get(var_dict, match.group(1),default=PydashPathNotFound) + evaluators[i]["id"] = pydash.get(var_dict, match.group(1), default=PydashPathNotFound) helper(evaluators[i]["condition"], var_pattern, var_dict) helper(evaluators[i]["provider_args"], var_pattern, var_dict) match = check_match(policy_dict["eval_expression"], var_pattern) if bool(match): - policy_dict["eval_expression"] = pydash.get(var_dict, match.group(1),default=PydashPathNotFound) + policy_dict["eval_expression"] = pydash.get(var_dict, match.group(1), default=PydashPathNotFound) - return policy_dict \ No newline at end of file + return policy_dict diff --git a/tests/core/test_policy_parameterization.py b/tests/core/test_policy_parameterization.py index 2ba1af7..02ad907 100644 --- a/tests/core/test_policy_parameterization.py +++ b/tests/core/test_policy_parameterization.py @@ -2,6 +2,7 @@ from tirith.core.policy_parameterization import replace_vars, PydashPathNotFound + @pytest.fixture def processed_policy(): var_dict = { From 485740b8e6c847c486184be7bf29290172e3639e Mon Sep 17 00:00:00 2001 From: Rafid Aslam Date: Tue, 27 Aug 2024 18:30:44 +0700 Subject: [PATCH 6/6] tirith parametrization --- src/tirith/cli.py | 20 ++++- src/tirith/core/core.py | 55 ++++++++++++- src/tirith/core/policy_parameterization.py | 83 ++++++++++++++------ src/tirith/prettyprinter.py | 19 +++-- tests/core/fixtures/input.json | 7 ++ tests/core/fixtures/policy_parametrized.json | 20 +++++ tests/core/test_policy_parameterization.py | 50 +++++++++--- 7 files changed, 209 insertions(+), 45 deletions(-) create mode 100644 tests/core/fixtures/input.json create mode 100644 tests/core/fixtures/policy_parametrized.json diff --git a/src/tirith/cli.py b/src/tirith/cli.py index 5b3a684..8e83da8 100755 --- a/src/tirith/cli.py +++ b/src/tirith/cli.py @@ -73,6 +73,24 @@ def __init__(self, prog="PROG") -> None: dest="inputPath", help="Input file path", ) + parser.add_argument( + "-var-path", + metavar="PATH", + type=str, + default=[], + action="append", + dest="varPaths", + help="Variable file path(s)", + ) + parser.add_argument( + "-var", + metavar="PATH", + type=str, + default=[], + action="append", + dest="inlineVars", + help="Inline variable(s)", + ) parser.add_argument( "--json", dest="json", @@ -111,7 +129,7 @@ def __init__(self, prog="PROG") -> None: setup_logging(verbose=args.verbose) try: - result = start_policy_evaluation(args.policyPath, args.inputPath) + result = start_policy_evaluation(args.policyPath, args.inputPath, args.varPaths, args.inlineVars) if args.json: formatted_result = json.dumps(result, indent=3) diff --git a/src/tirith/core/core.py b/src/tirith/core/core.py index 6f00205..9cb9437 100644 --- a/src/tirith/core/core.py +++ b/src/tirith/core/core.py @@ -10,6 +10,7 @@ from tirith.providers.common import ProviderError from ..providers import PROVIDERS_DICT from .evaluators import EVALUATORS_DICT +from .policy_parameterization import get_policy_with_vars_replaced logger = logging.getLogger(__name__) @@ -204,7 +205,17 @@ def final_evaluator(eval_string: str, eval_id_values: Dict[str, Optional[bool]]) return final_eval_result, [] -def start_policy_evaluation(policy_path: str, input_path: str) -> Dict: +def start_policy_evaluation( + policy_path: str, input_path: str, var_paths: List[str] = [], inline_vars: List[str] = [] +) -> Dict: + """ + Start Tirith policy evaluation from policy file, input file, and optional variable files. + + :param policy_path: Path to the policy file + :param input_path: Path to the input file + :param var_paths: List of paths to the variable files + :return: Policy evaluation result + """ with open(policy_path) as f: policy_data = json.load(f) # TODO: validate policy_data against schema @@ -218,12 +229,50 @@ def start_policy_evaluation(policy_path: str, input_path: str) -> Dict: input_data = json.load(f) # TODO: validate input_data using the optionally available validate function in provider - return start_policy_evaluation_from_dict(policy_data, input_data) + # TODO: Move this logic into another module + # Merge policy variables into one dictionary + var_dicts = [] + for var_path in var_paths: + with open(var_path, encoding="utf-8") as f: + var_dicts.append(json.load(f)) + + merged_var_dict = _merge_var_dicts(var_dicts) + + variable_pattern = re.compile(r"(?P\w+)=(?P.+)") + for inline_var in inline_vars: + match = re.fullmatch(variable_pattern, inline_var) + if match: + try: + merged_var_dict[match.group("var_name")] = json.loads(match.group("var_json")) + except json.JSONDecodeError: + logger.error(f"Failed to parse inline variable: {inline_var}") + else: + logger.error(f"Invalid inline variable: {inline_var}") + + return start_policy_evaluation_from_dict(policy_data, input_data, merged_var_dict) + +def _merge_var_dicts(var_dicts: List[dict]) -> dict: + """ + Utility to merge var_dicts + + :param var_dicts: List of var dictionaries + :return: A merged dictionary + """ + merged_var_dict = {} + for var_dict in var_dicts: + merged_var_dict.update(var_dict) + return merged_var_dict + + +def start_policy_evaluation_from_dict(policy_dict: Dict, input_dict: Dict, var_dict: Dict = {}) -> Dict: + policy_dict, not_found_vars = get_policy_with_vars_replaced(policy_dict, var_dict) + if not_found_vars: + return {"errors": [f"Variables not found: {', '.join(not_found_vars)}"]} -def start_policy_evaluation_from_dict(policy_dict: Dict, input_dict: Dict) -> Dict: policy_meta = policy_dict.get("meta") eval_objects = policy_dict.get("evaluators") + final_evaluation_policy_string = policy_dict.get("eval_expression") provider_module = policy_meta.get("required_provider", "core") # TODO: Write functionality for dynamically importing evaluators from other modules. diff --git a/src/tirith/core/policy_parameterization.py b/src/tirith/core/policy_parameterization.py index df0e52b..ce81daf 100644 --- a/src/tirith/core/policy_parameterization.py +++ b/src/tirith/core/policy_parameterization.py @@ -1,39 +1,74 @@ import re import pydash +from typing import List, Tuple + +_VAR_PATTERN = re.compile(r"{{\s*var\.([\w\.]+)\s*}}") -class PydashPathNotFound: - pass +class _VariableNotFound: + pass -def check_match(string: str, pattern: re.Pattern) -> re.Match: - match_ = re.fullmatch(pattern, string) - return match_ +def _replace_vars_in_dict(dictionary: dict, var_dict: dict, not_found_vars: List[str]): + """ + Replace the variables in the dictionary with the values from the var_dict -def helper(dictionary: dict, var_pattern: re.Pattern, var_dict: dict): + :param dictionary: The dictionary to replace the variables in + :param var_pattern: The pattern to match the variables + :param var_dict: The dictionary containing the variables + """ for key, value in dictionary.items(): - if isinstance(value, str): - match = check_match(value, var_pattern) - if bool(match): - dictionary[key] = pydash.get(var_dict, match.group(1), default=PydashPathNotFound) + if not isinstance(value, str): + continue + _replace_var_in_dict(dictionary, key, var_dict, not_found_vars) -def replace_vars(policy_dict: dict, var_dict: dict) -> dict: - var_pattern = re.compile(r"{{var\.([\w\.]+)}}") +def _replace_var_in_dict(dictionary: dict, key: str, var_dict: dict, not_found_vars: list): + """ + Replace the variable in the dictionary with the value from the var_dict + This only replaces single dictionary key - evaluators = policy_dict["evaluators"] - helper(policy_dict["meta"], var_pattern, var_dict) - for i in range(len(evaluators)): - match = check_match(evaluators[i]["id"], var_pattern) - if bool(match): - evaluators[i]["id"] = pydash.get(var_dict, match.group(1), default=PydashPathNotFound) + :param dictionary: The dictionary to replace the variable in + :param key: The key of the param `dictionary` to replace the variable in + :param var_dict: The dictionary containing the variables + :param not_found_vars: The list to store the variables that are not found in + """ + var_expression = dictionary[key] + + match = _VAR_PATTERN.match(var_expression) + if not match: + return - helper(evaluators[i]["condition"], var_pattern, var_dict) - helper(evaluators[i]["provider_args"], var_pattern, var_dict) + var_name = match.group(1) + var_value = pydash.get(var_dict, var_name, default=_VariableNotFound) + if var_value is _VariableNotFound: + not_found_vars.append(var_name) + return + dictionary[key] = var_value + + +def get_policy_with_vars_replaced(policy_dict: dict, var_dict: dict) -> Tuple[dict, List[str]]: + """ + Replace the variables in the policy_dict with the values from the var_dict + + :param policy_dict: The policy dictionary + :param var_dict: The dictionary containing the variables + :return: The policy dictionary with the variables replaced + and the list of variables that are not found + """ + not_found_vars = [] + # Replace vars in the meta key + _replace_vars_in_dict(policy_dict["meta"], var_dict, not_found_vars) + + # Replace vars in the evaluators + evaluators = policy_dict["evaluators"] + for evaluator in evaluators: + _replace_var_in_dict(evaluator, "id", var_dict, not_found_vars) + _replace_vars_in_dict(evaluator["provider_args"], var_dict, not_found_vars) + _replace_vars_in_dict(evaluator["condition"], var_dict, not_found_vars) - match = check_match(policy_dict["eval_expression"], var_pattern) - if bool(match): - policy_dict["eval_expression"] = pydash.get(var_dict, match.group(1), default=PydashPathNotFound) + # Replace vars in the eval_expression + _replace_var_in_dict(policy_dict, "eval_expression", var_dict, not_found_vars) - return policy_dict + return policy_dict, not_found_vars diff --git a/src/tirith/prettyprinter.py b/src/tirith/prettyprinter.py index 23deed3..4134ba7 100644 --- a/src/tirith/prettyprinter.py +++ b/src/tirith/prettyprinter.py @@ -76,7 +76,7 @@ def pretty_print_result_dict(final_result_dict: Dict) -> None: :param final_result_dict: Result dictionary generated by core. """ - checks = final_result_dict["evaluators"] + checks = final_result_dict.get("evaluators", []) num_passed_checks = 0 num_failed_checks = 0 num_skipped_checks = 0 @@ -116,10 +116,13 @@ def pretty_print_result_dict(final_result_dict: Dict) -> None: print(f"Passed: {num_passed_checks} Failed: {num_failed_checks} Skipped: {num_skipped_checks}") print() - print(f"Final expression used:\n-> {TermStyle.grey(final_result_dict['eval_expression'])}") - if final_result_dict["final_result"]: - print(TermStyle.success("✔ Passed final evaluator")) - elif final_result_dict["final_result"] is None: - print(TermStyle.skipped("= Skipped final evaluator")) - else: - print(TermStyle.fail("✘ Failed final evaluation")) + if "eval_expression" in final_result_dict: + print(f"Final expression used:\n-> {TermStyle.grey(final_result_dict['eval_expression'])}") + + if "final_result" in final_result_dict: + if final_result_dict["final_result"]: + print(TermStyle.success("✔ Passed final evaluator")) + elif final_result_dict["final_result"] is None: + print(TermStyle.skipped("= Skipped final evaluator")) + else: + print(TermStyle.fail("✘ Failed final evaluation")) diff --git a/tests/core/fixtures/input.json b/tests/core/fixtures/input.json new file mode 100644 index 0000000..7b74835 --- /dev/null +++ b/tests/core/fixtures/input.json @@ -0,0 +1,7 @@ +{ + "name": "John Doe", + "age": 30, + "city": { + "name": "New York" + } +} diff --git a/tests/core/fixtures/policy_parametrized.json b/tests/core/fixtures/policy_parametrized.json new file mode 100644 index 0000000..fdccb0e --- /dev/null +++ b/tests/core/fixtures/policy_parametrized.json @@ -0,0 +1,20 @@ +{ + "meta": { + "version": "v1", + "required_provider": "stackguardian/json" + }, + "evaluators": [ + { + "id": "city_check", + "provider_args": { + "operation_type": "get_value", + "key_path": "city" + }, + "condition": { + "type": "Equals", + "value": "{{ var.city }}" + } + } + ], + "eval_expression": "city_check" +} diff --git a/tests/core/test_policy_parameterization.py b/tests/core/test_policy_parameterization.py index 02ad907..db9fcc0 100644 --- a/tests/core/test_policy_parameterization.py +++ b/tests/core/test_policy_parameterization.py @@ -1,6 +1,8 @@ import pytest +import json +from subprocess import Popen, PIPE -from tirith.core.policy_parameterization import replace_vars, PydashPathNotFound +from tirith.core.policy_parameterization import get_policy_with_vars_replaced, _VariableNotFound @pytest.fixture @@ -27,20 +29,50 @@ def processed_policy(): } # Run the function once and return the result - return replace_vars(input_dict, var_dict) + return get_policy_with_vars_replaced(input_dict, var_dict) def test_nested_dict(processed_policy): - assert processed_policy["meta"]["required_provider"] == "stackguardian/json" - - -def test_path_not_found(processed_policy): - assert processed_policy["evaluators"][0]["provider_args"]["key_path"] == PydashPathNotFound + assert processed_policy[0]["meta"]["required_provider"] == "stackguardian/json" def test_var_value_in_list(processed_policy): - assert processed_policy["evaluators"][0]["condition"]["value"] == 2 + assert processed_policy[0]["evaluators"][0]["condition"]["value"] == 2 def test_eval_expression_parameterization(processed_policy): - assert processed_policy["eval_expression"] == "check0" + assert processed_policy[0]["eval_expression"] == "check0" + + +def test_not_found_variable(processed_policy): + assert processed_policy[1] == ["key_path"] + + +# TODO: Create testcases for: +# - test inline vars precendece over var files +# - test undefined vars +# - test var syntax is not valid +# - test with var files +# - test with var files and inline vars together +# - test with var files and inline vars overlapping +def test_e2e_inline_vars(): + # Run the tirith binary with the inline variables + process = Popen( + [ + "tirith", + "-policy-path", + "tests/core/fixtures/policy_parametrized.json", + "-input-path", + "tests/core/fixtures/input.json", + "-var", + 'city={"name": "New York"}', + "--json", + ], + stdout=PIPE, + stderr=PIPE, + ) + stdout, stderr = process.communicate() + tirith_result = json.loads(stdout) + assert tirith_result["final_result"] is True + assert process.returncode == 0 + assert stderr == b""