paranoid_
Core

Exit codes and CI usage

The score-to-verdict mapping, the exit codes, and the GitHub Action.

Score and verdict

The score starts at 100. Each finding subtracts a fixed weight by severity: critical 25, high 10, medium 4, low 1, info 0. The floor is 0. One critical finding is enough to lose a pass; three high findings do it too (two land exactly on the pass line at 80).

ScoreVerdictExit code
80 to 100pass0
50 to 79warn1 (or 2 with --strict)
0 to 49fail2

Exit code 2 is also used when the score drops below --fail-under (default 50), even if the verdict would otherwise be pass or warn. --strict turns a warn verdict into a fail before the exit code is picked, so warn always exits 2 under --strict. A .paranoid.toml at the repo root can set its own fail-under and strict defaults, used whenever the matching flag is not itself given; see Team policy file.

Exit code 3 means paranoid itself hit an error: a bad flag, not a git repository, a git failure, an unreadable file. It never means a finding fired; the report cannot be trusted either way when you see a 3. baseline, fix-prompt, rules, version, and attest keygen only ever exit 0 on success or 3 on error; they have no score or verdict of their own to map to 1 or 2.

paranoid attest verify has its own, separate exit code scheme, since it checks a signature, not a diff: 0 means the signature is valid, 2 means it is invalid, 3 means verification could not be attempted at all. See Signing & attest.

The report always lists which checks ran and which were skipped, with the reason. A pass with skipped checks is still visible in the report, so read the skipped-checks list in CI, not just the exit code.

The GitHub Action

The composite action at alainrk/paranoid/action@main runs verify on the pull request range, uploads the report as an artifact, appends it to the job summary, optionally posts a sticky PR comment, and sets the check status from the verdict.

permissions:
  contents: read
  pull-requests: write # only needed for the sticky comment

jobs:
  paranoid:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: alainrk/paranoid/action@main
        with:
          sandbox: none # or auto, when the runner has docker
          claims: summary.md # optional

Action inputs

InputDefaultMeaning
basePR base ref (falls back to the PR's base SHA)State before the agent worked
headPR headState after the agent worked
claimsnonePath to a free-text summary file
sessionnonePath to an agent session file; ignored when claims is also set
sandboxautoauto, docker, podman, or none
offlinefalseSkip registry lookups
fail-under50Fail when the score drops below this
strictfalseTreat a warn verdict as failure
baselinenonePath to a baseline file, overriding the auto-detected .paranoid-baseline.json
no-baselinefalseIgnore any baseline file, including the auto-detected one
versionmainparanoid ref to install with go install
commenttruePost or update a sticky PR comment; set false to skip it and drop the write permission
sariffalseAlso write paranoid-report.sarif

Outputs: verdict (pass, warn, or fail) and score (0 to 100).

The action has no input for .paranoid.toml: it does not need one, since the file is read from the checked-out repo itself. A repo's [[disable]] and [sandbox] keys apply exactly as they do outside CI. Its fail-under key does not: the action always passes --fail-under explicitly (this input's own default is 50), so cobra always sees the flag as set and it always wins over the policy file. strict is unaffected, since the action only adds --strict when its own strict input is true. See Team policy file.

Uploading findings to GitHub code scanning

Set sarif: "true" and add an upload-sarif step after the action. This needs the security-events: write permission, which the action itself never requests.

permissions:
  contents: read
  pull-requests: write # only needed for the sticky comment
  security-events: write # only needed to upload SARIF

jobs:
  paranoid:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: alainrk/paranoid/action@main
        with:
          sandbox: none
          sarif: "true"
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: paranoid-report.sarif

Findings then show up next to the rest of the repository's code scanning alerts, with the rule's severity, message, and file location; each rule links back to its entry in docs/rules.md. See Report & schema for the SARIF contract itself.

Adopting the Action on an existing repo

Generate and commit .paranoid-baseline.json once, locally, before turning the Action on. The Action needs no extra input for this: verify auto-detects the committed file at the repo root the same way it does outside CI. Use the baseline input only if you keep the file somewhere else, and no-baseline: "true" for a workflow that should ignore it entirely. See Baseline & suppressions.

Plain CI, no Action

The exit code is enough on any CI system:

paranoid verify --base "origin/$BASE_REF" --format md --output report.md

This repository runs the same check on every push and pull request; the report of each run is in the job summary. --format sarif works the same way outside the Action, for any CI system that accepts a SARIF file (GitHub's own upload-sarif step, or a third-party code scanning integration).