From 6c5e6787b0d0e5c0e9bd4d15996232e25f061263 Mon Sep 17 00:00:00 2001 From: Elie CHARRA Date: Wed, 27 Jul 2022 15:30:56 +0200 Subject: [PATCH] fix: fix broken tests Those tests were broken due to removal of SetResolveReadAttributesFunc. Sometimes in those methods we were casting field from different types to string. If we loose that case it causes some issues since in the detail fetcher we only take into account strings attributes. To fix that I added some cast directly in the detail fetcher. That should not cause any issues to retrieve details if we send additional (useless) fields to the ReadResource call. --- .../aws/cloudformation_stack_enumerator.go | 10 +++++-- enumeration/remote/common/details_fetcher.go | 8 ++++++ ..._encryption_default-false.res.golden.json} | 0 ...d657494d17ee2-6-allow-200.res.golden.json} | 0 ...657494d17ee2-17-allow-100.res.golden.json} | 0 ...ef59074b622e-17-allow-100.res.golden.json} | 0 ...6d657494d17ee2-6-deny-100.res.golden.json} | 0 ...4ef59074b622e-17-deny-100.res.golden.json} | 0 enumeration/resource/resource.go | 3 ++ .../aws_default_network_acl_rule.go | 5 ++-- .../aws_default_network_acl_rule_test.go | 28 +++++++++---------- pkg/middlewares/aws_network_acl_expander.go | 4 +-- .../aws_network_acl_expander_test.go | 18 ++++++------ pkg/resource/aws/aws_network_acl_rule.go | 15 +++++++--- 14 files changed, 57 insertions(+), 34 deletions(-) rename enumeration/remote/test/aws_ebs_encryption_by_default_list/{aws_ebs_encryption_by_default-ebs_encryption_default.res.golden.json => aws_ebs_encryption_by_default-ebs_encryption_default-false.res.golden.json} (100%) rename enumeration/remote/test/aws_ec2_network_acl_rule/{aws_network_acl_rule-nacl-2289824980-___0-acl-0ad6d657494d17ee2-6-allow.res.golden.json => aws_network_acl_rule-nacl-2289824980-false-___0-acl-0ad6d657494d17ee2-6-allow-200.res.golden.json} (100%) rename enumeration/remote/test/aws_ec2_network_acl_rule/{aws_network_acl_rule-nacl-246660311-172.16.1.0_0-acl-0ad6d657494d17ee2-17-allow.res.golden.json => aws_network_acl_rule-nacl-246660311-172.16.1.0_0-true-acl-0ad6d657494d17ee2-17-allow-100.res.golden.json} (100%) rename enumeration/remote/test/aws_ec2_network_acl_rule/{aws_network_acl_rule-nacl-4268384215-172.16.1.0_0-acl-0de54ef59074b622e-17-allow.res.golden.json => aws_network_acl_rule-nacl-4268384215-172.16.1.0_0-true-acl-0de54ef59074b622e-17-allow-100.res.golden.json} (100%) rename enumeration/remote/test/aws_ec2_network_acl_rule/{aws_network_acl_rule-nacl-4293207588-0.0.0.0_0-acl-0ad6d657494d17ee2-6-deny.res.golden.json => aws_network_acl_rule-nacl-4293207588-0.0.0.0_0-false-acl-0ad6d657494d17ee2-6-deny-100.res.golden.json} (100%) rename enumeration/remote/test/aws_ec2_network_acl_rule/{aws_network_acl_rule-nacl-515082162-0.0.0.0_0-acl-0de54ef59074b622e-17-deny.res.golden.json => aws_network_acl_rule-nacl-515082162-0.0.0.0_0-false-acl-0de54ef59074b622e-17-deny-100.res.golden.json} (100%) diff --git a/enumeration/remote/aws/cloudformation_stack_enumerator.go b/enumeration/remote/aws/cloudformation_stack_enumerator.go index f76f9fe7..c85dc56d 100644 --- a/enumeration/remote/aws/cloudformation_stack_enumerator.go +++ b/enumeration/remote/aws/cloudformation_stack_enumerator.go @@ -1,9 +1,11 @@ package aws import ( + "fmt" "strconv" "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/hashicorp/terraform/flatmap" "github.com/snyk/driftctl/enumeration/remote/aws/repository" remoteerror "github.com/snyk/driftctl/enumeration/remote/error" "github.com/snyk/driftctl/enumeration/resource" @@ -38,7 +40,9 @@ func (e *CloudformationStackEnumerator) Enumerate() ([]*resource.Resource, error attrs := map[string]interface{}{} if stack.Parameters != nil && len(stack.Parameters) > 0 { attrs["parameters.%"] = strconv.FormatInt(int64(len(stack.Parameters)), 10) - attrs["parameters"] = flattenParameters(stack.Parameters) + for k, v := range flattenParameters(stack.Parameters) { + attrs[fmt.Sprintf("parameters.%s", k)] = v + } } results = append( @@ -54,10 +58,10 @@ func (e *CloudformationStackEnumerator) Enumerate() ([]*resource.Resource, error return results, err } -func flattenParameters(parameters []*cloudformation.Parameter) interface{} { +func flattenParameters(parameters []*cloudformation.Parameter) flatmap.Map { params := make(map[string]interface{}, len(parameters)) for _, p := range parameters { params[*p.ParameterKey] = *p.ParameterValue } - return params + return flatmap.Flatten(params) } diff --git a/enumeration/remote/common/details_fetcher.go b/enumeration/remote/common/details_fetcher.go index 915c0788..abc78b59 100644 --- a/enumeration/remote/common/details_fetcher.go +++ b/enumeration/remote/common/details_fetcher.go @@ -1,6 +1,8 @@ package common import ( + "strconv" + "github.com/sirupsen/logrus" remoteerror "github.com/snyk/driftctl/enumeration/remote/error" "github.com/snyk/driftctl/enumeration/resource" @@ -29,6 +31,12 @@ func (f *GenericDetailsFetcher) ReadDetails(res *resource.Resource) (*resource.R attributes := map[string]string{} if res.Attributes() != nil { for k, v := range *res.Attributes() { + if b, ok := v.(bool); ok { + attributes[k] = strconv.FormatBool(b) + } + if i64, ok := v.(int64); ok { + attributes[k] = strconv.FormatInt(i64, 10) + } if str, ok := v.(string); ok { attributes[k] = str } diff --git a/enumeration/remote/test/aws_ebs_encryption_by_default_list/aws_ebs_encryption_by_default-ebs_encryption_default.res.golden.json b/enumeration/remote/test/aws_ebs_encryption_by_default_list/aws_ebs_encryption_by_default-ebs_encryption_default-false.res.golden.json similarity index 100% rename from enumeration/remote/test/aws_ebs_encryption_by_default_list/aws_ebs_encryption_by_default-ebs_encryption_default.res.golden.json rename to enumeration/remote/test/aws_ebs_encryption_by_default_list/aws_ebs_encryption_by_default-ebs_encryption_default-false.res.golden.json diff --git a/enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-2289824980-___0-acl-0ad6d657494d17ee2-6-allow.res.golden.json b/enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-2289824980-false-___0-acl-0ad6d657494d17ee2-6-allow-200.res.golden.json similarity index 100% rename from enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-2289824980-___0-acl-0ad6d657494d17ee2-6-allow.res.golden.json rename to enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-2289824980-false-___0-acl-0ad6d657494d17ee2-6-allow-200.res.golden.json diff --git a/enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-246660311-172.16.1.0_0-acl-0ad6d657494d17ee2-17-allow.res.golden.json b/enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-246660311-172.16.1.0_0-true-acl-0ad6d657494d17ee2-17-allow-100.res.golden.json similarity index 100% rename from enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-246660311-172.16.1.0_0-acl-0ad6d657494d17ee2-17-allow.res.golden.json rename to enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-246660311-172.16.1.0_0-true-acl-0ad6d657494d17ee2-17-allow-100.res.golden.json diff --git a/enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-4268384215-172.16.1.0_0-acl-0de54ef59074b622e-17-allow.res.golden.json b/enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-4268384215-172.16.1.0_0-true-acl-0de54ef59074b622e-17-allow-100.res.golden.json similarity index 100% rename from enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-4268384215-172.16.1.0_0-acl-0de54ef59074b622e-17-allow.res.golden.json rename to enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-4268384215-172.16.1.0_0-true-acl-0de54ef59074b622e-17-allow-100.res.golden.json diff --git a/enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-4293207588-0.0.0.0_0-acl-0ad6d657494d17ee2-6-deny.res.golden.json b/enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-4293207588-0.0.0.0_0-false-acl-0ad6d657494d17ee2-6-deny-100.res.golden.json similarity index 100% rename from enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-4293207588-0.0.0.0_0-acl-0ad6d657494d17ee2-6-deny.res.golden.json rename to enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-4293207588-0.0.0.0_0-false-acl-0ad6d657494d17ee2-6-deny-100.res.golden.json diff --git a/enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-515082162-0.0.0.0_0-acl-0de54ef59074b622e-17-deny.res.golden.json b/enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-515082162-0.0.0.0_0-false-acl-0de54ef59074b622e-17-deny-100.res.golden.json similarity index 100% rename from enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-515082162-0.0.0.0_0-acl-0de54ef59074b622e-17-deny.res.golden.json rename to enumeration/remote/test/aws_ec2_network_acl_rule/aws_network_acl_rule-nacl-515082162-0.0.0.0_0-false-acl-0de54ef59074b622e-17-deny-100.res.golden.json diff --git a/enumeration/resource/resource.go b/enumeration/resource/resource.go index f4ec6525..e7279276 100644 --- a/enumeration/resource/resource.go +++ b/enumeration/resource/resource.go @@ -188,6 +188,9 @@ func (a *Attributes) GetBool(path string) *bool { } func (a *Attributes) GetInt(path string) *int { + // This is a nonsense, if we want to retrieve an int this is gonna fail + // We were doing that because all numbers fields from cty are float64 but sometimes we want to retrieve an int + // TODO Change this to be compatible with both int and float64 underlying type val := a.GetFloat64(path) if val == nil { return nil diff --git a/pkg/middlewares/aws_default_network_acl_rule.go b/pkg/middlewares/aws_default_network_acl_rule.go index 7990af28..6d00b483 100644 --- a/pkg/middlewares/aws_default_network_acl_rule.go +++ b/pkg/middlewares/aws_default_network_acl_rule.go @@ -62,9 +62,10 @@ func (m AwsDefaultNetworkACLRule) Execute(remoteResources, resourcesFromState *[ func (m *AwsDefaultNetworkACLRule) isDefaultACLRule(res *resource.Resource) bool { isIPv4 := res.Attrs.GetString("cidr_block") != nil + ruleNumber, ruleNumberOk := (*res.Attrs)["rule_number"].(int64) if isIPv4 { - if number := res.Attrs.GetFloat64("rule_number"); number != nil && int(*number) != 32767 { + if ruleNumberOk && ruleNumber != 32767 { return false } if cidr := res.Attrs.GetString("cidr_block"); cidr != nil && *cidr != "0.0.0.0/0" { @@ -73,7 +74,7 @@ func (m *AwsDefaultNetworkACLRule) isDefaultACLRule(res *resource.Resource) bool } if !isIPv4 { - if number := res.Attrs.GetFloat64("rule_number"); number != nil && int(*number) != 32768 { + if ruleNumberOk && ruleNumber != 32768 { return false } if cidr := res.Attrs.GetString("ipv6_cidr_block"); cidr != nil && *cidr != "::/0" { diff --git a/pkg/middlewares/aws_default_network_acl_rule_test.go b/pkg/middlewares/aws_default_network_acl_rule_test.go index 5d0b99f0..18e46f46 100644 --- a/pkg/middlewares/aws_default_network_acl_rule_test.go +++ b/pkg/middlewares/aws_default_network_acl_rule_test.go @@ -27,7 +27,7 @@ func TestAwsDefaultNetworkACLRule_Execute(t *testing.T) { Id: "default-acl-rule", Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ - "rule_number": float64(32767), + "rule_number": int64(32767), "rule_action": "deny", "cidr_block": "0.0.0.0/0", "protocol": "-1", @@ -37,14 +37,14 @@ func TestAwsDefaultNetworkACLRule_Execute(t *testing.T) { Id: "non-default-acl", Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ - "rule_number": float64(100), + "rule_number": int64(100), }, }, { Id: "non-default-acl-2", Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ - "rule_number": float64(32767), + "rule_number": int64(32767), "rule_action": "allow", }, }, @@ -52,7 +52,7 @@ func TestAwsDefaultNetworkACLRule_Execute(t *testing.T) { Id: "non-default-acl-3", Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ - "rule_number": float64(32767), + "rule_number": int64(32767), "rule_action": "deny", "cidr_block": "1.2.3.0/0", }, @@ -61,7 +61,7 @@ func TestAwsDefaultNetworkACLRule_Execute(t *testing.T) { Id: "non-default-acl-4", Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ - "rule_number": float64(32767), + "rule_number": int64(32767), "rule_action": "deny", "cidr_block": "0.0.0.0/0", "protocol": "6", @@ -82,7 +82,7 @@ func TestAwsDefaultNetworkACLRule_Execute(t *testing.T) { Id: "default-acl-rule", Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ - "rule_number": float64(32767), + "rule_number": int64(32767), "rule_action": "deny", "cidr_block": "0.0.0.0/0", "protocol": "-1", @@ -92,14 +92,14 @@ func TestAwsDefaultNetworkACLRule_Execute(t *testing.T) { Id: "non-default-acl", Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ - "rule_number": float64(100), + "rule_number": int64(100), }, }, { Id: "non-default-acl-2", Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ - "rule_number": float64(32767), + "rule_number": int64(32767), "rule_action": "allow", }, }, @@ -107,7 +107,7 @@ func TestAwsDefaultNetworkACLRule_Execute(t *testing.T) { Id: "non-default-acl-3", Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ - "rule_number": float64(32767), + "rule_number": int64(32767), "rule_action": "deny", "cidr_block": "1.2.3.0/0", }, @@ -116,7 +116,7 @@ func TestAwsDefaultNetworkACLRule_Execute(t *testing.T) { Id: "non-default-acl-4", Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ - "rule_number": float64(32767), + "rule_number": int64(32767), "rule_action": "deny", "cidr_block": "0.0.0.0/0", "protocol": "6", @@ -135,7 +135,7 @@ func TestAwsDefaultNetworkACLRule_Execute(t *testing.T) { Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ "network_acl_id": "my-network", - "rule_number": float64(32767), + "rule_number": int64(32767), "rule_action": "deny", "cidr_block": "0.0.0.0/0", "protocol": "-1", @@ -146,7 +146,7 @@ func TestAwsDefaultNetworkACLRule_Execute(t *testing.T) { Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ "network_acl_id": "my-network", - "rule_number": float64(32768), + "rule_number": int64(32768), "rule_action": "deny", "ipv6_cidr_block": "::/0", "protocol": "-1", @@ -156,7 +156,7 @@ func TestAwsDefaultNetworkACLRule_Execute(t *testing.T) { Id: "non-default-acl", Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ - "rule_number": float64(32767), + "rule_number": int64(32767), "rule_action": "deny", "cidr_block": "0.0.0.0/0", "protocol": "6", @@ -172,7 +172,7 @@ func TestAwsDefaultNetworkACLRule_Execute(t *testing.T) { Id: "non-default-acl", Type: aws.AwsNetworkACLRuleResourceType, Attrs: &resource.Attributes{ - "rule_number": float64(32767), + "rule_number": int64(32767), "rule_action": "deny", "cidr_block": "0.0.0.0/0", "protocol": "6", diff --git a/pkg/middlewares/aws_network_acl_expander.go b/pkg/middlewares/aws_network_acl_expander.go index 72978b46..5a683903 100644 --- a/pkg/middlewares/aws_network_acl_expander.go +++ b/pkg/middlewares/aws_network_acl_expander.go @@ -72,7 +72,7 @@ func (e *AwsNetworkACLExpander) expandBlock(resourcesFromState *[]*resource.Reso for _, rule := range ruleBlock { attrs := rule.(map[string]interface{}) - attrs["rule_number"] = attrs["rule_no"] + attrs["rule_number"] = int64(attrs["rule_no"].(float64)) delete(attrs, "rule_no") attrs["egress"] = egress @@ -86,7 +86,7 @@ func (e *AwsNetworkACLExpander) expandBlock(resourcesFromState *[]*resource.Reso aws.AwsNetworkACLRuleResourceType, aws.CreateNetworkACLRuleID( networkAclId, - int64(attrs["rule_number"].(int)), + attrs["rule_number"].(int64), egress, attrs["protocol"].(string), ), diff --git a/pkg/middlewares/aws_network_acl_expander_test.go b/pkg/middlewares/aws_network_acl_expander_test.go index 6cc6178e..83ff247d 100644 --- a/pkg/middlewares/aws_network_acl_expander_test.go +++ b/pkg/middlewares/aws_network_acl_expander_test.go @@ -7,8 +7,8 @@ import ( "github.com/aws/aws-sdk-go/aws/awsutil" "github.com/r3labs/diff/v2" "github.com/snyk/driftctl/enumeration/resource" + "github.com/snyk/driftctl/enumeration/resource/aws" dctlresource "github.com/snyk/driftctl/pkg/resource" - "github.com/snyk/driftctl/pkg/resource/aws" ) func TestAwsNetworkACLExpander_Execute(t *testing.T) { @@ -87,7 +87,7 @@ func TestAwsNetworkACLExpander_Execute(t *testing.T) { "icmp_type": 0, "ipv6_cidr_block": "", "protocol": "17", - "rule_number": 100, + "rule_number": int64(100), "to_port": 80, }, ).Once().Return(&resource.Resource{ @@ -114,7 +114,7 @@ func TestAwsNetworkACLExpander_Execute(t *testing.T) { "icmp_type": 0, "ipv6_cidr_block": "", "protocol": "6", - "rule_number": 101, + "rule_number": int64(101), "to_port": 80, }, ).Once().Return(&resource.Resource{ @@ -141,7 +141,7 @@ func TestAwsNetworkACLExpander_Execute(t *testing.T) { "icmp_type": 0, "ipv6_cidr_block": "", "protocol": "6", - "rule_number": 103, + "rule_number": int64(103), "to_port": 80, }, ).Once().Return(&resource.Resource{ @@ -168,7 +168,7 @@ func TestAwsNetworkACLExpander_Execute(t *testing.T) { "icmp_type": 0, "ipv6_cidr_block": "", "protocol": "17", - "rule_number": 100, + "rule_number": int64(100), "to_port": 80, }, ).Once().Return(&resource.Resource{ @@ -190,7 +190,7 @@ func TestAwsNetworkACLExpander_Execute(t *testing.T) { "icmp_type": 0, "ipv6_cidr_block": "", "protocol": "17", - "rule_no": 100, + "rule_no": 100.0, "to_port": 80, }, }, @@ -203,7 +203,7 @@ func TestAwsNetworkACLExpander_Execute(t *testing.T) { "icmp_type": 0, "ipv6_cidr_block": "", "protocol": "6", - "rule_no": 101, + "rule_no": 101.0, "to_port": 80, }, // This one exist in state, test that we do not duplicate it @@ -216,7 +216,7 @@ func TestAwsNetworkACLExpander_Execute(t *testing.T) { "icmp_type": 0, "ipv6_cidr_block": "", "protocol": "6", - "rule_no": 103, + "rule_no": 103.0, "to_port": 80, }, }, @@ -235,7 +235,7 @@ func TestAwsNetworkACLExpander_Execute(t *testing.T) { "icmp_type": 0, "ipv6_cidr_block": "", "protocol": "17", - "rule_no": 100, + "rule_no": 100.0, "to_port": 80, }, }, diff --git a/pkg/resource/aws/aws_network_acl_rule.go b/pkg/resource/aws/aws_network_acl_rule.go index 69e87d78..b4d163a9 100644 --- a/pkg/resource/aws/aws_network_acl_rule.go +++ b/pkg/resource/aws/aws_network_acl_rule.go @@ -3,12 +3,11 @@ package aws import ( "bytes" "fmt" - dctlresource "github.com/snyk/driftctl/pkg/resource" "strconv" "github.com/hashicorp/terraform/helper/hashcode" - "github.com/snyk/driftctl/enumeration/resource" + dctlresource "github.com/snyk/driftctl/pkg/resource" ) const AwsNetworkACLRuleResourceType = "aws_network_acl_rule" @@ -178,6 +177,14 @@ func initAwsNetworkACLRuleMetaData(resourceSchemaRepository dctlresource.SchemaR _ = res.Attrs.SafeSet([]string{"protocol"}, strconv.Itoa(number)) } + // For some reason, when deserialising the state, this field is deserialized as a float + // We need to make this homogeneous between remote and IaC so we cast this to an int64 + // The real type returned by AWS SDK is int64 + ruleNumber := (*res.Attrs)["rule_number"] + if v, isFloat := ruleNumber.(float64); isFloat { + _ = res.Attrs.SafeSet([]string{"rule_number"}, int64(v)) + } + // ID can be different even if the resource is the same. // protocol is taken into account while creating the ID, if you set protocol="tcp" you'll end with // a resource with a different ID than if you set protocol="6" which is the same @@ -188,7 +195,7 @@ func initAwsNetworkACLRuleMetaData(resourceSchemaRepository dctlresource.SchemaR // This workaround is mandatory to harmonize resources ID res.Id = CreateNetworkACLRuleID( *res.Attrs.GetString("network_acl_id"), - int64(*res.Attrs.GetInt("rule_number")), + (*res.Attrs)["rule_number"].(int64), *res.Attrs.GetBool("egress"), *res.Attrs.GetString("protocol"), ) @@ -200,7 +207,7 @@ func initAwsNetworkACLRuleMetaData(resourceSchemaRepository dctlresource.SchemaR resourceSchemaRepository.SetFlags(AwsNetworkACLRuleResourceType, resource.FlagDeepMode) resourceSchemaRepository.SetHumanReadableAttributesFunc(AwsNetworkACLRuleResourceType, func(res *resource.Resource) map[string]string { - ruleNumber := strconv.FormatInt(int64(*res.Attrs.GetInt("rule_number")), 10) + ruleNumber := strconv.FormatInt((*res.Attrs)["rule_number"].(int64), 10) if ruleNumber == "32767" { ruleNumber = "*" }