diff --git a/Makefile b/Makefile index 9dcce8cbec3..010e9d80763 100644 --- a/Makefile +++ b/Makefile @@ -30,8 +30,7 @@ endif install: @if [[ -z "$(VIRTUAL_ENV)" ]]; then echo "Create and Activate VirtualEnv First, ie. python3 -m venv .venv && source .venv/bin/activate"; exit 1; fi poetry install - for pkg in $(PKG_SET); do echo "Install $$pkg" && cd $$pkg && poetry install --all-extras && cd ../..; done - + for pkg in $(PKG_SET); do echo "Install $$pkg" && env -C $$pkg poetry install --all-extras; done .PHONY: test test: diff --git a/tools/c7n_left/c7n_left/providers/terraform/graph.py b/tools/c7n_left/c7n_left/providers/terraform/graph.py index 2c50d3c4b32..ee2f6e5eb9a 100644 --- a/tools/c7n_left/c7n_left/providers/terraform/graph.py +++ b/tools/c7n_left/c7n_left/providers/terraform/graph.py @@ -2,6 +2,8 @@ # SPDX-License-Identifier: Apache-2.0 # +import uuid + from ...core import ResourceGraph from .resource import TerraformResource @@ -18,20 +20,23 @@ def get_resources_by_type(self, types=()): for type_name, type_items in self.resource_data.items(): if types and (type_name not in types and f"data.{type_name}" not in types): continue - elif type_name == "module": - yield type_name, [self.as_resource(type_name, d, "module") for d in type_items] - elif type_name == "moved": - yield type_name, [self.as_resource(type_name, d, "moved") for d in type_items] - elif type_name == "locals": - yield type_name, [self.as_resource(type_name, d, "local") for d in type_items] - elif type_name == "terraform": - yield type_name, [self.as_resource(type_name, d, "terraform") for d in type_items] - elif type_name == "provider": - yield type_name, [self.as_resource(type_name, d, "provider") for d in type_items] - elif type_name == "variable": - yield type_name, [self.as_resource(type_name, d, "variable") for d in type_items] - elif type_name == "output": - yield type_name, [self.as_resource(type_name, d, "output") for d in type_items] + elif type_name in ( + "module", + "moved", + "locals", + "terraform", + "provider", + "variable", + "output" + ): + if type_name == "locals": + name = "local" + else: + name = type_name + yield type_name, [ + self.as_resource(type_name, d, type_name=name) + for d in type_items + ] else: data_resources = [] resources = [] @@ -76,10 +81,11 @@ def __init__(self): @staticmethod def is_id_ref(v): - if len(v) != 36: - return False - if v.count("-") != 4: + try: + uuid.UUID(hex=v) + except ValueError: return False + return True def resolve_refs(self, block, types=None): @@ -95,7 +101,7 @@ def resolve_refs(self, block, types=None): continue yield r - def visit(self, block, root=False): + def visit(self, block): if not isinstance(block, dict): return () @@ -110,10 +116,14 @@ def visit(self, block, root=False): refs.add(v) if isinstance(v, (str, int, float, bool)): continue - if isinstance(v, dict) and k != "__tfmeta": - refs.update(self.visit(v)) + if isinstance(v, dict): + if k == "__tfmeta": + refs.update(r["id"]for r in v.get("references", ())) + else: + refs.update(self.visit(v)) if isinstance(v, list): - list(map(self.visit, v)) + for entry in v: + self.visit(entry) if refs and block.get("__tfmeta", {}).get("label"): self._ref_map.setdefault(bid, []).extend(refs) diff --git a/tools/c7n_left/tests/test_left.py b/tools/c7n_left/tests/test_left.py index 706006548ef..3639456ff92 100644 --- a/tools/c7n_left/tests/test_left.py +++ b/tools/c7n_left/tests/test_left.py @@ -29,11 +29,8 @@ ) from c7n_left.providers.terraform.graph import Resolver from c7n_left.providers.terraform.filters import Taggable - - LEFT_INSTALLED = True except ImportError: pytest.skip(reason="c7n_left not installed", allow_module_level=True) - LEFT_INSTALLED = False else: load_resources(("terraform.*",)) @@ -816,6 +813,59 @@ def test_traverse_multi_resource_nested_or(tmp_path): } +def test_traverse_match_values(policy_env, test): + policy_env.write_tf( + """ +resource "r" "r1" { + name = "r-r1" +} + +resource "r" "r2" { + label = "r-r2" +} + +resource "rr" "rx" { + rn = [r.r1.name] +} + +resource "rr" "ry" { + rl = [r.r2.label] +} + """ + ) + policy_env.write_policy( + { + "name": "test1", + "resource": "terraform.rr", + "filters": [ + { + "type": "traverse", + "resources": "r", + "attrs": [{"name": "r-r1"}], + } + ], + }, + ) + policy_env.write_policy( + { + "name": "test2", + "resource": "terraform.rr", + "filters": [ + { + "type": "traverse", + "resources": "r", + "attrs": [{"label": "r-r2"}], + } + ], + }, + ) + res1, res2 = (r.as_dict() for r in policy_env.run()) + assert res1["policy"]["name"] == "test1" + assert res1["resource"]["__tfmeta"]["path"] == "rr.rx" + assert res2["policy"]["name"] == "test2" + assert res2["resource"]["__tfmeta"]["path"] == "rr.ry" + + def test_traverse_filter_not_found(tmp_path): resources = run_policy( { diff --git a/tools/c7n_left/tests/test_left_test.py b/tools/c7n_left/tests/test_left_test.py index ba1020c2afd..2a6d2311db9 100644 --- a/tools/c7n_left/tests/test_left_test.py +++ b/tools/c7n_left/tests/test_left_test.py @@ -16,11 +16,8 @@ try: from c7n_left import cli from c7n_left import test as left_test - - LEFT_INSTALLED = True except ImportError: pytest.skip(reason="c7n_left not installed", allow_module_level=True) - LEFT_INSTALLED = False data_dir = Path(os.curdir).absolute() / "data"