---
title: "GitHub Action: gate x402 endpoints in CI | Settlens"
description: "Use the Settlens composite GitHub Action: inputs and outputs, complete workflows, secrets and allowed hosts, SARIF, permissions and pinning advice."
url: https://settlens.com/docs/github-action
last_updated: 2026-10-13
---

# GitHub Action

> **In short:** The Settlens composite GitHub Action runs settlens check against a configuration file, fails the job when a failing check reaches the fail-on severity (default high) and leaves JSON, HTML and SARIF reports for later steps. It runs passive checks only, from a checkout of the private Settlens repository.

Run Settlens checks on every pull request or on a schedule, fail the job at your severity threshold and keep the reports as build artifacts.

The repository includes a composite GitHub Action (`action.yml` at its root). It installs Node.js 24, installs Settlens' production dependencies from the lockfile, then runs [`settlens check`](https://settlens.com/docs/cli#check) against your [configuration file](https://settlens.com/docs/configuration). The job fails when a failing check reaches the `fail-on` severity, and the JSON, HTML and SARIF reports are left in the output directory for later steps.

The Action is not on the GitHub Marketplace: Settlens lives in a private repository that pilot participants receive, so workflows run the Action from a copy of that repository. It runs passive checks only; it has no input for the active probe.

_Diagram: A pull request or schedule triggers the workflow: checkout of your code and of Settlens, then the Settlens Action runs settlens check. The job status fails at the fail-on threshold, and the reports directory with JSON, HTML and SARIF files is uploaded with upload-artifact, even when the gate fails._

_Where the Action sits in a workflow._

## Inputs

Read from `action.yml`. Every input is optional.

_Action inputs_

| Input | Default | Passed to the CLI as | Description |
| --- | --- | --- | --- |
| config | settlens.config.json | --config | Path to a Settlens JSON configuration file. |
| output | reports | --out | Directory for JSON, HTML and SARIF evidence reports. |
| formats | json,html,sarif | --format | Comma-separated report formats. |
| fail-on | high | --fail-on | Minimum failing severity that blocks CI. |
| allowed-hosts | (empty) | SETTLENS_ALLOWED_HOSTS | Comma-separated exact hostnames allowed to receive custom headers. |

- **fail-on** takes `low`, `medium`, `high`, `critical` or `none`. Only failing checks count; warnings never fail the job.
- **allowed-hosts** is the allowlist for custom headers in the config. It is deliberately separate from the config file: a pull request that edits the config cannot add a new destination for your secrets without also changing the workflow.
- **config** and **output** are paths relative to the workspace root.

## Outputs

_Action outputs_

| Output | Description |
| --- | --- |
| report-directory | Directory containing the generated evidence. |

`report-directory` is set on every run, including when the gate fails: the step records the exit status of `settlens check`, writes the output, then exits with that status. The workflows below pass the literal `output` path to their upload steps.

## Workflow in your own repository

Check out the Settlens repository next to your code, pinned to a commit you reviewed, and run the Action from that path. `SETTLENS_REPO_TOKEN` is a token with read access to the Settlens repository only, such as a fine-grained personal access token or a GitHub App token; the default `GITHUB_TOKEN` cannot read another private repository.

**.github/workflows/settlens.yml**

```yaml
name: Settlens

on:
  pull_request:
  schedule:
    - cron: "17 6 * * 1-5" # weekdays, 06:17 UTC
  workflow_dispatch:

permissions:
  contents: read

jobs:
  x402-assessment:
    runs-on: ubuntu-latest
    steps:
      - name: Check out this repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd

      - name: Check out Settlens
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
        with:
          repository: OWNER/SETTLENS-REPOSITORY # the repository shared with your pilot
          ref: FULL-40-CHARACTER-COMMIT-SHA # a Settlens commit you reviewed
          path: .settlens
          token: ${{ secrets.SETTLENS_REPO_TOKEN }} # read-only access to that repository
          persist-credentials: false

      - name: Assess x402 endpoints
        uses: ./.settlens
        with:
          config: settlens.config.json
          output: reports
          fail-on: high
          allowed-hosts: staging.merchant.example
        env:
          ASSESSMENT_TOKEN: ${{ secrets.ASSESSMENT_TOKEN }} # read by ${ASSESSMENT_TOKEN} in the config

      - name: Upload evidence
        if: always()
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
        with:
          name: settlens-reports
          path: reports/
          if-no-files-found: error
          retention-days: 30
```

