Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"AttributeError: 'dict' object has no attribute 'startswith'" when using resources defining their own "references" blocks #726

Open
Aviss opened this issue Dec 4, 2023 · 0 comments
Assignees
Labels

Comments

@Aviss
Copy link

Aviss commented Dec 4, 2023

Description

I am using the Snowflake-Labs/snowflake provider and one of the resources breaks the parsing of the plan file.

I have attached a minimal example below but I highly suspect that the table_constraint is to blame. For foregin keys a references block is added:

resource "snowflake_table_constraint" "fk" {
  [...]
  foreign_key_properties {
        references {
          table_id = snowflake_table.table.id
          columns  = ["column"]
        }
  }
  [...]
}

which clashes with the reference sections in the plan file terraform generates:

[...]
"foreign_key_properties": [
  {
    "references": [
      {
        "columns": {
          "constant_value": [
            "column"
          ]
        },
        "table_id": {
          "references": [
            "snowflake_table.table.id",
            "snowflake_table.table"
          ]
        }
      }
    ]
  }
],
[...]

no tests are executed and Terraform Compliance exits with AttributeError: 'dict' object has no attribute 'startswith', implying it tries to parse the references as a list of strings when it is a list of objects/dicts here.

To Reproduce

Feature File:
Bug happens independent of Feature File

Plan File:

{
  "format_version": "1.2",
  "terraform_version": "1.5.6",
  "variables": {
    "snowflake-account": {
      "value": "REDACTED"
    },
    "snowflake-password": {
      "value": "REDACTED"
    },
    "snowflake-role": {
      "value": "REDACTED"
    },
    "snowflake-username": {
      "value": "REDACTED"
    }
  },
  "planned_values": {
    "root_module": {
      "resources": [
        {
          "address": "snowflake_database.db",
          "mode": "managed",
          "type": "snowflake_database",
          "name": "db",
          "provider_name": "registry.terraform.io/snowflake-labs/snowflake",
          "schema_version": 0,
          "values": {
            "comment": null,
            "data_retention_time_in_days": 1,
            "from_database": null,
            "from_replica": null,
            "from_share": null,
            "is_transient": false,
            "name": "db",
            "replication_configuration": []
          },
          "sensitive_values": {
            "replication_configuration": []
          }
        },
        {
          "address": "snowflake_schema.schema",
          "mode": "managed",
          "type": "snowflake_schema",
          "name": "schema",
          "provider_name": "registry.terraform.io/snowflake-labs/snowflake",
          "schema_version": 0,
          "values": {
            "comment": null,
            "data_retention_days": 1,
            "database": "db",
            "is_managed": false,
            "is_transient": false,
            "name": "schema",
            "tag": []
          },
          "sensitive_values": {
            "tag": []
          }
        },
        {
          "address": "snowflake_table.table",
          "mode": "managed",
          "type": "snowflake_table",
          "name": "table",
          "provider_name": "registry.terraform.io/snowflake-labs/snowflake",
          "schema_version": 0,
          "values": {
            "change_tracking": false,
            "cluster_by": null,
            "column": [
              {
                "comment": null,
                "default": [],
                "identity": [],
                "masking_policy": null,
                "name": "column",
                "nullable": false,
                "type": "string"
              }
            ],
            "comment": null,
            "data_retention_days": null,
            "data_retention_time_in_days": null,
            "database": "db",
            "name": "table",
            "primary_key": [],
            "schema": "schema",
            "tag": []
          },
          "sensitive_values": {
            "column": [
              {
                "default": [],
                "identity": []
              }
            ],
            "primary_key": [],
            "tag": []
          }
        },
        {
          "address": "snowflake_table.table-reference",
          "mode": "managed",
          "type": "snowflake_table",
          "name": "table-reference",
          "provider_name": "registry.terraform.io/snowflake-labs/snowflake",
          "schema_version": 0,
          "values": {
            "change_tracking": false,
            "cluster_by": null,
            "column": [
              {
                "comment": null,
                "default": [],
                "identity": [],
                "masking_policy": null,
                "name": "fk",
                "nullable": false,
                "type": "string"
              }
            ],
            "comment": null,
            "data_retention_days": null,
            "data_retention_time_in_days": null,
            "database": "db",
            "name": "table_reference",
            "primary_key": [],
            "schema": "schema",
            "tag": []
          },
          "sensitive_values": {
            "column": [
              {
                "default": [],
                "identity": []
              }
            ],
            "primary_key": [],
            "tag": []
          }
        },
        {
          "address": "snowflake_table_constraint.fk",
          "mode": "managed",
          "type": "snowflake_table_constraint",
          "name": "fk",
          "provider_name": "registry.terraform.io/snowflake-labs/snowflake",
          "schema_version": 0,
          "values": {
            "columns": [
              "fk"
            ],
            "comment": null,
            "deferrable": true,
            "enable": true,
            "enforced": false,
            "foreign_key_properties": [
              {
                "match": "FULL",
                "on_delete": "NO ACTION",
                "on_update": "NO ACTION",
                "references": [
                  {
                    "columns": [
                      "column"
                    ]
                  }
                ]
              }
            ],
            "initially": "DEFERRED",
            "name": "fk",
            "rely": true,
            "type": "FOREIGN KEY",
            "validate": false
          },
          "sensitive_values": {
            "columns": [
              false
            ],
            "foreign_key_properties": [
              {
                "references": [
                  {
                    "columns": [
                      false
                    ]
                  }
                ]
              }
            ]
          }
        },
        {
          "address": "snowflake_table_constraint.pk",
          "mode": "managed",
          "type": "snowflake_table_constraint",
          "name": "pk",
          "provider_name": "registry.terraform.io/snowflake-labs/snowflake",
          "schema_version": 0,
          "values": {
            "columns": [
              "column"
            ],
            "comment": null,
            "deferrable": true,
            "enable": true,
            "enforced": false,
            "foreign_key_properties": [],
            "initially": "DEFERRED",
            "name": "pk",
            "rely": true,
            "type": "PRIMARY KEY",
            "validate": false
          },
          "sensitive_values": {
            "columns": [
              false
            ],
            "foreign_key_properties": []
          }
        }
      ]
    }
  },
  "resource_changes": [
    {
      "address": "snowflake_database.db",
      "mode": "managed",
      "type": "snowflake_database",
      "name": "db",
      "provider_name": "registry.terraform.io/snowflake-labs/snowflake",
      "change": {
        "actions": [
          "create"
        ],
        "before": null,
        "after": {
          "comment": null,
          "data_retention_time_in_days": 1,
          "from_database": null,
          "from_replica": null,
          "from_share": null,
          "is_transient": false,
          "name": "db",
          "replication_configuration": []
        },
        "after_unknown": {
          "id": true,
          "replication_configuration": []
        },
        "before_sensitive": false,
        "after_sensitive": {
          "replication_configuration": []
        }
      }
    },
    {
      "address": "snowflake_schema.schema",
      "mode": "managed",
      "type": "snowflake_schema",
      "name": "schema",
      "provider_name": "registry.terraform.io/snowflake-labs/snowflake",
      "change": {
        "actions": [
          "create"
        ],
        "before": null,
        "after": {
          "comment": null,
          "data_retention_days": 1,
          "database": "db",
          "is_managed": false,
          "is_transient": false,
          "name": "schema",
          "tag": []
        },
        "after_unknown": {
          "id": true,
          "tag": []
        },
        "before_sensitive": false,
        "after_sensitive": {
          "tag": []
        }
      }
    },
    {
      "address": "snowflake_table.table",
      "mode": "managed",
      "type": "snowflake_table",
      "name": "table",
      "provider_name": "registry.terraform.io/snowflake-labs/snowflake",
      "change": {
        "actions": [
          "create"
        ],
        "before": null,
        "after": {
          "change_tracking": false,
          "cluster_by": null,
          "column": [
            {
              "comment": null,
              "default": [],
              "identity": [],
              "masking_policy": null,
              "name": "column",
              "nullable": false,
              "type": "string"
            }
          ],
          "comment": null,
          "data_retention_days": null,
          "data_retention_time_in_days": null,
          "database": "db",
          "name": "table",
          "primary_key": [],
          "schema": "schema",
          "tag": []
        },
        "after_unknown": {
          "column": [
            {
              "default": [],
              "identity": []
            }
          ],
          "id": true,
          "owner": true,
          "primary_key": [],
          "qualified_name": true,
          "tag": []
        },
        "before_sensitive": false,
        "after_sensitive": {
          "column": [
            {
              "default": [],
              "identity": []
            }
          ],
          "primary_key": [],
          "tag": []
        }
      }
    },
    {
      "address": "snowflake_table.table-reference",
      "mode": "managed",
      "type": "snowflake_table",
      "name": "table-reference",
      "provider_name": "registry.terraform.io/snowflake-labs/snowflake",
      "change": {
        "actions": [
          "create"
        ],
        "before": null,
        "after": {
          "change_tracking": false,
          "cluster_by": null,
          "column": [
            {
              "comment": null,
              "default": [],
              "identity": [],
              "masking_policy": null,
              "name": "fk",
              "nullable": false,
              "type": "string"
            }
          ],
          "comment": null,
          "data_retention_days": null,
          "data_retention_time_in_days": null,
          "database": "db",
          "name": "table_reference",
          "primary_key": [],
          "schema": "schema",
          "tag": []
        },
        "after_unknown": {
          "column": [
            {
              "default": [],
              "identity": []
            }
          ],
          "id": true,
          "owner": true,
          "primary_key": [],
          "qualified_name": true,
          "tag": []
        },
        "before_sensitive": false,
        "after_sensitive": {
          "column": [
            {
              "default": [],
              "identity": []
            }
          ],
          "primary_key": [],
          "tag": []
        }
      }
    },
    {
      "address": "snowflake_table_constraint.fk",
      "mode": "managed",
      "type": "snowflake_table_constraint",
      "name": "fk",
      "provider_name": "registry.terraform.io/snowflake-labs/snowflake",
      "change": {
        "actions": [
          "create"
        ],
        "before": null,
        "after": {
          "columns": [
            "fk"
          ],
          "comment": null,
          "deferrable": true,
          "enable": true,
          "enforced": false,
          "foreign_key_properties": [
            {
              "match": "FULL",
              "on_delete": "NO ACTION",
              "on_update": "NO ACTION",
              "references": [
                {
                  "columns": [
                    "column"
                  ]
                }
              ]
            }
          ],
          "initially": "DEFERRED",
          "name": "fk",
          "rely": true,
          "type": "FOREIGN KEY",
          "validate": false
        },
        "after_unknown": {
          "columns": [
            false
          ],
          "foreign_key_properties": [
            {
              "references": [
                {
                  "columns": [
                    false
                  ],
                  "table_id": true
                }
              ]
            }
          ],
          "id": true,
          "table_id": true
        },
        "before_sensitive": false,
        "after_sensitive": {
          "columns": [
            false
          ],
          "foreign_key_properties": [
            {
              "references": [
                {
                  "columns": [
                    false
                  ]
                }
              ]
            }
          ]
        }
      }
    },
    {
      "address": "snowflake_table_constraint.pk",
      "mode": "managed",
      "type": "snowflake_table_constraint",
      "name": "pk",
      "provider_name": "registry.terraform.io/snowflake-labs/snowflake",
      "change": {
        "actions": [
          "create"
        ],
        "before": null,
        "after": {
          "columns": [
            "column"
          ],
          "comment": null,
          "deferrable": true,
          "enable": true,
          "enforced": false,
          "foreign_key_properties": [],
          "initially": "DEFERRED",
          "name": "pk",
          "rely": true,
          "type": "PRIMARY KEY",
          "validate": false
        },
        "after_unknown": {
          "columns": [
            false
          ],
          "foreign_key_properties": [],
          "id": true,
          "table_id": true
        },
        "before_sensitive": false,
        "after_sensitive": {
          "columns": [
            false
          ],
          "foreign_key_properties": []
        }
      }
    }
  ],
  "configuration": {
    "provider_config": {
      "snowflake": {
        "name": "snowflake",
        "full_name": "registry.terraform.io/snowflake-labs/snowflake",
        "version_constraint": "0.73.0",
        "expressions": {
          "account": {
            "references": [
              "var.snowflake-account"
            ]
          },
          "password": {
            "references": [
              "var.snowflake-password"
            ]
          },
          "role": {
            "references": [
              "var.snowflake-role"
            ]
          },
          "username": {
            "references": [
              "var.snowflake-username"
            ]
          }
        }
      }
    },
    "root_module": {
      "resources": [
        {
          "address": "snowflake_database.db",
          "mode": "managed",
          "type": "snowflake_database",
          "name": "db",
          "provider_config_key": "snowflake",
          "expressions": {
            "name": {
              "constant_value": "db"
            }
          },
          "schema_version": 0
        },
        {
          "address": "snowflake_schema.schema",
          "mode": "managed",
          "type": "snowflake_schema",
          "name": "schema",
          "provider_config_key": "snowflake",
          "expressions": {
            "database": {
              "references": [
                "snowflake_database.db.name",
                "snowflake_database.db"
              ]
            },
            "name": {
              "constant_value": "schema"
            }
          },
          "schema_version": 0
        },
        {
          "address": "snowflake_table.table",
          "mode": "managed",
          "type": "snowflake_table",
          "name": "table",
          "provider_config_key": "snowflake",
          "expressions": {
            "column": [
              {
                "name": {
                  "constant_value": "column"
                },
                "nullable": {
                  "constant_value": false
                },
                "type": {
                  "constant_value": "string"
                }
              }
            ],
            "database": {
              "references": [
                "snowflake_database.db.name",
                "snowflake_database.db"
              ]
            },
            "name": {
              "constant_value": "table"
            },
            "schema": {
              "references": [
                "snowflake_schema.schema.name",
                "snowflake_schema.schema"
              ]
            }
          },
          "schema_version": 0
        },
        {
          "address": "snowflake_table.table-reference",
          "mode": "managed",
          "type": "snowflake_table",
          "name": "table-reference",
          "provider_config_key": "snowflake",
          "expressions": {
            "column": [
              {
                "name": {
                  "constant_value": "fk"
                },
                "nullable": {
                  "constant_value": false
                },
                "type": {
                  "constant_value": "string"
                }
              }
            ],
            "database": {
              "references": [
                "snowflake_database.db.name",
                "snowflake_database.db"
              ]
            },
            "name": {
              "constant_value": "table_reference"
            },
            "schema": {
              "references": [
                "snowflake_schema.schema.name",
                "snowflake_schema.schema"
              ]
            }
          },
          "schema_version": 0
        },
        {
          "address": "snowflake_table_constraint.fk",
          "mode": "managed",
          "type": "snowflake_table_constraint",
          "name": "fk",
          "provider_config_key": "snowflake",
          "expressions": {
            "columns": {
              "constant_value": [
                "fk"
              ]
            },
            "foreign_key_properties": [
              {
                "references": [
                  {
                    "columns": {
                      "constant_value": [
                        "column"
                      ]
                    },
                    "table_id": {
                      "references": [
                        "snowflake_table.table.id",
                        "snowflake_table.table"
                      ]
                    }
                  }
                ]
              }
            ],
            "name": {
              "constant_value": "fk"
            },
            "table_id": {
              "references": [
                "snowflake_table.table-reference.id",
                "snowflake_table.table-reference"
              ]
            },
            "type": {
              "constant_value": "FOREIGN KEY"
            }
          },
          "schema_version": 0,
          "depends_on": [
            "snowflake_table_constraint.pk"
          ]
        },
        {
          "address": "snowflake_table_constraint.pk",
          "mode": "managed",
          "type": "snowflake_table_constraint",
          "name": "pk",
          "provider_config_key": "snowflake",
          "expressions": {
            "columns": {
              "constant_value": [
                "column"
              ]
            },
            "name": {
              "constant_value": "pk"
            },
            "table_id": {
              "references": [
                "snowflake_table.table.id",
                "snowflake_table.table"
              ]
            },
            "type": {
              "constant_value": "PRIMARY KEY"
            }
          },
          "schema_version": 0
        }
      ],
      "variables": {
        "snowflake-account": {
          "default": null
        },
        "snowflake-password": {
          "default": null
        },
        "snowflake-role": {
          "default": null
        },
        "snowflake-username": {
          "default": null
        }
      }
    }
  },
  "relevant_attributes": [
    {
      "resource": "snowflake_database.db",
      "attribute": [
        "name"
      ]
    },
    {
      "resource": "snowflake_schema.schema",
      "attribute": [
        "name"
      ]
    },
    {
      "resource": "snowflake_table.table",
      "attribute": [
        "id"
      ]
    },
    {
      "resource": "snowflake_table.table-reference",
      "attribute": [
        "id"
      ]
    }
  ],
  "timestamp": "2023-12-04T12:35:20Z"
}

