Sentinel error "Error parsing policy: policy.sentinel:2:10: expected operand, found 'import' (and 3 more errors)"

tfplan = import “tfplan”

Functions

Find all resources of a specific type from all modules using the tfplan import

find_resources_from_plan = func(type) {
resources = {}

Iterate over all modules in the tfplan import

for tfplan.module_paths as path {
# Iterate over the named resources of desired type in the module
for tfplan.module(path).resources[type] else {} as name, instances {
# Iterate over resource instances
for instances as index, r {
# Get the address of the instance
if length(path) == 0 {
# root module
address = type + “.” + name + “[” + string(index) + “]”
} else {
# non-root module
address = “module.” + strings.join(path, “.module.”) + “.” +
type + “.” + name + “[” + string(index) + “]”
}

    # Add the instance to resources map, setting the key to the address
    resources[address] = r
  }
}

}

return resources
}

Validate that all instances of specified type have a specified top-level

attribute that contains all members of a given list

validate_attribute_contains_list = func(type, attribute, required_values) {
validated = true

Get all resource instances of the specified type

resource_instances = find_resources_from_plan(type)

Loop through the resource instances

for resource_instances as address, r {
# Skip resource instances that are being destroyed
# to avoid unnecessary policy violations.
# Used to be: if length(r.diff) == 0
if r.destroy and not r.requires_new {
print(“Skipping resource”, address, “that is being destroyed.”)
continue
}

# Determine if the attribute is computed
# We check "attribute.%" and "attribute.#" because an
# attribute of type map or list won't show up in the diff
if (r.diff[attribute + ".%"].computed else false) or
   (r.diff[attribute + ".#"].computed else false) {
  print("Resource", address, "has attribute", attribute,
        "that is computed.")
  # If you want computed values to cause the policy to fail,
  # uncomment the next line.
  # validated = false
} else {
  # Validate that the attribute is a map
  # but first check if r.applied[attribute] exists
  if r.applied[attribute] else "" is not "" and
     types.type_of(r.applied[attribute]) is "map" {

    # Check if "managed-by" key exists and has the value "Terraform"
    if r.applied[attribute]["managed-by"] != "Terraform" {
      print("Resource", address, "does not have the required 'managed-by' tag set to 'Terraform'")
      validated = false
    }
  } else {
    print("Resource", address, "is missing attribute", attribute,
          "or it is not a map")
    validated = false
  } # end check that attribute is map

} # end computed check

} # end resource instances

return validated
}

Rules

Call the validation function for all AWS resources

tags_validated = validate_attribute_contains_list(“aws_”, “tags”, [ “managed-by” ])

Main rule that evaluates results

main = rule {
tags_validated
}

i im currently using gitlab-ci to run my terraform plan. i’m trying to import the plan in my policy

@maxcellayim237 can you share the contents of your sentinel.hcl configuration file as well as the command line that you are running in GitLab?

@hcrhall for my .hcl,

policy “policy-tag” {
enforcement_level = “advisory”
}

this is my recent error in the screenshot

@maxcellayim237 How are you importing the plan data into your policy.

I see a policy block, but I don’t know how you are importing the plan into the policy. I believe that you have the following at the top of you policy which I am not sure will work as expected:
tfplan = import “tfplan”

Try changing it to:
import “tfplan/v2” as tfplan

You’ll then need to mock the tfplan/v2 plugin in your .hcl file as follows:

mock "tfplan/v2" {
  module {
    source = "testdata/mock-tfplan-v2.sentinel"
  }
}

You can read more about mocking in the following:

@hcrhall i made this repo public. https://gitlab.com/mayim1/test

i keep having this error with sentinel. i’m not using TFC UI. everything is automated with gitlab. the idea is i want sentinel to import the output of my terraform plan and run it against the policy. im not quite sure what im doing wrong

@maxcellayim237 I cannot access the repository that you have shared. Please try again.

Take a look at the following sample code that I have put on GitHub. It should help you understand what is required to get this working:

The command-line and flags are pretty straightforward, what I think you are probably missing is the configuration syntax in the sentinel.hcl

@hcrhall that works. i have the exact replication in my gitlab env but got this error " Module installation failed:"

i also made the repo public if you want to take a look https://gitlab.com/mayim1/test .

in my case, i’m using gitlab-ci.yaml whi i expects should work the same as github action. here is my gitlab-ci file:

stages:

  • sentinel
    variables:
    VERSION: ‘0.24.1’
    sentinel:
    stage: sentinel
    image:
    name: ubuntu:latest
    script:

It looks like the $PWD is different in your setup which is why you are getting the module installation failure. Easiest way to resolve the issue would be to add a cd compliance/config as the first line of your script. Then everything should work as expected.

Otherwise change the source paths in the sentinel.hcl for all of the configuration blocks.

@hcrhall yes that worked. thanks

@hcrhall lastly. i see you use the data in plan.json as mock data cicd/terraform/plan.json at nn · nanjehj/cicd · GitHub. lets say i have different terraform files and i run terraform plan which saves the output of my plan

- terraform plan -out=tfplan
- export TFPLAN=$(terraform show -json tfplan > tfplan.json || echo "Plan failed")

i tried coping the output of tfplan.json and saving it in a file then applying the policy against that file, i was expecting it to fail since it violated the policy but it showed PASS. i guess its because the syntax is not the same as the mockdata.

my question is in real life env where we implement these policies against actual terraform plan and not against mock data, how does that work ??

my question is in real life env where we implement these policies against actual terraform plan and not against mock data, how does that work ??

The mock data is used to mimic the exact scenario in which the policy should fail. If you find that your policy is passing when it should in fact fail, that is an indication that you have not catered for all permutations of the configuration. A mock is simply a snapshot of how Terraform will represent the plan when your terraform configuration is written in a particular way.

The most common reason why policies pass against the actual plan is because the configuration you are checking is computed and only known after the configuration is applied.

Read more here: