/hclgrep

Syntax based grep for HCL(v2)

Primary LanguageGoBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

hclgrep

workflow

Search for HCL(v2) using syntax tree.

The idea is heavily inspired by https://github.com/mvdan/gogrep.

Install

go install github.com/magodo/hclgrep@latest

Usage

usage: hclgrep [options] commands [FILE...]

An option is one of the following:

-H                  prefix the filename and byte offset of a match

A command is one of the following:

-x  pattern         find all nodes matching a pattern
-g  pattern         discard nodes not matching a pattern
-v  pattern         discard nodes matching a pattern
-p  number          navigate up a number of node parents
-rx name="regexp"   filter nodes by regexp against wildcard value of "name"
-w  name            print the wildcard node only (must be the last command)

A pattern is a piece of HCL code which may include wildcards. It can be:

  • A body (zero or more attributes, and zero or more blocks)
  • An expression

There are two types of wildcards can be used in a pattern, depending on the scope it resides in:

  • Attribute wildcard ("@"): represents an attribute, a block, or an object element
  • Expression wildcard ("$"): represents an expression or a place that a string is accepted (i.e. as a block type, block label)

The wildcards are followed by a name. Each wildcard with the same name must match the same node/string, excluding "_". Example:

$x.$_ = $x # assignment of self to a field in self

The wildcard name is only recorded for "-x" command or "-g" command (the first match in DFS).

If "*" is before the name, it will match any number of nodes. Example:

[$*_] # any number of elements in a tuple

resource foo "name" {
    @*_  # any number of attributes/blocks inside the resource block body
}

Example

  • Grep dynamic blocks used in Terraform config

      $ hclgrep -x 'dynamic $_ {@*_}' main.tf
    
  • Grep potential mis-used "count" in Terraform config

      $ hclgrep -x 'var.$_[count.index]' main.tf
    
  • Grep module source addresses in Terraform config

      $ hclgrep -x 'module $_ {@*_}' \
          -x 'source = $addr' \
          -w addr main.tf
    
  • Grep AzureRM Terraform network security rule resource which allows 22 port for inbound traffic

      $ hclgrep -x 'resource azurerm_network_security_rule $_ {@*_}' \
      -g 'direction = "Inbound"' \
      -g 'access = "Allow"' \
      -g 'destination_port_range = $port' \
      -rx 'port="22|\*"' \
      main.tf
    
  • Grep for the evaluated Terraform configurations, run following command in the root module (given there is no output variables defined)

      $ terraform show -no-color | sed --expression 's;(sensitive value);"";' | hclgrep -x '<pattern>'
    

Limitation

  • The any expression wildcard ($*) doesn't work inside a traversal.
  • The any wildcard doesn't remember the matched wildcard name.