Skip to content
Open
11 changes: 10 additions & 1 deletion src/tirith/core/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,17 @@ def generate_evaluator_result(evaluator_obj, input_data, provider_module):
has_evaluation_passed = None
continue

# Run evaluation on the provider's input value
evaluation_result = evaluator_instance.evaluate(evaluator_input["value"], evaluator_data)
evaluation_result["meta"] = evaluator_input.get("meta")

# Copy metadata and addresses if provided by the provider
if "meta" in evaluator_input:
evaluation_result["meta"] = evaluator_input["meta"]

# Copy addresses directly if provided
if "addresses" in evaluator_input:
evaluation_result["addresses"] = evaluator_input["addresses"]

evaluation_results.append(evaluation_result)
has_valid_evaluation = True

Expand Down
5 changes: 5 additions & 0 deletions src/tirith/prettyprinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@

for result_num, result_dict in enumerate(check_dict["result"]):
result_message = result_dict["message"]

# Include addresses in the message if it exists in the result_dict
if "addresses" in result_dict:
result_message = f"{result_message} - (Addresses: `{result_dict['addresses']}`)"

Check warning on line 105 in src/tirith/prettyprinter.py

View check run for this annotation

Codecov / codecov/patch

src/tirith/prettyprinter.py#L105

Added line #L105 was not covered by tests

if result_dict["passed"]:
print(TermStyle.green(f" {result_num+1}. PASSED: {result_message}"))
elif check_dict["passed"] is None:
Expand Down
7 changes: 6 additions & 1 deletion src/tirith/providers/json/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ def get_value(provider_args: Dict, input_data: Dict) -> List[dict]:
)
]

outputs = [create_result_dict(value=value, meta=None, err=None) for value in values]
# Create result dict with addresses as a separate property, not in meta
outputs = []
for value in values:
result = create_result_dict(value=value, meta=None, err=None)
result["addresses"] = key_path
Comment thread
refeed marked this conversation as resolved.
Outdated
outputs.append(result)

return outputs

Expand Down
123 changes: 78 additions & 45 deletions src/tirith/providers/terraform_plan/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,24 +97,36 @@
is_attribute_found = True
local_is_found_attribute = True
attribute_value = input_resource_change_attrs[attribute]
outputs.append(
{
"value": attribute_value,
"meta": resource_change,
"err": None,
}
)
result = {
"value": attribute_value,
"meta": resource_change,
"err": None,
"addresses": resource_change.get("address")
Comment thread
refeed marked this conversation as resolved.
Outdated
}
outputs.append(result)
elif "." in attribute or "*" in attribute:
evaluated_outputs = _wrapper_get_exp_attribute(attribute, input_resource_change_attrs)
if evaluated_outputs:
is_attribute_found = True
local_is_found_attribute = True
for evaluated_output in evaluated_outputs:
outputs.append({"value": evaluated_output, "meta": resource_change, "err": None})
result = {
"value": evaluated_output,
"meta": resource_change,
"err": None,
"addresses": resource_change.get("address")
}
outputs.append(result)

# If we didn't find the attribute in this resource, add a None value so it still gets evaluated
if not local_is_found_attribute:
outputs.append({"value": None, "meta": resource_change, "err": None})
result = {
"value": None,
"meta": resource_change,
"err": None,
"addresses": resource_change.get("address")
}
outputs.append(result)
else:
outputs.append(
{
Expand Down Expand Up @@ -154,13 +166,13 @@
if resource_type in (resource_change["type"], "*"):
is_resource_type_found = True
for action in resource_change["change"]["actions"]:
outputs.append(
{
"value": action,
"meta": resource_change,
"err": None,
}
)
result = {
"value": action,
"meta": resource_change,
"err": None,
"addresses": resource_change.get("address")
}
outputs.append(result)
if not is_resource_type_found:
outputs.append(
{
Expand All @@ -175,6 +187,7 @@
elif input_type == "count":
count = 0
resource_meta = {}
addresses = None
resource_type = provider_inputs["terraform_resource_type"]
for resource_change in resource_changes:
# Skip if resource type is in exclude_resource_types when using wildcard
Expand All @@ -184,15 +197,18 @@
# No need to check if the resource is not found
# because the count of a resource can be zero
resource_meta = resource_change
# Use the last encountered address (this is just for count, which is an aggregate result)
if "address" in resource_change:
addresses = resource_change["address"]
count += 1

outputs.append(
{
"value": count,
"meta": resource_meta,
"err": None,
}
)
result = {
"value": count,
"meta": resource_meta,
"err": None,
"addresses": addresses
}
outputs.append(result)
return outputs
# CASE 4
elif input_type == "direct_dependencies":
Expand Down Expand Up @@ -252,7 +268,6 @@
continue

is_provider_full_name_found = True

attribute_value = None

if attribute_to_get == "version_constraint":
Expand All @@ -271,12 +286,13 @@
}
)
return
outputs.append(
{
"value": attribute_value,
"meta": provider_config_dict,
}
)

result = {
"value": attribute_value,
"meta": provider_config_dict,
"addresses": terraform_provider_full_name
}
outputs.append(result)

if not is_provider_full_name_found:
outputs.append(
Expand All @@ -297,7 +313,8 @@
:param provider_inputs: The provider inputs
:param outputs: The outputs
"""
outputs.append({"value": input_data.get("terraform_version"), "meta": input_data})
# For terraform_version, there's no specific address as it applies to the entire plan
outputs.append({"value": input_data.get("terraform_version"), "meta": input_data, "addresses": "terraform_version"})


def direct_dependencies_operator(input_data: dict, provider_inputs: dict, outputs: list):
Expand All @@ -316,12 +333,16 @@
is_resource_found = False

for resource in config_resources:

if resource.get("type") != resource_type:
continue
is_resource_found = True
deps_resource_type = {resource_id.split(".")[0] for resource_id in resource.get("depends_on", [])}
outputs.append({"value": list(deps_resource_type), "meta": config_resources})
result = {"value": list(deps_resource_type), "meta": config_resources}
# Add addresses if available
address = resource.get("address")
if address:
result["addresses"] = address
outputs.append(result)

if not is_resource_found:
outputs.append(
Expand All @@ -347,7 +368,7 @@
resource_changes = input_data.get("resource_changes", [])
referenced_by = provider_inputs.get("referenced_by")

reference_target_addresses = set()
reference_target_address = set()
Comment thread
refeed marked this conversation as resolved.
Outdated
is_resource_found = False

# Loop for adding reference_target
Expand All @@ -356,7 +377,7 @@
"destroy"
]:
continue
reference_target_addresses.add(resource_change.get("address"))
reference_target_address.add(resource_change.get("address"))
is_resource_found = True

if not is_resource_found:
Expand Down Expand Up @@ -384,15 +405,19 @@
reference_address = relative_reference_address
else:
reference_address = f"{module_path}.{relative_reference_address}"
if reference_address in reference_target_addresses:
reference_target_addresses.remove(reference_address)
outputs.append(
{"value": True, "meta": {"address": reference_address, "referenced_by": resource_config}}
)
if reference_address in reference_target_address:
reference_target_address.remove(reference_address)
result = {"value": True, "meta": {"referenced_by": resource_config}}

Check warning on line 410 in src/tirith/providers/terraform_plan/handler.py

View check run for this annotation

Codecov / codecov/patch

src/tirith/providers/terraform_plan/handler.py#L409-L410

Added lines #L409 - L410 were not covered by tests
# Add addresses to the output
result["addresses"] = reference_address
outputs.append(result)

Check warning on line 413 in src/tirith/providers/terraform_plan/handler.py

View check run for this annotation

Codecov / codecov/patch

src/tirith/providers/terraform_plan/handler.py#L412-L413

Added lines #L412 - L413 were not covered by tests

# For all of the reference_target_addresses that don't have a reference
for reference_target_address in reference_target_addresses:
outputs.append({"value": False, "meta": {"address": reference_target_address, "referenced_by": {}}})
# For all of the reference_target_address that don't have a reference
for reference_target_address in reference_target_address:
result = {"value": False, "meta": {"referenced_by": {}}}
# Add addresses to the output
result["addresses"] = reference_target_address
outputs.append(result)


def get_module_resources_by_type_recursive(module: dict, resource_type: str, current_module_path: str = "") -> iter:
Expand Down Expand Up @@ -478,7 +503,10 @@
return

is_all_resource_type_references_to = resource_type_count == reference_count
outputs.append({"value": is_all_resource_type_references_to, "meta": config_resources})
result = {"value": is_all_resource_type_references_to, "meta": config_resources}

Check warning on line 506 in src/tirith/providers/terraform_plan/handler.py

View check run for this annotation

Codecov / codecov/patch

src/tirith/providers/terraform_plan/handler.py#L506

Added line #L506 was not covered by tests
# While we don't have a specific address for the entire result, we can include the resource type
result["addresses"] = resource_type
outputs.append(result)

Check warning on line 509 in src/tirith/providers/terraform_plan/handler.py

View check run for this annotation

Codecov / codecov/patch

src/tirith/providers/terraform_plan/handler.py#L508-L509

Added lines #L508 - L509 were not covered by tests
Comment thread
refeed marked this conversation as resolved.


def direct_references_operator(input_data: dict, provider_inputs: dict, outputs: list):
Expand Down Expand Up @@ -530,7 +558,12 @@
# Only get the resource type
resource_references.add(reference.split(".")[0])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the address from the reference

addresses.append(reference)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@refeed I am unable to understand why do we need to do this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because that's the real addresses the optype is processing. The resource var that's placed in the meta key was actually not placed correctly, it only contains one resource even though this optype is processing more than one resources


outputs.append({"value": list(resource_references), "meta": resource})
result = {"value": list(resource_references), "meta": resource}
# Add addresses if available
address = resource.get("address")
if address:
result["addresses"] = address
outputs.append(result)

if not is_resource_found:
outputs.append(
Expand Down
Loading