goss Documentation

Quick and Easy server testing/validation

RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy goss on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name goss -p 8000:8000 --restart always mysql:5.7
Configured Services & Ports
βš™οΈ db
image: mysql:5.7
βš™οΈ wordpress
image: wordpress:latest
πŸ”Œ Ports: 8000:80
docker-compose.yml
yaml (docker-compose.yml)
version: '3.3'

services:
  db:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress

  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
volumes:
  db_data: {}

File: README.md

Goss - Quick and Easy server validation




**

Goss in 45 seconds

Note: For testing containers see the dgoss wrapper.
Also, user submitted wrapper scripts for Kubernetes kgoss
and Docker Compose dcgoss.

Note: For some Docker/Kubernetes healthcheck, health endpoint, and
container ordering examples, see my blog post.

Introduction

What is Goss?

Goss is a YAML based serverspec alternative tool for validating a server's configuration.
It eases the process of writing tests by allowing the user to generate tests from the current system state.
Once the test suite is written they can be executed, waited-on, or served as a health endpoint.

Why use Goss?

  • Goss is EASY! - Goss in 45 seconds
  • Goss is FAST! - small-medium test suites are near instantaneous, see benchmarks
  • Goss is SMALL! - <10MB single self-contained binary

Installation

Note: For macOS and Windows, see: platform-feature-parity.

This will install goss and dgoss.

Note: Using curl | sh is not recommended for production systems, use manual installation below.

bash
# Install latest version to /usr/local/bin
curl -fsSL https://goss.rocks/install | sh

# Install v0.4.10 version to ~/bin
curl -fsSL https://goss.rocks/install | GOSS_VER=v0.4.10 GOSS_DST=~/bin sh

Manual installation

!!! warning

text
If you're using goss in a CI pipeline, it's recommended that you don't
download the `latest` and instead use a specific release tag. Using the
latest release may lead to unexpected behaviour.

Specific Version

bash
# See https://github.com/goss-org/goss/releases for release versions
VERSION=v0.4.10
curl -L "https://github.com/goss-org/goss/releases/download/${VERSION}/goss_${VERSION#v}_linux_x86_64.tar.gz" | tar xz -C /usr/local/bin goss
chmod +rx /usr/local/bin/goss

# (optional) dgoss docker wrapper (use 'master' for latest version)
VERSION=v0.4.10
curl -L "https://github.com/goss-org/goss/releases/download/${VERSION}/dgoss" -o /usr/local/bin/dgoss
chmod +rx /usr/local/bin/dgoss

Build it yourself

bash
make build

Alternatively, you can build it with goreleaser. To
build a binary, use gorelease build, and to only build for the same OS and
architecture as the machine you're building on, include the --single-target
flag. The --clean flag will clean up any existing builds, and --snapshot
will allow you to build against something other than a tag.

Here's an example:

console
$ goreleaser build --clean --single-target --snapshot
  β€’ skipping validate...
  β€’ cleaning distribution directory
  β€’ loading environment variables
  β€’ getting and validating git state
    β€’ ignoring errors because this is a snapshot     error=git doesn't contain any tags - either add a tag or use --snapshot
    β€’ using tags                                     previous= current=v0.0.0
    β€’ pipe skipped or partially skipped              reason=disabled during snapshot mode
  β€’ parsing tag
  β€’ setting defaults
  β€’ partial
  β€’ snapshotting
    β€’ building snapshot...                           version=0.0.1-next
  β€’ running before hooks
    β€’ running                                        hook=go mod tidy
  β€’ ensuring distribution directory
  β€’ setting up metadata
  β€’ writing release metadata
  β€’ loading go mod information
  β€’ build prerequisites
  β€’ building binaries
    β€’ partial build                                  match=target=linux_arm64_v8.0
    β€’ building                                       paths=cmd/goss binaries=goss target=linux_arm64_v8.0
      β€’ took: 31s
  β€’ writing artifacts metadata
  β€’ build succeeded after 31s
  β€’ thanks for using GoReleaser!
$ tree dist
dist
β”œβ”€β”€ artifacts.json
β”œβ”€β”€ binaries_linux_arm64_v8.0
β”‚   └── goss                            <- your binary
β”œβ”€β”€ config.yaml
└── metadata.json

2 directories, 4 files

Full Documentation

Full Documentation

Using the container image

Using the Goss container image

Quick start

Writing a simple sshd test

An initial set of tests can be derived from the system state by using the add
or autoadd commands.

Let's write a simple sshd test using autoadd.

txt
# Running it as root will allow it to also detect ports
$ sudo goss autoadd sshd

Generated goss.yaml:

yaml
port:
  tcp:22:
    listening: true
    ip:
    - 0.0.0.0
  tcp6:22:
    listening: true
    ip:
    - '::'
service:
  sshd:
    enabled: true
    running: true
user:
  sshd:
    exists: true
    uid: 74
    gid: 74
    groups:
    - sshd
    home: /var/empty/sshd
    shell: /sbin/nologin
group:
  sshd:
    exists: true
    gid: 74
process:
  sshd:
    running: true

Now that we have a test suite, we can:

  • Run it once
console
$ goss validate
...............

Total Duration: 0.021s # <- yeah, it's that fast..
Count: 15, Failed: 0
  • Edit it to use templates, and run with a vars file
console
goss --vars vars.yaml validate
  • keep running it until the system enters a valid state or we timeout
console
goss validate --retry-timeout 30s --sleep 1s
  • serve the tests as a health endpoint
console
$ goss serve &
$ curl localhost:8080/healthz

# JSON endpoint
$ goss serve --format json &
$ curl localhost:8080/healthz

# rspecish response via content negotiation
$ goss serve --format json &
$ curl -H "Accept: application/vnd.goss-rspecish" localhost:8080/healthz

Manually editing Goss files

Goss files can be manually edited to improve readability and expressiveness of tests.

