Skip to content

Commit

Permalink
Apply suggestions from code review
Browse files Browse the repository at this point in the history
Co-authored-by: Amndeep Singh Mann <[email protected]>
Signed-off-by: wdower <[email protected]>
  • Loading branch information
wdower and Amndeep7 authored Dec 5, 2024
1 parent d914fce commit 3543dbd
Show file tree
Hide file tree
Showing 7 changed files with 24 additions and 25 deletions.
13 changes: 6 additions & 7 deletions src/courses/advanced/04.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Now that you have learned about making and running InSpec profiles, let's dig de

### Core Resources

As you saw in the [Beginner class](../beginner/README.md), when writing InSpec code, many core resources are available because they are included in the main InSpec code base.
As you saw in the [Beginner class](../beginner/README.md), when writing InSpec code, many resources are automatically available because they come "batteries included" with InSpec.

* You can [explore the core InSpec resources](https://www.inspec.io/docs/reference/resources/) on Chef's documentation website.
* You can also [examine the source code](https://github.com/inspec/inspec/tree/master/lib/inspec/resources) to see what's available. For example, you can see how `file` and other InSpec resources are implemented.
Expand All @@ -32,7 +32,7 @@ Once you create and populate a custom resource Ruby file inside the `libraries`

### Resource Structure

Resources are written as regular Ruby classes, which inherit from the base `inspec.resource` class. The number (1) specifies the version of the parent class that this resource plugin uses. As Chef InSpec evolves, this interface may change and may require a higher version.
Like InSpec controls, InSpec resources are written as regular Ruby classes, which means you have the full power of Ruby at your fingertips as you craft this resource.

In addition to the resource name, the following attributes can be configured:

Expand All @@ -50,7 +50,6 @@ The following methods are available to the resource:

Let's look at a simple default resource to get an idea how these resources are used. We'll take a look at the [source code](https://github.com/inspec/inspec/blob/526b52657be571ba1573c12d666dc1f6330f2307/lib/inspec/resources/etc_hosts.rb) for the InSpec resource that models an operating system's hostfile, which is a simple file where we can map IP addresses (e.g. 198.162.8.1) to domain names (e.g. my-heimdall-deployment.my-domain.dev) without having to add a record to a DNS server somewhere.

The example shows a full resource using attributes and methods to return data about the modeled file:

```ruby
require "inspec/utils/parser"
Expand Down Expand Up @@ -131,14 +130,14 @@ The `class` is where a Ruby class definition is given. Classes define the struct
#### name
The `name` defines what token we can use to invoke this resource within our controls. Remember all those `describe` blocks we wrote that invoked the `nginx` resource? We used the term `nginx` to invoke the resource because that token is the defined `name` of the resource in its class definition.
#### supports
The `supports` keyword is used to define what types of system should be able to use this resource.or restrict the Ruby resource to work in specific ways, as shown in the example above that is used to restrict our class to specific platforms.
The `supports` keyword is used to define what types of platforms should be able to use this resource. The example above only supports the Windows and Unix-based operating systems, but other resources could state that they only support specific cloud providers or specific Linux distro releases.
#### desc
A simple human-friendly description of the purpose of this resource. This is also what gets printed when you run `<resource> help` in the InSpec shell.
A simple, human-friendly description of the purpose of this resource. This is also what gets printed when you run `<resource> help` in the InSpec shell.
#### examples
A simple use case example or a set of them. The example is usually a `describe` block using the resource, given as a multi-line comment.
One or more simple sample usages of the resource. It typically consists of a `describe` block using the resource, given as a multi-line string via the squiggly `heredoc` syntax.
#### private
This is a keyword that asserts that every function definition that shows up below this line in the class file should be considered _private_, or not accessible to users who instantiate an object out of this class. For example, when using this resource in a control file, you cannot invoke the `parse_data` function, because it is a private function that should really only be invoked by the resource class itself when the object is first created.
#### initialize method
An `initialize` method is required if your resource needs to be able to accept a parameter when called in a test (e.g. `file('this/path/is/a/parameter')`).
An `initialize` method is required if your resource needs to be able to accept a parameter when called in a test (e.g. the `file` resource takes in a string parameter that specifies the location of the file being examined: `file('this/path/is/a/parameter')`).
#### functionality methods
These methods return data from the resource so that you can use it in tests. There can be just a few of them, or there can be a whole bunch. These methods are how we define the custom matchers that can be invoked in an InSpec control file. We'll build some simple examples in the next section.
20 changes: 10 additions & 10 deletions src/courses/advanced/05.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ author: Aaron Lippold
headerDepth: 3
---

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

### Create a New InSpec Profile

Expand Down Expand Up @@ -34,17 +34,17 @@ Creating new profile at /workspaces/saf-training-lab-environment/git

:::

### Develop Controls to Test / Run Profile
### Develop Example Use-case Tests

To write tests, we first need to know and have what we are testing! In your Codespaces environment, there is a git repository that we will test under the `resources` folder. The git repository will be the test target, similarly to how the docker containers acted as test targets in previous sections. Unzip the target git repository using the following command:
To write resources, we first need to know what we are testing! In your Codespaces environment, there is a git repository that we will test under the `resources` folder. The git repository will be the test target, similarly to how the docker containers acted as test targets in previous sections. Unzip the target git repository using the following command:

```sh
unzip ./resources/git_test.zip
```

This will generate a `git_test` repository which we will use for these examples.

Now let's write some controls and test that they run. You can put these controls in the `example.rb` file generated in the `controls` folder of your `git` InSpec profile. These controls are written using the `command` resource which is provided by InSpec. We will write a `git` resource in this section to improve this test. **Note that you will need to put the full directory path of the `.git` file from your `git_test` repository as the `git_dir` value on line 4 of `example.rb`. To get the full path of your current location in the terminal, use `pwd`.**
Now let's write some tests and confirm that they run. You can put these tests in the `example.rb` file generated in the `controls` folder of your `git` InSpec profile. These tests are written using the `command` resource which is provided by InSpec. We will write a `git` resource in this section to improve this test. **Note that you will need to put the full directory path of the `.git` file from your `git_test` repository as the `git_dir` value on line 4 of `example.rb`. To get the full path of your current location in the terminal, use `pwd`.**

```ruby
# encoding: utf-8
Expand Down Expand Up @@ -121,9 +121,9 @@ Recall that other developers and assessors need to be able to understand how you

Let's rewrite these tests in a way that abstracts away the complexity of working with the `git` command into a resource.

### Rewrite test
### Rewrite a Test

Let's rewrite the first test in our example file to make it more readable with a `git` resource as follows:
Let's rewrite the first test in our example file to make it more readable by inventing a `git` resource that can simplify our test as follows:

```ruby
# The following banches should exist
Expand Down Expand Up @@ -322,9 +322,9 @@ Test Summary: 4 successful, 1 failure, 0 skipped

:::

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 `include` as a predicate method.
Now the error message says that the `branches` method is returning a null value which is a problem because it actually needs to return something, like an array, that implements the predicate method `include?`. A predicate method is one that evaluates a condition, in this case whether a given branch is "included" in the set of branches, and returns true or false accordingly.

We can use the InSpec helper method which enables you to invoke any other inspec resource as seen below:
To resolve this problem, we can use the `inspec` helper method to invoke the built-in `command` resource to extract this data as shown below:

```ruby
# encoding: utf-8
Expand All @@ -344,7 +344,7 @@ class Git < Inspec.resource(1)
end
```

We have borrowed the built-in `command` resource to handle running Git's CLI commands.
You might notice some similarities between this code and what we originally started with in our `example.rb` file - this is intentional! Resources are used to encapsulate complicated behaviors, such as the mechanics of dealing with niche `git` subcommands, and expose clean interfaces for use by control authors.

Now we see that we get a passing test!

Expand Down Expand Up @@ -458,7 +458,7 @@ As a solo exercise, try to create a method in the git.rb file to check what the
::: important This is Test-Driven Development!
Did you notice the overall arc of how we wrote this resource? We started with a set of tests before we even wrote any resource code, so we _knew_ we would start out with a failing profile.

However, that failing profile helped us define how we should build our resource. Since we knew what sort of tests we wanted to be able to run, we knew what functions we needed to write to support them in the `git` resource. Test-driven development is an excellent method of structuring your code before you even start writing it!
However, that failing profile helped us define how we should build our resource. Since we knew what sort of tests we wanted to be able to run, we knew what functions we needed to write to support them in the `git` resource. Test-driven development is an excellent method of defining requirements for your code before you even start writing it!
:::

## Run the InSpec shell with a custom resource
Expand Down
4 changes: 2 additions & 2 deletions src/courses/advanced/06.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe yaml('file_name') do
end
```

We test early and often, according to a test-driven development paradigm. We know that the test we wrote is not complete, but we can see if we are on the right track. Remember that the command line output can help guide your development!
We test early and often as according to the test-driven development paradigm. We know that the test we wrote is not complete, but we can see if we are on the right track. Remember that the command line output can help guide your development!

::: code-tabs

Expand Down Expand Up @@ -131,7 +131,7 @@ Test Summary: 2 successful, 0 failures, 0 skipped
```
:::
Much like our `git ` example, this series of tests works, but it could be made better. We essentially parsed the Compose file with a simple YAML file parser. If anybody else reads this code, it might not be clear what specific system component we are testing. Recall that we want InSpec tests to be extremely intuitive to read, even by people who did not write the code (and even by people who are not InSpec developers!).
Much like our `git ` example, this series of tests works, but it could be made better. We essentially parsed the Compose file with a simple YAML file parser which is fine for a one-off. However, if anybody else reads this code, it might not be clear what specific system component we are testing. Recall that we want InSpec tests to be extremely intuitive to read, even by people who did not write the code (and even by people who are not InSpec developers!). Furthermore, Compose files are very common! There's a high likelihood that you'd need to assess the contents of one again. Instead of writing a lot of repetitive code, we could create a resource specific to Compose files that exposes relevant attributes in an easy to access manner for reuse by our other controls - or even the broader security community if we choose to publish it publicly and/or get it merged into InSpec proper.
:::danger If you received an error above! - Concept Check
Expand Down
2 changes: 1 addition & 1 deletion src/courses/advanced/08.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ GitHub Actions organizes the tasks inside a pipeline into **jobs**. A given pipe

Pipeline orchestrators all have some system for selecting a **runner** node that will be assigned to handle the tasks we define for the pipeline. Runners are any system -- containers or full virtual machines in a cloud environment -- that handle the actual task execution for a pipeline.

In the case of GitHub Actions, when we trigger a pipeline, GitHub by default sends the jobs to its cloud environment to hosted runner nodes. The operating system of the runner for a particular job can be specified in the workflow file. See the [docs](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners) for details.
In the case of GitHub Actions, when we trigger a pipeline, GitHub by default sends the jobs to runner nodes hosted in its cloud environment. The operating system of the runner for a particular job can be specified in the workflow file. See the [docs](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners) for details.

In the next sections, we will create a GitHub Action workflow to handle these jobs for us. We will commit the workflow file to our repository and watch it work!

Expand Down
2 changes: 1 addition & 1 deletion src/courses/advanced/09.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ jobs:
- `name` is a simple title for this job.
- `runs-on` declares what operating system we want our runner node to be. We picked Ubuntu (and we suggest you do to to make sure the rest of the workflow commands work correctly).
- `env` declares environment variables for use by any step of this job. We will go ahead and set a few variables for running InSpec later on:
- `CHEF_LICENSE` will automatically accept the license prompt when you run InSpec the first time so that we don' hang waiting for input!
- `CHEF_LICENSE` will automatically accept the license prompt when you run InSpec the first time so that we don't hang waiting for input!
- `PROFILE` is set to the path of the InSpec profile we will use to test. This will make it easier to refer to the profile multiple times and still make it easy to swap out.

### The Next Step
Expand Down
2 changes: 1 addition & 1 deletion src/courses/advanced/10.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ Remember that we used the `checkout` action earlier, so the pipeline is currentl

In our `VALIDATE - Apply An Attestation` step, we invoke the SAF CLI.

The [SAF CLI](https://saf-cli.mitre.org/) is one the tool that the SAF supports to help automate security validation. It is our "kitchen-sink" utility for pipelines. If you took the [SAF User Class](../user/README.md), you are already familiar with the SAF CLI's [attestation](../user/12.md) function.
The [SAF CLI](https://saf-cli.mitre.org/) is a key tool amongst the many that the SAF utilizes to help automate security processes. It is our custom-made, "kitchen-sink" utility - and it sees a lot of use in CI/CD pipelines. If you took the [SAF User Class](../user/README.md), you are already familiar with the SAF CLI's [attestation](../user/12.md) function.

This tool was installed alongside InSpec when you ran the `./build-lab.sh` script into your codespace. Note that we also installed it as a step in the pipeline. For general installation instructions, see the first link in the above paragraph.

Expand Down
6 changes: 3 additions & 3 deletions src/courses/advanced/11.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ headerDepth: 3

## Verification

At this point, we have a much more mature workflow file. We have one more activity to do -- verification, or checking that the output of our validation run met our expectations.
At this point, we have a much more mature workflow file, but we still have one more activity left to do -- verification, or checking that the output of our validation run met our expectations.

Note that "meeting our expectations" does *not* automatically mean that there are no failing tests. In many real-world use cases, security tests fail, but the software is still considered worth the risk to deploy because of mitigations for that risk, or perhaps the requirement is inapplicable due to the details of the deployment. With that said, we still want to run our tests to make sure we are continually collecting data; we just don't want our pipeline to halt if it finds a test that we were always expecting to fail.

Expand Down Expand Up @@ -136,8 +136,8 @@ jobs:

A few things to note here:

- We added the `summary` step because it will print us a concise summary inside the pipeline job view itself. That command takes one file argument; the results file we want to summarize.
- The `validate threshold` command, however, needs two files -- one is our report file as usual, and the other is a **threshold file**.
- We added the `summary` step because it will print us a concise summary inside the pipeline job view itself. That command takes one file argument: the results file we want to summarize.
- The `validate threshold` command needs *two files*: one is our report file as usual, and the other is a **threshold file**.

#### Threshold Files

Expand Down

0 comments on commit 3543dbd

Please sign in to comment.