@@ -15,8 +15,10 @@ package table
1515
1616import (
1717 "context"
18+ "encoding/json"
1819 "errors"
1920 "fmt"
21+ "reflect"
2022 "strings"
2123 "time"
2224
@@ -28,6 +30,7 @@ import (
2830 "github.com/aws/aws-sdk-go-v2/aws"
2931 svcsdk "github.com/aws/aws-sdk-go-v2/service/dynamodb"
3032 svcsdktypes "github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
33+ awsiampolicy "github.com/micahhausler/aws-iam-policy/policy"
3134 corev1 "k8s.io/api/core/v1"
3235
3336 "github.com/aws-controllers-k8s/dynamodb-controller/apis/v1alpha1"
@@ -694,14 +697,7 @@ func customPreCompare(
694697 delta .Add ("Spec.ContributorInsights" , a .ko .Spec .ContributorInsights , b .ko .Spec .ContributorInsights )
695698 }
696699 }
697-
698- if ackcompare .HasNilDifference (a .ko .Spec .ResourcePolicy , b .ko .Spec .ResourcePolicy ) {
699- delta .Add ("Spec.ResourcePolicy" , a .ko .Spec .ResourcePolicy , b .ko .Spec .ResourcePolicy )
700- } else if a .ko .Spec .ResourcePolicy != nil && b .ko .Spec .ResourcePolicy != nil {
701- if * a .ko .Spec .ResourcePolicy != * b .ko .Spec .ResourcePolicy {
702- delta .Add ("Spec.ResourcePolicy" , a .ko .Spec .ResourcePolicy , b .ko .Spec .ResourcePolicy )
703- }
704- }
700+ compareResourcePolicyDocument (delta , a , b )
705701
706702}
707703
@@ -917,3 +913,43 @@ func (rm *resourceManager) updateContributorInsights(
917913
918914 return nil
919915}
916+
917+ // compareResourcePolicyDocument is a custom comparison function for
918+ // ResourcePolicy documents. The reason why we need a custom function for
919+ // this field is to handle the variability in shapes of JSON objects representing
920+ // IAM policies, especially when it comes to statements, actions, and other fields.
921+ func compareResourcePolicyDocument (
922+ delta * ackcompare.Delta ,
923+ a * resource ,
924+ b * resource ,
925+ ) {
926+ // Handle cases where one policy is nil and the other is not.
927+ // This means one resource has a policy and the other doesn't - they're different.
928+ if ackcompare .HasNilDifference (a .ko .Spec .ResourcePolicy , b .ko .Spec .ResourcePolicy ) {
929+ delta .Add ("Spec.ResourcePolicy" , a .ko .Spec .ResourcePolicy , b .ko .Spec .ResourcePolicy )
930+ return
931+ }
932+
933+ // If both policies are nil, there's no difference - both resources have no policy.
934+ if a .ko .Spec .ResourcePolicy == nil && b .ko .Spec .ResourcePolicy == nil {
935+ return
936+ }
937+
938+ // At this point, both policies are non-nil. We need to compare their JSON content.
939+ // To handle the variability in shapes of JSON objects representing IAM policies,
940+ // especially when it comes to statements, actions, and other fields, we need
941+ // a custom json.Unmarshaller approach crafted to our specific needs. Luckily,
942+ // it happens that @micahhausler built a library dedicated to this very special
943+ // need: github.com/micahhausler/aws-iam-policy.
944+ //
945+ // Copied from IAM Controller: https://github.com/aws-controllers-k8s/iam-controller/blob/main/pkg/resource/role/hooks.go#L398-L432
946+ // Based on review feedback: https://github.com/aws-controllers-k8s/dynamodb-controller/pull/154#discussion_r2443876840
947+ var policyDocumentA awsiampolicy.Policy
948+ _ = json .Unmarshal ([]byte (* a .ko .Spec .ResourcePolicy ), & policyDocumentA )
949+ var policyDocumentB awsiampolicy.Policy
950+ _ = json .Unmarshal ([]byte (* b .ko .Spec .ResourcePolicy ), & policyDocumentB )
951+
952+ if ! reflect .DeepEqual (policyDocumentA , policyDocumentB ) {
953+ delta .Add ("Spec.ResourcePolicy" , a .ko .Spec .ResourcePolicy , b .ko .Spec .ResourcePolicy )
954+ }
955+ }
0 commit comments