A Json draft 7 schema available
at https://goss.readthedocs.io/en/stable/schema.yaml makes it easier to edit simple goss.yaml files in IDEs,
providing usual coding assistance such as inline documentation, completion and static analysis.
See #793 for screenshots.

For example, to configure the Json schema in JetBrains intellij IDEA,
follow documented instructions,
with arguments such as:

  • schema url=https://goss.readthedocs.io/en/stable/schema.yaml
  • schema version=Json schema version 7
  • file path pattern=*/goss.yaml

In addition, Goss files can also be further manually edited (without yet full json support) to use:

Some examples:

yaml+jinja
user:
  sshd:
    title: UID must be between 50-100, GID doesn't matter. home is flexible
    meta:
      desc: Ensure sshd is enabled and running since it's needed for system management
      sev: 5
    exists: true
    uid:
      # Validate that UID is between 50 and 100
      and:
        gt: 50
        lt: 100
    home:
      # Home can be any of the following
      or:
      - /var/empty/sshd
      - /var/run/sshd

package:
  kernel:
    installed: true
    versions:
      # Must have 3 kernels and none of them can be 4.4.0
      and:
      - have-len: 3
      - not:
          contain-element: 4.4.0

  # Loaded from --vars YAML/JSON file
  {{.Vars.package}}:
    installed: true

{{if eq .Env.OS "centos"}}
  # This test is only when $OS environment variable is set to "centos"
  libselinux:
    installed: true
{{end}}

Goss.yaml files with templates can still be validated through the Json schema after being rendered
using the goss render command. See example below

console
$ cd docs
$ goss --vars ./vars.yaml render > rendered_goss.yaml
# proceed with json schema validation of rendered_goss.yaml in your favorite IDE
# or in one of the Json schema validator listed in https://json-schema.org/implementations.html
# The following example is for a Linux AMD64 host
$ curl -LO https://github.com/neilpa/yajsv/releases/download/v1.4.1/yajsv.linux.amd64
$ chmod a+x yajsv.linux.amd64
$ sudo mv yajsv.linux.amd64 /usr/sbin/yajsv

$ yajsv -s goss-json-schema.yaml rendered_goss.yaml

rendered_goss.yaml: fail: process.chrome: skip is required
rendered_goss.yaml: fail: service.sshd: skip is required
1 of 1 failed validation
rendered_goss.yaml: fail: process.chrome: skip is required
rendered_goss.yaml: fail: service.sshd: skip is required

JSON Schema maintains a table of validators.

Supported resources

  • package - add new package
  • file - add new file
  • addr - add new remote address:port - ex: google.com:80
  • port - add new listening [protocol]:port - ex: 80 or udp:123
  • service - add new service
  • user - add new user
  • group - add new group
  • command - add new command
  • dns - add new dns
  • process - add new process name
  • kernel-param - add new kernel-param
  • mount - add new mount
  • interface - add new network interface
  • http - add new network http url with proxy support
  • goss - add new goss file, it will be imported from this one
  • matching - test for matches in supplied content

Supported output formats

  • rspecish - (default) Similar to rspec output
  • documentation - Verbose test results
  • json - JSON, detailed test result
  • tap - TAP style
  • junit - JUnit style
  • nagios - Nagios/Sensu compatible output /w exit code 2 for failures.
  • prometheus - Prometheus compatible output.
  • silent - No output. Avoids exposing system information (e.g. when serving tests as a healthcheck endpoint).

Community Contributions

  • goss-ansible - Ansible module for Goss.
  • degoss - Ansible role for installing, running, and removing Goss in a single go.
  • ansible-goss-install - Ansible role for installing Goss (option for install as user or root)
  • kitchen-goss - A test-kitchen verifier plugin for Goss.
  • goss-fpm-files - Might be useful for building goss system packages.
  • packer-provisioner-goss - A packer plugin to run Goss as a provision step.
  • gossboss - Collect and view aggregated Goss test results from multiple remote Goss servers.

Limitations

goss works well on Linux, but support on Windows & macOS is alpha. See platform-feature-parity.

The following tests have limitations.

Package:

  • rpm
  • deb
  • Alpine apk
  • pacman

Service:

  • systemd
  • sysV init
  • OpenRC init
  • Upstart

File: docs/cli.md

Command Line Interface

Usage

console
NAME:
   goss - Quick and Easy server validation

USAGE:
   goss [global options] command [command options] [arguments...]

VERSION:
   0.0.0

COMMANDS:
     validate, v  Validate system
     serve, s     Serve a health endpoint
     render, r    render gossfile after imports
     autoadd, aa  automatically add all matching resource to the test suite
     add, a       add a resource to the test suite
     help, h      Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --gossfile value, -g value  Goss file to read from / write to (default: "./goss.yaml") [$GOSS_FILE]
   --vars value                json/yaml file containing variables for template. Can be specified multiple times. When specified multiple times it will load variables from all files. Non-empty map keys that overlap will be overriden by subsequent file that defines them. [$GOSS_VARS]
   --vars-inline value         json/yaml string containing variables for template (overwrites vars) [$GOSS_VARS_INLINE]
   --package value             Package type to use [rpm, deb, apk, pacman]
   --help, -h                  show help
   --version, -v               print the version

!!! note
Most flags can be set by using environment variables, see --help for more info.

Global options

--gossfile/-g <gossfile>
: The file to use when reading/writing tests. Use --gossfile - or -g - to read from STDIN.

text
Valid formats:

* `yaml` *(default)*
* `json`

--vars <varfile>
: Files to read variables from when rendering gossfile templates. Can be specified multiple
times. When specified multiple times it will load variables from all files. Non-empty map keys that overlap will
be overriden by subsequent file that defines them.

text
Valid formats:

* `yaml` *(default)*
* `json`

--package <type>
: The package type to check for.

text
Valid options are:

* `apk`
* `deb`
* `pacman`
* `rpm`

