# Cross-platform resources

> The thirteen resource types that work on Linux, macOS, and Windows targets.

Source: https://refpoint.dev/docs/resources/cross-platform

These thirteen resource types dispatch on the probed platform, so a control built
from them runs anywhere. Where behaviour differs by platform, the difference is
noted on the attribute.

## file

Path-addressed. Stats the path through the transport.

| Attribute | Type | Notes |
|---|---|---|
| `path` | string | Address |
| `exists` | bool | |
| `owner` | string | Unix owner username |
| `group` | string | Unix group name |
| `permissions` | string | Octal mode with an optional comparison prefix |
| `acl_owner` | string | Windows ACL owner, for example `BUILTIN\Administrators` |
| `type` | string | `file` or `folder` |
| `sha256` | string | Hex-encoded expected digest |
| `content_match` block | repeatable | See below |

`permissions` accepts `0644`, `== 0600`, `<= 0644`, `>= 0700`, `<`, `>`, and
`!=`. A bare value means equality.

The `content_match` block:

| Attribute | Type | Notes |
|---|---|---|
| `pattern` | string, required | |
| `mode` | string | `line` (default) matches the regex per line. `regex` is the same, kept distinct for intent. `exact` is whole-content equality after trimming trailing newlines |
| `negate` | bool | The rule must not match |

```hcl
check "shadow-perms" "file" {
  path        = "/etc/shadow"
  exists      = true
  owner       = "root"
  permissions = "<= 0640"

  content_match {
    pattern = "^root:[^!*]"
    negate  = true
  }
}
```

## directory

Path-addressed. The same ownership and permission vocabulary as `file`, without
content matching.

| Attribute | Type |
|---|---|
| `path` | string, address |
| `exists` | bool |
| `owner` | string |
| `group` | string |
| `permissions` | string |
| `acl_owner` | string |

## folder_contents

Path-addressed. Scans regular files directly inside a directory, not
recursively, and evaluates `content_match` rules across them. A rule passes
when any file satisfies it, which is what drop-in configuration directories
such as `/etc/ssh/sshd_config.d/` or `/etc/sysctl.d/` need.

| Attribute | Type | Notes |
|---|---|---|
| `path` | string, address | |
| `glob` | string | Filename filter, for example `*.conf`. Empty means all regular files |
| `content_match` block | repeatable | The same shape as `file` |

## command

The address is the command line itself. This is the one resource subject to the
`allowed_commands` gates on both the operator and profile sides.

| Attribute | Type | Notes |
|---|---|---|
| `cmd` | string, address | |
| `exit_status` | int | |
| `stdout_match` block | repeatable | `pattern`, `mode` (`line`, `regex`, `exact`), `negate` |
| `stderr_match` block | repeatable | The same shape |

```hcl
check "kernel" "command" {
  cmd         = "uname -r"
  exit_status = 0

  stdout_match {
    pattern = "^6\\."
  }
}
```

The matched stream is attached to the check as observed evidence, recorded once
rather than repeated per assertion. When both streams are asserted on, stdout
takes the check-level slot. That stored output is not filtered, so a command
that prints a secret puts that secret in the report.

## process

Name-addressed. Unix filters `ps aux` by the name, and Windows has its own
path.

| Attribute | Type | Notes |
|---|---|---|
| `name` | string, address | |
| `running` | bool | |
| `user` | string | Owning user |
| `args_match` | string | Regex against the command line |

## service

Name-addressed. Unix uses `systemctl is-active` with a `service ... status`
fallback, and Windows has its own path.

| Attribute | Type |
|---|---|
| `name` | string, address |
| `running` | bool |
| `enabled` | bool |

## package

Name-addressed, dispatching on the target's package manager.

| Attribute | Type | Notes |
|---|---|---|
| `name` | string, address | |
| `installed` | bool | |
| `version` | string | A plain value is a substring match. With an operator prefix it becomes a dpkg-style version comparison |

The operator form matters. `version = "8.9"` substring-matches and would accept
`18.9.1`, while `version = "== 8.9"` compares segments properly. The accepted
operators are `==`, `!=`, `<`, `<=`, `>`, and `>=`.

## user

Name-addressed. Unix reads `getent passwd`, and Windows has its own path.

