In #1454, we welcomed a newly-revamped JUnit formatter which has
a dependency on Nokogiri. Unfortunately, this had led us to problems
getting InSpec included in Chef omnibus builds (see chef/chef#5937)
because Chef is using Ruby 2.4.1 and the Nokogiri maintainers have
not yet released a windows binary gem that supports Ruby 2.4.x.
This has led to breaking builds in Chef's CI platform and would
block the acceptance of chef/chef#5937.
This change replaces Nokogiri use with REXML instead. While REXML
can be slower than Nokogiri, it does not require native extensions
and is supported on all Chef platforms.
Signed-off-by: Adam Leff <adam@leff.co>
* Enable customization of supermarket_url
It looks like this was originally supposed to work, but at some point
the default value was put in the method body rather than in the method
parameters.
This change allows you to configure the supermarket_url in test kitchen
like so:
```
verifier:
inspec_tests:
- name: linux-hardening
supermarket: som3guy/apache-disa-stig
supermarket_url: https://my.supermarket.com
```
Signed-off-by: Ryan Larson <ryan.mango.larson@gmail.com>
If a repo did not exist, running matchers against it (such as `exist`)
were failing due to a bug in `#to_s` when fetching the repo name. The
`info` method would return nil and we'd still try to treat it as a hash.
This change ensures that info is always a hash, possibly empty if the
repo doesn't exist, and uses the repo name provided by the user rather
than shortening it to be consistent with our other resources which don't
manipulate the user input in the formatter.
Also added a method_missing to allow users to interrogate repo options,
such as baseurl or gpgcheck.
Signed-off-by: Adam Leff <adam@leff.co>
The CLI output for the vendoring of profiles has been updated slightly
to be more clear, and the functional tests have been modified to match
as well.
Signed-off-by: Adam Leff <adam@leff.co>
Per PR feedback, `Inspec::ProfileVendor` is created to centralize
the logic and data of vendoring profile dependencies. The `BaseCLI`
class and the `Habitat::Profile` class have been modified to use it
Signed-off-by: Adam Leff <adam@leff.co>
This change adds support in Habitat-packaged profiles for
profiles that depend on other profiles. When `inspec habitat
profile create` or `inspec habitat profile upload` is run,
it will see if the profile's dependencies have been vendored
yet, and if not, it will vendor them before creating the
habitat artifact.
For the git and URL fetchers, more explicit creation of the
target directories for the vendored profiles is done. This
is implicitly done via normal CLI interactions a user may
go through, but in our case, we want to ensure those directories
are there before the fetchers try to write out content.
By adding this support, we also fix a bug experienced in Habitat
where a profile that was packaged before an `inspec exec` was run
for the profile would cause a failure in Habitat. This is caused
by `inspec exec` doing a vendor of the dependencies if necessary
and generating the inspec.lock file. In Habitat, the package dir
is not writable by the hab user and InSpec would fail to run due
to an inability to write out an inspec.lock.
Signed-off-by: Adam Leff <adam@leff.co>
Netstat will sometimes output an IPv6 address that is not
formatted correctly; the address is either truncated or uses
or implies the `::` shorthand notation twice. This yields an
invalid IPv6 address and causes IPAddr.new to choke.
This change guards against invalid IP addresses and ensures they
do not end up in the port resource's entries list.
Signed-off-by: Adam Leff <adam@leff.co>
* add tag object
Signed-off-by: Christoph Hartmann <chris@lollyrock.com>
* add tests for to_hash function in tag
Signed-off-by: Christoph Hartmann <chris@lollyrock.com>
When SimpleConfig parses a config file that has sections, such as a mysqld
config file, the values within that section are returned via a Hash. However,
we do not provide an easy way to write tests for those deep hash values:
```
describe mysql_conf('/tmp/my.cnf') do
its('mysqld.expire_logs_days') { should cmp 10 }
end
MySQL Configuration
∅ undefined method `expire_logs_days' for #<Hash:0x007fe463795a00>
```
This change provides a method-based accessor for Hashes that are built via
SimpleConfig.
```
describe mysql_conf('/tmp/my.cnf') do
its('mysqld.expire_logs_days') { should cmp 10 }
end
MySQL Configuration
✔ mysqld.expire_logs_days should cmp == 10
```
Fixes#1541 by changing the way the attributes are fetched.
Signed-off-by: Adam Leff <adam@leff.co>
When attempting to access array values via the `json` resource:
```
describe json('/tmp/test.json') do
its(['array',0]) { should eq "zero" }
end
```
... the resulting data would be an array of the size of the original array
with all the values replaced with nils:
```
expected: "zero"
got: [nil, nil, nil]
```
This was due to a bug in the ObjectTraverser mixin that mapped array values
back through `extract_value` rather than properly handling the passed-in
key(s). This worked fine for the specific data format created by the `csv`
resource but did not work `json` or any other resource that subclassed the
`JsonConfig` resource.
This change fixes the logic when dealing with an array when it's encountered,
and fixes up the `csv` resource with its own `value` method.
This change also adds tests for ObjectTraverser.
Signed-off-by: Adam Leff <adam@leff.co>
As raised in #1526, adding an additional example showing how
a user can use the `where` accessor to find commands matching
a pattern and write a test using the results.
Signed-off-by: Adam Leff <adam@leff.co>
Currently, if the inspec.yml for a profile is invalid (such as including
an improperly-defined multi-line string), InSpec will throw an exception
from the YAML parser that does not given a clear indication that the
issue was encountered while parsing the inspec.yml file.
This change introduces a better exception message to clue the user into
where the problem actually lies.
Signed-off-by: Adam Leff <adam@leff.co>
On Linux, netstat may show a tcp6/udp6 protocol line but include a
v4 address. This happens with AF_INET6 sockets that can accept
both v4 and v6 traffic. The port check was not properly handling
this situation and trying to pass a v4 address to URI bracketed as
if it was a v6 address.
Signed-off-by: Adam Leff <adam@leff.co>
* Add open_timeout to NET::HTTP.start call
Signed-off-by: Makoto Nozaki <makoto.nozaki@twosigma.com>
* Code cleanup based on the discussion at #1538
Signed-off-by: Makoto Nozaki <makoto.nozaki@twosigma.com>
When running a InSpec profile built with Habitat, we now
write the formatter/reporter data to a JSON file in the
pkg.svc_var_path rather than STDOUT. This will allow for
programmatic collection of this data and future enhancements
to allow this data to be passed around a Habitat ring.
This also corrects an issue creating a Habitat profile if the
profile had never been in the local InSpec cache. By setting a
mock Backend when creating the profile object, similarly to what
the archivers do, this issue is avoided.
Signed-off-by: Adam Leff <adam@leff.co>
Fixes issue #1508
* Windows terminals don't support extended ANSI colours. Use basic + intensity
* Windows terminals don't support UTF-8 well so don't use special characters
Other OS'es get what they had before.
Signed-off-by: Richard Nixon <richard.nixon@btinternet.com>
Two new commands have been created:
* inspec habitat profile create /path/to/profile
* inspec habitat profile upload /path/to/profile
The `create` command creates a Habitat artifact that contains the contents
of the Habitat profile found at the provided path. This will be used later
in some Habitat + InSpec integrations.
The `upload` command does the same create process but then uploads the
resulting artifact to the Habitat Depot.
Signed-off-by: Adam Leff <adam@leff.co>
The following new resources have been added; however, they
presently only support FreeBSD and similar.
* `zfs_dataset`: tests if a named ZFS dataset is present
and/or has certain properties.
* `zfs_pool`: tests if a named ZFS pool is present and/or
has certain properties.
Additionally, the `mount` resource has been reworked to
include support for FreeBSD; while the existing class
was renamed to LinuxMountParser.
Unit-tests were added for all of the above.
Signed-off-by: Joseph Benden <joe@benden.us>
When in inspec shell, you need to type the `help` command to find out info
about your target system. This info would be super helpful right out of the
gate so users have confidence that they're targeting the correct system.
The target info is still available via the `help` command as it always has
been, as well.
Signed-off-by: Adam Leff <adam@leff.co>
The inline docs for SourceReaders::InspecReader#new state that it takes
a SourceReader object for the target... but we're trying to create the
SourceReader object! It actually takes a FileProvider object that is
capabile of listing files for the given profile and reading them.
Signed-off-by: Adam Leff <adam@leff.co>
When running InSpec with multiple profiles, and two or more of the profiles
are read in using the "Flat" SourceReader (i.e. they are not actual profiles
with a metadata file like inspec.yml, but rather just a folder containing
.rb files with controls and tests in them), InSpec would throw a NilClass
error when building the necessary objects for the formatter.
The cause was in `#profile_contains_example` in the formatter code which
checks to see if the profile name is the same as the profile_id in the given
example. However, if both of those were nil, it would potentially match the
wrong Flat-read profile.
This change fixes this in two ways: refusing to match if the profile name
or example profile ID is nil, and adding a default name to a profile if
it doesn't have a title or name. This will solve the matching issue and also
clean up the formatter output so users can more easily tell what tests
are from which profile/path.
Signed-off-by: Adam Leff <adam@leff.co>
The crontab resource parses a particular user's crontab file into
individual entries and allows the user to assert information about
each entry as needed.
Signed-off-by: Adam Leff <adam@leff.co>
The other Chef tooling (chef-client, chef, kitchen, berks, etc.)
support a `-v` flag to display the version. Currently, inspec
errors out with the following error:
```
Could not find command "_v".
```
This adds a Thor map so that `-v` executes the `version` command.
Signed-off-by: Adam Leff <adam@leff.co>
This pull request adds a packages resource so that we can check for pattern matches against all the packages on a system. This initially implements only dpkg support for debian-based platforms so we can cover this use case:
```ruby
describe packages(/^xserver-xorg.*/) do
its("list") { should be_empty }
end
```
This uses FilterTable so we can supply additional queries, too.
```ruby
describe packages(/vi.+/).where { status != 'installed' } do
its('statuses') { should be_empty }
end
```
Users can specify the name as a string or a regular expression. If it is a string, we will escape it and convert it to a regular expression to use in matching against the full returned list of packages. If it is a regular expression, we take that as is and use it to filter the results.
While some package management systems such as `dpkg` can take a shell glob argument to filter their results, we eschew this and require a regular expression to match multiple package names because we will need this to work across other platforms in the future. This means that the following:
```ruby
packages("vim")
```
Will return *all* the "vim" packages on the system. The `packages` resource will take `"vim"`, turn it into `/vim/`, and greedily match anything with "vim" in the name. To match only a single package named `vim`, it needs to be an anchored regular expression.
```ruby
packages(/^vim$/)
```
Signed-off-by: Joshua Timberman <joshua@chef.io>
Use entries instead of list
Added a few more tests and non installed package in output
Signed-off-by: Alex Pop <apop@chef.io>
fix lint
Signed-off-by: Alex Pop <apop@chef.io>
Signed-off-by: Joshua Timberman <joshua@chef.io>
We do not store a token in the config file but rather generate one on
each commmand. This is just a first pass and needs some work.
Signed-off-by: Montague, Brent <brent@bmontague.com>
Based on some feedback from @arlimus there were some methods that
were not part of the public inteface that I moved to private.
I changed the examples collection from a delete from the output_hash
to retrieve the controls.
Created a helper for the all_unique_controls which was used in two helper
methods.
Signed-off-by: Franklin Webber <franklin@chef.io>
The class size is too big and Rubocop is right. There are a few
more classes in there that could be extracted but I am going to
ignore it. The other issues that it presented were fair.
Signed-off-by: Franklin Webber <franklin@chef.io>
* Moved things around for better understanding of the class
* Used `private` to denote what was on the public interface
* Solved the ugly TODO which was calculating the state of the control's
summary
* Used `#examples` instead of `res = control[:results]` throughout the
#summary and #title methods
Signed-off-by: Franklin Webber <franklin@chef.io>
* Fixes an issue when specifying no profile
* Fixes an issue when displaying a profile that has included/required profiels
* Fixes an issue when specifying profiles with only metadata
* Fixes formatting for spacing to ensure it adheres to previous alignment
* Fixes issue with the Control object and the rolling up of failed
and skipped examples.
Signed-off-by: Franklin Webber <franklin@chef.io>
The profiles will display the controls with their results and
then display the examples not associated with any control but
within the profile.
Signed-off-by: Franklin Webber <franklin@chef.io>
A lot of the work in #flush_current_control is acting on the control.
I am starting the flip of the control and bringing those messages being
sent originating from a control class itself.
Signed-off-by: Franklin Webber <franklin@chef.io>
Cleans up the #stop action on the JSON formatter by creating more
methods that memoize values or provide values through a method
interface.
There is still more that can be done with the whole mapping
examples to controls through profiles.
Signed-off-by: Franklin Webber <franklin@chef.io>
The full JSON formatter was using the start step to setup the profiles_info.
I moved that to a memozied method so that the first time it is called it will
be created.
Signed-off-by: Franklin Webber <franklin@chef.io>
While rebasing the branch where I was working on the cli formatter I
noticed the addition of junit. However, it was not in the help.
Signed-off-by: Franklin Webber <franklin@chef.io>
Reverts the work-around that pulls down the latest 100 tools
and filters for type == 'compliance_profile' in the client.
Go back to using tool-search with the new type parameter.
Omit start:0 because that's the default.
Keep the number of items returned at 100, which is more than the
default 10.
Signed-off-by: Robb Kidd <robb@thekidds.org>
Previous, require_controls was including all controls from the named
profile, despite the documented behavior being that it only includes
controls explicitly pulled in by the user. The cause was two-fold:
1) A previous refactor meant that we weren't removing the rule from the
correct context, and
2) We weren't descending down the dependency tree when filtering rules.
This commit fixes the require_controls DSL method and adds a test to
help prevent future regressions.
Signed-off-by: Steven Danna <steve@chef.io>
Before, a URL based source might be downloaded multiple times during the
dependency fetching and lockfile creation. This commit tries to avoid
this by:
1) Memoizing data about the archive to avoid re-fetching the archive
2) Adding a CachedFetcher wrapper around the fetcher class to help
ensure that callers always consult the cache before fetching.
Signed-off-by: Steven Danna <steve@chef.io>
This commit threads through some state related to whether or not a
profile is "local", that is whether it is a directory on disk. If it
is, we then write out the lockfile to disk.
Signed-off-by: Steven Danna <steve@chef.io>
This allows users to run:
inspec exec ./ --cache PATH
which will use `PATH` as the dir to retrieve and store remote
dependencies. The hope is that this can eventually be used with
`inspec vendor PATH` to package up a profile for offline use.
Signed-off-by: Steven Danna <steve@chef.io>
If a URL based source does not match the shasum recorded in the
lockfile, it likely means a new version has been pushed to the remote
source. In this case, we fail to help ensure that when using a lockfile
we always run the same code as when the lockfile was created.
Signed-off-by: Steven Danna <steve@chef.io>
All resources from deps are added into the control_eval_context used by
the current profile. However, if there is a name conflict, the last
loaded resource wins. The new `require_resource` dsl method allows the
user to do the following:
require_resource(profile: 'profile_name',
resource: 'other',
as: 'renamed')
describe renamed do
...
end
Signed-off-by: Steven Danna <steve@chef.io>
This is a regression introduced by the changes from string to symbol
keys in v0.34.0. It seems that our test cookbook that had a nested
dependency example wasn't actually wired up to run.
This adds a basic functional test and corrects the typo.
Signed-off-by: Steven Danna <steve@chef.io>
The recent changes to provide isolated views of the available resources
was not extended to Rspec::ExampleGroups. This ensures that
ExampleGroups have access to the same resources as the enclosing
Inspec::Rule.
Signed-off-by: Steven Danna <steve@chef.io>
This adds a new git fetcher. In doing so, it also refactors how the
fetchers work a bit to better support fetchers that need to resolve
user-provided sources to fully specified sources appropriate for a
lockfile.
Signed-off-by: Steven Danna <steve@chef.io>
We already monkeypatch require so that it is redirected through the
require_loader. All of the tests pass with this removal. We might
cause some breakage with this removal that we aren't testing, but given
that we are mucking with `require` it seems preferable to have one
mechanism by which we do that and solve any bugs with that single path.
Signed-off-by: Steven Danna <steve@chef.io>
Previously, libraries were loaded by instance_eval'ing them against
the same execution context used for control files. All resources were
registered against a single global registry when the `name` dsl method
was invoked. To obtain seperation of resources, we would mutate the
instance variable holding the globale registry and then change it back
at the end.
Now, we instance_eval library files inside an anonymous class. This
class has its own version of `Inspec.resource` that returns another
class with the resource DSL method and the profile-specific resource
registry.
The goal of these changes is to ensure that the libraries from
dependencies are loaded even if their controls are never included. To
facilitate this, we break up the loading into seperate steps, and move
the loading code into the Profile which has acceess to the dependency
information.
Signed-off-by: Steven Danna <steve@chef.io>
Previously, all resources were loaded into a single resource registry.
Now, each profile context has a resource registry, when a profile's
library is loaded into the profile context, we update the
profile-context-specific resource registry. This local registry is
then used to populate the execution context that the rules are
evaluated in.
Signed-off-by: Steven Danna <steve@chef.io>