From 2ef94bead94e3a03642f4b11cf4132479262f3ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20S=C3=B6derlund?= Date: Thu, 6 May 2021 08:02:59 +0200 Subject: [PATCH] feat(iampolicy): add AddBinding and RemoveBinding helpers Reference implementation for adding and removing bindings. --- iampolicy/add.go | 28 ++++++++++++++++++++++++++++ iampolicy/remove.go | 36 ++++++++++++++++++++++++++++++++++++ iampolicy/remove_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 iampolicy/add.go create mode 100644 iampolicy/remove.go create mode 100644 iampolicy/remove_test.go diff --git a/iampolicy/add.go b/iampolicy/add.go new file mode 100644 index 00000000..ef9822ea --- /dev/null +++ b/iampolicy/add.go @@ -0,0 +1,28 @@ +package iampolicy + +import "google.golang.org/genproto/googleapis/iam/v1" + +// AddBinding adds the provided role and member binding to the policy. +// If the role and member already exists, no updates are made. +// No validation on the role or member is performed. +func AddBinding(policy *iam.Policy, role, member string) { + // Add binding to policy. + var added bool + for _, binding := range policy.Bindings { + if binding.Role == role { + for _, bindingMember := range binding.Members { + if bindingMember == member { + return // already have this policy binding + } + } + binding.Members = append(binding.Members, member) + added = true + } + } + if !added { + policy.Bindings = append(policy.Bindings, &iam.Binding{ + Role: role, + Members: []string{member}, + }) + } +} diff --git a/iampolicy/remove.go b/iampolicy/remove.go new file mode 100644 index 00000000..2498d612 --- /dev/null +++ b/iampolicy/remove.go @@ -0,0 +1,36 @@ +package iampolicy + +import "google.golang.org/genproto/googleapis/iam/v1" + +// RemoveBinding removes the provided role and member binding from the policy. +// If a binding of the the role and member don't exist, no updates are made. +// No validation on the role or member is performed. +func RemoveBinding(policy *iam.Policy, role, member string) { + for _, binding := range policy.Bindings { + if binding.Role == role { + binding.Members = removeMember(binding.Members, member) + if len(binding.Members) == 0 { + policy.Bindings = removeRole(policy.Bindings, role) + } + return + } + } +} + +func removeMember(members []string, member string) []string { + for i, candidate := range members { + if candidate == member { + return append(members[:i], members[i+1:]...) + } + } + return members +} + +func removeRole(bindings []*iam.Binding, role string) []*iam.Binding { + for i, binding := range bindings { + if binding.Role == role { + return append(bindings[:i], bindings[i+1:]...) + } + } + return bindings +} diff --git a/iampolicy/remove_test.go b/iampolicy/remove_test.go new file mode 100644 index 00000000..0deacb9b --- /dev/null +++ b/iampolicy/remove_test.go @@ -0,0 +1,40 @@ +package iampolicy + +import ( + "testing" + + "google.golang.org/genproto/googleapis/iam/v1" + "google.golang.org/protobuf/testing/protocmp" + "gotest.tools/v3/assert" +) + +func TestRemoveBinding(t *testing.T) { + t.Run("ok", func(t *testing.T) { + actual := &iam.Policy{ + Bindings: []*iam.Binding{ + { + Role: "roles/test", + Members: []string{"foo", "bar"}, + }, + { + Role: "roles/test2", + Members: []string{"foo", "bar"}, + }, + }, + } + RemoveBinding(actual, "roles/test2", "bar") + expected := &iam.Policy{ + Bindings: []*iam.Binding{ + { + Role: "roles/test", + Members: []string{"foo", "bar"}, + }, + { + Role: "roles/test2", + Members: []string{"foo"}, + }, + }, + } + assert.DeepEqual(t, expected, actual, protocmp.Transform()) + }) +}