--loglevel <level>, -L <level>
: Goss logging verbosity level (default: INFO).
This is a global option: it applies to every command, and may be given either
before or after the command name.
Lower levels of tracing include all upper levels traces also
(ie. INFO includes WARN and ERROR).
level can be one of:

text
* `ERROR` - Critical errors that halt goss or significantly affect its functionality,
    requiring immediate intervention.
* `WARN` - Non-critical issues that may require attention, such as overwritten keys
    or deprecated features.
* `INFO` - General operational messages, useful for tasks where a more structured
    output is needed (e.g. goss serve).
* `DEBUG` - Information useful for the goss user to debug.
* `TRACE` - Detailed internal system activities useful for goss developers to debug.

Commands

Commands are the actions goss can run.

  • add: add a single test for a resource
  • autoadd: automatically add multiple tests for a resource
  • render: renders and outputs the gossfile, importing all included gossfiles
  • serve: serves the gossfile validation as an HTTP endpoint on a specified address and port,
    so you can use your gossfile as a health report for the host
  • validate: runs the goss test suite on your server

`add`

!!! abstract "Add system resource to test suite"
console goss add [--exclude-attr ] <test> [<test>] goss a [--exclude-attr ] <test> [<test>]

This will add a test for a resource. Non existent resources will add a test to ensure they do not exist on the system.
A sub-command resource type has to be provided when running add.

--exclude-attr
: Ignore non-required attribute(s) matching the provided glob when adding a new resource,
may be specified multiple times.

!!! example
console goss add file /etc/passwd goss a user nobody goss add --exclude-attr home --exclude-attr shell user nobody goss a --exclude-attr '*' user nobody

Resources types

Type Description
addr Verify if a remote address:port is reachable
command Run a command and validate the exit status and/or output
dns Resolves a dns name and validates the addresses
file Validate a file existence, permissions, stats (size, etc) and contents
goss Includes the contents of another gossfile
group can validate the existence and values of a group on the system
http Validate the HTTP response code, headers, and content of a URI
interface Validate the existence and values (es. the addresses) of a network interface
kernel-param Validate kernel parameters (sysctl values)
mount Validate the existence and options relative to a mount point
package Validate the status of a package using the package manager specified on the commandline with --package
port Validate the status of a local port, for example 80 or udp:123
process Validate the status of a process
service Validate if a service is running and/or enabled at boot
user Validate the existence and values of a user on the system

`autoadd`

!!! abstract "Auto add all matching resources to test suite"
console goss autoadd [arguments...] goss aa [arguments...]

Automatically adds all existing resources matching the provided argument.

Will automatically add the following matching resources:

  • file - only if argument contains /
  • group
  • package
  • port
  • process - Also adding any ports it's listening to (if run as root)
  • service
  • user

Will NOT automatically add:

  • addr
  • command - for safety
  • dns
  • http
  • interface
  • kernel-param
  • mount

!!! example
console goss autoadd sshd

text
Generates the following `goss.yaml`

```yaml
port:
  tcp:22:
    listening: true
    ip:
    - 0.0.0.0
  tcp6:22:
    listening: true
    ip:
    - '::'
service:
  sshd:
    enabled: true
    running: true
user:
  sshd:
    exists: true
    uid: 74
    gid: 74
    groups:
    - sshd
    home: /var/empty/sshd
    shell: /sbin/nologin
group:
  sshd:
    exists: true
    gid: 74
process:
  sshd:
    running: true
```

`render`

!!! abstract "Render gossfile after importing all referenced gossfiles"
goss render goss r

This command allows you to keep your tests separated and render a single, valid, gossfile,
by including them with the gossfile directive.

--debug
: This prints the rendered golang template prior to printing the parsed JSON/YAML gossfile.

!!! example
```console
$ cat goss_httpd_package.yaml
package:
httpd:
installed: true
versions:
- 2.2.15

text
$ cat goss_httpd_service.yaml
service:
  httpd:
    enabled: true
    running: true

$ cat goss_nginx_service-NO.yaml
service:
  nginx:
    enabled: false
    running: false

$ cat goss.yaml
gossfile:
  goss_httpd_package.yaml: {}
  goss_httpd_service.yaml: {}
  goss_nginx_service-NO.yaml: {}

$ goss -g goss.yaml render
package:
  httpd:
    installed: true
    versions:
    - 2.2.15
service:
  httpd:
    enabled: true
    running: true
  nginx:
    enabled: false
    running: false
```

`serve`

!!! abstract "Serve a health endpoint"
console goss serve [<opts>...] goss s [<opts>...]

serve exposes the goss test suite as a health endpoint on your server.
The end-point will return the stest results in the format requested and an http status of 200 or 503.

serve will look for a test suite in the same order as validate

--cache <duration>, -c <duration>
: Time to cache the results (default: 5s)

--endpoint <endpoint>, -e <endpoint>
: Endpoint to expose (default: /healthz)

--format <format>, -f <format>
: Output format, same as validate

--listen-addr [ip]:port, -l [ip]:port
: Address to listen on (default: :8080)

--max-concurrent <num>
: Max number of tests to run concurrently

!!! example
console $ goss serve & $ curl http://localhost:8080/healthz # JSON endpoint $ goss serve --format json & $ curl localhost:8080/healthz # rspecish output format in response via content negotiation goss serve --format json & curl -H "Accept: application/vnd.goss-rspecish" localhost:8080/healthz

The application/vnd.goss-{output format} media type can be used in the Accept request header
to determine the response's content-type.
You can also Accept: application/json to get back application/json.

`validate`

!!! abstract "Validate the system"
console goss validate [<opts>...] goss v [<opts>...]

validate runs the goss test suite on your server. Prints an rspec-like (by default) output of test results.
Exits with status 0 on success, non-0 otherwise.

--format <format>, -f <format>
: Output format. Can be one of:

text
- `documentation` - Verbose test results
- `json` - Detailed test result on a single line (See `pretty` format option)
- `junit`
- `nagios` - Nagios/Sensu compatible output /w exit code 2 for failures
- `rspecish` **(default)** - Similar to rspec output
- `tap`
- `prometheus` - Prometheus compatible output.
- `silent` - No output. Avoids exposing system information (e.g. when serving tests as a healthcheck endpoint)

