$id: "https://raw.githubusercontent.com/krameff/syver/main/docs/schema.yaml" # Note: this schema was authored using intellij support for Json schema version 7 # providing coding assistance # This schema is based on content from https://github.com/krameff/syver/blob/main/docs/gossfile.md and # and https://github.com/krameff/syver/blob/main/README.md # It was tested in intellij against https://github.com/krameff/syver/blob/main/docs/goss.yaml # both for completion and code analysis use-cases. # Limitations / missing support # - patterns # - advanced matchers # - templates $schema: http://json-schema.org/draft-07/schema# title: "Goss-file-schema" definitions: title: type: string default: "UID must be between 50-100, GID doesn't matter. home is flexible" description: title attribute is persisted when adding other resources with goss add meta: description: meta (arbitrary data) attributes are persisted when adding other resources with goss add type: object register: type: string description: "Discovery only. Variable name written to Discovered JSON output." dependsOnList: type: array items: type: string description: "Prerequisite resource keys; this test is skipped when a dependency fails." fileDiscoveryTest: allOf: - $ref: "#/definitions/fileTest" - type: object required: - register packageDiscoveryTest: allOf: - $ref: "#/definitions/packageTest" - type: object required: - register addrTest: required: - reachable - timeout properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } reachable: type: boolean default: true timeout: type: integer default: 500 examples: - 500 # optional attributes local-address: type: string default: 127.0.0.1 commandTest: type: object properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } exit-status: type: integer description: "Validates the exit-status and output of a command" exec: description: "command to execute, defaults to the hash key" type: string stdout: type: array description: "can be a string or pattern, see https://github.com/krameff/syver/blob/main/docs/gossfile.md#matchers" items: type: string stderr: type: array description: "can be a string or pattern, see https://github.com/krameff/syver/blob/main/docs/gossfile.md#matchers" items: type: string timeout: type: integer description: "in milliseconds" skip: type: boolean default: false register: { "$ref": "#/definitions/register" } depends-on: { "$ref": "#/definitions/dependsOnList" } required: - exit-status dnsTest: required: - resolvable properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } resolvable: type: boolean default: true # optional attributes addrs: description: | list of addresses e.g. ["127.0.0.1", "::1"] type: array items: type: string default: ["127.0.0.1", "::1"] server: description: "Eg 8.8.8.8. Also supports server:port " type: string default: 8.8.8.8 timeout: type: integer default: 500 description: in milliseconds (Only used when server attribute is provided) fileTest: required: - exists properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } exists: type: boolean default: true mode: type: string default: "0644" size: type: integer default: 2118 description: in bytes owner: type: string default: root uid: type: integer group: type: string default: root gid: type: integer acl: type: - array - "null" description: >- Windows only. The file's DACL, one element per ACE, spelled as icacls prints it: PRINCIPAL:(I)(DENY)(OI)(CI)(IO)(NP)(RIGHTS), with each parenthesised group present only when it applies. Principals are DOMAIN\Name, which is LOCALISED -- use acl-sid for a spec that must run on a non-English Windows. A bare list asserts the ACEs are present; consist-of asserts these and no others. Errors on every other platform rather than reporting an empty list. acl-sid: type: - array - "null" description: >- Windows only. Exactly the ACEs acl reports, in the same order, with principals as SID strings (S-1-5-32-544) instead of localised names. The portable form: a spec written with acl-sid runs on any Windows locale. syver add emits acl, not this; switching is a deliberate edit. filetype: type: string default: file enum: - file - symlink - directory contents: type: - array - "null" description: >- Check file content for these patterns. can be a string or a pattern. null is accepted as well as an array because `syver render` emits `contents: null` for a file resource that does not set it, and the documented workflow is to schema-validate that rendered output. items: type: string description: string or patterns contains: type: array description: >- Deprecated: renamed to contents. Still accepted, but validating a spec that uses it prints a deprecation warning. Kept in the schema so existing files continue to validate. items: type: string description: string or patterns md5: type: string default: 7c9bb14b3bf178e82c00c2a4398c93cd description: md5 checksum of file sha256: type: string default: 7f78ce27859049f725936f7b52c6e25d774012947d915e7b394402cfceb70c4c description: "A stronger checksum alternatives to md5 (recommended)" sha512: type: string default: cb71b1940dc879a3688bd502846bff6316dd537bbe917484964fe0f098e9245d80958258dc3bd6297bf42d5bd978cbe2c03d077d4ed45b2b1ed9cd831ceb1bd0 description: "A stronger checksum alternatives to md5 (recommended)" linked-to: type: string default: /usr/sbin/sendmail.sendmail skip: type: boolean default: false register: { "$ref": "#/definitions/register" } depends-on: { "$ref": "#/definitions/dependsOnList" } gossfileTest: properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } file: type: string default: myapp_gossfile.yaml skip: type: boolean default: false groupTest: required: - exists properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } exists: type: boolean default: true gid: type: integer default: 65534 skip: type: boolean default: false httpTest: required: - status properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } status: type: integer default: 200 allow-insecure: type: boolean default: false no-follow-redirects: type: boolean default: false description: Setting this to true will NOT follow redirects timeout: type: integer default: 1000 request-headers: description: | Set request header values, e.g. [ "Content-Type: text/html" ] type: array items: type: string default: [ "Content-Type: text/html" ] request-query-params: description: | Set URL query parameters, properly encoded. Each key takes a list, so a key can repeat, e.g. { "foo": [ "bar" ] } type: object additionalProperties: type: array items: type: string headers: type: array description: | Check http response headers for these patterns (e.g. "Content-Type: text/html") NOTE: only the first Host header will be used to set the Request.Host value if multiple are provided. items: type: string default: [ ] request-body: type: object default: '{"key": "value"}' description: request body body: type: array description: Check http response content for these patterns username: type: string description: username for basic auth default: "" password: type: string description: password for basic auth default: "" ca-file: type: string default: "" description: | CA root certs pem file, ex: /etc/ssl/cert.pem cert-file: type: string default: "" description: | certificate file to use for authentication (used with key-file) key-file: type: string default: "" description: | private-key file to use for authentication (used with cert-file) proxy: type: string default: "" description: | proxy server to proxy traffic through. Proxy can also be set with environment variables http_proxy. skip: type: boolean default: false method: type: string default: PUT description: http method enum: # See https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods # Note: not yet clear whether goss supports all methods - GET - PUT - HEAD - POST - DELETE - PATCH - CONNECT - OPTIONS - TRACE interfaceTest: required: - exists properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } exists: type: boolean default: true addrs: type: array items: type: string default: - 172.17.0.2/16 - fe80::42:acff:fe11:2/64 mtu: type: integer default: 1500 kernelParamTest: description: | To see the full list of current values, run sysctl -a. required: - value properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } value: type: string default: Linux matchingTest: properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } content: anyOf: - type: string default: "some string" - type: array default: - 2 - type: object default: foo: bar baz: ring matches: anyOf: - type: integer - type: object - type: array mountTest: required: - exists properties: timeout: type: integer title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } exists: type: boolean default: true opts: type: array items: type: string default: - rw - relatime vfs-opts: description: | The superblock options, as distinct from the per-mount options in opts. See mount(2) and the mountinfo section of proc(5). type: array items: type: string default: - rw source: type: string default: /dev/mapper/fedora-home filesystem: type: string default: xfs usage: description: | % of blocks used in this mountpoint type: object properties: lt: type: integer default: 95 packageTest: required: - installed properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } installed: type: boolean default: true versions: oneOf: - type: object # matcher - type: array items: type: string default: - 2.2.15 skip: type: boolean default: false register: { "$ref": "#/definitions/register" } depends-on: { "$ref": "#/definitions/dependsOnList" } portTest: required: - listening properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } listening: type: boolean default: true ip: description: what IP(s) is it listening on type: array items: type: string default: - 0.0.0.0 pid: description: what PID(s) own the socket type: array items: type: integer skip: type: boolean default: false processTest: required: - running properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } running: type: boolean default: true status: description: process state(s), e.g. detect zombie processes type: array items: type: string enum: - running - sleep - stop - idle - wait - lock - zombie user: description: user(s) the process is running as, e.g. flag anything running as root type: array items: type: string registryTest: required: - exists properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } exists: description: whether the registry key or value is present type: boolean default: true value: description: >- the data held by the value, always read as a string. REG_MULTI_SZ is returned as its entries joined by newlines, not as a list, so use substring or regexp matchers rather than list matchers. type: description: >- the value's data type. REG_EXPAND_SZ values are compared as stored, unexpanded, so %SystemRoot% is matched literally. type: string enum: - REG_NONE - REG_SZ - REG_EXPAND_SZ - REG_BINARY - REG_DWORD - REG_DWORD_BIG_ENDIAN - REG_LINK - REG_MULTI_SZ - REG_RESOURCE_LIST - REG_FULL_RESOURCE_DESCRIPTOR - REG_RESOURCE_REQUIREMENTS_LIST - REG_QWORD view: description: >- which WOW64 registry view to read. Defaults to native, which is what the OS shows a 64-bit process and what every spec written before this attribute existed gets. Quote it: this schema types the attribute as a string, so an unquoted 32 or 64 fails validation here even though syver itself coerces the YAML integer and accepts it. type: string enum: - "32" - "64" - native default: native skip: type: boolean default: false serviceTest: # Nothing is required. The code requires no attribute, and a Windows spec # may assert only Windows attributes such as `dependencies`. properties: title: { "$ref":"#/definitions/title" } meta: { "$ref":"#/definitions/meta" } enabled: type: boolean default: true running: type: boolean default: true runlevels: type: array items: type: string description: >- The runlevels the service is enabled in. Supported on Alpine init, sysv init and upstart. start-type: type: string description: >- Windows only. How the service starts, as the Service Control Manager records it. 'enabled' above is derived from this field and is true for boot, system and automatic. enum: - boot - system - automatic - manual - disabled delayed-start: type: boolean description: >- Windows only. A separate configuration flag, not a sixth start type: the Services UI's "Automatic (Delayed Start)" is start-type automatic plus this. Only meaningful alongside an automatic start type. run-as: type: string description: >- Windows only. The account the service runs under, exactly as the SCM stores it and NOT normalised -- 'LocalSystem', 'localSystem' and 'NT AUTHORITY\\LocalService' are all forms Windows itself reports. dependencies: type: - array - "null" description: >- Windows only. Services and load-order groups that must start first, verbatim from the SCM. A name beginning with '+' is a load-order group rather than a service, which is how Windows spells it. display-name: type: string description: >- Windows only. The friendly name, as distinct from the service key name. LOCALISED: a spec that must run on more than one Windows language should assert the key name instead. pid: type: integer description: >- Windows only. The process the service runs in, 0 when it is not running. 'syver add service' does not emit it, because a pid changes at every restart; assert a range such as 'gt: 0' rather than a value. skip: type: boolean default: false userTest: required: - exists properties: title: { "$ref": "#/definitions/title" } meta: { "$ref": "#/definitions/meta" } exists: type: boolean default: true # optional attributes uid: anyOf: - { "$ref": "#/definitions/matchingTest" } - type: integer default: 65534 gid: anyOf: - { "$ref": "#/definitions/matchingTest" } - type: integer default: 65534 groups: anyOf: - { "$ref": "#/definitions/matchingTest" } - type: array items: type: string default: - nfsnobody home: anyOf: - { "$ref": "#/definitions/matchingTest" } - type: string default: /var/lib/nfs shell: type: string default: /sbin/nologin skip: type: boolean default: false description: "A file describing a series of tests" type: "object" properties: addr: type: object description: "Validates if a remote address:port are accessible." examples: - tcp://ip-address-or-domain-name:80: reachable: true timeout: 500 local-address: 127.0.0.1 additionalProperties: $ref: "#/definitions/addrTest" command: type: object description: "test executing a command" additionalProperties: $ref: "#/definitions/commandTest" dns: type: object description: "Validates that the provided address is resolvable and the addrs it resolves to." x-intellij-html-description: |
Validates that the provided address is resolvable and the addrs it resolves to.
dns:
localhost:
# required attributes
resolvable: true
# optional attributes
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)It is possible to validate the following types of DNS records, but requires the server attribute be set:
To validate specific DNS address types, prepend the hostname with the type and a colon, a few examples:
dns:
# Validate a CNAME record
CNAME:c.dnstest.io:
resolvable: true
server: 208.67.222.222
addrs:
- "a.dnstest.io."
# Validate a PTR record
PTR:8.8.8.8:
resolvable: true
server: 8.8.8.8
addrs:
- "dns.google."
# Validate and 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."Please note that if you want localhost to only resolve 127.0.0.1 you'll need to use Advanced Matchers
dns:
localhost:
resolvable: true
addrs:
consist-of: [127.0.0.1]
timeout: 500 # in milliseconds
additionalProperties:
$ref: "#/definitions/dnsTest"
discovery:
type: object
description: |
Discovery-phase resource checks. Run with --format discovery to emit Discovered vars.
Each entry requires register. See https://github.com/krameff/syver/blob/main/docs/gossfile.md#discovery
properties:
file:
type: object
additionalProperties:
$ref: "#/definitions/fileDiscoveryTest"
package:
type: object
additionalProperties:
$ref: "#/definitions/packageDiscoveryTest"
file:
type: object
description: "Validates the state of a file, directory, or symbolic link"
additionalProperties:
$ref: "#/definitions/fileTest"
syverfile:
type: object
description: |
Input alias for '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.
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.
additionalProperties:
$ref: "#/definitions/gossfileTest"
gossfile:
type: object
description: |
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.
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.
x-intellij-html-description: |
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.
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.
additionalProperties:
$ref: "#/definitions/gossfileTest"
group:
type: object
description: "Validates the state of a group"
additionalProperties:
$ref: "#/definitions/groupTest"
http:
type: object
description: "description: Validates network interface values"
additionalProperties:
$ref: "#/definitions/httpTest"
interface:
type: object
description: "test "
additionalProperties:
$ref: "#/definitions/interfaceTest"
kernel-param:
type: object
description: "test "
additionalProperties:
$ref: "#/definitions/kernelParamTest"
matching:
type: object
description: "Validates specified content against a matcher. Best used with Templates."
x-intellij-html-description: |
Validates specified content against a matcher. Best used with Templates.
With Templates:
Let's say we have a data.json file that gets generated as part of some testing pipeline:
{
"instance_count": 14,
"failures": 3,
"status": "FAIL"
}
This could then be passed into goss: goss --vars data.json validate
And then validated against:
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:
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-with-value:
foo: bar
- have-key: baz
additionalProperties:
$ref: "#/definitions/matchTest"
mount:
type: object
description: "Validates mount point attributes."
additionalProperties:
$ref: "#/definitions/mountTest"
package:
type: object
description: |
Validates the state of a package"
NOTE: this check uses the --package parameter passed on the command line.
additionalProperties:
$ref: "#/definitions/packageTest"
port:
type: object
description: |
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)
x-intellij-html-description: |
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)
port:
# {tcp,tcp6,udp,udp6}:port_num
tcp:22:
# required attributes
listening: true
# optional attributes
ip: # what IP(s) is it listening on
- 0.0.0.0
skip: false
additionalProperties:
$ref: "#/definitions/portTest"
process:
type: object
description: "Validates if a process is running."
additionalProperties:
$ref: "#/definitions/processTest"
registry:
type: object
description: "Validates a Windows registry key or value. Windows only."
additionalProperties:
$ref: "#/definitions/registryTest"
service:
type: object
description: "Validates the state of a service."
additionalProperties:
$ref: "#/definitions/serviceTest"
user:
type: object
description: |
Validates the state of a user"
NOTE: This check is inspecting the contents of local passwd file /etc/passwd, this does not validate remote users (e.g. LDAP).
additionalProperties:
$ref: "#/definitions/userTest"