Write Custom Policies

Preview Checks

Use the preview action to run a check without affecting an asset's score, with an optional deadline after which the check starts scoring

Now that you understand how scoring works, consider what happens when you add a new check to a policy: it immediately affects the score of every asset and policy it is applied to. That can be disruptive. A brand-new check can suddenly drop scores across your fleet before any team has a chance to remediate the findings.

The preview action solves this. A check in preview still runs on every matching asset and its results still appear in scan output, but the result does not count toward the asset's score. This lets you roll out a new check or try a modification, show teams what would happen, and give them a window to fix things before the check starts affecting scores.

How a previewed check behaves

A check with the preview action:

  • Still runs. cnspec evaluates the check against the asset.
  • Still reports results. Failures appear in scan output, grouped separately under a Remediation deadline heading.
  • Does not affect the score. The result is excluded from the asset's and policy's score calculation. It simply exists but isn't counted.

This is different from disabling a check. A disabled check doesn't run at all, so you see nothing. A previewed check runs and shows results; it just doesn't score them.

Put a check in preview

You apply the preview action through an override group. The check itself is defined as usual; the override group references it by uid and sets action: preview.

groups:
  # The check is defined and assigned here, as normal.
  - filters:
      - mql: asset.family.contains('unix')
    checks:
      - uid: sshd-use-pam

  # This override puts the check into preview.
  - type: override
    title: UsePAM in preview
    checks:
      - uid: sshd-use-pam
        action: preview

With no end date, this is a standing preview: the check runs and reports but never affects the score until you remove the override.

Set a deadline with valid.until

Add a valid block with an until date to give the preview a deadline. While the current date is before until, the check is in preview and doesn't score. Once the date passes, the override stops applying and the check reverts to a normal, scored check.

- type: override
  title: UsePAM in preview until October 2026
  valid:
    until: 2026-10-01
  checks:
    - uid: sshd-use-pam
      action: preview

The date uses YYYY-MM-DD format. In scan output, previewed checks with a deadline are listed under a Remediation deadline heading that shows the date and how far away it is, so teams know exactly how long they have to remediate before the check counts.

Because the override simply stops applying after until, you don't need to change anything when the deadline arrives. The check starts scoring automatically on that date.

Full example

This policy assigns four SSH checks and uses overrides to demonstrate every preview state. You can find this example in the cnspec repo at examples/preview-dates.mql.yaml.

policies:
  - uid: sshd-preview-example
    name: SSHd preview/date example policy
    version: 1.0.0
    tags:
      mondoo.com/category: security
      mondoo.com/platform: unix
    groups:
      # Main group: assigns all four checks.
      - filters:
          - mql: asset.family.contains('unix')
        checks:
          - uid: sshd-protocol-v2
          - uid: sshd-use-pam
          - uid: sshd-authorizedkeyscommanduser-root
          - uid: sshd-port-22

      # Preview with a deadline: scores normally starting 2026-10-01.
      - type: override
        title: UsePAM in preview until October 2026
        valid:
          until: 2026-10-01
        checks:
          - uid: sshd-use-pam
            action: preview

      # Standing preview: never scores until you remove this override.
      - type: override
        title: AuthorizedKeysCommandUser standing preview
        checks:
          - uid: sshd-authorizedkeyscommanduser-root
            action: preview

      # Expired preview: the until date has passed, so this check scores normally.
      - type: override
        title: Port preview expired April 2026
        valid:
          until: 2026-04-11
        checks:
          - uid: sshd-port-22
            action: preview

queries:
  # Normal check: scores immediately, no preview.
  - uid: sshd-protocol-v2
    title: SSHd should use protocol version 2
    mql: sshd.config.params.Protocol == "2"
    impact: 80

  - uid: sshd-use-pam
    title: SSHd should enable PAM
    mql: sshd.config.params.UsePAM == "yes"
    impact: 60

  - uid: sshd-authorizedkeyscommanduser-root
    title: SSHd AuthorizedKeysCommandUser should be root
    mql: sshd.config.params.AuthorizedKeysCommandUser == "root"
    impact: 40

  - uid: sshd-port-22
    title: SSHd should listen on port 22
    mql: sshd.config.params.Port == "22"
    impact: 30

In this policy:

  • sshd-protocol-v2 has no override, so it scores normally.
  • sshd-use-pam is in preview until 2026-10-01. It runs and reports but doesn't score until that date.
  • sshd-authorizedkeyscommanduser-root is in a standing preview with no end date. It never scores until you remove the override.
  • sshd-port-22 had a preview that expired on 2026-04-11. Because that date has passed, it now scores normally.

When to use preview

  • Rolling out a new check. Add it in preview so teams can see and fix failures before the check affects scores.
  • Phased remediation deadlines. Give a fleet a fixed window (via valid.until) to remediate, after which the check counts automatically.
  • Evaluating a check. Run a check across your assets to gauge its impact before committing to scoring it.

Next steps

On this page