--format-options, -o
: Output format option:

text
- `perfdata` - Outputs Nagios "performance data". Applies to `nagios` output
- `verbose`  - Gives verbose output. Applies to `nagios` and `prometheus` output
- `pretty`   - Pretty printing for the `json` output
- `sort`     - Sorts the results

--max-concurrent <num>
: Max number of tests to run concurrently

--color/--no-color
: Force color or disable color

--retry-timeout <timeout>, -r <timeout>
: Retry on failure so long as elapsed + sleep time is less than this

text
*default: `0`*

--sleep <duration>, -s <duration>
: Time to sleep between retries

text
*default: `1s`*

!!! example

text
```console
$ goss validate --format documentation
File: /etc/hosts: exists: matches expectation: [true]
DNS: localhost: resolvable: matches expectation: [true]
[...]
Total Duration: 0.002s
Count: 10, Failed: 2, Skipped: 0

$ curl -s https://static/or/dynamic/goss.json | goss validate
...F.F
[...]
Total Duration: 0.002s
Count: 6, Failed: 2, Skipped: 0

$ goss render | ssh remote-host 'goss -g - validate'
......

Total Duration: 0.002s
Count: 6, Failed: 0, Skipped: 0

$ goss validate --format nagios -o verbose -o perfdata
GOSS CRITICAL - Count: 76, Failed: 1, Skipped: 0, Duration: 1.009s|total=76 failed=1 skipped=0 duration=1.009s
Fail 1 - DNS: localhost: addrs: doesn't match, expect: [["127.0.0.1","::1"]] found: [["127.0.0.1"]]
$ echo $?
2
```

File: docs/container_image.md

Goss container image

Dockerfiles

Using the base image

This is a simple alpine image with Goss preinstalled on it.
Can be used as a base image for your projects to allow for easy health checking.

Mount example

Create the container

sh
docker run --name goss ghcr.io/goss-org/goss goss

Create your container and mount goss

sh
docker run --rm -it --volumes-from goss --name weby nginx

Run goss inside your container

sh
docker exec weby /goss/goss autoadd nginx

HEALTHCHECK example

dockerfile
FROM ghcr.io/goss-org/goss:latest

COPY goss/ /goss/
HEALTHCHECK --interval=1s --timeout=6s CMD goss -g /goss/goss.yaml validate

# your stuff..

Startup delay example

dockerfile
FROM ghcr.io/goss-org/goss:latest

COPY goss/ /goss/

# Alternatively, the -r option can be set
# using the GOSS_RETRY_TIMEOUT env variable
CMD goss -g /goss/goss.yaml validate -r 5m && exec real_comand..

File: docs/gossfile.md

The `gossfile` configuration

Goss test creation

Goss tests can be created by using either of following methods.

  1. goss autoadd <resource to test>
  2. goss add <resource to test>
  3. manually create YAML/JSON test file by hand.

To customize the parameters generated by goss add and goss autoadd YAML file you need to manually edit it.

goss add package nginx will generate below YAML

yaml
package:
  nginx:
    installed: true
    versions:
    - 1.17.8

To test uninstall scenario you would need to manually edit it and set it as below.

yaml
package:
  nginx:
    installed: false

Important note about goss file format

It is important to note that both YAML and JSON are formats that describe a nested data structure.

yaml title="wrong way to write a goss file"
file:
  /etc/httpd/conf/httpd.conf:
    exists: true

service:
  httpd:
    enabled: true
    running: true

file:
  /var/www/html:
    filetype: directory
    exists: true

If you try to validate this file, it will only run the second file test:

console
$ goss validate --format documentation
File: /var/www/html: exists: matches expectation: [true]
File: /var/www/html: filetype: matches expectation: ["directory"]
Service: httpd: enabled: matches expectation: [true]
Service: httpd: running: matches expectation: [true]

Total Duration: 0.014s
Count: 8, Failed: 0, Skipped: 0

As you can see, the first file check has not been run because the second file entry overwrites the previous one.

You need to make sure all the entries of the same type are under the same declaration.

yaml title="this is the correct way to write a goss file"
file:
  /etc/httpd/conf/httpd.conf:
    exists: true
  /var/www/html:
    filetype: directory
    exists: true

service:
  httpd:
    enabled: true
    running: true

Running validate with this configuration will correctly check both files:

console
$ goss validate --format documentation
File: /var/www/html: exists: matches expectation: [true]
File: /var/www/html: filetype: matches expectation: ["directory"]
File: /etc/httpd/conf/httpd.conf: exists: matches expectation: [true]
Service: httpd: enabled: matches expectation: [true]
Service: httpd: running: matches expectation: [true]

Total Duration: 0.014s
Count: 10, Failed: 0, Skipped: 0

Please note that using the goss add and goss autoadd command will create a valid file,
but if you're writing your files by hand you'll save a lot of time by taking this in consideration.

If you want to keep your tests in separate files, the best way to obtain a single, valid,
file is to create a main goss file that includes the others with the gossfile directive
and then render it.

Schema

A Json draft 7 schema
available at https://goss.readthedocs.io/en/stable/schema.yaml
makes it easier to edit simple goss.yaml files in IDEs, providing usual coding assistance
such as inline documentation, completion and static analysis.
See #793 for screenshots.

For example, to configure the Json schema in JetBrains intellij IDEA,
follow documented instructions,
with arguments such as:

  • schema url=https://goss.readthedocs.io/en/stable/schema.yaml
  • schema version=Json schema version 7
  • file path pattern=*/goss.yaml

Available tests

addr

Validates if a remote address:port are accessible.

yaml
addr:
  tcp://ip-address-or-domain-name:80:
    # required attributes
    reachable: true
    # optional attributes
    # defaults to hash key
    address: "tcp://ip-address-or-domain-name:80"
    timeout: 500
    local-address: 127.0.0.1

