Repository: GoogleCloudPlatform/terraform-validator
Pull request #148 (2020-08-01 03:27:54)

Add policy change detection capabilities.
A generalized approach to detecting IAMPolicy changes on Assets.

In this approach, we create two sets of Assets: before and after. The after Assets is the currently generated ReadPlannedAssets. In the before, we parse the plan's resource_changes to create tfplan.Assets based on the current rather than planned state.

To detect policy changes, we simply compare the sets of Assets and record when

1. New policies are created.
2. Policies or resources are deleted.
3. Assets with the same name have different policies.


Patch:
diff --git a/go.mod b/go.mod
index 4ee92170..2af2b4d1 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ require (
 	github.com/forseti-security/config-validator v0.0.0-20191121204425-eb1b299ab838
 	github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
 	github.com/golang/protobuf v1.3.2
+	github.com/google/go-cmp v0.3.1
 	github.com/hashicorp/terraform-plugin-sdk v1.4.0
 	github.com/pkg/errors v0.8.1
 	github.com/spf13/cobra v0.0.5
diff --git a/policy/policy.go b/policy/policy.go
new file mode 100644
index 00000000..e6409a97
--- /dev/null
+++ b/policy/policy.go
@@ -0,0 +1,102 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package policy provides utilities for easy operations on IAM policy in terraform.
+package policy
+
+import (
+	"context"
+
+	"github.com/GoogleCloudPlatform/terraform-validator/converters/google"
+	"github.com/GoogleCloudPlatform/terraform-validator/tfgcv"
+	"github.com/pkg/errors"
+)
+
+// Overlay contains the policies that have changed in the plan.
+// It is a map from the resource path to the new policy.
+// Only resources with a change in policy are included.
+type Overlay map[string]*google.IAMPolicy
+
+// BuildOverlay creates the Overlay for the current plan.
+func BuildOverlay(path, project, ancestry string, offline bool) (Overlay, error) {
+	ctx := context.Background()
+
+	before, err := tfgcv.ReadCurrentAssets(ctx, path, project, ancestry, offline)
+	if err != nil {
+		if errors.Cause(err) == tfgcv.ErrParsingProviderProject {
+			return nil, errors.New("unable to parse provider project, please use --project flag")
+		}
+		return nil, errors.Wrap(err, "converting tfplan to CAI assets")
+	}
+
+	after, err := tfgcv.ReadPlannedAssets(ctx, path, project, ancestry, offline)
+	if err != nil {
+		if errors.Cause(err) == tfgcv.ErrParsingProviderProject {
+			return nil, errors.New("unable to parse provider project, please use --project flag")
+		}
+		return nil, errors.Wrap(err, "converting tfplan to CAI assets")
+	}
+
+	return extractOverlay(before, after), nil
+}
+
+// extractOverlay compares the current and planned assets to determine
+// what policies have changed.
+func extractOverlay(before, after []google.Asset) Overlay {
+	emptyPolicy := func() *google.IAMPolicy {return &google.IAMPolicy{Bindings:[]google.IAMBinding{}}}
+
+	afterIndex := make(map[string]google.Asset)
+	for _, a := range after {
+		afterIndex[a.Name] = a
+	}
+	beforeIndex := make(map[string]google.Asset)
+	for _, b := range before {
+		beforeIndex[b.Name] = b
+	}
+
+	// Cover updates to policy and deletions of policy or resource.
+	overlay := Overlay{}
+	for name, b := range beforeIndex {
+		a, ok := afterIndex[name]
+		switch {
+		case !ok:
+			// If it doesn't exist in the after, it means the entire resource, not just
+			// the policy, is being deleted.
+			if b.IAMPolicy != nil {
+				// We don't treat this policy deletion any differently.  It's still
+				// a policy deletion, even if more than the policy is being deleted.
+				overlay[name] = emptyPolicy()
+			}
+		case a.IAMPolicy != b.IAMPolicy:
+			if a.IAMPolicy != nil {
+				overlay[name] = a.IAMPolicy
+			} else {
+				// If the policy exists in the before and not in the after, then the
+				// policy has been deleted. The resource has not been deleted because
+				// that case would have already been caught above.
+				overlay[name] = emptyPolicy()
+			}
+		}
+	}
+
+	// Cover the case where new resources were created.
+	for name, a := range afterIndex {
+		_, ok := beforeIndex[name]
+		if !ok && a.IAMPolicy != nil {
+			overlay[name] = a.IAMPolicy
+		}
+	}
+
+	return overlay
+}
diff --git a/tfgcv/planned_assets.go b/tfgcv/planned_assets.go
index 96e3d064..029981ea 100644
--- a/tfgcv/planned_assets.go
+++ b/tfgcv/planned_assets.go
@@ -37,27 +37,18 @@ import (
 // than fetching the ancestry information using Google API.
 // It ignores non-supported resources.
 func ReadPlannedAssets(ctx context.Context, path, project, ancestry string, offline bool) ([]google.Asset, error) {
-	ua := option.WithUserAgent(fmt.Sprintf("config-validator-tf/%s", BuildVersion()))
-	ancestryManager, err := ancestrymanager.New(context.Background(), project, ancestry, offline, ua)
-	if err != nil {
-		return nil, errors.Wrap(err, "constructing resource manager client")
-	}
-	converter, err := google.NewConverter(ctx, ancestryManager, project, "", offline)
+	converter, err := newConverter(ctx, path, project, ancestry, offline)
 	if err != nil {
-		return nil, errors.Wrap(err, "building google converter")
+		return nil, err
 	}
 
 	var resources []tfplan.Resource
 
 	switch version.LeastSupportedVersion() {
 	case version.TF12:
-		if ".json" != filepath.Ext(path) {
-			return nil, errors.New(fmt.Sprintf("Terraform 0.12 support plans only in JSON format, got: %s", filepath.Ext(path)))
-		}
-		// JSON format means Terraform 12
-		data, err := ioutil.ReadFile(path)
+		data, err := readTF12Data(path)
 		if err != nil {
-			return nil, errors.Wrap(err, "opening JSON plan file")
+			return nil, err
 		}
 
 		resources, err = tfplan.ComposeTF12Resources(data, converter.Schemas())
@@ -102,4 +93,72 @@ func ReadPlannedAssets(ctx context.Context, path, project, ancestry string, offl
 	return converter.Assets(), nil
 }
 
+// ReadCurrentAssets extracts CAI assets from a terraform plan file.
+// This is the same as ReadPlannedAssets, but operates on the current rather than
+// the planned resources.
+// Only supports version.TF12
+func ReadCurrentAssets(ctx context.Context, path, project, ancestry string, offline bool) ([]google.Asset, error) {
+	converter, err := newConverter(ctx, path, project, ancestry, offline)
+	if err != nil {
+		return nil, err
+	}
+
+	var resources []tfplan.Resource
+
+	switch version.LeastSupportedVersion() {
+	case version.TF12:
+		data, err := readTF12Data(path)
+		if err != nil {
+			return nil, err
+		}
+		if ".json" != filepath.Ext(path) {
+			return nil, errors.New(fmt.Sprintf("Terraform 0.12 support plans only in JSON format, got: %s", filepath.Ext(path)))
+		}
+
+		resources, err = tfplan.ComposeCurrentTF12Resources(data, converter.Schemas())
+		if err != nil {
+			return nil, errors.Wrap(err, "unmarshal from JSON and composing terraform plan")
+		}
+	default:
+		return nil, fmt.Errorf("terraform version %s is not supported by this version of validator, see README.md to switch to the right version", version.LeastSupportedVersion())
+	}
+
+	for _, r := range resources {
+		if err := converter.AddResource(&r); err != nil {
+			if errors.Cause(err) == google.ErrDuplicateAsset {
+				glog.Warningf("converting resource: %v", err)
+			} else {
+				return nil, errors.Wrapf(err, "converting resource %v", r.Kind())
+			}
+		}
+	}
+
+	return converter.Assets(), nil
+}
+
+func newConverter(ctx context.Context, path, project, ancestry string, offline bool) (*google.Converter, error) {
+	ua := option.WithUserAgent(fmt.Sprintf("config-validator-tf/%s", BuildVersion()))
+	ancestryManager, err := ancestrymanager.New(context.Background(), project, ancestry, offline, ua)
+	if err != nil {
+		return nil, errors.Wrap(err, "constructing resource manager client")
+	}
+	converter, err := google.NewConverter(ctx, ancestryManager, project, "", offline)
+	if err != nil {
+		return nil, errors.Wrap(err, "building google converter")
+	}
+	return converter, nil
+}
+
+func readTF12Data(path string) ([]byte, error) {
+	if ".json" != filepath.Ext(path) {
+		return nil, errors.New(fmt.Sprintf("Terraform 0.12 support plans only in JSON format, got: %s", filepath.Ext(path)))
+	}
+	// JSON format means Terraform 12
+	data, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, errors.Wrap(err, "opening JSON plan file")
+	}
+	return data, nil
+}
+
 var ErrParsingProviderProject = errors.New("unable to parse provider project")
diff --git a/tfplan/json_plan.go b/tfplan/json_plan.go
index 37430758..7319418f 100644
--- a/tfplan/json_plan.go
+++ b/tfplan/json_plan.go
@@ -27,6 +27,7 @@ import (
 const maxChildModuleLevel = 10000
 
 // jsonPlan structure used to parse Terraform 12 plan exported in json format by 'terraform show -json ./binary_plan.tfplan' command.
+// https://www.terraform.io/docs/internals/json-format.html#plan-representation
 type jsonPlan struct {
 	PlannedValues struct {
 		RootModules struct {
@@ -34,6 +35,33 @@ type jsonPlan struct {
 			ChildModules []childModule  `json:"child_modules"`
 		} `json:"root_module"`
 	} `json:"planned_values"`
+	ResourceChanges []jsonResourceChange `json:"resource_changes"`
+}
+
+type jsonResourceChange struct {
+	Address      string `json:"address"`
+	Mode         string `json:"mode"`
+	Kind         string `json:"type"`
+	Name         string `json:"name"`
+	ProviderName string `json:"provider_name"`
+	Change       struct {
+		// Valid actions values are:
+		//    ["no-op"]
+		//    ["create"]
+		//    ["read"]
+		//    ["update"]
+		//    ["delete", "create"]
+		//    ["create", "delete"]
+		//    ["delete"]
+		Actions []string               `json:"actions"`
+		Before  map[string]interface{} `json:"before"`
+		After   map[string]interface{} `json:"after"`
+	} `json:"change"`
+}
+
+// isCreate returns true if the action on the resource is ["create"].
+func (c *jsonResourceChange) isCreate() bool {
+	return len(c.Change.Actions) == 1 && c.Change.Actions[0] == "create"
 }
 
 type childModule struct {
@@ -56,10 +84,28 @@ type jsonResource struct {
 // ComposeTF12Resources inspects a plan and returns the planned resources that match the provided resource schema map.
 // ComposeTF12Resources works in a same way as tfplan.ComposeResources and returns array of tfplan.Resource
 func ComposeTF12Resources(data []byte, schemas map[string]*schema.Resource) ([]Resource, error) {
-	resources, err := readJSONResources(data)
+	plan, err := readPlan(data)
+	if err != nil {
+		return nil, err
+	}
+	resources := readPlannedJSONResources(plan)
+	return jsonToResources(resources, schemas), nil
+}
+
+// ComposeCurrentTF12Resources inspects a plan and returns the current resources that match the provided resource schema map.
+// This works the same as ComposeTF12Resources but operates on current rather than planned resources.
+func ComposeCurrentTF12Resources(data []byte, schemas map[string]*schema.Resource) ([]Resource, error) {
+	plan, err := readPlan(data)
 	if err != nil {
-		return nil, errors.Wrap(err, "read resources")
+		return nil, err
 	}
+	resources := readCurrentJSONResources(plan)
+	return jsonToResources(resources, schemas), nil
+}
+
+// jsonToResource converts the jsonResources to tfplan.Resource using the provided schemas.
+// Any resources not supported by the schemas are silently skipped.
+func jsonToResources(resources []jsonResource, schemas map[string]*schema.Resource) []Resource {
 	var instances []Resource
 	for _, r := range resources {
 		sch, ok := schemas[r.Kind]
@@ -82,7 +128,18 @@ func ComposeTF12Resources(data []byte, schemas map[string]*schema.Resource) ([]R
 			},
 		})
 	}
-	return instances, nil
+	return instances
+}
+
+func jsonResourceFromChange(c jsonResourceChange) jsonResource {
+	return jsonResource{
+		Name:         c.Name,
+		Address:      c.Address,
+		Mode:         c.Mode,
+		Kind:         c.Kind,
+		ProviderName: c.ProviderName,
+		Values:       c.Change.Before,
+	}
 }
 
 // attributes function takes json parsed JSON object (value param) and fill map[string]string with it's
@@ -167,14 +224,20 @@ func attributes(value interface{}, address []string, res map[string]string, sche
 	}
 }
 
-// readJSONResources unmarshal json data to go struct
-// and returns array of all jsonResources both from root and child modules.
-func readJSONResources(data []byte) ([]jsonResource, error) {
+// readPlan converts the raw bytes into a jsonPlan
+func readPlan(data []byte) (jsonPlan, error) {
 	plan := jsonPlan{}
 	err := json.Unmarshal(data, &plan)
 	if err != nil {
-		return nil, err
+		return jsonPlan{}, errors.Wrap(err, "read resources")
 	}
+	return plan, nil
+}
+
+// readPlannedJSONResources reads a jsonPlan and returns an array of all
+// planned jsonResources.
+// This includes resources from both from root and child modules.
+func readPlannedJSONResources(plan jsonPlan) []jsonResource {
 	var result []jsonResource
 	for _, resource := range plan.PlannedValues.RootModules.Resources {
 		resource.Module = "root"
@@ -183,7 +246,27 @@ func readJSONResources(data []byte) ([]jsonResource, error) {
 	for _, module := range plan.PlannedValues.RootModules.ChildModules {
 		result = append(result, resourcesFromModule(&module, 0)...)
 	}
-	return result, nil
+	return result
+}
+
+// readCurrentJSONResources constructs jsonResources for the current state.
+func readCurrentJSONResources(plan jsonPlan) []jsonResource {
+	var result []jsonResource
+	for _, c := range plan.ResourceChanges {
+		// Ignore resources being created because they don't currently exist.
+		if c.isCreate() {
+			continue
+		}
+		result = append(result, jsonResource{
+			Name:         c.Name,
+			Address:      c.Address,
+			Mode:         c.Mode,
+			Kind:         c.Kind,
+			ProviderName: c.ProviderName,
+			Values:       c.Change.Before,
+		})
+	}
+	return result
 }
 
 func resourcesFromModule(module *childModule, level int) []jsonResource {


Test patch:
diff --git a/policy/policy_test.go b/policy/policy_test.go
new file mode 100644
index 00000000..d8b2510f
--- /dev/null
+++ b/policy/policy_test.go
@@ -0,0 +1,187 @@
+package policy
+
+import (
+	"path/filepath"
+	"sort"
+	"testing"
+
+	"github.com/GoogleCloudPlatform/terraform-validator/converters/google"
+	"github.com/google/go-cmp/cmp"
+)
+
+const (
+	testDataDir        = "./testdata"
+	pathPrefix         = "//cloudresourcemanager.googleapis.com"
+	testOrgID          = "123456789"
+	testOrgPath        = pathPrefix + "/organizations/" + testOrgID
+	testFolderName     = "example-tf-folder"
+	testFolderID       = "123456789"
+	testFolderNamePath = pathPrefix + "/" + testFolderName
+	testFolderIDPath   = pathPrefix + "/folders/" + testFolderID
+	testProjectName    = "example-tf-project"
+	testProjectPath    = pathPrefix + "/projects/" + testProjectName
+	testAncestryName   = "ancestry"
+)
+
+// TestOverlayWithCreates verifies that the overlay handles iam resource creation correctly.
+func TestOverlayWithCreates(t *testing.T) {
+	policy := func() *google.IAMPolicy {
+		return &google.IAMPolicy{
+			Bindings: []google.IAMBinding{
+				{
+					Role:    "roles/bigquery.admin",
+					Members: []string{"user:user2@example.com"},
+				},
+				{
+					Role:    "roles/editor",
+					Members: []string{"user:user1@example.com"},
+				},
+			},
+		}
+	}
+	wantOverlay := Overlay{
+		testOrgPath:        policy(),
+		testFolderNamePath: policy(),
+		testProjectPath:    policy(),
+	}
+
+	tests := []struct {
+		name string
+		file string
+	}{
+		{
+			name: "binding_member",
+			file: "tf12plan_create_binding_member.json",
+		},
+		{
+			name: "iam_policy",
+			file: "tf12plan_create_iam_policy.json",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			file := filepath.Join(testDataDir, tt.file)
+			got, err := BuildOverlay(file, testProjectName, testAncestryName, true)
+			sortOverlay(got)
+			if err != nil {
+				t.Fatalf("BuildOverly(%s) error: %v", file, err)
+			}
+			if diff := cmp.Diff(wantOverlay, got); diff != "" {
+				t.Fatalf("BuildOverlay(%s)) diff (-want +got): %s", file, diff)
+			}
+		})
+	}
+}
+
+// TestOverlayWithUpdates verifies that the overlay handles iam resource creation correctly.
+func TestOverlayWithUpdates(t *testing.T) {
+	policy := func() *google.IAMPolicy {
+		return &google.IAMPolicy{
+			Bindings: []google.IAMBinding{
+				{
+					Role:    "roles/bigquery.admin",
+					Members: []string{"user:user4@example.com"},
+				},
+				{
+					Role:    "roles/editor",
+					Members: []string{"user:user3@example.com"},
+				},
+			},
+		}
+	}
+	wantOverlay := Overlay{
+		testOrgPath:      policy(),
+		testFolderIDPath: policy(),
+		testProjectPath:  policy(),
+	}
+
+	tests := []struct {
+		name string
+		file string
+	}{
+		{
+			name: "binding_member",
+			file: "tf12plan_update_binding_member.json",
+		},
+		{
+			name: "iam_policy",
+			file: "tf12plan_update_iam_policy.json",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			file := filepath.Join(testDataDir, tt.file)
+			got, err := BuildOverlay(file, testProjectName, testAncestryName, true)
+			sortOverlay(got)
+			if err != nil {
+				t.Fatalf("BuildOverly(%s) error: %v", file, err)
+			}
+			if diff := cmp.Diff(wantOverlay, got); diff != "" {
+				t.Fatalf("BuildOverlay(%s)) diff (-want +got): %s", file, diff)
+			}
+		})
+	}
+}
+
+// TestOverlayWithDeletes verifies that the overlay handles iam resource creation correctly.
+func TestOverlayWithDeletes(t *testing.T) {
+	policy := func() *google.IAMPolicy {
+		return &google.IAMPolicy{
+			Bindings: []google.IAMBinding{},
+		}
+	}
+	wantOverlay := Overlay{
+		testOrgPath:      policy(),
+		testFolderIDPath: policy(),
+		testProjectPath:  policy(),
+	}
+
+	tests := []struct {
+		name string
+		file string
+	}{
+		{
+			name: "binding_member",
+			file: "tf12plan_delete_binding_member.json",
+		},
+		{
+			name: "iam_policy",
+			file: "tf12plan_delete_iam_policy.json",
+		},
+		{
+			name: "delete_resources",
+			file: "tf12plan_delete_resources.json",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			file := filepath.Join(testDataDir, tt.file)
+			got, err := BuildOverlay(file, testProjectName, testAncestryName, true)
+			sortOverlay(got)
+			if err != nil {
+				t.Fatalf("BuildOverly(%s) error: %v", file, err)
+			}
+			if diff := cmp.Diff(wantOverlay, got); diff != "" {
+				t.Fatalf("BuildOverlay(%s)) diff (-want +got): %s", file, diff)
+			}
+		})
+	}
+}
+
+// sortBindings provides a deterministic sorting of all fields in the Overlay.
+// Sorting is done in place.
+func sortOverlay(overlay Overlay) {
+	for _, policy := range overlay {
+		if policy == nil {
+			continue
+		}
+		// Sort the bindings themselves by role.
+		sort.Slice(policy.Bindings, func(i, j int) bool {
+			return policy.Bindings[i].Role < policy.Bindings[j].Role
+		})
+		// For each binding, ensure members are ordered.
+		for _, b := range policy.Bindings {
+			sort.Strings(b.Members)
+		}
+	}
+}
diff --git a/policy/testdata/tf12plan_create_binding_member.json b/policy/testdata/tf12plan_create_binding_member.json
new file mode 100644
index 00000000..f515d0dd
--- /dev/null
+++ b/policy/testdata/tf12plan_create_binding_member.json
@@ -0,0 +1,385 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.12.25",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_folder_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_folder_iam_binding",
+          "name": "binding",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "folder": "example-tf-folder",
+            "members": [
+              "user:user1@example.com"
+            ],
+            "role": "roles/editor"
+          }
+        },
+        {
+          "address": "google_folder_iam_member.member",
+          "mode": "managed",
+          "type": "google_folder_iam_member",
+          "name": "member",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "folder": "example-tf-folder",
+            "member": "user:user2@example.com",
+            "role": "roles/bigquery.admin"
+          }
+        },
+        {
+          "address": "google_organization_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_organization_iam_binding",
+          "name": "binding",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "members": [
+              "user:user1@example.com"
+            ],
+            "org_id": "123456789",
+            "role": "roles/editor"
+          }
+        },
+        {
+          "address": "google_organization_iam_member.member",
+          "mode": "managed",
+          "type": "google_organization_iam_member",
+          "name": "member",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "member": "user:user2@example.com",
+            "org_id": "123456789",
+            "role": "roles/bigquery.admin"
+          }
+        },
+        {
+          "address": "google_project_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_project_iam_binding",
+          "name": "binding",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "members": [
+              "user:user1@example.com"
+            ],
+            "project": "example-tf-project",
+            "role": "roles/editor"
+          }
+        },
+        {
+          "address": "google_project_iam_member.member",
+          "mode": "managed",
+          "type": "google_project_iam_member",
+          "name": "member",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "member": "user:user2@example.com",
+            "project": "example-tf-project",
+            "role": "roles/bigquery.admin"
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_folder_iam_binding.binding",
+      "mode": "managed",
+      "type": "google_folder_iam_binding",
+      "name": "binding",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "folder": "example-tf-folder",
+          "members": [
+            "user:user1@example.com"
+          ],
+          "role": "roles/editor"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true,
+          "members": [
+            false
+          ]
+        }
+      }
+    },
+    {
+      "address": "google_folder_iam_member.member",
+      "mode": "managed",
+      "type": "google_folder_iam_member",
+      "name": "member",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "folder": "example-tf-folder",
+          "member": "user:user2@example.com",
+          "role": "roles/bigquery.admin"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true
+        }
+      }
+    },
+    {
+      "address": "google_organization_iam_binding.binding",
+      "mode": "managed",
+      "type": "google_organization_iam_binding",
+      "name": "binding",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "members": [
+            "user:user1@example.com"
+          ],
+          "org_id": "123456789",
+          "role": "roles/editor"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true,
+          "members": [
+            false
+          ]
+        }
+      }
+    },
+    {
+      "address": "google_organization_iam_member.member",
+      "mode": "managed",
+      "type": "google_organization_iam_member",
+      "name": "member",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "member": "user:user2@example.com",
+          "org_id": "123456789",
+          "role": "roles/bigquery.admin"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true
+        }
+      }
+    },
+    {
+      "address": "google_project_iam_binding.binding",
+      "mode": "managed",
+      "type": "google_project_iam_binding",
+      "name": "binding",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "members": [
+            "user:user1@example.com"
+          ],
+          "project": "example-tf-project",
+          "role": "roles/editor"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true,
+          "members": [
+            false
+          ]
+        }
+      }
+    },
+    {
+      "address": "google_project_iam_member.member",
+      "mode": "managed",
+      "type": "google_project_iam_member",
+      "name": "member",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "member": "user:user2@example.com",
+          "project": "example-tf-project",
+          "role": "roles/bigquery.admin"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true
+        }
+      }
+    }
+  ],
+  "configuration": {
+    "provider_config": {
+      "google": {
+        "name": "google",
+        "expressions": {
+          "project": {
+            "constant_value": "example-tf-validator"
+          },
+          "region": {
+            "constant_value": "us-central1"
+          },
+          "zone": {
+            "constant_value": "us-central1-a"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_folder_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_folder_iam_binding",
+          "name": "binding",
+          "provider_config_key": "google",
+          "expressions": {
+            "folder": {
+              "constant_value": "example-tf-folder"
+            },
+            "members": {
+              "constant_value": [
+                "user:user1@example.com"
+              ]
+            },
+            "role": {
+              "constant_value": "roles/editor"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_folder_iam_member.member",
+          "mode": "managed",
+          "type": "google_folder_iam_member",
+          "name": "member",
+          "provider_config_key": "google",
+          "expressions": {
+            "folder": {
+              "constant_value": "example-tf-folder"
+            },
+            "member": {
+              "constant_value": "user:user2@example.com"
+            },
+            "role": {
+              "constant_value": "roles/bigquery.admin"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_organization_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_organization_iam_binding",
+          "name": "binding",
+          "provider_config_key": "google",
+          "expressions": {
+            "members": {
+              "constant_value": [
+                "user:user1@example.com"
+              ]
+            },
+            "org_id": {
+              "constant_value": "123456789"
+            },
+            "role": {
+              "constant_value": "roles/editor"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_organization_iam_member.member",
+          "mode": "managed",
+          "type": "google_organization_iam_member",
+          "name": "member",
+          "provider_config_key": "google",
+          "expressions": {
+            "member": {
+              "constant_value": "user:user2@example.com"
+            },
+            "org_id": {
+              "constant_value": "123456789"
+            },
+            "role": {
+              "constant_value": "roles/bigquery.admin"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_project_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_project_iam_binding",
+          "name": "binding",
+          "provider_config_key": "google",
+          "expressions": {
+            "members": {
+              "constant_value": [
+                "user:user1@example.com"
+              ]
+            },
+            "project": {
+              "constant_value": "example-tf-project"
+            },
+            "role": {
+              "constant_value": "roles/editor"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_project_iam_member.member",
+          "mode": "managed",
+          "type": "google_project_iam_member",
+          "name": "member",
+          "provider_config_key": "google",
+          "expressions": {
+            "member": {
+              "constant_value": "user:user2@example.com"
+            },
+            "project": {
+              "constant_value": "example-tf-project"
+            },
+            "role": {
+              "constant_value": "roles/bigquery.admin"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
diff --git a/policy/testdata/tf12plan_create_iam_policy.json b/policy/testdata/tf12plan_create_iam_policy.json
new file mode 100644
index 00000000..59122224
--- /dev/null
+++ b/policy/testdata/tf12plan_create_iam_policy.json
@@ -0,0 +1,261 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.12.25",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_folder_iam_policy.policy",
+          "mode": "managed",
+          "type": "google_folder_iam_policy",
+          "name": "policy",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "folder": "example-tf-folder",
+            "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+          }
+        },
+        {
+          "address": "google_organization_iam_policy.policy",
+          "mode": "managed",
+          "type": "google_organization_iam_policy",
+          "name": "policy",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "org_id": "123456789",
+            "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+          }
+        },
+        {
+          "address": "google_project_iam_policy.admin",
+          "mode": "managed",
+          "type": "google_project_iam_policy",
+          "name": "admin",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "authoritative": null,
+            "disable_project": null,
+            "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}",
+            "project": "example-tf-project"
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_folder_iam_policy.policy",
+      "mode": "managed",
+      "type": "google_folder_iam_policy",
+      "name": "policy",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "folder": "example-tf-folder",
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true
+        }
+      }
+    },
+    {
+      "address": "google_organization_iam_policy.policy",
+      "mode": "managed",
+      "type": "google_organization_iam_policy",
+      "name": "policy",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "org_id": "123456789",
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true
+        }
+      }
+    },
+    {
+      "address": "google_project_iam_policy.admin",
+      "mode": "managed",
+      "type": "google_project_iam_policy",
+      "name": "admin",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "authoritative": null,
+          "disable_project": null,
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}",
+          "project": "example-tf-project"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true,
+          "restore_policy": true
+        }
+      }
+    }
+  ],
+  "prior_state": {
+    "format_version": "0.1",
+    "terraform_version": "0.12.25",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "data.google_iam_policy.example",
+            "mode": "data",
+            "type": "google_iam_policy",
+            "name": "example",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "audit_config": null,
+              "binding": [
+                {
+                  "members": [
+                    "user:user1@example.com"
+                  ],
+                  "role": "roles/editor"
+                },
+                {
+                  "members": [
+                    "user:user2@example.com"
+                  ],
+                  "role": "roles/bigquery.admin"
+                }
+              ],
+              "id": "123456789",
+              "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+            }
+          }
+        ]
+      }
+    }
+  },
+  "configuration": {
+    "provider_config": {
+      "google": {
+        "name": "google",
+        "expressions": {
+          "project": {
+            "constant_value": "example-tf-validator"
+          },
+          "region": {
+            "constant_value": "us-central1"
+          },
+          "zone": {
+            "constant_value": "us-central1-a"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_folder_iam_policy.policy",
+          "mode": "managed",
+          "type": "google_folder_iam_policy",
+          "name": "policy",
+          "provider_config_key": "google",
+          "expressions": {
+            "folder": {
+              "constant_value": "example-tf-folder"
+            },
+            "policy_data": {
+              "references": [
+                "data.google_iam_policy.example"
+              ]
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_organization_iam_policy.policy",
+          "mode": "managed",
+          "type": "google_organization_iam_policy",
+          "name": "policy",
+          "provider_config_key": "google",
+          "expressions": {
+            "org_id": {
+              "constant_value": "123456789"
+            },
+            "policy_data": {
+              "references": [
+                "data.google_iam_policy.example"
+              ]
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_project_iam_policy.admin",
+          "mode": "managed",
+          "type": "google_project_iam_policy",
+          "name": "admin",
+          "provider_config_key": "google",
+          "expressions": {
+            "policy_data": {
+              "references": [
+                "data.google_iam_policy.example"
+              ]
+            },
+            "project": {
+              "constant_value": "example-tf-project"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "data.google_iam_policy.example",
+          "mode": "data",
+          "type": "google_iam_policy",
+          "name": "example",
+          "provider_config_key": "google",
+          "expressions": {
+            "binding": [
+              {
+                "members": {
+                  "constant_value": [
+                    "user:user1@example.com"
+                  ]
+                },
+                "role": {
+                  "constant_value": "roles/editor"
+                }
+              },
+              {
+                "members": {
+                  "constant_value": [
+                    "user:user2@example.com"
+                  ]
+                },
+                "role": {
+                  "constant_value": "roles/bigquery.admin"
+                }
+              }
+            ]
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
diff --git a/policy/testdata/tf12plan_delete_binding_member.json b/policy/testdata/tf12plan_delete_binding_member.json
new file mode 100644
index 00000000..8c932e5e
--- /dev/null
+++ b/policy/testdata/tf12plan_delete_binding_member.json
@@ -0,0 +1,546 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.12.25",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_folder.example_tf_folder",
+          "mode": "managed",
+          "type": "google_folder",
+          "name": "example_tf_folder",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "create_time": "2020-08-01T01:04:57.985Z",
+            "display_name": "example-tf-folder",
+            "id": "folders/123456789",
+            "lifecycle_state": "ACTIVE",
+            "name": "folders/123456789",
+            "parent": "organizations/123456789",
+            "timeouts": null
+          }
+        },
+        {
+          "address": "google_project.example_tf_project",
+          "mode": "managed",
+          "type": "google_project",
+          "name": "example_tf_project",
+          "provider_name": "google",
+          "schema_version": 1,
+          "values": {
+            "app_engine": [],
+            "auto_create_network": true,
+            "billing_account": "123456-ABCDEF-987654",
+            "folder_id": "123456789",
+            "id": "example-tf-project",
+            "labels": null,
+            "name": "example-tf-project",
+            "number": "123456789",
+            "org_id": "",
+            "policy_data": null,
+            "policy_etag": null,
+            "project_id": "example-tf-project",
+            "skip_delete": null,
+            "timeouts": null
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_folder.example_tf_folder",
+      "mode": "managed",
+      "type": "google_folder",
+      "name": "example_tf_folder",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "no-op"
+        ],
+        "before": {
+          "create_time": "2020-08-01T01:04:57.985Z",
+          "display_name": "example-tf-folder",
+          "id": "folders/123456789",
+          "lifecycle_state": "ACTIVE",
+          "name": "folders/123456789",
+          "parent": "organizations/123456789",
+          "timeouts": null
+        },
+        "after": {
+          "create_time": "2020-08-01T01:04:57.985Z",
+          "display_name": "example-tf-folder",
+          "id": "folders/123456789",
+          "lifecycle_state": "ACTIVE",
+          "name": "folders/123456789",
+          "parent": "organizations/123456789",
+          "timeouts": null
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_folder_iam_binding.binding",
+      "mode": "managed",
+      "type": "google_folder_iam_binding",
+      "name": "binding",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "etag": "BwWrxn+Sq/k=",
+          "folder": "folders/123456789",
+          "id": "folders/123456789/roles/editor",
+          "members": [
+            "user:user1@example.com"
+          ],
+          "role": "roles/editor"
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_folder_iam_member.member",
+      "mode": "managed",
+      "type": "google_folder_iam_member",
+      "name": "member",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "etag": "BwWrxn+Sq/k=",
+          "folder": "folders/123456789",
+          "id": "folders/123456789/roles/bigquery.admin/user:user2@example.com",
+          "member": "user:user2@example.com",
+          "role": "roles/bigquery.admin"
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_organization_iam_binding.binding",
+      "mode": "managed",
+      "type": "google_organization_iam_binding",
+      "name": "binding",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "etag": "BwWrxnDz7Zc=",
+          "id": "123456789/roles/editor",
+          "members": [
+            "user:user1@example.com"
+          ],
+          "org_id": "123456789",
+          "role": "roles/editor"
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_organization_iam_member.member",
+      "mode": "managed",
+      "type": "google_organization_iam_member",
+      "name": "member",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "etag": "BwWrxnDz7Zc=",
+          "id": "123456789/roles/bigquery.admin/user:user2@example.com",
+          "member": "user:user2@example.com",
+          "org_id": "123456789",
+          "role": "roles/bigquery.admin"
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_project.example_tf_project",
+      "mode": "managed",
+      "type": "google_project",
+      "name": "example_tf_project",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "no-op"
+        ],
+        "before": {
+          "app_engine": [],
+          "auto_create_network": true,
+          "billing_account": "123456-ABCDEF-987654",
+          "folder_id": "123456789",
+          "id": "example-tf-project",
+          "labels": null,
+          "name": "example-tf-project",
+          "number": "123456789",
+          "org_id": "",
+          "policy_data": null,
+          "policy_etag": null,
+          "project_id": "example-tf-project",
+          "skip_delete": null,
+          "timeouts": null
+        },
+        "after": {
+          "app_engine": [],
+          "auto_create_network": true,
+          "billing_account": "123456-ABCDEF-987654",
+          "folder_id": "123456789",
+          "id": "example-tf-project",
+          "labels": null,
+          "name": "example-tf-project",
+          "number": "123456789",
+          "org_id": "",
+          "policy_data": null,
+          "policy_etag": null,
+          "project_id": "example-tf-project",
+          "skip_delete": null,
+          "timeouts": null
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_project_iam_binding.binding",
+      "mode": "managed",
+      "type": "google_project_iam_binding",
+      "name": "binding",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "etag": "BwWrxoAEG3A=",
+          "id": "example-tf-project/roles/editor",
+          "members": [
+            "user:user1@example.com"
+          ],
+          "project": "example-tf-project",
+          "role": "roles/editor"
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_project_iam_member.member",
+      "mode": "managed",
+      "type": "google_project_iam_member",
+      "name": "member",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "etag": "BwWrxoAEG3A=",
+          "id": "example-tf-project/roles/bigquery.admin/user:user2@example.com",
+          "member": "user:user2@example.com",
+          "project": "example-tf-project",
+          "role": "roles/bigquery.admin"
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    }
+  ],
+  "prior_state": {
+    "format_version": "0.1",
+    "terraform_version": "0.12.25",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "data.google_iam_policy.example",
+            "mode": "data",
+            "type": "google_iam_policy",
+            "name": "example",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "audit_config": null,
+              "binding": [
+                {
+                  "members": [
+                    "user:user1@example.com"
+                  ],
+                  "role": "roles/editor"
+                },
+                {
+                  "members": [
+                    "user:user2@example.com"
+                  ],
+                  "role": "roles/bigquery.admin"
+                }
+              ],
+              "id": "123456789",
+              "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+            }
+          },
+          {
+            "address": "data.google_organization.assist",
+            "mode": "data",
+            "type": "google_organization",
+            "name": "assist",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "create_time": "2020-01-13T17:05:56.627Z",
+              "directory_customer_id": "C04jvfuw8",
+              "domain": "iam-assist-test.joonix.net",
+              "id": "123456789",
+              "lifecycle_state": "ACTIVE",
+              "name": "organizations/123456789",
+              "organization": "organizations/123456789"
+            }
+          },
+          {
+            "address": "google_folder.example_tf_folder",
+            "mode": "managed",
+            "type": "google_folder",
+            "name": "example_tf_folder",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "create_time": "2020-08-01T01:04:57.985Z",
+              "display_name": "example-tf-folder",
+              "id": "folders/123456789",
+              "lifecycle_state": "ACTIVE",
+              "name": "folders/123456789",
+              "parent": "organizations/123456789",
+              "timeouts": null
+            }
+          },
+          {
+            "address": "google_folder_iam_binding.binding",
+            "mode": "managed",
+            "type": "google_folder_iam_binding",
+            "name": "binding",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxn+Sq/k=",
+              "folder": "folders/123456789",
+              "id": "folders/123456789/roles/editor",
+              "members": [
+                "user:user1@example.com"
+              ],
+              "role": "roles/editor"
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder"
+            ]
+          },
+          {
+            "address": "google_folder_iam_member.member",
+            "mode": "managed",
+            "type": "google_folder_iam_member",
+            "name": "member",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxn+Sq/k=",
+              "folder": "folders/123456789",
+              "id": "folders/123456789/roles/bigquery.admin/user:user2@example.com",
+              "member": "user:user2@example.com",
+              "role": "roles/bigquery.admin"
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder"
+            ]
+          },
+          {
+            "address": "google_organization_iam_binding.binding",
+            "mode": "managed",
+            "type": "google_organization_iam_binding",
+            "name": "binding",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxnDz7Zc=",
+              "id": "123456789/roles/editor",
+              "members": [
+                "user:user1@example.com"
+              ],
+              "org_id": "123456789",
+              "role": "roles/editor"
+            }
+          },
+          {
+            "address": "google_organization_iam_member.member",
+            "mode": "managed",
+            "type": "google_organization_iam_member",
+            "name": "member",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxnDz7Zc=",
+              "id": "123456789/roles/bigquery.admin/user:user2@example.com",
+              "member": "user:user2@example.com",
+              "org_id": "123456789",
+              "role": "roles/bigquery.admin"
+            }
+          },
+          {
+            "address": "google_project.example_tf_project",
+            "mode": "managed",
+            "type": "google_project",
+            "name": "example_tf_project",
+            "provider_name": "google",
+            "schema_version": 1,
+            "values": {
+              "app_engine": [],
+              "auto_create_network": true,
+              "billing_account": "123456-ABCDEF-987654",
+              "folder_id": "123456789",
+              "id": "example-tf-project",
+              "labels": null,
+              "name": "example-tf-project",
+              "number": "123456789",
+              "org_id": "",
+              "policy_data": null,
+              "policy_etag": null,
+              "project_id": "example-tf-project",
+              "skip_delete": null,
+              "timeouts": null
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder"
+            ]
+          },
+          {
+            "address": "google_project_iam_binding.binding",
+            "mode": "managed",
+            "type": "google_project_iam_binding",
+            "name": "binding",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxoAEG3A=",
+              "id": "example-tf-project/roles/editor",
+              "members": [
+                "user:user1@example.com"
+              ],
+              "project": "example-tf-project",
+              "role": "roles/editor"
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder",
+              "google_project.example_tf_project"
+            ]
+          },
+          {
+            "address": "google_project_iam_member.member",
+            "mode": "managed",
+            "type": "google_project_iam_member",
+            "name": "member",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxoAEG3A=",
+              "id": "example-tf-project/roles/bigquery.admin/user:user2@example.com",
+              "member": "user:user2@example.com",
+              "project": "example-tf-project",
+              "role": "roles/bigquery.admin"
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder",
+              "google_project.example_tf_project"
+            ]
+          }
+        ]
+      }
+    }
+  },
+  "configuration": {
+    "provider_config": {
+      "google": {
+        "name": "google",
+        "expressions": {
+          "project": {
+            "constant_value": "tf-validator"
+          },
+          "region": {
+            "constant_value": "us-central1"
+          },
+          "zone": {
+            "constant_value": "us-central1-a"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_folder.example_tf_folder",
+          "mode": "managed",
+          "type": "google_folder",
+          "name": "example_tf_folder",
+          "provider_config_key": "google",
+          "expressions": {
+            "display_name": {
+              "constant_value": "example-tf-folder"
+            },
+            "parent": {
+              "references": [
+                "data.google_organization.assist"
+              ]
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_project.example_tf_project",
+          "mode": "managed",
+          "type": "google_project",
+          "name": "example_tf_project",
+          "provider_config_key": "google",
+          "expressions": {
+            "billing_account": {
+              "constant_value": "123456-ABCDEF-987654"
+            },
+            "folder_id": {
+              "references": [
+                "google_folder.example_tf_folder"
+              ]
+            },
+            "name": {
+              "constant_value": "example-tf-project"
+            },
+            "project_id": {
+              "constant_value": "example-tf-project"
+            }
+          },
+          "schema_version": 1
+        },
+        {
+          "address": "data.google_organization.assist",
+          "mode": "data",
+          "type": "google_organization",
+          "name": "assist",
+          "provider_config_key": "google",
+          "expressions": {
+            "organization": {
+              "constant_value": "organizations/123456789"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
diff --git a/policy/testdata/tf12plan_delete_iam_policy.json b/policy/testdata/tf12plan_delete_iam_policy.json
new file mode 100644
index 00000000..4ab0d793
--- /dev/null
+++ b/policy/testdata/tf12plan_delete_iam_policy.json
@@ -0,0 +1,493 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.12.25",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_folder.example_tf_folder",
+          "mode": "managed",
+          "type": "google_folder",
+          "name": "example_tf_folder",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "create_time": "2020-08-01T01:04:57.985Z",
+            "display_name": "example-tf-folder",
+            "id": "folders/123456789",
+            "lifecycle_state": "ACTIVE",
+            "name": "folders/123456789",
+            "parent": "organizations/123456789",
+            "timeouts": null
+          }
+        },
+        {
+          "address": "google_project.example_tf_project",
+          "mode": "managed",
+          "type": "google_project",
+          "name": "example_tf_project",
+          "provider_name": "google",
+          "schema_version": 1,
+          "values": {
+            "app_engine": [],
+            "auto_create_network": true,
+            "billing_account": "123456-ABCDEF-987654",
+            "folder_id": "123456789",
+            "id": "example-tf-project",
+            "labels": null,
+            "name": "example-tf-project",
+            "number": "123456789",
+            "org_id": "",
+            "policy_data": null,
+            "policy_etag": null,
+            "project_id": "example-tf-project",
+            "skip_delete": null,
+            "timeouts": null
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_folder.example_tf_folder",
+      "mode": "managed",
+      "type": "google_folder",
+      "name": "example_tf_folder",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "no-op"
+        ],
+        "before": {
+          "create_time": "2020-08-01T01:04:57.985Z",
+          "display_name": "example-tf-folder",
+          "id": "folders/123456789",
+          "lifecycle_state": "ACTIVE",
+          "name": "folders/123456789",
+          "parent": "organizations/123456789",
+          "timeouts": null
+        },
+        "after": {
+          "create_time": "2020-08-01T01:04:57.985Z",
+          "display_name": "example-tf-folder",
+          "id": "folders/123456789",
+          "lifecycle_state": "ACTIVE",
+          "name": "folders/123456789",
+          "parent": "organizations/123456789",
+          "timeouts": null
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_folder_iam_policy.policy",
+      "mode": "managed",
+      "type": "google_folder_iam_policy",
+      "name": "policy",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "etag": "BwWrxn+Sq/k=",
+          "folder": "folders/123456789",
+          "id": "folders/123456789",
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_organization_iam_binding.binding",
+      "mode": "managed",
+      "type": "google_organization_iam_binding",
+      "name": "binding",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "etag": "BwWrxnDz7Zc=",
+          "id": "123456789/roles/editor",
+          "members": [
+            "user:user1@example.com"
+          ],
+          "org_id": "123456789",
+          "role": "roles/editor"
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_organization_iam_member.member",
+      "mode": "managed",
+      "type": "google_organization_iam_member",
+      "name": "member",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "etag": "BwWrxnDz7Zc=",
+          "id": "123456789/roles/bigquery.admin/user:user2@example.com",
+          "member": "user:user2@example.com",
+          "org_id": "123456789",
+          "role": "roles/bigquery.admin"
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_project.example_tf_project",
+      "mode": "managed",
+      "type": "google_project",
+      "name": "example_tf_project",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "no-op"
+        ],
+        "before": {
+          "app_engine": [],
+          "auto_create_network": true,
+          "billing_account": "123456-ABCDEF-987654",
+          "folder_id": "123456789",
+          "id": "example-tf-project",
+          "labels": null,
+          "name": "example-tf-project",
+          "number": "123456789",
+          "org_id": "",
+          "policy_data": null,
+          "policy_etag": null,
+          "project_id": "example-tf-project",
+          "skip_delete": null,
+          "timeouts": null
+        },
+        "after": {
+          "app_engine": [],
+          "auto_create_network": true,
+          "billing_account": "123456-ABCDEF-987654",
+          "folder_id": "123456789",
+          "id": "example-tf-project",
+          "labels": null,
+          "name": "example-tf-project",
+          "number": "123456789",
+          "org_id": "",
+          "policy_data": null,
+          "policy_etag": null,
+          "project_id": "example-tf-project",
+          "skip_delete": null,
+          "timeouts": null
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_project_iam_policy.policy",
+      "mode": "managed",
+      "type": "google_project_iam_policy",
+      "name": "policy",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "authoritative": null,
+          "disable_project": null,
+          "etag": "BwWrxn9rU1A=",
+          "id": "example-tf-project",
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}",
+          "project": "example-tf-project",
+          "restore_policy": null
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    }
+  ],
+  "prior_state": {
+    "format_version": "0.1",
+    "terraform_version": "0.12.25",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "data.google_iam_policy.example",
+            "mode": "data",
+            "type": "google_iam_policy",
+            "name": "example",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "audit_config": null,
+              "binding": [
+                {
+                  "members": [
+                    "user:user1@example.com"
+                  ],
+                  "role": "roles/editor"
+                },
+                {
+                  "members": [
+                    "user:user2@example.com"
+                  ],
+                  "role": "roles/bigquery.admin"
+                }
+              ],
+              "id": "123456789",
+              "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+            }
+          },
+          {
+            "address": "data.google_organization.assist",
+            "mode": "data",
+            "type": "google_organization",
+            "name": "assist",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "create_time": "2020-01-13T17:05:56.627Z",
+              "directory_customer_id": "C04jvfuw8",
+              "domain": "iam-assist-test.joonix.net",
+              "id": "123456789",
+              "lifecycle_state": "ACTIVE",
+              "name": "organizations/123456789",
+              "organization": "organizations/123456789"
+            }
+          },
+          {
+            "address": "google_folder.example_tf_folder",
+            "mode": "managed",
+            "type": "google_folder",
+            "name": "example_tf_folder",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "create_time": "2020-08-01T01:04:57.985Z",
+              "display_name": "example-tf-folder",
+              "id": "folders/123456789",
+              "lifecycle_state": "ACTIVE",
+              "name": "folders/123456789",
+              "parent": "organizations/123456789",
+              "timeouts": null
+            }
+          },
+          {
+            "address": "google_folder_iam_policy.policy",
+            "mode": "managed",
+            "type": "google_folder_iam_policy",
+            "name": "policy",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxn+Sq/k=",
+              "folder": "folders/123456789",
+              "id": "folders/123456789",
+              "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder"
+            ]
+          },
+          {
+            "address": "google_organization_iam_binding.binding",
+            "mode": "managed",
+            "type": "google_organization_iam_binding",
+            "name": "binding",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxnDz7Zc=",
+              "id": "123456789/roles/editor",
+              "members": [
+                "user:user1@example.com"
+              ],
+              "org_id": "123456789",
+              "role": "roles/editor"
+            }
+          },
+          {
+            "address": "google_organization_iam_member.member",
+            "mode": "managed",
+            "type": "google_organization_iam_member",
+            "name": "member",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxnDz7Zc=",
+              "id": "123456789/roles/bigquery.admin/user:user2@example.com",
+              "member": "user:user2@example.com",
+              "org_id": "123456789",
+              "role": "roles/bigquery.admin"
+            }
+          },
+          {
+            "address": "google_project.example_tf_project",
+            "mode": "managed",
+            "type": "google_project",
+            "name": "example_tf_project",
+            "provider_name": "google",
+            "schema_version": 1,
+            "values": {
+              "app_engine": [],
+              "auto_create_network": true,
+              "billing_account": "123456-ABCDEF-987654",
+              "folder_id": "123456789",
+              "id": "example-tf-project",
+              "labels": null,
+              "name": "example-tf-project",
+              "number": "123456789",
+              "org_id": "",
+              "policy_data": null,
+              "policy_etag": null,
+              "project_id": "example-tf-project",
+              "skip_delete": null,
+              "timeouts": null
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder"
+            ]
+          },
+          {
+            "address": "google_project_iam_policy.policy",
+            "mode": "managed",
+            "type": "google_project_iam_policy",
+            "name": "policy",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "authoritative": null,
+              "disable_project": null,
+              "etag": "BwWrxn9rU1A=",
+              "id": "example-tf-project",
+              "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}",
+              "project": "example-tf-project",
+              "restore_policy": null
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder",
+              "google_project.example_tf_project"
+            ]
+          }
+        ]
+      }
+    }
+  },
+  "configuration": {
+    "provider_config": {
+      "google": {
+        "name": "google",
+        "expressions": {
+          "project": {
+            "constant_value": "tf-validator"
+          },
+          "region": {
+            "constant_value": "us-central1"
+          },
+          "zone": {
+            "constant_value": "us-central1-a"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_folder.example_tf_folder",
+          "mode": "managed",
+          "type": "google_folder",
+          "name": "example_tf_folder",
+          "provider_config_key": "google",
+          "expressions": {
+            "display_name": {
+              "constant_value": "example-tf-folder"
+            },
+            "parent": {
+              "references": [
+                "data.google_organization.assist"
+              ]
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_project.example_tf_project",
+          "mode": "managed",
+          "type": "google_project",
+          "name": "example_tf_project",
+          "provider_config_key": "google",
+          "expressions": {
+            "billing_account": {
+              "constant_value": "123456-ABCDEF-987654"
+            },
+            "folder_id": {
+              "references": [
+                "google_folder.example_tf_folder"
+              ]
+            },
+            "name": {
+              "constant_value": "example-tf-project"
+            },
+            "project_id": {
+              "constant_value": "example-tf-project"
+            }
+          },
+          "schema_version": 1
+        },
+        {
+          "address": "data.google_iam_policy.example",
+          "mode": "data",
+          "type": "google_iam_policy",
+          "name": "example",
+          "provider_config_key": "google",
+          "expressions": {
+            "binding": [
+              {
+                "members": {
+                  "constant_value": [
+                    "user:user3@example.com"
+                  ]
+                },
+                "role": {
+                  "constant_value": "roles/editor"
+                }
+              },
+              {
+                "members": {
+                  "constant_value": [
+                    "user:user4@example.com"
+                  ]
+                },
+                "role": {
+                  "constant_value": "roles/bigquery.admin"
+                }
+              }
+            ]
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "data.google_organization.assist",
+          "mode": "data",
+          "type": "google_organization",
+          "name": "assist",
+          "provider_config_key": "google",
+          "expressions": {
+            "organization": {
+              "constant_value": "organizations/123456789"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
diff --git a/policy/testdata/tf12plan_delete_resources.json b/policy/testdata/tf12plan_delete_resources.json
new file mode 100644
index 00000000..426127b6
--- /dev/null
+++ b/policy/testdata/tf12plan_delete_resources.json
@@ -0,0 +1,336 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.12.25",
+  "planned_values": {
+    "root_module": {}
+  },
+  "resource_changes": [
+    {
+      "address": "google_folder.example_tf_folder",
+      "mode": "managed",
+      "type": "google_folder",
+      "name": "example_tf_folder",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "create_time": "2020-08-01T01:04:57.985Z",
+          "display_name": "example-tf-folder",
+          "id": "folders/123456789",
+          "lifecycle_state": "ACTIVE",
+          "name": "folders/123456789",
+          "parent": "organizations/123456789",
+          "timeouts": null
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_folder_iam_policy.policy",
+      "mode": "managed",
+      "type": "google_folder_iam_policy",
+      "name": "policy",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "etag": "BwWrxn+Sq/k=",
+          "folder": "folders/123456789",
+          "id": "folders/123456789",
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_organization_iam_binding.binding",
+      "mode": "managed",
+      "type": "google_organization_iam_binding",
+      "name": "binding",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "etag": "BwWrxnDz7Zc=",
+          "id": "123456789/roles/editor",
+          "members": [
+            "user:user1@example.com"
+          ],
+          "org_id": "123456789",
+          "role": "roles/editor"
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_organization_iam_member.member",
+      "mode": "managed",
+      "type": "google_organization_iam_member",
+      "name": "member",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "etag": "BwWrxnDz7Zc=",
+          "id": "123456789/roles/bigquery.admin/user:user2@example.com",
+          "member": "user:user2@example.com",
+          "org_id": "123456789",
+          "role": "roles/bigquery.admin"
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_project.example_tf_project",
+      "mode": "managed",
+      "type": "google_project",
+      "name": "example_tf_project",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "app_engine": [],
+          "auto_create_network": true,
+          "billing_account": "123456-ABCDEF-987654",
+          "folder_id": "123456789",
+          "id": "example-tf-project",
+          "labels": null,
+          "name": "example-tf-project",
+          "number": "123456789",
+          "org_id": "",
+          "policy_data": null,
+          "policy_etag": null,
+          "project_id": "example-tf-project",
+          "skip_delete": null,
+          "timeouts": null
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_project_iam_policy.policy",
+      "mode": "managed",
+      "type": "google_project_iam_policy",
+      "name": "policy",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete"
+        ],
+        "before": {
+          "authoritative": null,
+          "disable_project": null,
+          "etag": "BwWrxn9rU1A=",
+          "id": "example-tf-project",
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}",
+          "project": "example-tf-project",
+          "restore_policy": null
+        },
+        "after": null,
+        "after_unknown": {}
+      }
+    }
+  ],
+  "prior_state": {
+    "format_version": "0.1",
+    "terraform_version": "0.12.25",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "data.google_iam_policy.example",
+            "mode": "data",
+            "type": "google_iam_policy",
+            "name": "example",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "audit_config": null,
+              "binding": [
+                {
+                  "members": [
+                    "user:user1@example.com"
+                  ],
+                  "role": "roles/editor"
+                },
+                {
+                  "members": [
+                    "user:user2@example.com"
+                  ],
+                  "role": "roles/bigquery.admin"
+                }
+              ],
+              "id": "123456789",
+              "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+            }
+          },
+          {
+            "address": "data.google_organization.assist",
+            "mode": "data",
+            "type": "google_organization",
+            "name": "assist",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "create_time": "2020-01-13T17:05:56.627Z",
+              "directory_customer_id": "C04jvfuw8",
+              "domain": "iam-assist-test.joonix.net",
+              "id": "123456789",
+              "lifecycle_state": "ACTIVE",
+              "name": "organizations/123456789",
+              "organization": "organizations/123456789"
+            }
+          },
+          {
+            "address": "google_folder.example_tf_folder",
+            "mode": "managed",
+            "type": "google_folder",
+            "name": "example_tf_folder",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "create_time": "2020-08-01T01:04:57.985Z",
+              "display_name": "example-tf-folder",
+              "id": "folders/123456789",
+              "lifecycle_state": "ACTIVE",
+              "name": "folders/123456789",
+              "parent": "organizations/123456789",
+              "timeouts": null
+            }
+          },
+          {
+            "address": "google_folder_iam_policy.policy",
+            "mode": "managed",
+            "type": "google_folder_iam_policy",
+            "name": "policy",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxn+Sq/k=",
+              "folder": "folders/123456789",
+              "id": "folders/123456789",
+              "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder"
+            ]
+          },
+          {
+            "address": "google_organization_iam_binding.binding",
+            "mode": "managed",
+            "type": "google_organization_iam_binding",
+            "name": "binding",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxnDz7Zc=",
+              "id": "123456789/roles/editor",
+              "members": [
+                "user:user1@example.com"
+              ],
+              "org_id": "123456789",
+              "role": "roles/editor"
+            }
+          },
+          {
+            "address": "google_organization_iam_member.member",
+            "mode": "managed",
+            "type": "google_organization_iam_member",
+            "name": "member",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxnDz7Zc=",
+              "id": "123456789/roles/bigquery.admin/user:user2@example.com",
+              "member": "user:user2@example.com",
+              "org_id": "123456789",
+              "role": "roles/bigquery.admin"
+            }
+          },
+          {
+            "address": "google_project.example_tf_project",
+            "mode": "managed",
+            "type": "google_project",
+            "name": "example_tf_project",
+            "provider_name": "google",
+            "schema_version": 1,
+            "values": {
+              "app_engine": [],
+              "auto_create_network": true,
+              "billing_account": "123456-ABCDEF-987654",
+              "folder_id": "123456789",
+              "id": "example-tf-project",
+              "labels": null,
+              "name": "example-tf-project",
+              "number": "123456789",
+              "org_id": "",
+              "policy_data": null,
+              "policy_etag": null,
+              "project_id": "example-tf-project",
+              "skip_delete": null,
+              "timeouts": null
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder"
+            ]
+          },
+          {
+            "address": "google_project_iam_policy.policy",
+            "mode": "managed",
+            "type": "google_project_iam_policy",
+            "name": "policy",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "authoritative": null,
+              "disable_project": null,
+              "etag": "BwWrxn9rU1A=",
+              "id": "example-tf-project",
+              "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}",
+              "project": "example-tf-project",
+              "restore_policy": null
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder",
+              "google_project.example_tf_project"
+            ]
+          }
+        ]
+      }
+    }
+  },
+  "configuration": {
+    "provider_config": {
+      "google": {
+        "name": "google",
+        "expressions": {
+          "project": {
+            "constant_value": "tf-validator"
+          },
+          "region": {
+            "constant_value": "us-central1"
+          },
+          "zone": {
+            "constant_value": "us-central1-a"
+          }
+        }
+      }
+    },
+    "root_module": {}
+  }
+}
diff --git a/policy/testdata/tf12plan_update_binding_member.json b/policy/testdata/tf12plan_update_binding_member.json
new file mode 100644
index 00000000..6e3be7e1
--- /dev/null
+++ b/policy/testdata/tf12plan_update_binding_member.json
@@ -0,0 +1,816 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.12.25",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_folder.example_tf_folder",
+          "mode": "managed",
+          "type": "google_folder",
+          "name": "example_tf_folder",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "create_time": "2020-08-01T01:04:57.985Z",
+            "display_name": "example-tf-folder",
+            "id": "folders/123456789",
+            "lifecycle_state": "ACTIVE",
+            "name": "folders/123456789",
+            "parent": "organizations/123456789",
+            "timeouts": null
+          }
+        },
+        {
+          "address": "google_folder_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_folder_iam_binding",
+          "name": "binding",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "etag": "BwWrxn+Sq/k=",
+            "folder": "folders/123456789",
+            "id": "folders/123456789/roles/editor",
+            "members": [
+              "user:user3@example.com"
+            ],
+            "role": "roles/editor"
+          }
+        },
+        {
+          "address": "google_folder_iam_member.member",
+          "mode": "managed",
+          "type": "google_folder_iam_member",
+          "name": "member",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "folder": "folders/123456789",
+            "member": "user:user4@example.com",
+            "role": "roles/bigquery.admin"
+          }
+        },
+        {
+          "address": "google_organization_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_organization_iam_binding",
+          "name": "binding",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "etag": "BwWrxnDz7Zc=",
+            "id": "123456789/roles/editor",
+            "members": [
+              "user:user3@example.com"
+            ],
+            "org_id": "123456789",
+            "role": "roles/editor"
+          }
+        },
+        {
+          "address": "google_organization_iam_member.member",
+          "mode": "managed",
+          "type": "google_organization_iam_member",
+          "name": "member",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "member": "user:user4@example.com",
+            "org_id": "123456789",
+            "role": "roles/bigquery.admin"
+          }
+        },
+        {
+          "address": "google_project.example_tf_project",
+          "mode": "managed",
+          "type": "google_project",
+          "name": "example_tf_project",
+          "provider_name": "google",
+          "schema_version": 1,
+          "values": {
+            "app_engine": [],
+            "auto_create_network": true,
+            "billing_account": "123456-ABCDEF-987654",
+            "folder_id": "123456789",
+            "id": "example-tf-project",
+            "labels": null,
+            "name": "example-tf-project",
+            "number": "123456789",
+            "org_id": "",
+            "policy_data": null,
+            "policy_etag": null,
+            "project_id": "example-tf-project",
+            "skip_delete": null,
+            "timeouts": null
+          }
+        },
+        {
+          "address": "google_project_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_project_iam_binding",
+          "name": "binding",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "etag": "BwWrxoAEG3A=",
+            "id": "example-tf-project/roles/editor",
+            "members": [
+              "user:user3@example.com"
+            ],
+            "project": "example-tf-project",
+            "role": "roles/editor"
+          }
+        },
+        {
+          "address": "google_project_iam_member.member",
+          "mode": "managed",
+          "type": "google_project_iam_member",
+          "name": "member",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "member": "user:user4@example.com",
+            "project": "example-tf-project",
+            "role": "roles/bigquery.admin"
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_folder.example_tf_folder",
+      "mode": "managed",
+      "type": "google_folder",
+      "name": "example_tf_folder",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "no-op"
+        ],
+        "before": {
+          "create_time": "2020-08-01T01:04:57.985Z",
+          "display_name": "example-tf-folder",
+          "id": "folders/123456789",
+          "lifecycle_state": "ACTIVE",
+          "name": "folders/123456789",
+          "parent": "organizations/123456789",
+          "timeouts": null
+        },
+        "after": {
+          "create_time": "2020-08-01T01:04:57.985Z",
+          "display_name": "example-tf-folder",
+          "id": "folders/123456789",
+          "lifecycle_state": "ACTIVE",
+          "name": "folders/123456789",
+          "parent": "organizations/123456789",
+          "timeouts": null
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_folder_iam_binding.binding",
+      "mode": "managed",
+      "type": "google_folder_iam_binding",
+      "name": "binding",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "before": {
+          "etag": "BwWrxn+Sq/k=",
+          "folder": "folders/123456789",
+          "id": "folders/123456789/roles/editor",
+          "members": [
+            "user:user1@example.com"
+          ],
+          "role": "roles/editor"
+        },
+        "after": {
+          "etag": "BwWrxn+Sq/k=",
+          "folder": "folders/123456789",
+          "id": "folders/123456789/roles/editor",
+          "members": [
+            "user:user3@example.com"
+          ],
+          "role": "roles/editor"
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_folder_iam_member.member",
+      "mode": "managed",
+      "type": "google_folder_iam_member",
+      "name": "member",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete",
+          "create"
+        ],
+        "before": {
+          "etag": "BwWrxn+Sq/k=",
+          "folder": "folders/123456789",
+          "id": "folders/123456789/roles/bigquery.admin/user:user2@example.com",
+          "member": "user:user2@example.com",
+          "role": "roles/bigquery.admin"
+        },
+        "after": {
+          "folder": "folders/123456789",
+          "member": "user:user4@example.com",
+          "role": "roles/bigquery.admin"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true
+        }
+      }
+    },
+    {
+      "address": "google_organization_iam_binding.binding",
+      "mode": "managed",
+      "type": "google_organization_iam_binding",
+      "name": "binding",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "before": {
+          "etag": "BwWrxnDz7Zc=",
+          "id": "123456789/roles/editor",
+          "members": [
+            "user:user1@example.com"
+          ],
+          "org_id": "123456789",
+          "role": "roles/editor"
+        },
+        "after": {
+          "etag": "BwWrxnDz7Zc=",
+          "id": "123456789/roles/editor",
+          "members": [
+            "user:user3@example.com"
+          ],
+          "org_id": "123456789",
+          "role": "roles/editor"
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_organization_iam_member.member",
+      "mode": "managed",
+      "type": "google_organization_iam_member",
+      "name": "member",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete",
+          "create"
+        ],
+        "before": {
+          "etag": "BwWrxnDz7Zc=",
+          "id": "123456789/roles/bigquery.admin/user:user2@example.com",
+          "member": "user:user2@example.com",
+          "org_id": "123456789",
+          "role": "roles/bigquery.admin"
+        },
+        "after": {
+          "member": "user:user4@example.com",
+          "org_id": "123456789",
+          "role": "roles/bigquery.admin"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true
+        }
+      }
+    },
+    {
+      "address": "google_project.example_tf_project",
+      "mode": "managed",
+      "type": "google_project",
+      "name": "example_tf_project",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "no-op"
+        ],
+        "before": {
+          "app_engine": [],
+          "auto_create_network": true,
+          "billing_account": "123456-ABCDEF-987654",
+          "folder_id": "123456789",
+          "id": "example-tf-project",
+          "labels": null,
+          "name": "example-tf-project",
+          "number": "123456789",
+          "org_id": "",
+          "policy_data": null,
+          "policy_etag": null,
+          "project_id": "example-tf-project",
+          "skip_delete": null,
+          "timeouts": null
+        },
+        "after": {
+          "app_engine": [],
+          "auto_create_network": true,
+          "billing_account": "123456-ABCDEF-987654",
+          "folder_id": "123456789",
+          "id": "example-tf-project",
+          "labels": null,
+          "name": "example-tf-project",
+          "number": "123456789",
+          "org_id": "",
+          "policy_data": null,
+          "policy_etag": null,
+          "project_id": "example-tf-project",
+          "skip_delete": null,
+          "timeouts": null
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_project_iam_binding.binding",
+      "mode": "managed",
+      "type": "google_project_iam_binding",
+      "name": "binding",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "before": {
+          "etag": "BwWrxoAEG3A=",
+          "id": "example-tf-project/roles/editor",
+          "members": [
+            "user:user1@example.com"
+          ],
+          "project": "example-tf-project",
+          "role": "roles/editor"
+        },
+        "after": {
+          "etag": "BwWrxoAEG3A=",
+          "id": "example-tf-project/roles/editor",
+          "members": [
+            "user:user3@example.com"
+          ],
+          "project": "example-tf-project",
+          "role": "roles/editor"
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_project_iam_member.member",
+      "mode": "managed",
+      "type": "google_project_iam_member",
+      "name": "member",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete",
+          "create"
+        ],
+        "before": {
+          "etag": "BwWrxoAEG3A=",
+          "id": "example-tf-project/roles/bigquery.admin/user:user2@example.com",
+          "member": "user:user2@example.com",
+          "project": "example-tf-project",
+          "role": "roles/bigquery.admin"
+        },
+        "after": {
+          "member": "user:user4@example.com",
+          "project": "example-tf-project",
+          "role": "roles/bigquery.admin"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true
+        }
+      }
+    }
+  ],
+  "prior_state": {
+    "format_version": "0.1",
+    "terraform_version": "0.12.25",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "data.google_iam_policy.example",
+            "mode": "data",
+            "type": "google_iam_policy",
+            "name": "example",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "audit_config": null,
+              "binding": [
+                {
+                  "members": [
+                    "user:user1@example.com"
+                  ],
+                  "role": "roles/editor"
+                },
+                {
+                  "members": [
+                    "user:user2@example.com"
+                  ],
+                  "role": "roles/bigquery.admin"
+                }
+              ],
+              "id": "123456789",
+              "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+            }
+          },
+          {
+            "address": "data.google_organization.assist",
+            "mode": "data",
+            "type": "google_organization",
+            "name": "assist",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "create_time": "2020-01-13T17:05:56.627Z",
+              "directory_customer_id": "C04jvfuw8",
+              "domain": "iam-assist-test.joonix.net",
+              "id": "123456789",
+              "lifecycle_state": "ACTIVE",
+              "name": "organizations/123456789",
+              "organization": "organizations/123456789"
+            }
+          },
+          {
+            "address": "google_folder.example_tf_folder",
+            "mode": "managed",
+            "type": "google_folder",
+            "name": "example_tf_folder",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "create_time": "2020-08-01T01:04:57.985Z",
+              "display_name": "example-tf-folder",
+              "id": "folders/123456789",
+              "lifecycle_state": "ACTIVE",
+              "name": "folders/123456789",
+              "parent": "organizations/123456789",
+              "timeouts": null
+            }
+          },
+          {
+            "address": "google_folder_iam_binding.binding",
+            "mode": "managed",
+            "type": "google_folder_iam_binding",
+            "name": "binding",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxn+Sq/k=",
+              "folder": "folders/123456789",
+              "id": "folders/123456789/roles/editor",
+              "members": [
+                "user:user1@example.com"
+              ],
+              "role": "roles/editor"
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder"
+            ]
+          },
+          {
+            "address": "google_folder_iam_member.member",
+            "mode": "managed",
+            "type": "google_folder_iam_member",
+            "name": "member",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxn+Sq/k=",
+              "folder": "folders/123456789",
+              "id": "folders/123456789/roles/bigquery.admin/user:user2@example.com",
+              "member": "user:user2@example.com",
+              "role": "roles/bigquery.admin"
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder"
+            ]
+          },
+          {
+            "address": "google_organization_iam_binding.binding",
+            "mode": "managed",
+            "type": "google_organization_iam_binding",
+            "name": "binding",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxnDz7Zc=",
+              "id": "123456789/roles/editor",
+              "members": [
+                "user:user1@example.com"
+              ],
+              "org_id": "123456789",
+              "role": "roles/editor"
+            }
+          },
+          {
+            "address": "google_organization_iam_member.member",
+            "mode": "managed",
+            "type": "google_organization_iam_member",
+            "name": "member",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxnDz7Zc=",
+              "id": "123456789/roles/bigquery.admin/user:user2@example.com",
+              "member": "user:user2@example.com",
+              "org_id": "123456789",
+              "role": "roles/bigquery.admin"
+            }
+          },
+          {
+            "address": "google_project.example_tf_project",
+            "mode": "managed",
+            "type": "google_project",
+            "name": "example_tf_project",
+            "provider_name": "google",
+            "schema_version": 1,
+            "values": {
+              "app_engine": [],
+              "auto_create_network": true,
+              "billing_account": "123456-ABCDEF-987654",
+              "folder_id": "123456789",
+              "id": "example-tf-project",
+              "labels": null,
+              "name": "example-tf-project",
+              "number": "123456789",
+              "org_id": "",
+              "policy_data": null,
+              "policy_etag": null,
+              "project_id": "example-tf-project",
+              "skip_delete": null,
+              "timeouts": null
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder"
+            ]
+          },
+          {
+            "address": "google_project_iam_binding.binding",
+            "mode": "managed",
+            "type": "google_project_iam_binding",
+            "name": "binding",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxoAEG3A=",
+              "id": "example-tf-project/roles/editor",
+              "members": [
+                "user:user1@example.com"
+              ],
+              "project": "example-tf-project",
+              "role": "roles/editor"
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder",
+              "google_project.example_tf_project"
+            ]
+          },
+          {
+            "address": "google_project_iam_member.member",
+            "mode": "managed",
+            "type": "google_project_iam_member",
+            "name": "member",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxoAEG3A=",
+              "id": "example-tf-project/roles/bigquery.admin/user:user2@example.com",
+              "member": "user:user2@example.com",
+              "project": "example-tf-project",
+              "role": "roles/bigquery.admin"
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder",
+              "google_project.example_tf_project"
+            ]
+          }
+        ]
+      }
+    }
+  },
+  "configuration": {
+    "provider_config": {
+      "google": {
+        "name": "google",
+        "expressions": {
+          "project": {
+            "constant_value": "tf-validator"
+          },
+          "region": {
+            "constant_value": "us-central1"
+          },
+          "zone": {
+            "constant_value": "us-central1-a"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_folder.example_tf_folder",
+          "mode": "managed",
+          "type": "google_folder",
+          "name": "example_tf_folder",
+          "provider_config_key": "google",
+          "expressions": {
+            "display_name": {
+              "constant_value": "example-tf-folder"
+            },
+            "parent": {
+              "references": [
+                "data.google_organization.assist"
+              ]
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_folder_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_folder_iam_binding",
+          "name": "binding",
+          "provider_config_key": "google",
+          "expressions": {
+            "folder": {
+              "references": [
+                "google_folder.example_tf_folder"
+              ]
+            },
+            "members": {
+              "constant_value": [
+                "user:user3@example.com"
+              ]
+            },
+            "role": {
+              "constant_value": "roles/editor"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_folder_iam_member.member",
+          "mode": "managed",
+          "type": "google_folder_iam_member",
+          "name": "member",
+          "provider_config_key": "google",
+          "expressions": {
+            "folder": {
+              "references": [
+                "google_folder.example_tf_folder"
+              ]
+            },
+            "member": {
+              "constant_value": "user:user4@example.com"
+            },
+            "role": {
+              "constant_value": "roles/bigquery.admin"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_organization_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_organization_iam_binding",
+          "name": "binding",
+          "provider_config_key": "google",
+          "expressions": {
+            "members": {
+              "constant_value": [
+                "user:user3@example.com"
+              ]
+            },
+            "org_id": {
+              "references": [
+                "data.google_organization.assist"
+              ]
+            },
+            "role": {
+              "constant_value": "roles/editor"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_organization_iam_member.member",
+          "mode": "managed",
+          "type": "google_organization_iam_member",
+          "name": "member",
+          "provider_config_key": "google",
+          "expressions": {
+            "member": {
+              "constant_value": "user:user4@example.com"
+            },
+            "org_id": {
+              "references": [
+                "data.google_organization.assist"
+              ]
+            },
+            "role": {
+              "constant_value": "roles/bigquery.admin"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_project.example_tf_project",
+          "mode": "managed",
+          "type": "google_project",
+          "name": "example_tf_project",
+          "provider_config_key": "google",
+          "expressions": {
+            "billing_account": {
+              "constant_value": "123456-ABCDEF-987654"
+            },
+            "folder_id": {
+              "references": [
+                "google_folder.example_tf_folder"
+              ]
+            },
+            "name": {
+              "constant_value": "example-tf-project"
+            },
+            "project_id": {
+              "constant_value": "example-tf-project"
+            }
+          },
+          "schema_version": 1
+        },
+        {
+          "address": "google_project_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_project_iam_binding",
+          "name": "binding",
+          "provider_config_key": "google",
+          "expressions": {
+            "members": {
+              "constant_value": [
+                "user:user3@example.com"
+              ]
+            },
+            "project": {
+              "references": [
+                "google_project.example_tf_project"
+              ]
+            },
+            "role": {
+              "constant_value": "roles/editor"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_project_iam_member.member",
+          "mode": "managed",
+          "type": "google_project_iam_member",
+          "name": "member",
+          "provider_config_key": "google",
+          "expressions": {
+            "member": {
+              "constant_value": "user:user4@example.com"
+            },
+            "project": {
+              "references": [
+                "google_project.example_tf_project"
+              ]
+            },
+            "role": {
+              "constant_value": "roles/bigquery.admin"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "data.google_organization.assist",
+          "mode": "data",
+          "type": "google_organization",
+          "name": "assist",
+          "provider_config_key": "google",
+          "expressions": {
+            "organization": {
+              "constant_value": "organizations/123456789"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
diff --git a/policy/testdata/tf12plan_update_iam_policy.json b/policy/testdata/tf12plan_update_iam_policy.json
new file mode 100644
index 00000000..5d18c02c
--- /dev/null
+++ b/policy/testdata/tf12plan_update_iam_policy.json
@@ -0,0 +1,667 @@
+{
+  "format_version": "0.1",
+  "terraform_version": "0.12.25",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_folder.example_tf_folder",
+          "mode": "managed",
+          "type": "google_folder",
+          "name": "example_tf_folder",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "create_time": "2020-08-01T01:04:57.985Z",
+            "display_name": "example-tf-folder",
+            "id": "folders/123456789",
+            "lifecycle_state": "ACTIVE",
+            "name": "folders/123456789",
+            "parent": "organizations/123456789",
+            "timeouts": null
+          }
+        },
+        {
+          "address": "google_folder_iam_policy.policy",
+          "mode": "managed",
+          "type": "google_folder_iam_policy",
+          "name": "policy",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "etag": "BwWrxn+Sq/k=",
+            "folder": "folders/123456789",
+            "id": "folders/123456789",
+            "policy_data": "{\"bindings\":[{\"members\":[\"user:user4@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user3@example.com\"],\"role\":\"roles/editor\"}]}"
+          }
+        },
+        {
+          "address": "google_organization_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_organization_iam_binding",
+          "name": "binding",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "etag": "BwWrxnDz7Zc=",
+            "id": "123456789/roles/editor",
+            "members": [
+              "user:user3@example.com"
+            ],
+            "org_id": "123456789",
+            "role": "roles/editor"
+          }
+        },
+        {
+          "address": "google_organization_iam_member.member",
+          "mode": "managed",
+          "type": "google_organization_iam_member",
+          "name": "member",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "member": "user:user4@example.com",
+            "org_id": "123456789",
+            "role": "roles/bigquery.admin"
+          }
+        },
+        {
+          "address": "google_project.example_tf_project",
+          "mode": "managed",
+          "type": "google_project",
+          "name": "example_tf_project",
+          "provider_name": "google",
+          "schema_version": 1,
+          "values": {
+            "app_engine": [],
+            "auto_create_network": true,
+            "billing_account": "123456-ABCDEF-987654",
+            "folder_id": "123456789",
+            "id": "example-tf-project",
+            "labels": {},
+            "name": "example-tf-project",
+            "number": "123456789",
+            "org_id": "",
+            "policy_data": null,
+            "policy_etag": null,
+            "project_id": "example-tf-project",
+            "skip_delete": null,
+            "timeouts": null
+          }
+        },
+        {
+          "address": "google_project_iam_policy.policy",
+          "mode": "managed",
+          "type": "google_project_iam_policy",
+          "name": "policy",
+          "provider_name": "google",
+          "schema_version": 0,
+          "values": {
+            "authoritative": null,
+            "disable_project": null,
+            "etag": "BwWrxoAEG3A=",
+            "id": "example-tf-project",
+            "policy_data": "{\"bindings\":[{\"members\":[\"user:user4@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user3@example.com\"],\"role\":\"roles/editor\"}]}",
+            "project": "example-tf-project",
+            "restore_policy": null
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "google_folder.example_tf_folder",
+      "mode": "managed",
+      "type": "google_folder",
+      "name": "example_tf_folder",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "no-op"
+        ],
+        "before": {
+          "create_time": "2020-08-01T01:04:57.985Z",
+          "display_name": "example-tf-folder",
+          "id": "folders/123456789",
+          "lifecycle_state": "ACTIVE",
+          "name": "folders/123456789",
+          "parent": "organizations/123456789",
+          "timeouts": null
+        },
+        "after": {
+          "create_time": "2020-08-01T01:04:57.985Z",
+          "display_name": "example-tf-folder",
+          "id": "folders/123456789",
+          "lifecycle_state": "ACTIVE",
+          "name": "folders/123456789",
+          "parent": "organizations/123456789",
+          "timeouts": null
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_folder_iam_policy.policy",
+      "mode": "managed",
+      "type": "google_folder_iam_policy",
+      "name": "policy",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "before": {
+          "etag": "BwWrxn+Sq/k=",
+          "folder": "folders/123456789",
+          "id": "folders/123456789",
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+        },
+        "after": {
+          "etag": "BwWrxn+Sq/k=",
+          "folder": "folders/123456789",
+          "id": "folders/123456789",
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:user4@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user3@example.com\"],\"role\":\"roles/editor\"}]}"
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_organization_iam_binding.binding",
+      "mode": "managed",
+      "type": "google_organization_iam_binding",
+      "name": "binding",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "before": {
+          "etag": "BwWrxnDz7Zc=",
+          "id": "123456789/roles/editor",
+          "members": [
+            "user:user1@example.com"
+          ],
+          "org_id": "123456789",
+          "role": "roles/editor"
+        },
+        "after": {
+          "etag": "BwWrxnDz7Zc=",
+          "id": "123456789/roles/editor",
+          "members": [
+            "user:user3@example.com"
+          ],
+          "org_id": "123456789",
+          "role": "roles/editor"
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_organization_iam_member.member",
+      "mode": "managed",
+      "type": "google_organization_iam_member",
+      "name": "member",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "delete",
+          "create"
+        ],
+        "before": {
+          "etag": "BwWrxnDz7Zc=",
+          "id": "123456789/roles/bigquery.admin/user:user2@example.com",
+          "member": "user:user2@example.com",
+          "org_id": "123456789",
+          "role": "roles/bigquery.admin"
+        },
+        "after": {
+          "member": "user:user4@example.com",
+          "org_id": "123456789",
+          "role": "roles/bigquery.admin"
+        },
+        "after_unknown": {
+          "etag": true,
+          "id": true
+        }
+      }
+    },
+    {
+      "address": "google_project.example_tf_project",
+      "mode": "managed",
+      "type": "google_project",
+      "name": "example_tf_project",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "no-op"
+        ],
+        "before": {
+          "app_engine": [],
+          "auto_create_network": true,
+          "billing_account": "123456-ABCDEF-987654",
+          "folder_id": "123456789",
+          "id": "example-tf-project",
+          "labels": {},
+          "name": "example-tf-project",
+          "number": "123456789",
+          "org_id": "",
+          "policy_data": null,
+          "policy_etag": null,
+          "project_id": "example-tf-project",
+          "skip_delete": null,
+          "timeouts": null
+        },
+        "after": {
+          "app_engine": [],
+          "auto_create_network": true,
+          "billing_account": "123456-ABCDEF-987654",
+          "folder_id": "123456789",
+          "id": "example-tf-project",
+          "labels": {},
+          "name": "example-tf-project",
+          "number": "123456789",
+          "org_id": "",
+          "policy_data": null,
+          "policy_etag": null,
+          "project_id": "example-tf-project",
+          "skip_delete": null,
+          "timeouts": null
+        },
+        "after_unknown": {}
+      }
+    },
+    {
+      "address": "google_project_iam_policy.policy",
+      "mode": "managed",
+      "type": "google_project_iam_policy",
+      "name": "policy",
+      "provider_name": "google",
+      "change": {
+        "actions": [
+          "update"
+        ],
+        "before": {
+          "authoritative": null,
+          "disable_project": null,
+          "etag": "BwWrxoAEG3A=",
+          "id": "example-tf-project",
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}",
+          "project": "example-tf-project",
+          "restore_policy": null
+        },
+        "after": {
+          "authoritative": null,
+          "disable_project": null,
+          "etag": "BwWrxoAEG3A=",
+          "id": "example-tf-project",
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:user4@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user3@example.com\"],\"role\":\"roles/editor\"}]}",
+          "project": "example-tf-project",
+          "restore_policy": null
+        },
+        "after_unknown": {}
+      }
+    }
+  ],
+  "prior_state": {
+    "format_version": "0.1",
+    "terraform_version": "0.12.25",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "data.google_iam_policy.example",
+            "mode": "data",
+            "type": "google_iam_policy",
+            "name": "example",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "audit_config": null,
+              "binding": [
+                {
+                  "members": [
+                    "user:user4@example.com"
+                  ],
+                  "role": "roles/bigquery.admin"
+                },
+                {
+                  "members": [
+                    "user:user3@example.com"
+                  ],
+                  "role": "roles/editor"
+                }
+              ],
+              "id": "123456789",
+              "policy_data": "{\"bindings\":[{\"members\":[\"user:user4@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user3@example.com\"],\"role\":\"roles/editor\"}]}"
+            }
+          },
+          {
+            "address": "data.google_organization.assist",
+            "mode": "data",
+            "type": "google_organization",
+            "name": "assist",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "create_time": "2020-01-13T17:05:56.627Z",
+              "directory_customer_id": "C04jvfuw8",
+              "domain": "iam-assist-test.joonix.net",
+              "id": "123456789",
+              "lifecycle_state": "ACTIVE",
+              "name": "organizations/123456789",
+              "organization": "organizations/123456789"
+            }
+          },
+          {
+            "address": "google_folder.example_tf_folder",
+            "mode": "managed",
+            "type": "google_folder",
+            "name": "example_tf_folder",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "create_time": "2020-08-01T01:04:57.985Z",
+              "display_name": "example-tf-folder",
+              "id": "folders/123456789",
+              "lifecycle_state": "ACTIVE",
+              "name": "folders/123456789",
+              "parent": "organizations/123456789",
+              "timeouts": null
+            }
+          },
+          {
+            "address": "google_folder_iam_policy.policy",
+            "mode": "managed",
+            "type": "google_folder_iam_policy",
+            "name": "policy",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxn+Sq/k=",
+              "folder": "folders/123456789",
+              "id": "folders/123456789",
+              "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}"
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder"
+            ]
+          },
+          {
+            "address": "google_organization_iam_binding.binding",
+            "mode": "managed",
+            "type": "google_organization_iam_binding",
+            "name": "binding",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxnDz7Zc=",
+              "id": "123456789/roles/editor",
+              "members": [
+                "user:user1@example.com"
+              ],
+              "org_id": "123456789",
+              "role": "roles/editor"
+            }
+          },
+          {
+            "address": "google_organization_iam_member.member",
+            "mode": "managed",
+            "type": "google_organization_iam_member",
+            "name": "member",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "etag": "BwWrxnDz7Zc=",
+              "id": "123456789/roles/bigquery.admin/user:user2@example.com",
+              "member": "user:user2@example.com",
+              "org_id": "123456789",
+              "role": "roles/bigquery.admin"
+            }
+          },
+          {
+            "address": "google_project.example_tf_project",
+            "mode": "managed",
+            "type": "google_project",
+            "name": "example_tf_project",
+            "provider_name": "google",
+            "schema_version": 1,
+            "values": {
+              "app_engine": [],
+              "auto_create_network": true,
+              "billing_account": "123456-ABCDEF-987654",
+              "folder_id": "123456789",
+              "id": "example-tf-project",
+              "labels": {},
+              "name": "example-tf-project",
+              "number": "123456789",
+              "org_id": "",
+              "policy_data": null,
+              "policy_etag": null,
+              "project_id": "example-tf-project",
+              "skip_delete": null,
+              "timeouts": null
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder"
+            ]
+          },
+          {
+            "address": "google_project_iam_policy.policy",
+            "mode": "managed",
+            "type": "google_project_iam_policy",
+            "name": "policy",
+            "provider_name": "google",
+            "schema_version": 0,
+            "values": {
+              "authoritative": null,
+              "disable_project": null,
+              "etag": "BwWrxoAEG3A=",
+              "id": "example-tf-project",
+              "policy_data": "{\"bindings\":[{\"members\":[\"user:user2@example.com\"],\"role\":\"roles/bigquery.admin\"},{\"members\":[\"user:user1@example.com\"],\"role\":\"roles/editor\"}]}",
+              "project": "example-tf-project",
+              "restore_policy": null
+            },
+            "depends_on": [
+              "google_folder.example_tf_folder",
+              "google_project.example_tf_project"
+            ]
+          }
+        ]
+      }
+    }
+  },
+  "configuration": {
+    "provider_config": {
+      "google": {
+        "name": "google",
+        "expressions": {
+          "project": {
+            "constant_value": "tf-validator"
+          },
+          "region": {
+            "constant_value": "us-central1"
+          },
+          "zone": {
+            "constant_value": "us-central1-a"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "google_folder.example_tf_folder",
+          "mode": "managed",
+          "type": "google_folder",
+          "name": "example_tf_folder",
+          "provider_config_key": "google",
+          "expressions": {
+            "display_name": {
+              "constant_value": "example-tf-folder"
+            },
+            "parent": {
+              "references": [
+                "data.google_organization.assist"
+              ]
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_folder_iam_policy.policy",
+          "mode": "managed",
+          "type": "google_folder_iam_policy",
+          "name": "policy",
+          "provider_config_key": "google",
+          "expressions": {
+            "folder": {
+              "references": [
+                "google_folder.example_tf_folder"
+              ]
+            },
+            "policy_data": {
+              "references": [
+                "data.google_iam_policy.example"
+              ]
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_organization_iam_binding.binding",
+          "mode": "managed",
+          "type": "google_organization_iam_binding",
+          "name": "binding",
+          "provider_config_key": "google",
+          "expressions": {
+            "members": {
+              "constant_value": [
+                "user:user3@example.com"
+              ]
+            },
+            "org_id": {
+              "references": [
+                "data.google_organization.assist"
+              ]
+            },
+            "role": {
+              "constant_value": "roles/editor"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_organization_iam_member.member",
+          "mode": "managed",
+          "type": "google_organization_iam_member",
+          "name": "member",
+          "provider_config_key": "google",
+          "expressions": {
+            "member": {
+              "constant_value": "user:user4@example.com"
+            },
+            "org_id": {
+              "references": [
+                "data.google_organization.assist"
+              ]
+            },
+            "role": {
+              "constant_value": "roles/bigquery.admin"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "google_project.example_tf_project",
+          "mode": "managed",
+          "type": "google_project",
+          "name": "example_tf_project",
+          "provider_config_key": "google",
+          "expressions": {
+            "billing_account": {
+              "constant_value": "123456-ABCDEF-987654"
+            },
+            "folder_id": {
+              "references": [
+                "google_folder.example_tf_folder"
+              ]
+            },
+            "name": {
+              "constant_value": "example-tf-project"
+            },
+            "project_id": {
+              "constant_value": "example-tf-project"
+            }
+          },
+          "schema_version": 1
+        },
+        {
+          "address": "google_project_iam_policy.policy",
+          "mode": "managed",
+          "type": "google_project_iam_policy",
+          "name": "policy",
+          "provider_config_key": "google",
+          "expressions": {
+            "policy_data": {
+              "references": [
+                "data.google_iam_policy.example"
+              ]
+            },
+            "project": {
+              "references": [
+                "google_project.example_tf_project"
+              ]
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "data.google_iam_policy.example",
+          "mode": "data",
+          "type": "google_iam_policy",
+          "name": "example",
+          "provider_config_key": "google",
+          "expressions": {
+            "binding": [
+              {
+                "members": {
+                  "constant_value": [
+                    "user:user3@example.com"
+                  ]
+                },
+                "role": {
+                  "constant_value": "roles/editor"
+                }
+              },
+              {
+                "members": {
+                  "constant_value": [
+                    "user:user4@example.com"
+                  ]
+                },
+                "role": {
+                  "constant_value": "roles/bigquery.admin"
+                }
+              }
+            ]
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "data.google_organization.assist",
+          "mode": "data",
+          "type": "google_organization",
+          "name": "assist",
+          "provider_config_key": "google",
+          "expressions": {
+            "organization": {
+              "constant_value": "organizations/123456789"
+            }
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
diff --git a/test/read_planned_assets/tf12plan.allcoverage.json b/test/read_planned_assets/tf12plan.allcoverage.json
index 3d5485c3..de8d8742 100644
--- a/test/read_planned_assets/tf12plan.allcoverage.json
+++ b/test/read_planned_assets/tf12plan.allcoverage.json
@@ -377,9 +377,31 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "description": null,
+          "disk_encryption_key": [
+
+          ],
+          "disk_encryption_key_raw": null,
+          "image": "projects/debian-cloud/global/images/debian-8-jessie-v20170523",
+          "labels": {
+            "disk-label-key-a": "disk-label-val-a"
+          },
+          "name": "my-disk",
+          "project": "foobar",
+          "snapshot": null,
+          "source_image_encryption_key": [
+
+          ],
+          "source_snapshot_encryption_key": [
+
+          ],
+          "timeouts": null,
+          "type": "pd-ssd",
+          "zone": "projects/foobar/global/zones/us-central1-a"
+        },
         "after": {
           "description": null,
           "disk_encryption_key": [
@@ -438,9 +460,41 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "allow": [
+            {
+              "ports": [
+                "80",
+                "8080",
+                "1000-2000"
+              ],
+              "protocol": "tcp"
+            },
+            {
+              "ports": [
+
+              ],
+              "protocol": "icmp"
+            }
+          ],
+          "deny": [
+
+          ],
+          "description": null,
+          "disabled": null,
+          "name": "my-test-firewall",
+          "network": "default",
+          "priority": 1000,
+          "source_service_accounts": null,
+          "source_tags": [
+            "web"
+          ],
+          "target_service_accounts": null,
+          "target_tags": null,
+          "timeouts": null
+        },
         "after": {
           "allow": [
             {
@@ -513,9 +567,77 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "allow_stopping_for_update": null,
+          "attached_disk": [
+
+          ],
+          "boot_disk": [
+            {
+              "auto_delete": true,
+              "disk_encryption_key_raw": null,
+              "initialize_params": [
+                {
+                  "image": "projects/debian-cloud/global/images/debian-8-jessie-v20170523"
+                }
+              ]
+            }
+          ],
+          "can_ip_forward": false,
+          "deletion_protection": false,
+          "description": null,
+          "disk": [
+
+          ],
+          "hostname": null,
+          "labels": null,
+          "machine_type": "n1-standard-1",
+          "metadata": {
+            "foo": "bar"
+          },
+          "metadata_startup_script": "echo hi > /test.txt",
+          "min_cpu_platform": null,
+          "name": "my-instance",
+          "network_interface": [
+            {
+              "access_config": [
+                {
+                  "public_ptr_domain_name": null
+                }
+              ],
+              "alias_ip_range": [
+
+              ],
+              "network": "default"
+            }
+          ],
+          "project": "foobar",
+          "scratch_disk": [
+            {
+              "interface": "SCSI"
+            }
+          ],
+          "service_account": [
+            {
+              "scopes": [
+                "https://www.googleapis.com/auth/compute.readonly",
+                "https://www.googleapis.com/auth/devstorage.read_only",
+                "https://www.googleapis.com/auth/userinfo.email"
+              ]
+            }
+          ],
+          "shielded_instance_config": [
+
+          ],
+          "tags": [
+            "bar",
+            "foo"
+          ],
+          "timeouts": null,
+          "zone": "projects/foobar/global/zones/us-central1-a"
+        },
         "after": {
           "allow_stopping_for_update": null,
           "attached_disk": [
@@ -669,9 +791,15 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "folder": "my-folder",
+          "members": [
+            "user:alice@example.com"
+          ],
+          "role": "roles/browser"
+        },
         "after": {
           "folder": "my-folder",
           "members": [
@@ -696,9 +824,13 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "folder": "my-folder",
+          "member": "user:jane@example.com",
+          "role": "roles/viewer"
+        },
         "after": {
           "folder": "my-folder",
           "member": "user:jane@example.com",
@@ -718,9 +850,12 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "folder": "my-folder",
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:bob@example.com\"],\"role\":\"roles/editor\"}]}"
+        },
         "after": {
           "folder": "my-folder",
           "policy_data": "{\"bindings\":[{\"members\":[\"user:bob@example.com\"],\"role\":\"roles/editor\"}]}"
@@ -739,9 +874,15 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "members": [
+            "user:alice@example.com"
+          ],
+          "org_id": "123456789",
+          "role": "roles/browser"
+        },
         "after": {
           "members": [
             "user:alice@example.com"
@@ -766,9 +907,13 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "member": "user:jane@example.com",
+          "org_id": "123456789",
+          "role": "roles/viewer"
+        },
         "after": {
           "member": "user:jane@example.com",
           "org_id": "123456789",
@@ -788,9 +933,12 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "org_id": "123456789",
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:bob@example.com\"],\"role\":\"roles/editor\"}]}"
+        },
         "after": {
           "org_id": "123456789",
           "policy_data": "{\"bindings\":[{\"members\":[\"user:bob@example.com\"],\"role\":\"roles/editor\"}]}"
@@ -809,9 +957,19 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "auto_create_network": true,
+          "billing_account": "012345-567890-ABCDEF",
+          "labels": {
+            "project-label-key-a": "project-label-val-a"
+          },
+          "name": "My Project Name",
+          "org_id": "my-org",
+          "project_id": "foobar",
+          "timeouts": null
+        },
         "after": {
           "auto_create_network": true,
           "billing_account": "012345-567890-ABCDEF",
@@ -844,9 +1002,15 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "members": [
+            "user:alice@example.com"
+          ],
+          "project": "foobar",
+          "role": "roles/browser"
+        },
         "after": {
           "members": [
             "user:alice@example.com"
@@ -871,9 +1035,13 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "member": "user:jane@example.com",
+          "project": "foobar",
+          "role": "roles/viewer"
+        },
         "after": {
           "member": "user:jane@example.com",
           "project": "foobar",
@@ -893,9 +1061,14 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "authoritative": null,
+          "disable_project": null,
+          "policy_data": "{\"bindings\":[{\"members\":[\"user:bob@example.com\"],\"role\":\"roles/editor\"}]}",
+          "project": "foobar"
+        },
         "after": {
           "authoritative": null,
           "disable_project": null,
@@ -917,9 +1090,30 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "database_version": "POSTGRES_9_6",
+          "name": "master-instance",
+          "region": "us-central1",
+          "settings": [
+            {
+              "authorized_gae_applications": null,
+              "database_flags": [
+
+              ],
+              "disk_autoresize": true,
+              "maintenance_window": [
+
+              ],
+              "pricing_plan": "PER_USE",
+              "replication_type": "SYNCHRONOUS",
+              "tier": "db-f1-micro",
+              "user_labels": null
+            }
+          ],
+          "timeouts": null
+        },
         "after": {
           "database_version": "POSTGRES_9_6",
           "name": "master-instance",
@@ -985,9 +1179,41 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "cors": [
+
+          ],
+          "encryption": [
+
+          ],
+          "force_destroy": false,
+          "labels": null,
+          "lifecycle_rule": [
+
+          ],
+          "location": "EU",
+          "logging": [
+
+          ],
+          "name": "test-bucket",
+          "predefined_acl": null,
+          "requester_pays": null,
+          "retention_policy": [
+
+          ],
+          "storage_class": "STANDARD",
+          "versioning": [
+
+          ],
+          "website": [
+            {
+              "main_page_suffix": "index.html",
+              "not_found_page": "404.html"
+            }
+          ]
+        },
         "after": {
           "cors": [
 
diff --git a/test/read_planned_assets/tf12plan.json b/test/read_planned_assets/tf12plan.json
index 401cd875..d46f88cf 100644
--- a/test/read_planned_assets/tf12plan.json
+++ b/test/read_planned_assets/tf12plan.json
@@ -172,9 +172,31 @@
       "provider_name": "google",
       "change": {
         "actions": [
-          "create"
+          "no-op"
         ],
-        "before": null,
+        "before": {
+          "allow": [
+            {
+              "ports": [
+                "8181"
+              ],
+              "protocol": "udp"
+            }
+          ],
+          "deny": [],
+          "description": null,
+          "disabled": null,
+          "name": "server-fiewall",
+          "network": "default",
+          "priority": 1000,
+          "source_service_accounts": null,
+          "source_tags": [
+            "server"
+          ],
+          "target_service_accounts": null,
+          "target_tags": null,
+          "timeouts": null
+        },
         "after": {
           "allow": [
             {
diff --git a/tfgcv/planned_assets_test.go b/tfgcv/planned_assets_test.go
index 9bbd0f48..6c368f1a 100644
--- a/tfgcv/planned_assets_test.go
+++ b/tfgcv/planned_assets_test.go
@@ -14,19 +14,20 @@ const (
 	testAncestryName = "ancestry"
 )
 
-func TestReadPlannedAssets(t *testing.T) {
-	type args struct {
-		file     string
-		project  string
-		ancestry string
-	}
-	type testcase struct {
-		name    string
-		args    args
-		want    int
-		wantErr bool
-	}
 
+type args struct {
+	file     string
+	project  string
+	ancestry string
+}
+type testcase struct {
+	name    string
+	args    args
+	want    int
+	wantErr bool
+}
+
+func testCases(t *testing.T) []testcase {
 	var tests []testcase
 
 	if version.Supported(version.TF12) {
@@ -53,7 +54,6 @@ func TestReadPlannedAssets(t *testing.T) {
 			},
 		}...)
 	}
-
 	if version.Supported(version.TF11) {
 		tests = append(tests, []testcase{
 			{
@@ -72,8 +72,11 @@ func TestReadPlannedAssets(t *testing.T) {
 			// },
 		}...)
 	}
+	return tests
+}
 
-	for _, tt := range tests {
+func TestReadPlannedAssets(t *testing.T) {
+	for _, tt := range testCases(t) {
 		t.Run(tt.name, func(t *testing.T) {
 			testFile := filepath.Join(testDataDir, tt.args.file)
 			var offline bool
@@ -92,3 +95,24 @@ func TestReadPlannedAssets(t *testing.T) {
 		})
 	}
 }
+
+func TestReadCurrentAssets(t *testing.T) {
+	for _, tt := range testCases(t) {
+		t.Run(tt.name, func(t *testing.T) {
+			testFile := filepath.Join(testDataDir, tt.args.file)
+			var offline bool
+			if version.Supported(version.TF12) {
+				offline = true
+			}
+			ctx := context.Background()
+			got, err := ReadCurrentAssets(ctx, testFile, tt.args.project, tt.args.ancestry, offline)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("ReadCurrentAssets() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if len(got) != tt.want {
+				t.Errorf("ReadCurrentAssets() = %v, want %v", len(got), tt.want)
+			}
+		})
+	}
+}
diff --git a/tfplan/json_plan_test.go b/tfplan/json_plan_test.go
index 1e158a71..d6e200dd 100644
--- a/tfplan/json_plan_test.go
+++ b/tfplan/json_plan_test.go
@@ -7,7 +7,8 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
-func TestReadJSONResources(t *testing.T) {
+func newPlan(t *testing.T) jsonPlan {
+	t.Helper()
 	data := []byte(`
 {
   "planned_values": {
@@ -17,7 +18,11 @@ func TestReadJSONResources(t *testing.T) {
           "address": "module.foo",
           "resources": [
             {
-              "address": "module.foo.google_compute_instance.quz1"
+              "address": "module.foo.google_compute_instance.quz1",
+              "values": {
+								"key1": "value1",
+								"nestedKey1": { "insideKey1": "insideValue1"}
+              }
             }
           ],
           "child_modules": [
@@ -25,17 +30,68 @@ func TestReadJSONResources(t *testing.T) {
               "address": "module.foo.bar",
               "resources": [
                 {
-                  "address": "module.foo.bar.google_compute_instance.quz2"
-                }
+                  "address": "module.foo.bar.google_compute_instance.quz2",
+									"values": {"key2": "value2"}
+                },
+								{
+									"address": "module.foo.bar.google_compute_instance.quz4",
+									"values": {"key4": "value4"}
+								}  
               ]
             }
           ]
         }
       ]
     }
-  }
+  },
+	"resource_changes": [
+		{
+			"address": "module.foo.google_compute_instance.quz1",
+			"change": {
+				"actions": ["delete", "create"],
+				"before": {"key1": "value1"},
+				"after": {
+					"key1": "value1",
+					"nestedKey1": { "insideKey1": "insideValue1"}
+				}
+			}
+		},
+		{
+			"address": "module.foo.bar.google_compute_instance.quz2",
+			"change": {
+				"actions": ["noop"],
+				"before": {"key2": "value2"},
+				"after": {"key2": "value2"}
+			}
+		},
+		{
+			"address": "module.foo.bar.google_compute_instance.quz3",
+			"change": {
+				"actions": ["delete"],
+				"before": {"key3": "value3"},
+				"after": {}
+			}
+		},  
+		{
+			"address": "module.foo.bar.google_compute_instance.quz4",
+			"change": {
+				"actions": ["create"],
+				"before": {},
+				"after": {"key4": "value4"}
+			}
+		}  
+	]
 }
 `)
+	plan := jsonPlan{}
+	err := json.Unmarshal(data, &plan)
+	if err != nil {
+		t.Fatalf("parsing %s: %v", string(data), err)
+	}
+	return plan
+}
+
+func TestReadPlannedJSONResources(t *testing.T) {
 	wantJSON := []byte(`
 [
   {
@@ -45,7 +101,10 @@ func TestReadJSONResources(t *testing.T) {
     "name": "",
     "provider_name": "",
     "type": "",
-    "values": null
+		"values": {
+			"key1": "value1",
+			"nestedKey1": { "insideKey1": "insideValue1"}
+		}
   },
   {
     "address": "module.foo.bar.google_compute_instance.quz2",
@@ -54,14 +113,60 @@ func TestReadJSONResources(t *testing.T) {
     "name": "",
     "provider_name": "",
     "type": "",
-    "values": null
+		"values": {"key2": "value2"}
+  },
+  {
+    "address": "module.foo.bar.google_compute_instance.quz4",
+    "mode": "",
+    "module": "foo.bar",
+    "name": "",
+    "provider_name": "",
+    "type": "",
+		"values": {"key4": "value4"}
   }
 ]
 `)
-	got, err := readJSONResources(data)
+	got := readPlannedJSONResources(newPlan(t))
+	gotJSON, err := json.Marshal(got)
 	if err != nil {
-		t.Fatalf("got error: %v", err)
+		t.Fatalf("marshaling: %v", err)
 	}
+	require.JSONEq(t, string(wantJSON), string(gotJSON))
+}
+
+func TestReadCurrentJSONResource(t *testing.T) {
+	wantJSON := []byte(`
+[
+  {
+    "address": "module.foo.google_compute_instance.quz1",
+    "mode": "",
+    "module": "",
+    "name": "",
+    "provider_name": "",
+    "type": "",
+    "values": {"key1": "value1"}
+  },
+  {
+    "address": "module.foo.bar.google_compute_instance.quz2",
+    "mode": "",
+    "module": "",
+    "name": "",
+    "provider_name": "",
+    "type": "",
+    "values": {"key2": "value2"}
+  },
+  {
+    "address": "module.foo.bar.google_compute_instance.quz3",
+    "mode": "",
+    "module": "",
+    "name": "",
+    "provider_name": "",
+    "type": "",
+		"values": {"key3": "value3"}
+  }
+]
+`)
+	got := readCurrentJSONResources(newPlan(t))
 	gotJSON, err := json.Marshal(got)
 	if err != nil {
 		t.Fatalf("marshaling: %v", err)