> For the complete documentation index, see [llms.txt](https://docs.nullify.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nullify.ai/configuration/configuration-pull-requests.md).

# Pull Request Configuration

## Overview

**Settings → Pull Requests** (or the PR settings API) controls how Nullify's check and reviews behave on each pull request: which findings fail the check, whether scan failures fail it, what priority of finding is severe enough to count, and whether Nullify reviews the pull request at all.

These settings are tenant-wide — they apply to every connected repository — and require the **config:write** permission to change. They map directly to the admin API (`PUT /admin/pr-gate-settings`), so the same behaviour can be automated.

## The Nullify check

Nullify reports a single check named **Nullify** on every pull request, covering code (SAST), dependency (SCA), container, secrets and supply-chain analysis together. The check has three outcomes: **failed** (blocks a required check), **neutral** (Nullify could not finish checking the change; satisfies a required check without claiming the change is clean), and **passed**.

By default the check is **information only**: it reports findings and incomplete scans on the pull request and always passes. Three independent controls turn it into a gate, and you can combine them: two findings controls and one for scans that cannot complete.

| Control                                                                                       | API field                  | Fails the check when                                                                                                                                 |
| --------------------------------------------------------------------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Findings that fail the check](#findings-that-fail-the-check)                                 | `findingsPolicy`           | The pull request introduces a finding the chosen policy blocks on.                                                                                   |
| [Always block new CVEs at or above the cutoff](#always-block-new-cves-at-or-above-the-cutoff) | `cvssEnforcement`          | The pull request introduces a dependency or container CVE at or above the CVSS cutoff, regardless of AI triage, whether it has not run or disagrees. |
| [Fail checks when scans cannot complete](#fail-checks-when-scans-cannot-complete)             | `failOnIncompleteCoverage` | A required Nullify scan, supply chain included, could not complete after its recovery attempts. Independent of the findings controls.                |

With every control off, the check passes on every pull request, including when a scanner failed. Its summary still lists findings, and a check that passed without a complete scan says so.

{% hint style="info" %}
Failing the check does not block the merge on its own. To turn it into a hard merge requirement, mark the **Nullify** check as required in your provider's branch-protection / merge-check rules (for example, GitHub branch protection's "Require status checks to pass").
{% endhint %}

## Settings

### Findings that fail the check

| Policy                      | API value   | Fails the check when                                                                                                                                                                                                                                                                                                                 |
| --------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| No findings block (default) | `none`      | Never, on findings alone.                                                                                                                                                                                                                                                                                                            |
| Confirmed new findings      | `confirmed` | The pull request introduces a code, dependency, container or secret vulnerability that AI triage confirmed at or above the [blocking priority](#blocking-priority), or an enforced supply-chain policy finding at or above it. A finding that has not been triaged, or whose triage failed, never fails the check under this policy. |

The earlier values `net_new` and `triaged_confirmed` no longer exist; the API rejects them with `400`. Gates saved before this change were moved automatically: an enabled gate became `confirmed`, a disabled gate became `none`. **Fail checks when scans cannot complete** kept its stored value.

Pushes never fail on findings under any policy; a push fails only when a scan could not complete and **Fail checks when scans cannot complete** is on.

The gate evaluates **net-new findings only**: issues this pull request introduces relative to its target branch. Pre-existing findings never fail an unrelated pull request, so turning a policy on does not block in-flight work retroactively.

If Nullify could not compare the pull request against its target branch, findings above the threshold conclude the check **neutral** rather than failing it, because Nullify cannot confirm the pull request introduced them.

### Always block new CVEs at or above the cutoff

Off by default. When on, the check fails on any pull request that introduces a dependency or container CVE with a CVSS score at or above the cutoff, regardless of AI triage. The cutoff defaults to **9.0**; set another value from 0 to 10 in the **CVSS cutoff** field or with `scaBlockCvssThreshold`.

* Only a CVE the pull request introduces counts, so Nullify needs its comparison against the target branch. Without it, a CVE at or above the cutoff leaves the check **neutral**.
* Only allowlisting, archiving or a manual priority override (including marking it a false positive yourself) exempts a finding. An AI priority or an AI false-positive verdict does not, because this rule applies regardless of triage.
* Pushes never fail on this rule.

When off, a CVE's CVSS score never fails the check on its own: under **Confirmed new findings** it still needs AI confirmation.

### Fail checks when scans cannot complete

Off by default, and independent of the findings controls: it works with **No findings block** and the CVSS rule off too. When on, the check fails when a required scan could not complete after its recovery attempts:

* exhausted scanner failures, interruptions and timeouts, and scan results Nullify could not read;
* lost code-analysis (SAST) shards; findings from the shards that did complete still count;
* supply-chain (SCPM) policy-load failures and required rules that did not finish.

Scanners you disabled, scanners that do not apply, intentional skips and a scan waiting on another scan of the same branch never count as failures.

The setting in force when the scan started applies, so an outage while the scan runs cannot switch it off. If Nullify has no record of it and cannot read your settings, it never fails the check on a scan that could not complete: the check concludes neutral.

A missing target-branch comparison is outside this setting. Under a findings control it concludes the check **neutral**, and with no findings control it passes.

{% hint style="warning" %}
**Fail checks when scans cannot complete** blocks every pull request while a Nullify scanner is unavailable, until it recovers. Choose it only when an unchecked change must never merge. An administrator can mark a blocked check as passing from Nullify.
{% endhint %}

Without it, a scan that did not finish concludes the check **neutral** under a findings control, or passing under an information-only gate, with a note in the check summary. Neutral satisfies a required check. If Nullify cannot read your gate settings and has no record of them from when the scan started, the check concludes neutral.

### Blocking priority

Sets the lowest finding priority that counts, for the **Confirmed new findings** policy and for change requests:

* **Urgent** — only `URGENT` findings count.
* **Urgent + Important** — both `URGENT` and `IMPORTANT` findings count.

Lower-priority findings (`MEDIUM` and below) are always reported but never fail the check.

### PR reviews

When on (the default), Nullify reviews the pull requests it scans: inline comments on findings, a review summary and, when allowed below, an approving or a request-changes review. When off, Nullify posts no review on any pull request and the two settings below do nothing. The next time Nullify scans a pull request after you turn reviews off, it dismisses its own outstanding request-changes reviews on it, so a stale Nullify review does not keep blocking the merge; reviews from people are never touched. If Nullify cannot read this setting, or Nullify pauses reviews platform-wide, it posts no review and dismisses nothing. The **Nullify** check is unaffected either way.

When Nullify has a concrete security concern about code the pull request introduced or changed, it posts a review. A pull request with no security concern receives no review comment at all; the passing **Nullify** check is the all-clear signal.

### Clean pull request

* **No review (default)** — Nullify never submits an approving review. A clean pull request is left without a review.
* **Approve** — Nullify may submit an **approving** review on a pull request with no blocking findings, and only when every scanner finished. Because a bot approval can satisfy a required-reviewer rule, this is opt-in.

{% hint style="warning" %}
Approving reviews mean a Nullify approval can count toward a required-reviewer rule on your branch protection. Leave this off if you want every pull request to still require a human approver.
{% endhint %}

### Security concerns

* **Comment (default)** — Nullify raises concerns at or above the blocking priority as **comments**.
* **Request changes** — Nullify submits a **request-changes** review for them. Because a request-changes review can block a merge under branch protection, this is opt-in.

{% hint style="info" %}
The review verdict and the **Nullify** check are independent. The check's outcome comes only from the gate controls and the blocking priority; a *request changes* review does not by itself fail the check, and a failing check does not depend on the review verdict.
{% endhint %}

## Equivalent API

| Setting                                      | API field                    | Values                                           |
| -------------------------------------------- | ---------------------------- | ------------------------------------------------ |
| Findings that fail the check                 | `findingsPolicy`             | `none`, `confirmed`                              |
| Always block new CVEs at or above the cutoff | `cvssEnforcement`            | `true` / `false`                                 |
| CVSS cutoff                                  | `scaBlockCvssThreshold`      | Number from 0 to 10; omitted or null uses 9.0    |
| Fail checks when scans cannot complete       | `failOnIncompleteCoverage`   | `true` / `false`; omitted keeps the stored value |
| Blocking priority                            | `minPriority`                | `URGENT`, `IMPORTANT`                            |
| PR reviews                                   | `prReviewsEnabled`           | `true` / `false`                                 |
| Clean pull request: Approve                  | `allowApprovingReviews`      | `true` / `false`                                 |
| Security concerns: Request changes           | `allowRequestChangesReviews` | `true` / `false`                                 |

```http
PUT /admin/pr-gate-settings
{
  "findingsPolicy": "confirmed",
  "cvssEnforcement": true,
  "enabled": true,
  "failOnIncompleteCoverage": false,
  "minPriority": "IMPORTANT",
  "prReviewsEnabled": true,
  "allowApprovingReviews": false,
  "allowRequestChangesReviews": false,
  "scaBlockCvssThreshold": 9.0
}
```

Tenants that have never saved the page get an information-only gate: `findingsPolicy` `none`, `cvssEnforcement` and `failOnIncompleteCoverage` false, `URGENT`, PR reviews on, and both review options off.

`findingsPolicy` and `cvssEnforcement` are authoritative for findings. `enabled` is kept for older clients: `GET` derives it (true when `findingsPolicy` is `confirmed` or `cvssEnforcement` is on). A `PUT` that sends `findingsPolicy` must send a matching `enabled`, or it is rejected with `400`; `cvssEnforcement` is only accepted alongside `findingsPolicy`. A `PUT` without `findingsPolicy` turns the findings controls off when `enabled` is false. When `enabled` is true it keeps the stored findings policy and CVSS enforcement, and uses `confirmed` if nothing else would block. `failOnIncompleteCoverage` is independent of all of these: a `PUT` that sends it replaces the stored value, and one that omits it keeps it. A `PUT` without `prReviewsEnabled` keeps the stored value.

A passing check is not proof every scanner completed. Without **Fail checks when scans cannot complete**, read the check summary for any stage that did not finish. Every settings change is written to the audit log with its previous and new values.

`PUT` replaces the settings. Read the current settings first and retain every value you intend to preserve; omitting `scaBlockCvssThreshold` resets it to 9.0. Supply-chain enforcement rules also affect gate results; `GET /admin/pr-gate-settings` returns the resolved `scpm` policy details. That response alone does not establish whether supply-chain detection is enabled for your tenant.
