home icon Kha Research Blog
GithubTwitter

Using semgrep in vim

In this post, I want to share my workflow for harnessing the power of Semgrep in Vim. Semgrep, a robust code analysis tool, can significantly enhance your codebase investigation process. Let me take you through my method for optimizing and simplifying code pattern searches effectively within Neovim.

My approach to using Semgrep is rather straightforward. I execute Semgrep from the command line to search for specific code patterns. For instance, you can look for a pattern in a Go codebase like this:

semgrep --quiet --lang=go --pattern="func min(...)"

My Refined Workflow

Here's the step-by-step approach I've refined for maximizing Semgrep's capabilities:

  1. Pattern Configuration: I begin by configuring the code pattern directly in a dedicated file, typically named semgrep_rule.yml.
  2. Running Semgrep: After configuring the pattern, I save the configuration file and execute Semgrep to initiate the code search.
  3. Loading Results in Neovim: Once Semgrep completes its search, I promptly load the results directly into Neovim for in-depth investigation.

To streamline this process, I've created a convenient script. It's worth noting that I use a random name for added flexibility when working on multiple sessions:

function run_semgrep() {
  # Generate a random string for file name
  random_value=$(cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 6 | head -n 1)

  # Create a temporary config file with a random value and a .yaml prefix
  config_tempfile="/tmp/config.${random_value}.yaml"

  # Copy the content of ~/.semgrep/config.yml to the temporary config file
  cp ~/.semgrep/config.yml "$config_tempfile"
  echo "Make config file $config_tempfile"


  # Open the temporary config file in nvim for editing
  nvim "$config_tempfile"

  # Create a temporary output file with a random value
  output_tempfile="/tmp/output.${random_value}.txt"

  # After closing nvim, execute semgrep
  echo 'Running semgrep .. Please wait'
  semgrep --vim  -f $config_tempfile --output $output_tempfile

  # Check if the output file is not empty
  if [ -s "$output_tempfile" ]; then
    # Open the output tempfile with nvim
    nvim -c ":cfile $output_tempfile"
  fi

  # Clean up the temporary files
  echo "Clean up ... $config_tempfile"
  echo "Clean up ... $output_tempfile"
  rm "$config_tempfile"
  rm "$output_tempfile"
}

Here's an example configuration for finding structs that contain a function as a field:

rules:
  - id: find-field-func
    patterns:
      - pattern: |
          type $T struct {
            $FIELD func(...) $RESULT
          }
    message: Semgrep found matches
    languages:
      - go
    severity: WARNING

To make my life easier, I've created an alias:

alias sg="run_semgrep"

In summary, this workflow eliminates the need for manual codebase investigation, making my development process significantly more efficient.