| Attribute | Type | Platform |
|---|---|---|
| `name` | string, address | |
| `exists` | bool | both |
| `uid` | int | Unix |
| `gid` | int | Unix |
| `shell` | string | Unix |
| `home` | string | Unix |
| `enabled` | bool | Windows account enabled state |
| `sid` | string | Windows SID |

## port

Port-addressed. Unix probes `ss -lnp` with a `netstat -lnp` fallback.

| Attribute | Type | Notes |
|---|---|---|
| `port` | number, address | |
| `listening` | bool | |
| `protocol` | string | `tcp` or `udp` |
| `address` | string | Expected bind address |
| `process` | string | Expected owning process |

## kernel_param

Parameter-addressed, read via `sysctl -n`. On Windows it refuses with an
explanatory assertion rather than a silent pass.

| Attribute | Type |
|---|---|
| `param` | string, address |
| `value` | string |

## http

URL-addressed. Requests are made from the refpoint host, not from the scan
target. This answers whether the endpoint is healthy as seen from here, not
whether the target can reach it. Response bodies are read up to 1 MiB and
redirects are followed at most three times.

| Attribute | Type | Notes |
|---|---|---|
| `url` | string, address | |
| `status` | int | Final status after redirects |
| `tls_min_version` | string | `1.2` or `1.3`. Fails on plain HTTP |
| `cert_expiry_within_days` | int | Fails when the leaf certificate expires within N days |
| `insecure` | bool | Skip chain verification, for internal private CAs. Expiry checks still run against the presented certificate |
| `allow_private_addresses` | bool | Opt in to loopback, link-local and RFC1918 destinations, subject to the operator's `allow_private_http` |
| `header` block | repeatable | The label is the header name. `present` (default true), `match` (substring on the value) |
| `body` block | repeatable | `pattern`, `mode` (`contains` default, `regex`, `sha256`), `negate` |

A header assertion records the verdict, not the value: `absent`, `matched`, or
`present, did not match`. Response headers carry session tokens and reports are
commonly published, so the value never reaches the report. Body matches
likewise store a pass or a fail, never the body.

## json

Path-addressed. Reads the JSON file through the transport, so remote targets
work, and asserts on nodes selected with a small jq-shaped syntax. Nothing has
to be installed on the target and `jq` does not need to be in
`allowed_commands`.

| Attribute | Type | Notes |
|---|---|---|
| `path` | string, address | |
| `query` block | repeatable | The label is a selector, the body holds the assertions below |

A selector is `.a.b`, `.a[0]`, `."quoted-key"`, or `.` for the whole document.
Iteration such as `.a[]` is not supported. Each `query` block can carry any of
these assertions, and all of them must hold:

| Attribute | Type | Notes |
|---|---|---|
| `exists` | bool | The only assertion that passes on an absent node |
| `equals` | any | Compared by JSON type. Numbers compare numerically |
| `length` | int | Elements of an array or object, or characters of a string |
| `contains` | any | Array membership, object key, or substring, by node type |
| `type` | string | `null`, `bool`, `number`, `string`, `array`, `object` |
| `matches` | string | Regular expression against a string node |
| `show_value` | bool | Echo a failing value into the report. Off by default, because configuration files hold credentials |

```hcl
check "health" "json" {
  path = "/var/lib/app/health.json"

  query ".status" {
    equals = "healthy"
  }

  query ".components" {
    type   = "array"
    length = 8
  }

  query ".components[0].status" {
    equals = "healthy"
  }
}
```

A failing `equals` reports the mismatch, not the value, unless `show_value` is
set. The file is read as a whole and parsed once, so several `query` blocks
cost one read.

## x509_certificate

Path-addressed. Reads the certificate file through the transport, so remote
targets work, which is the difference from `http`.

| Attribute | Type | Notes |
|---|---|---|
| `path` | string, address | |
| `expiry_within_days` | int | Already-expired certificates always fail |
| `key_algorithm` | string | `RSA`, `ECDSA`, `Ed25519` |
| `min_key_bits` | int | Modulus bits for RSA, curve size for ECDSA, 256 for Ed25519 |
| `issuer_match` | string | Substring on the RFC 2253 issuer DN |
| `subject_match` | string | Substring on the RFC 2253 subject DN |
| `san_contains` | list(string) | DNS or IP SAN entries that must all be present |