The schedule turns the same job into a recurring check of production endpoints. To compare each run with the previous one and alert only on changes, use [Monitor](https://settlens.com/docs/monitor) instead.

## Workflow in the Settlens repository

When the workflow lives in the repository that contains Settlens at its root, the Action is simply `uses: ./`. This is the shape of the example shipped in the repository (`examples/github-workflow.yml`), where the allowlist comes from a repository variable:

**.github/workflows/settlens.yml**

```yaml
name: Settlens

on:
  pull_request:
  workflow_dispatch:

permissions:
  contents: read

jobs:
  x402-assessment:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd

      - name: Assess x402 endpoints
        uses: ./
        with:
          config: settlens.config.json
          fail-on: high
          allowed-hosts: ${{ vars.SETTLENS_ALLOWED_HOSTS }}

      - name: Upload evidence
        if: always()
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
        with:
          name: settlens-reports
          path: reports/
          if-no-files-found: error
          retention-days: 30
```

## Secrets and custom headers

When a target needs authentication, reference the secret from the config as `${NAME}`, provide it to the step as an environment variable, and list the target's hostname in `allowed-hosts`. Settlens refuses to send any custom header to a host that is not on that list, and it never writes header values to reports. See [Headers and secrets](https://settlens.com/docs/configuration#headers).

Workflows triggered by `pull_request` from a fork do not receive repository secrets, so targets that need them cannot be assessed on fork pull requests.

## SARIF and code scanning

The SARIF file lists failing and warning checks, one rule per check id (format details in [Reports](https://settlens.com/docs/reports#sarif)).

Settlens findings concern a URL, not a line of code, but [code scanning](https://docs.github.com/en/code-security/reference/code-scanning/sarif-files/sarif-support) only displays results that have a location. Each result is therefore anchored at line 1 of the file named by the `config` input, so the alerts appear on your configuration file, with the target URL in the message. Each target gets its own fingerprint, so the same check failing on two endpoints stays two alerts.

> **Code scanning on private repositories**
>
> On private repositories, code scanning requires GitHub Code Security; without it the upload fails. The findings are also in the job status, the console summary and the uploaded JSON and HTML reports.

To upload the file, the job needs the `security-events: write` permission, and the condition below skips fork pull requests, whose token cannot write security events:

**Optional SARIF upload step**

```yaml
# Add to the job: permissions: { contents: read, security-events: write }
      - name: Upload SARIF
        if: >-
          always() &&
          hashFiles('reports/**/*.sarif') != '' &&
          (github.event_name != 'pull_request' ||
          github.event.pull_request.head.repo.full_name == github.repository)
        uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a
        with:
          sarif_file: reports
```

## Permissions

- `contents: read` is enough to run the Action and upload artifacts.
- Add `security-events: write` only to the job that uploads SARIF.
- The Action needs no wallet, no private key and no write access. Settlens itself contacts only the targets and facilitators in your config; installing its dependencies contacts the npm registry.

## Pinning

- Pin the Settlens checkout to a full commit SHA (`ref:`), never a branch, so a change to the repository cannot change what runs in your CI without a review.
- Pin every third-party action to a full 40-character commit SHA. `action.yml` itself pins `actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e` and Node.js 24.
- Dependencies come from the lockfile with `npm ci --prefix "$GITHUB_ACTION_PATH" --omit=dev --ignore-scripts`: exact versions, no development dependencies and no install scripts.
- Keep `allowed-hosts` in the workflow or in a repository variable, never in the config file it protects.

Next: tune the [configuration](https://settlens.com/docs/configuration), look up findings in the [check catalog](https://settlens.com/docs/checks), or [request a pilot](https://settlens.com/contact) to get access to the repository.

## Sources

1. [Creating a composite action](https://docs.github.com/en/actions/tutorials/create-actions/create-a-composite-action) — GitHub Docs
2. [Secure use reference (pin actions to a full-length commit SHA)](https://docs.github.com/en/actions/reference/security/secure-use) — GitHub Docs
3. [SARIF support for code scanning](https://docs.github.com/en/code-security/reference/code-scanning/sarif-files/sarif-support) — GitHub Docs