command

Validates the exit-status and output of a command.
This can be used in combination with the gjson matcher to create powerful goss custom tests.

yaml
command:
  'go version':
    # required attributes
    exit-status: 0
    # optional attributes
    # defaults to hash key
    exec: "go version"
    stdout:
    - go version go1.6 linux/amd64
    stderr: []
    timeout: 10000 # in milliseconds
    skip: false
    retry_count: 1   # Enables retry mechanism when greater than 0; number of additional attempts
    retry_delay: 500  # Delay in milliseconds before each retry; duration strings like 500ms or 2s also work

stdout and stderr can be a string or pattern

!!! warning "An empty list asserts nothing"

text
A list of patterns is a list of conditions that must all be satisfied. An
empty list is therefore zero conditions, and always passes:

```yaml
stderr: []   # asserts nothing; passes even when stderr has output
stderr: ""   # asserts stderr is empty
```

This is why `goss add` writes `stderr: ""` rather than `stderr: []` when a
command produced no error output. Use `[]` only where you deliberately want
no assertion at all.

`goss validate` prints a warning to stderr for each empty list it finds. The
check is still skipped and still passes β€” the warning only tells you that the
line asserts nothing.

The exec attribute is the command to run; this defaults to the name of
the hash for backwards compatibility

dns

Validates that the provided address is resolvable and the addrs it resolves to.

yaml
dns:
  localhost:
    # required attributes
    resolvable: true
    # optional attributes
    # defaults to hash key
    resolve: localhost
    addrs:
    - 127.0.0.1
    - ::1
    server: 8.8.8.8 # Also supports server:port
    timeout: 500 # in milliseconds (Only used when server attribute is provided)
    retry_count: 1  # Enables retry mechanism when greater than 0; number of additional attempts
    retry_delay: 500  # Delay in milliseconds before each retry; duration strings like 500ms or 2s also work

It is possible to validate the following types of DNS records, but requires the server attribute be set:

  • A
  • AAAA
  • CAA
  • CNAME
  • MX
  • NS
  • PTR
  • SRV
  • SSHFP
  • TXT

To validate specific DNS address types, prepend the hostname with the type and a colon, a few examples:

yaml
dns:
  # Validate a CNAME record
  CNAME:c.dnstest.io:
    resolvable: true
    server: 208.67.222.222
    addrs:
    - "a.dnstest.io."
    retry_count: 2
    retry_delay: 250ms

  # Validate a PTR record
  PTR:8.8.8.8:
    resolvable: true
    server: 8.8.8.8
    addrs:
    - "dns.google."
    retry_count: 2
    retry_delay: 250ms

  # Validate an SRV record
  SRV:_https._tcp.dnstest.io:
    resolvable: true
    server: 208.67.222.222
    addrs:
    - "0 5 443 a.dnstest.io."
    - "10 10 443 b.dnstest.io."
    retry_count: 2
    retry_delay: 250ms

  # Validate an SSHFP record
  SSHFP:mars.yellowjacket.io:
    resolvable: true
    server: 8.8.8.8
    addrs:
    - "1 2 422F22EFB548FEAC403A633A86F74553599B85AC93E7EC3BB0A46B6CD6DDABF8"
    - "3 1 1B28EEA699B1C784DC16F1122EEDDCF3131C89D2"
    - "3 2 F5982E00758BF5016B9FDDF26D8E495C376E657BAAC4C7DB1B363C06F0D093CC"
    - "4 1 5802C65FB3F3B62242055A12455C8E9C5B5A3CDA"
    - "4 2 99DB27696110BB3918599BF35D932D35DAA3DE09D6F42506FDAA08EBD2AD7311"
    - "1 1 B6B05D527AE206A2A7163AB349166E15D1AFC7E9"

Please note that if you want localhost to only resolve 127.0.0.1 you'll need to use Advanced Matchers

yaml
dns:
  localhost:
    resolvable: true
    addrs:
      consist-of: [127.0.0.1]
    timeout: 500 # in milliseconds

file

Validates the state of a file, directory, socket, or symbolic link

yaml
file:
  /etc/passwd:
    # required attributes
    exists: true
    # optional attributes
    # defaults to hash key
    path: /etc/passwd
    mode: "0644"
    size: 2118 # in bytes
    owner: root
    group: root
    filetype: file # file, symlink, directory, socket
    contents: [] # Check file content for these patterns
    md5: 7c9bb14b3bf178e82c00c2a4398c93cd # md5 checksum of file
    # A stronger checksum alternatives to md5 (recommended)
    sha256: 7f78ce27859049f725936f7b52c6e25d774012947d915e7b394402cfceb70c4c
    sha512: cb71b1940dc879a3688bd502846bff6316dd537bbe917484964fe0f098e9245d80958258dc3bd6297bf42d5bd978cbe2c03d077d4ed45b2b1ed9cd831ceb1bd0
  /etc/alternatives/mta:
    # required attributes
    exists: true
    # optional attributes
    filetype: symlink # file, symlink, directory, socket
    linked-to: /usr/sbin/sendmail.sendmail
    skip: false

contents can be a string or a pattern

!!! warning "An empty list asserts nothing"

