Playing with conftest and yum repository policies

A project to modernise an old Terraform code base came across my desk recently and while investigating the more recent developments in testing tools and workflows I stumbled onto conftest, a utility to help you write tests against structured configuration data. I was interested in trying the technology out but I don’t want to put something i have this little experience in on the main flow of work so I decided to do a few tests with it against a smaller, more self contained, use case.

My home lab runs a lot of CentOS and Fedora so when I found an old yum repository client configuration with gpgcheck disabled the streams aligned and I had my small problem to solve. I added the card to my list and in an impossible amount of hubris marked it as small. I’d read a few blog posts by this point and thought, “I can do that.” But I couldn’t.

I threw hours into getting the policies to fail in the correct way. Now I look back at the six lines, one of which is white space, I can’t help but ask “WTF was I doing to take that long?”

violation[msg] {
    configuration_block := input[configuration_block_name]

    not configuration_block.gpgcheck = 1
    msg = sprintf("gpgcheck should be enabled in %s", [configuration_block_name])
}

Every character of that policy took minutes off my life. I don’t want to consider how long I invested putting the sample configuration file through the same few commands. It started out promisingly, using parse I could see how my sample data was being structured.

$ conftest parse -i ini basic-single-repo.repo 
{
        "code": {
                "baseurl": "https://packages.microsoft.com/yumrepos/vscode",
                "enabled": 1,
                "gpgcheck": 1,
                "gpgkey": "https://packages.microsoft.com/keys/microsoft.asc",
                "name": "Visual Studio Code"
        }
}

Then I tried to write the policy. It honestly felt like trying to fix an engine through the exhaust pipe. Action at a distance didn’t quite match the level of frustration. I started scattering sprintf throughout the code and forced it to raise failure just to check a value. Then I started running under --trace to see more of what the internals were doing. This was oddly calming to watch, even though nothing was actually working, and eventually I stumbled on to the trace() function and trace(sprintf("%v", [input])) . Finally a way to output things. But only in the verbose --trace mode. Things did get easier once I’d found trace and searching through GitHub for other peoples examples and reading them helped me get a better perspective on what I was trying to do.

I’ve now managed to reach the first real milestone since I started playing with conftest. I have working Open policy agent policies that cover the original insecure yum client configuration and I can run them against arbitrary files using the code directly from GitHub.

conftest test -i ini --update github.com/deanwilson/opa-policies.git//yumrepo basic-single-repo-broken.repo

FAIL - basic-single-repo-broken.repo - gpgcheck should be enabled in code
FAIL - basic-single-repo-broken.repo - baseurl in code should use https URLs
FAIL - basic-single-repo-broken.repo - gpgkey in code should use https URLs
FAIL - basic-single-repo-broken.repo - metalink in code should use https URLs
FAIL - basic-single-repo-broken.repo - mirrorlist in code should use https URLs

5 tests, 0 passed, 0 warnings, 5 failures

I’m still at the beginner stage of learning OPA / rego / conftest and I don’t feel comfortable suggesting the tooling for the Terraform project just yet but I can see the potential it offers. I intend to try a few more small policy cases to build up some more experience with the language, and hopefully get unit testing working (that’s still too raw to talk about in this post), but I’m glad I spent some time actually trying to get the code to work. I need to think some more about when I’d use Augeas and RSpec vs conftest and Rego but it’s always nice to have flexible options.

As an aside trying out rego with a project that has repo in the file names was a massive mistake. Typos? Oh yes. Auto complete not getting very far due to the shared root? Very much so.