Skip to content

Quickstart

Scaffold a profile, validate it, and run your first scan.

On this page

This page takes you from an empty directory to a saved JSON result you can re-render, diff, and file as evidence. It should take about ten minutes.

Scaffold a profile

refpoint init my-baseline --title "My Baseline" --author "Platform Team"

That writes a profile root and one example control:

my-baseline/
├── profile.rpp
└── controls/
    └── example.rpc

profile.rpp carries a commented allowed_commands hint. Without it, the first command check anyone adds is refused with no obvious cause.

Write a control

Open my-baseline/controls/example.rpc and replace the example with something you actually care about.

control "ssh-01" {
  title       = "SSH root login is disabled"
  description = "Direct root login over SSH removes accountability."
  impact      = 0.9
  remediation = "Set PermitRootLogin no in /etc/ssh/sshd_config and reload sshd."

  platform = ["linux"]

  tags = {
    category = "ssh"
  }

  only_if "package" {
    name      = "openssh-server"
    installed = true
  }

  check "root-login" "sshd_config" {
    option "PermitRootLogin" {
      value = "no"
    }
  }
}

The only_if block is a precondition. On a host with no SSH server the control is reported as skipped with a reason, rather than failing for a service that was never meant to be there.

Validate before you run

refpoint check my-baseline

check parses the profile and decodes every check body, only_if precondition, and any_of member against its resource provider. It collects every problem in one pass instead of stopping at the first, and each finding renders with a clickable path:line:col and a “did you mean” suggestion.

It also reports which executables the profile’s command checks would run:

Profile "my-baseline" is valid (12 controls loaded)
Commands used:     getent, systemctl
Declares no allowed_commands, so the operator's list governs alone.
Run with: --allowed-commands getent,systemctl

Run it

refpoint run my-baseline

With no target given, the run defaults to local. Every run prints a three-line banner to stderr before anything else:

refpoint <version>
config loaded: <absolute path or "none">
profiles run: <absolute path>

That goes to stderr, not stdout, so a report streaming to stdout is never contaminated. The config path is announced because the working directory is searched first, and a config.toml shipped inside a cloned repository would otherwise govern the run silently.

Preview a fleet run first

refpoint run my-baseline --targets web-01,web-02 --dry-run

The dry run opens transports, probes each target’s platform, and classifies every control as run, waive, or skip with a reason. It executes no checks and always exits 0. Controls guarded by only_if are marked conditional, since the precondition is decided on the target at run time.

Save the result and work with it

refpoint run my-baseline --format json --output result.json
refpoint report result.json --format html --output report.html
refpoint tui result.json
refpoint diff last-week.json result.json

The JSON file is the artifact of record. Re-renderings produced by report are derivative and are not attested.

Read the exit code

Code Condition
0 Everything passed
1 At least one control failed, and either no threshold was set or the score met it
2 At least one target was unreachable or a control errored
5 Controls failed and the weighted score fell below --threshold
130 Interrupted by SIGINT or SIGTERM

Code 2 is the one to watch in CI. It means the scan could not see part of what it was asked to look at, which is a broken run rather than a fleet to remediate. Unreachable targets are counted separately and are never pruned from the report, so a job that reached only half its hosts can never report a clean pass.