text
As with [`stdout` and `stderr`](#command), `contents: []` is a list of zero
conditions and always passes. `goss add file` writes it to record that it
captured no content expectation, so it is normal in generated gossfiles β€”
but it does not check that the file is empty. To assert emptiness, use
`contents: ""`.

`goss validate` warns on stderr about each one, so a gossfile generated by
`goss add file` produces one warning per file until you replace or remove
the `contents` line.

gossfile

Import other gossfiles from this one. This is the best way to maintain a large number of tests, and/or create profiles.
See render for more examples. Glob patterns can be also be used to specify matching gossfiles.

yaml
gossfile:
  myapplication:
    file: myapp_gossfile.yaml
    skip: false
  *.yaml:
    skip: true
  goss_httpd.yaml: {}
  /etc/goss.d/*.yaml: {}

You can specify the gossfile(s) either as the resource key, or using the 'file' attribute.

If the 'skip' attribute is true, then the file is not processed.
If the filename is a glob pattern, then none of the matching files are processed.
Note that this is not the same as skipping the contained resources;
any overrides in the referenced gossfile will not be processed, and the resource count will not be incremented.
Skipping a gossfile include is the same as omitting the gossfile resource entirely.

group

Validates the state of a group

yaml
group:
  nfsnobody:
    # required attributes
    exists: true
    # optional attributes
    # defaults to hash key
    groupname: /etc/passwd
    gid: 65534
    skip: false

http

Validates HTTP response status code and content.

yaml
http:
  https://www.google.com:
    # required attributes
    status: 200
    # optional attributes
    # defaults to hash key
    url: https://www.google.com
    allow-insecure: false
    no-follow-redirects: false # Setting this to true will NOT follow redirects
    timeout: 1000
    request-headers: # Set request header values
       - "Content-Type: text/html"
    headers: [] # Check http response headers for these patterns (e.g. "Content-Type: text/html")
    request-body: '{"key": "value"}' # request body
    body: [] # Check http response content for these patterns
    username: ""  # username for basic auth
    password: ""  # password for basic auth
    ca-file: ""   # CA root certs pem file, ex: /etc/ssl/cert.pem
    cert-file: "" # certificate file to use for authentication (used with key-file)
    key-file: ""  # private-key file to use for authentication (used with cert-file)
    proxy: "" # proxy server to proxy traffic through. Proxy can also be set with environment variables http_proxy.
    skip: false
    method: PUT # http method

!!! note
only the first Host header will be used to set the Request.Host value if multiple are provided.

interface

Validates network interface values

yaml
interface:
  eth0:
    # required attributes
    exists: true
    # optional attributes
    # defaults to hash key
    name: eth0
    addrs:
    - 172.17.0.2/16
    - fe80::42:acff:fe11:2/64
    mtu: 1500

kernel-param

Validates kernel param (sysctl) value.

yaml
kernel-param:
  kernel.ostype:
    # required attributes
    value: Linux
    # optional attributes
    # defaults to hash key
    name: kernel.ostype

To see the full list of current values, run sysctl -a.

mount

Validates mount point attributes.

yaml
mount:
  /home:
    # required attributes
    exists: true
    # optional attributes
    # defaults to hash key
    timeout: 1000
    mountpoint: /home
    opts:
    - rw
    - relatime
    # This maps to the per-superblock options, see:
    # https://man7.org/linux/man-pages/man5/proc.5.html
    # https://man7.org/linux/man-pages/man2/mount.2.html
    vfs-opts:
    - rw
    source: /dev/mapper/fedora-home
    filesystem: xfs
    usage: #% of blocks used in this mountpoint
      lt: 95

matching

Validates specified content against a matcher. Best used with Templates.

With [Templates](#templates)

Let's say we have a data.json file that gets generated as part of some testing pipeline:

json
{
  "instance_count": 14,
  "failures": 3,
  "status": "FAIL"
}

This could then be passed into goss: goss --vars data.json validate

And then validated against:

yaml+jinja
matching:
  check_instance_count: # Make sure there is at least one instance
    content: {{ .Vars.instance_count }}
    matches:
      gt: 0

  check_failure_count_from_all_instance: # expect no failures
    content: {{ .Vars.failures }}
    matches: 0

  check_status:
    content: {{ .Vars.status }}
    matches:
      - not: FAIL

Without [Templates](#templates)

yaml
matching:
  has_substr: # friendly test name
    content: some string
    matches:
      match-regexp: some str
  has_2:
    content:
      - 2
    matches:
      contain-element: 2
  has_foo_bar_and_baz:
    content:
      foo: bar
      baz: bing
    matches:
      and:
        - have-key: baz

package

Validates the state of a package

yaml
package:
  httpd:
    # required attributes
    installed: true
    # optional attributes
    # defaults to hash key
    name: httpd
    versions:
    - 2.2.15
    skip: false
    retry_count: 1   # Enables retry mechanism when greater than 0; number of additional attempts
    retry_delay: 10000  # Delay in milliseconds before each retry; duration strings like 500ms or 2s also work

!!! note
this check uses the --package <format> parameter passed on the command line.

port

Validates the state of a local port.

!!! note
Goss might consider your port to be listening on tcp6 rather than tcp,
try running goss add port .. to see how goss detects it.
(explanation)

yaml
port:
  # {tcp,tcp6,udp,udp6}:port_num
  tcp:22:
    # required attributes
    listening: true
    # optional attributes
    # defaults to hash key
    port: 'tcp:22'
    ip: # what IP(s) is it listening on
    - 0.0.0.0
    skip: false

process

Validates if a process is running.

yaml
process:
  chrome:
    # required attributes
    running: true
    # optional attributes
    # defaults to hash key
    comm: chrome
    skip: false

!!! note
This check is inspecting the name of the binary, not the name of the process.

text
For example, a process with the name `nginx: master process /usr/sbin/nginx` would be checked with the process `nginx`.
To discover the binary of a pid run `cat -E /proc//comm`.

service

Validates the state of a service.

yaml
service:
  sshd:
    # Optional attributes
    # defaults to hash key
    name: sshd
    enabled: true
    running: true
    runlevels: ["3", "4", "5"]  # Alpine example, runlevels: ["default"]
    skip: false

runlevels is only supported on Alpine init, sysv init, and upstart

!!! note
This will not automatically check if the process is alive, it will check the status from systemd/upstart/init.

user

Validates the state of a user

yaml
user:
  nfsnobody:
    # required attributes
    exists: true
    # optional attributes
    # defaults to hash key
    username: nfsnobody
    uid: 65534
    gid: 65534
    groups:
    - nfsnobody
    home: /var/lib/nfs
    shell: /sbin/nologin
    skip: false

!!! note
This check is inspecting the contents of local passwd file /etc/passwd,
this does not validate remote users (e.g. LDAP).

Matchers

Default Matchers

Default matchers are determined by the attribute value received from the system.

Bool, Strings, Integers

Bool, Strings and integers are compared using equality, for example:

yaml
matching:
  basic_string:
    content: 'foo'
    matches: 'foo'

user:
  nfsnobody:
    exists: true
    uid: 65534

Arrays

Arrays are treated as a contains-elements by default,
this validates that the expected test is a subset of the returned system state.

yaml
matching:
  basic_array:
    content:
      - 'group1'
      - 'group2'
      - 'group3'
    matches:
      - 'group1'
      - 'group2'

  # This fails, since the returned result and it's no longer a subset
  basic_array_failing:
    content:
      - 'group1'
      - 'group2'
      - 'group3'
    matches:
      - 'group1'
      - 'group2'
      - 'group2' # this 2nd group2 is not in the returned content

io.Readers

This is the most magical matcher for goss. It remains a default for historic and performance reasons.
Some attributes return an io.Reader that is read line by line (ex. file content, command, http body).
This allows goss to validate large files/content efficiently.

Each pattern is checked against the attribute output, the type of patterns are:

  • "foo" - checks if any line contains foo
  • "!foo" - inverse of above, checks that no line contains foo
  • "\\!foo" - escape sequence, check if any line contains !string
  • "/[Rr]egex/" - verifies that line matches regex
  • "!/[Rr]egex/" - inverse of above, checks that no line matches regex

!!! note
Regex support is based on Golang's regex engine

!!! warning
You will need the double backslash (\\) escape for Regex special entities, for example \\s for blank spaces.

!!! example
yaml file: /tmp/test.txt: exists: true contents: - "foo" - "!bar" - "/[Gg]oss/"

text
The above can be expressed as:

```yaml
file:
/tmp/test.txt:
    exists: true
    contents:
    and:
        - contain-element: "foo"
        - not: {contain-element: "bar"}
        - contain-element: {match-regexp: "[Gg]oss"}

```

Transforms

If the system state type and the expected type don't match,
goss will attempt to transform the system state type before matching it.

For example, kernel-param attribute returns a string, however, it can be tested using numeric comparisons:

!!! example "kernel-param test"
yaml kernel-param: net.core.somaxconn: value: "128"

!!! example "(failing) kernel-param test with transform"
yaml kernel-param: net.core.somaxconn: value: {gt: 200}

When a transformed test fails, it will detail the transformers used,
the -o exclude_raw option can be used to exclude the raw, untransformed attribute value:

coonsole
$ goss v
F

Failures/Skipped:

KernelParam: net.core.somaxconn: value:
Expected
    128
to be >
    200
the transform chain was
    [{"to-numeric":{}}]
the raw value was
    "128"

Total Duration: 0.001s
Count: 1, Failed: 1, Skipped: 0

$ goss v -o exclude_raw
F

Failures/Skipped:

KernelParam: net.core.somaxconn: value:
Expected
    128
to be >
    200
the transform chain was
    [{"to-numeric":{}}]

Total Duration: 0.001s
Count: 1, Failed: 1, Skipped: 0

Advanced Matchers

Goss supports advanced matchers by converting YAML input to gomega matchers.

String Matchers

These will convert the system attribute to a string prior to matching.

  • '55' - Checks that the numeric is "55" when converted to string
  • have-prefix: pre - Checks if string starts with "pre"
  • have-suffix: suf - Checks if string ends with "suf"
  • match-regexp: '.*' - Checks if string matches regexp
  • contain-substring: '2' - Checks if string contains "2"

!!! example
yaml matching: example: content: 42 matches: and: - '42' - have-prefix: '4' - have-suffix: '2' - match-regexp: '\d{2}' - contain-substring: '2'

Numeric matchers

These will convert the system attribute to a numeric prior to matching.

  • 42 - If the expected type is a number
  • gt, ge, lt, le - Greater than, greater than or equal, less than, etc..

!!! example
yaml matching: example: content: "42" matches: and: - 42 - 42.0 - gt: 40 - lt: 45

Array matchers

These will convert the system attribute to an array prior to matching. Strings are split on "\n"

  • contain-element: matcher - Checks if the array contains an element that passes the matcher
  • contain-elements: [matcher, ...] - checks if the array is a superset of the provided matchers
  • [matcher, ...] - same as above
  • equal: [value, ...] - Checks if the array is exactly equal to provided array
  • consist-of: [matcher, ...] - Checks if the array consists of the provided matchers (order does not matter)

!!! example
yaml matching: example: content: [foo, bar, moo] matches: and: - contain-elements: [foo, bar] - [foo, bar] # same as above - equal: [foo, bar, moo] # order matters, exact match - consist-of: [foo, have-prefix: m, bar] # order doesn't matter, can use matchers - contain-element: have-prefix: b

Misc matchers

These matchers don't really fall into any of the above categories, or span multiple categories.

  • equal - Useful when needing to override a default matcher
  • have-len: 3 - Checks if the array/string/map has length of 3
  • have-key: "foo" - Checks if key exists in map, useful with gjson
  • not: matcher - Checks that a matcher does not match
  • and: [matcher, ..] - Checks that all matchers match
  • or: [matcher, ..] - Checks that any matchers match

!!! note
When system returns a string it is converted into a one element array and matched

See the following for examples: [link..]fixme

semver-constraint

Checks that all versions match semver constraint or range syntax.
This uses semver under the hood, however, wildcards
(e.g. 1.X are not officially supported and may go away in a future release).

!!! example
yaml matching: semver: content: - 1.0.1 - 1.9.9 matches: semver-constraint: ">1.0.0 <2.0.0 !=1.5.0" semver2: content: - 1.0.1 - 1.5.0 - 1.9.9 matches: not: semver-constraint: ">1.0.0 <2.0.0 !=1.5.0" semver3: content: 1.0.1 matches: semver-constraint: ">5.0.0 || < 1.5.0"

gjson

Checks extracted gjson passes the matcher

Example:

yaml
matching:
  example:
    content: '{"foo": "bar", "moo" {"nested": "cow"}, "count": "15"}'
    matches:
      gjson:
        moo.nested: cow
        foo: {have-prefix: b}
        count: {le: 25}
        '@this': {have-key: "foo"}
        moo:
          and:
            - {have-key: "nested"}
            - {not: {have-key: "nested2"}}

XML

Execute an XPath request on a XML string.

This uses xpath Go library under the hood,
which supports these features.

Example:

yaml
matching:
  example:
    content: |
      <?xml version="1.0" encoding="UTF-8"?>
      <order date="2019-02-01">
        
          
              <title>Harry Potter et le prisonnier d’Azkaban</title>
              <quantity>1</quantity>
              25
          
          
              <title>Le seigneur des anneaux</title>
              <quantity>1</quantity>
              18
          
        
      </order>
    matches:
      xml:
        xpath: "boolean(//book[title='Le seigneur des anneaux'])"
        result: "true"

Templates

Goss test files can leverage golang's text/template
to allow for dynamic or conditional tests.

Available variables:

  • {{.Env}} - Containing environment variables
  • {{.Vars}} - Containing the values defined in --vars file

Available functions:

  • built-in text/template functions

  • Sprig functions

  • Custom functions:

    mkSlice "ARG1" "ARG2"
    : Returns a slice of all the arguments. See examples below for usage.

    getEnv "var" ["default"]
    : A more forgiving env var lookup. If key is missing either "" or default (if provided) is returned.

    readFile "fileName"
    : Reads file content into a string, trims whitespace. Useful when a file contains a token.
    !!! note
    Goss will error out during the parsing phase if the file does not exist, no tests will be executed.

    regexMatch "(some)?reg[eE]xp"
    : Tests the piped input against the regular expression argument.

    toLower
    : Changes piped input to lowercase

    toUpper
    : Changes piped input to UPPERCASE

    findStringSubmatch regex string
    : Returns map[string]interface{} with the names of the parenthesized subexpressions, like (?P<first>[a-z])

    text
    {{ $regexDBrc := "\\'mysql:\\/\\/(?P<login>[a-z0-9]+):(?P[a-z0-9]+)@localhost\\/(?P<database>roundcube_[a-z0-9]+)\\';"}}
    
      {{ $rcConf := readFile /home/user/roundcube/config.inc.php | findStringSubmatch $regexDBrc }}
      {{ $UserDBrc := get $rcConf "login" }}
      {{ $PassDBrc  := get $rcConf "password" }}
      {{ $DBrc := get $rcConf "database" }}

    If not exists named parenthesized subexps, returns stringfied array string:

    text
    {{ $regexDBrc := "\\'mysql:\\/\\/([a-z0-9]+):([a-z0-9]+)@localhost\\/(roundcube_[a-z0-9]+)\\';"}}
    
      {{ $rcConf := readFile /home/user/roundcube/config.inc.php | findStringSubmatch $regexDBrc }}
      {{ $UserDBrc := get $rcConf "1" }}
      {{ $PassDBrc  := get $rcConf "2" }}
      {{ $DBrc := get $rcConf "3" }}

    NOTE: stringfied string array begins with "1" ("0" is all the string matched)

!!! warning

text
gossfiles containing text/template `{{}}` controls will no longer work with `goss add/autoadd`.
One way to get around this is to split your template and static goss files and use [gossfile](#gossfile) to import.

!!! note

text
Some of Sprig functions have the same name as the older Custom Goss functions.
The Sprig functions are overwritten by the custom functions for backwards compatibility.

Examples

Using puppetlabs/facter or chef/ohai
as external tools to provide vars.

bash
goss --vars <(ohai) validate
goss --vars <(facter -j) validate

Using mkSlice to define a loop locally.

yaml+jinja
file:
{{- range mkSlice "/etc/passwd" "/etc/group"}}
  {{.}}:
    exists: true
    mode: "0644"
    owner: root
    group: root
    filetype: file
{{end}}

Using upper function from Sprig.

yaml+jinja
matching:
  sping_basic:
    content: {{ "hello!" | upper | repeat 5 }}
    matches:
      match-regexp: "HELLO!HELLO!HELLO!HELLO!HELLO!"

Using Env variables and a vars file:

yaml title="vars.yaml"
centos:
  packages:
    kernel:
      - "4.9.11-centos"
      - "4.9.11-centos2"
debian:
  packages:
    kernel:
      - "4.9.11-debian"
      - "4.9.11-debian2"
users:
  - user1
  - user2
yaml+jinja title="goss.yaml"
package:
# Looping over a variables defined in a vars.yaml using $OS environment variable as a lookup key
{{range $name, $vers := index .Vars .Env.OS "packages"}}
  {{$name}}:
    installed: true
    versions:
    {{range $vers}}
      - {{.}}
    {{end}}
{{end}}

# This test is only when the OS environment variable matches the pattern
{{if .Env.OS | regexMatch "[Cc]ent(OS|os)"}}
  libselinux:
    installed: true
{{end}}

# Loop over users
user:
{{range .Vars.users}}
  {{.}}:
    exists: true
    groups:
    - {{.}}
    home: /home/{{.}}
    shell: /bin/bash
{{end}}


package:
{{if eq .Env.OS "centos"}}
  # This test is only when $OS environment variable is set to "centos"
  libselinux:
    installed: true
{{end}}
console title="rendered results"
# To validate:
$ OS=centos goss --vars vars.yaml validate
# To render:
$ OS=centos goss --vars vars.yaml render
# To render with debugging enabled:
$ OS=centos goss --vars vars.yaml render --debug

File: docs/index.md

Goss - Quick and Easy server validation

--8<-- "README.md:intro"
--8<-- "README.md:about"