Skip to content
SAF Advanced InSpec Profile Developer CourseSAF Advanced InSpec Profile Developer Course
MITRE InSpec Advanced Profile Developer Course
Course
Resources
Installation
  • Course

    • 1. Course Overview
      • 2. Review the Fundamentals
        • 3. Practice the Fundamentals
          • 4. Tools for Automation
            • 5. Automate Security Testing
              • 6. Explore InSpec Resources
                • 7. Local vs Built-in Resources
                  • 8. Create a Custom Resource - The Git Example
                    • 8.1. Create new InSpec profile
                      • 8.2. Develop controls to test / run profile
                        • 8.3. Rewrite test
                          • 8.4. Develop git resources
                          • 9. Create a Custom Resource - The Docker Example
                            • 10. Writing Plural Resources
                              • 11. Dissecting Resources
                                • 12. Exercise - Develop your own resources
                                  • 13. Add Your Resource to InSpec
                                    • 14. Custom Resource Examples from InSpec

                                    8. Create a Custom Resource - The Git Example

                                    June 7, 2022About 3 min

                                    On This Page
                                    • 8.1. Create new InSpec profile
                                    • 8.2. Develop controls to test / run profile
                                    • 8.3. Rewrite test
                                    • 8.4. Develop git resources

                                    Let's practice creating our own custom resource. Let's say we want to write tests that examine the current state of a local Git repository. We want to create a git resource to handle all of InSpec's interactions with the Git repo under the hood, so that we can focus on writing clean and easy-to-read profile code.

                                    Let's take a look at this InSpec video that walks through this example and then try it out ourselves.

                                    # 8.1. Create new InSpec profile

                                    Let's start by creating a new profile:

                                    inspec init profile git
                                    

                                    # 8.2. Develop controls to test / run profile

                                    Now let's write some controls and test that they run:

                                    # encoding: utf-8
                                    # copyright: 2018, The Authors
                                    
                                    git_dir = "/home/chef/apache/.git"
                                    
                                    # The following banches should exist
                                    describe command("git --git-dir #{git_dir} branch") do
                                      its('stdout') { should match /master/ }
                                    end
                                    
                                    describe command("git --git-dir #{git_dir} branch") do
                                      its('stdout') { should match /testBranch/ }
                                    end
                                    
                                    # What is the current branch
                                    describe command("git --git-dir #{git_dir} branch") do
                                      its('stdout') { should match /^\* master/ }
                                    end
                                    
                                    # What is the latest commit
                                    describe command("git --git-dir #{git_dir} log -1 --pretty=format:'%h'") do
                                      its('stdout') { should match /edc207f/ }
                                    end
                                    
                                    # What is the second to last commit
                                    describe command("git --git-dir #{git_dir} log --skip=1 -1 --pretty=format:'%h'") do
                                      its('stdout') { should match /8c30bff/ }
                                    end
                                    

                                    # 8.3. Rewrite test

                                    Let's rewrite the first test in our example file as follows:

                                    # The following banches should exist
                                    describe git(git_dir) do
                                      its('branches') { should include 'master' }
                                    end
                                    

                                    Now let's run the profile.

                                    inspec exec git
                                    

                                    We should get an error because the git method and resource are not defined yet. We should fix that.

                                    # 8.4. Develop git resources

                                    Let's start by creating a new file called git.rb in the libraries directory. The content of the file should look like this:

                                    # encoding: utf-8
                                    # copyright: 2019, The Authors
                                    
                                    class Git < Inspec.resource(1)
                                        name 'git'
                                    
                                    end
                                    

                                    Setting Up a Resource Using InSpec Init

                                    Instead of just creating the git.rb file in the libraries directory, you can use InSpec to assist you in creating a resource. Run inspec init resource <your-resource-name> and follow the prompts to create the foundation and see examples for a resource.

                                    Now run the profile again.

                                    inspec exec git
                                    

                                    This time we get another error letting us know that we have a resource that has been given the incorrect number of arguments. This means we have given an additional parameter to this resource that we have not yet accepted.

                                    Each resource will require an initialization method.

                                    For our git.rb file let's add that initialization method:

                                    # encoding: utf-8
                                    # copyright: 2019, The Authors
                                    
                                    class Git < Inspec.resource(1)
                                        name 'git'
                                    
                                        def initialize(path)
                                            @path = path
                                        end
                                    
                                    end
                                    

                                    This is saving the path we are passing in from the control into an instance method called path.

                                    Now when we run the profile.

                                    inspec exec git
                                    

                                    The test will run but we will get an error saying we do not have a branches method.

                                    So let's go back to our git.rb file to fix that by adding a branches method:

                                    # encoding: utf-8
                                    # copyright: 2019, The Authors
                                    
                                    class Git < Inspec.resource(1)
                                        name 'git'
                                    
                                        def initialize(path)
                                            @path = path
                                        end
                                    
                                        def branches
                                    
                                        end
                                    
                                    end
                                    

                                    We have now defined the branches method. Let's see what the test output shows us.

                                    inspec exec git
                                    

                                    Now the error message says that the branches method is returning a null value when it's expecting an array or something that is able to accept the include method invoked on it.

                                    We can use the InSpec helper method which enables you to invoke any other inspec resource as seen below:

                                    # encoding: utf-8
                                    # copyright: 2019, The Authors
                                    
                                    class Git < Inspec.resource(1)
                                        name 'git'
                                    
                                        def initialize(path)
                                            @path = path
                                        end
                                    
                                        def branches
                                            inspec.command("git --git-dir #{@path} branch").stdout
                                        end
                                    
                                    end
                                    

                                    We have borrowed the built-in command resource to handle running Git's CLI commands.

                                    Now we see that we get a passing test!

                                    Now let's adjust our test to also check for our second branch that we created earlier as well as check our current branch:

                                    # The following banches should exist
                                    describe git(git_dir) do
                                      its('branches') { should include 'master' }
                                      its('branches') { should include 'testBranch' }
                                      its('current_branch') { should cmp 'master' }
                                    end
                                    

                                    Let's head over to the git.rb file to create the current_branch method we are invoking in the above test:

                                    # encoding: utf-8
                                    # copyright: 2019, The Authors
                                    
                                    class Git < Inspec.resource(1)
                                        name 'git'
                                    
                                        def initialize(path)
                                            @path = path
                                        end
                                    
                                        def branches
                                            inspec.command("git --git-dir #{@path} branch").stdout
                                        end
                                    
                                        def current_branch
                                            branch_name = inspec.command("git --git-dir #{@path} branch").stdout.strip.split("\n").find do |name|
                                                name.start_with?('*')
                                            end
                                            branch_name.gsub(/^\*/,'').strip
                                        end
                                    
                                    end
                                    

                                    Now we can run the profile again.

                                    inspec exec git
                                    

                                    All the tests should pass!

                                    EXERCISE:
                                    As a solo exercise, try to create a method in the git.rb file to check what the last commit is.

                                    Edit this pageopen in new window
                                    Last update: 6/14/2022, 1:32:24 AM
                                    Contributors: Emily Rodriguez,Emily Rodriguez,Mo Shark,Will Dower
                                    Prev
                                    7. Local vs Built-in Resources
                                    Next
                                    9. Create a Custom Resource - The Docker Example
                                    Apache-2.0 | Copyright © 2022 - The MITRE Corporation
                                    Copyright © 2022 Aaron Lippold