terraform-compliance / cli

a lightweight, security focused, BDD test framework against terraform.
https://terraform-compliance.com
MIT License
1.34k stars 151 forks source link

ERROR: state.out.json is not a valid terraform plan json output. #305

Open kjr247 opened 4 years ago

kjr247 commented 4 years ago

Description : OS: macos catalina docker terraform-compliance v1.2.7 I'm just running the scripts on the docs, and it doesn't seem to work when I pass it proper json files. Is this still maintained?

To Reproduce

  1. <Either a sample terraform code, or your terraform plan file if it doesn't have any confidential information>
    
    # main.tf
    provider "aws" {
    region = var.region
    }

locals { common_tags = { Environment = var.env_name TerraformWorkspace = var.env_name } }

terraform { backend "remote" { organization = "***" workspaces { prefix = "**" } } }


```hcl
# variables.tf
variable "region" {
  description = "AWS region"
}

variable "env_name" {
}
  1. <Used terraform-compliance parameters> ??
  2. using docker
  3. 
    $ terraform show -json > state.out.json
    $ terraform state pull > state.out
    $ terraform-compliance -p state.out.json
    # terraform-compliance v1.2.7 initiated

ERROR: state.out.json is not a valid terraform plan json output.

5. <Your feature/scenario/steps>
```gherkin
Given I have followed the instructions from the docs to run the above commands
Then it must not error
And it must show me all the power and glory of terraform-compliance.

Expected behavior : Shouldn't error out and should work based on the docs.

Tested versions :

Additional context

eerkunt commented 4 years ago

Hello @kjr247,

Yes the tool is maintained, since we have a release frequency around once a week.

I tried to reproduce your problem, but couldn't. It works with states without a problem, maybe using an remote backend make things weird on the terraform side. Is it possible to share the state.out.json ?

Apart from that, in case you didn't terraform apply, I suppose you need to change your tests like ;

Given I want to see all the power and glory of terraform-compliance
When I run terraform-compliance
Then it first requires a valid state file
And terraform apply must run in order to create that
jantman commented 3 years ago

I'm seeing the same issue with a state file of mine, created with 0.12.26 (state version 4). Unfortunately, adding the --debug command line flag generates zero additional output:

terraform-compliance v1.3.0 initiated

ERROR: tfstate.out is not a valid terraform plan json output.

Running terraform-compliance via Python's trace module (python -mtrace --trace venv/lib/python3.8/site-packages/terraform_compliance/main.py --features scenarios/ --planfile tfstate.out --debug) shows that the error is being thrown by terraform_compliance.common.readable_plan.ReadablePlan:69, which is asserting that a number of keys exist in the JSON file specified as --planfile.

In my case, for a state file, it's failing on the first one: format_version. Which is completely correct, because a Terraform State version 4 file doesn't have a format_version key, it has a version key. It also doesn't have a values key, which is checked a few lines down. However, the JSON that's output by terraform show -json has the format_version and values keys, and works with terraform-compliance. It appears that ReadablePlan is actually looking for the JSON terraform show output, not a state file.

This is unfortunate, since it means that even the simple example in the documentation of terraform state pull > state.out && terraform-compliance -p state.out [...] fails.

Digging a bit deeper into the code, it appears that for my JSON state file, the call to filetype.guess is returning None, which is skipping over calling convert_terraform_plan_to_json() which would fix this. This is likely because terraform state files are already JSON files, not binary like the plan files.

The best thing that I can figure is that the example in the docs of terraform state pull > state.out && terraform-compliance -p state.out [...] is wrong, and really assumes that there's a terraform show -json in between there. Unfortunately, that's quite problematic as it means that you need an initialized terraform directory, complete with providers, in order to check a state file... which eliminates the possibility of doing something like pointing terraform-compliance at an entire directory of state files (e.g. from an S3 bucket, or some other remote state storage).

jantman commented 3 years ago

First off, let me say that I absolutely love this project. It has the distinct possibility of being able to do absolutely wonderful things for our current workflow, which is based on detecting issues after-the-fact.