Sample Terraform Code:

terraform {
  required_providers {
    snowflake = {
      source  = "Snowflake-Labs/snowflake"
      version = "0.73.0"
    }
  }
}

provider "snowflake" {
  account  = var.snowflake-account
  role     = var.snowflake-role
  username = var.snowflake-username
  password = var.snowflake-password
}

resource "snowflake_database" "db" {
  name = "db"
}

resource "snowflake_schema" "schema" {
  database = snowflake_database.db.name
  name     = "schema"
}

resource "snowflake_table" "table" {
  database = snowflake_database.db.name
  schema   = snowflake_schema.schema.name
  name     = "table"

  column {
    name     = "column"
    type     = "string"
    nullable = false
  }
}

resource "snowflake_table" "table-reference" {
  database = snowflake_database.db.name
  schema   = snowflake_schema.schema.name
  name     = "table_reference"

  column {
    name     = "fk"
    type     = "string"
    nullable = false
  }
}

resource "snowflake_table_constraint" "pk" {
  name     = "pk"
  type     = "PRIMARY KEY"
  table_id = snowflake_table.table.id
  columns  = ["column"]
}

resource "snowflake_table_constraint" "fk" {
  name     = "fk"
  type     = "FOREIGN KEY"
  table_id = snowflake_table.table-reference.id
  columns  = ["fk"]
  foreign_key_properties {
        references {
          table_id = snowflake_table.table.id
          columns  = ["column"]
        }
  }
  depends_on = [snowflake_table_constraint.pk]
}

Used terraform-compliance Parameters:

Running via Docker:
Yes

Error Output:

❗  ERROR: Hook 'load_terraform_data' from /usr/local/lib/python3.7/site-packages/terraform_compliance/steps/terrain.py:9 raised: 'AttributeError: 'dict' object has no attribute 'startswith''

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/radish/hookregistry.py", line 132, in call
    func(model, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/terraform_compliance/steps/terrain.py", line 11, in load_terraform_data
    world.config.terraform = TerraformParser(world.config.user_data['plan_file'])
  File "/usr/local/lib/python3.7/site-packages/terraform_compliance/extensions/terraform.py", line 60, in __init__
    self.parse()
  File "/usr/local/lib/python3.7/site-packages/terraform_compliance/extensions/terraform.py", line 567, in parse
    self._mount_references()
  File "/usr/local/lib/python3.7/site-packages/terraform_compliance/extensions/terraform.py", line 430, in _mount_references
    if r.startswith('var'):
AttributeError: 'dict' object has no attribute 'startswith'

Expected Behavior:

The tests are executed normally

Tested Versions:

  • terraform-compliance version: 1.3.45
  • terraform version: v1.5.6

Additional Context:

@Aviss Aviss added the bug label Dec 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants