Feature Friday #36: Formatting policy with cffmt

Posted by Nick Anderson
November 15, 2024

Looking for a tool to help you format your CFEngine policy? Have you heard of cffmt?

You might recall that we had a chat with the author, Miek Gieben in The agent is in - Episode 24.1 In case you missed it, cffmt is a command line tool for formatting CFEngine policy files, like gofmt for .cf files.2 Let’s take a look.

Consistent formatting can really ease reading of policy, but sometimes editors are configured differently and you can end up with inconsistently formatted policy. For example, here is a contrived policy file with some irregular formatting:

bundle agent __main__
{
      vars: "String1"
      string => "Hello String1";
    "list" slist => { "one", "two", "three", "four", "five" };

  files:

  "/tmp/hello-world.txt"               content => "$(String1)",
      perms => mog( "600",
                    "root",
                    "root"),
               comment => "Important stuff";

  classes:
      "Some_class"
        expression => "any";

      reports:
      Some_class:: "Some_class is defined.";
@if minium_version(3.21)
      any::
  "Running 3.21 or later $(sys.cf_version)";
@endif
}

Let’s use cffmt to clean it up. First, we need to install cffmt which we can do using go install:

go install github.com/miekg/cf/cmd/cffmt@main
go: downloading github.com/miekg/cf v0.1.25
go: downloading github.com/shivamMg/ppds v0.0.1
go: downloading github.com/alecthomas/chroma/v2 v2.12.0
go: downloading github.com/dlclark/regexp2 v1.10.0

Once installed you should find cffmt in ~/go/bin/. Simply run cffmt with the path to the policy file as an argument.

~/go/bin/cffmt /tmp/feature-friday-36-0.cf

We can see it emits a much more nicely formatted policy file:

bundle agent __main__
{
  vars:

    "String1" string => "Hello String1";
    "list"    slist => { "one", "two", "three", "four", "five" };


  files:

    "/tmp/hello-world.txt"
      content => "$(String1)",
      perms   => mog("600", "root", "root"),
      comment => "Important stuff";


  classes:

    "Some_class" expression => "any";


  reports:

    Some_class::
      "Some_class is defined.";

@if minium_version(3.21)

    any::
      "Running 3.21 or later $(sys.cf_version)";

@endif
}

While cffmt is quite opinionated, it does provide the capability to skip formatting a file if there is a top-level comment # cffmt:no which is useful if you are auto-formatting many policy files. You can also instruct it to format slist vars with an entry on each line by placing a # cffmt:list comment preceding the definition.

Happy Friday! 🎉


  1. Find Miek Gieben on Mastadon, LinkedIn, and GitHub↩︎

  2. Find documentation and source for cffmt on Github: https://github.com/miekg/cf ↩︎