I believe this is the same as #235. I'd be willing to try to work up a PR to fix this, but it feels to me like there are a few other issues that I'd run into... mainly that I really want to be able to call terraform-compliance programmatically via Python instead of just via the cli entrypoint, as well as use multiple feature directories, but it appears that the current layout of terraform_compliance.main.cli precludes that.

markvoll commented 3 years ago

I am also seeing this issue with terraform 12.26.

I think the problem is here: https://github.com/eerkunt/terraform-compliance/blob/02be1d2c4c98754f41998ccb2e9557708eac141b/terraform_compliance/common/readable_plan.py#L56

Specifically the state file that I have doesn't have a 'format_version' field in the json. I am also not seeing 'values' in data. which is another check right below that might fail.

Guessing that state file formatting changed in newer versions of terraform.

pat-wong-ronin commented 3 years ago

Getting this issue with:

eerkunt commented 3 years ago

This is interesting, I can't reproduce the problem with 0.12.28.

Is it possible to provide a plan.out.json ? Maybe I am missing something

dkinder commented 3 years ago

I am also seeing this issue with:

when running :

# A
$ terraform state pull > state.out
$ terraform-compliance --debug -p ./state.out-f ./scenarios

OR

# B 
$ terraform show -json > state.out.json
$ terraform-compliance --debug -p ./state.out -f ./scenarios

I get

terraform-compliance v1.3.6 initiated

ERROR: ./state.out is not a valid JSON file

However, when I do this:

# C
$ terraform plan -out=state.out
$ terraform-compliance --debug -p ./state.out -f ./scenarios

It works.

I have several other states that use # B and work. I'm only seeing this on one of my code bases. Is there an explanation for this?

wahlfeld10x commented 3 years ago

Also having this issue:

// my state file

bash-5.0# cat state.out | jq .
{
  "version": 4,
  "terraform_version": "0.12.29",
  "serial": 582,
  "lineage": "d4fb72f6-340e-b5af-5897-d5ab8bf7e937",
  "outputs": {

..blabla...

}

// running tf compliance I get

bash-5.0# terraform-compliance --debug -f git::ssh://git@...blabla... -p state.out
terraform-compliance v1.3.7 initiated

Using remote git repository: :ssh://git@...blabla...
ERROR: state.out is not a valid JSON file

This message seems to correspond to line: https://github.com/eerkunt/terraform-compliance/blob/02be1d2c4c98754f41998ccb2e9557708eac141b/terraform_compliance/common/readable_plan.py#L43-L45

timgates42 commented 3 years ago

If processing pretty printed json plan files which contain multiple lines I notice this change https://github.com/eerkunt/terraform-compliance/pull/387 makes it process only the second line of the json file and get a JSON decode error.

eerkunt commented 3 years ago

That was definitely the problem. I will have a think about this for supporting the github actions & native cli usage.

Currently, the workaround for working on states is running like ;

$ terraform plan -out=state.out
$ terraform-compliance -p ./state.out -f ./scenarios
Prazzy commented 3 years ago

State output file

  "format_version": "0.1",
  "terraform_version": "0.14.3",
  "values": {
    "root_module": {
      "child_modules": [
        {
          "resources": [
            {

I get

terraform-compliance v1.3.15 initiated

ERROR: state.out.json is not a valid terraform plan json output.

It seems the issue is in this code where it's not considering "child_modules" tag.

# Check if this is a state file            
if 'values' in data:                
     assert data['values']['root_module']['resources']

Code: https://github.com/terraform-compliance/cli/blob/ac843f3cda214b9c0d32be459fb623ccc18a9525/terraform_compliance/common/readable_plan.py#L76

neuralNet007 commented 2 years ago

Hey, I had a similar error with my main.tfplan.json file because the file format wasn't UTF-8. I generated the file using terraform show -json main.tfplan > main.tfplan.json. After hours of agony, I noticed this LOC https://github.com/terraform-compliance/cli/blob/ac843f3cda214b9c0d32be459fb623ccc18a9525/terraform_compliance/common/readable_plan.py#L40 Checking the format of my main.tfplan.json, I realized it wasn't UTF-8. I then changed my command to output the json file to the following: terraform show -json main.tfplan | out-file -encoding ASCII main.tfplan.json and now it's working like a charm.