CI/CD Integration Guide

Tool: vise-scan CLI (single-file, self-contained — no runtime to install) Platforms: Linux x64 · macOS ARM64 · Windows x64/ARM64 Distribution: https://download.visesec.com/cli/<version>/ (same endpoint the IDE extensions use) Updated: 2026-06-22

The CLI is a single self-contained binary. Every recipe below pins a version and verifies the download against a published SHA256SUMS before running it — never pipe an unverified binary into your pipeline.

Important — CI/CD scanning is an Enterprise (Team-CI) capability

The CLI detects a CI environment and exits 4 unless it sees a valid Enterprise entitlement. Authenticate it with a machine-unbound CI token, not a license key:

  • In your account portal → Settings → CI tokens → Generate CI token. The token is machine-unbound (works on ephemeral runners), does not consume a developer seat, and is revocable any time.
  • Store it as a secret named VISE_CI_TOKEN; every recipe reads it from the environment (it never appears on the command line).
  • A regular --license-key is machine-bound and will not work in CI.
  • Local, non-CI scanning stays free at any tier — this gate only applies to pipelines.

Quick Start

# Local (free, any tier) — exits 2 if Critical/High found
vise-scan ./src --format text --quiet

# In CI (Enterprise) — VISE_CI_TOKEN is read from the environment
export VISE_CI_TOKEN="<your-ci-token>"
vise-scan ./src --edition enterprise --format sarif --output results.sarif --quiet

Exit Codes

The exit code is the gate. It reflects the highest severity found (plus error states):

Code Meaning Pipeline Action
0 No vulnerabilities Pass
1 Medium/Low/Info only Pass (or warn)
2 Critical or High found Fail the build
3 Invalid arguments Fail (config error)
4 Entitlement error — missing/invalid VISE_CI_TOKEN, or non-Enterprise in CI Fail (setup error)
5 Scan error Fail (runtime error)
6 Cancelled Fail
7 Timeout Fail (raise --timeout)

A clean gate is simply: fail when exit code ≥ 2.


GitHub Actions

Recommended: the vise-action

The published Action handles download, checksum verification, OS/arch detection, the scan, the gate, and the SARIF upload — in one step:

name: Security Scan
on: [push, pull_request]

permissions:
  contents: read
  security-events: write   # required for the SARIF upload

jobs:
  security-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: visesec/vise-action@v1
        with:
          path: .
          ci-token: ${{ secrets.VISE_CI_TOKEN }}
          min-severity: medium
          upload-sarif: true

That's the whole integration. The job fails automatically when Critical/High are found.

Action inputs

Input Default Description
path . Directory to scan
version 1.0.0 CLI version to download (pin it)
ci-token Enterprise CI token (machine-unbound). Pass ${{ secrets.VISE_CI_TOKEN }}
edition enterprise Scan edition (CI requires enterprise)
min-severity info info / low / medium / high / critical
format sarif sarif / json / text
output vise-results.sarif Report path
exclude Comma-separated globs to skip
fail-on-findings true Set false for report-only (don't fail on exit 2)
upload-sarif false Auto-upload SARIF to GitHub code scanning
download-base-url https://download.visesec.com/cli Override for an air-gapped mirror

Outputs: exit-code (raw scanner code) and sarif-file (report path).

PR gate — report findings, fail only on High+

name: PR Security Gate
on:
  pull_request:
    branches: [main]

permissions:
  contents: read
  security-events: write

jobs:
  security-gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - id: scan
        uses: visesec/vise-action@v1
        with:
          path: .
          ci-token: ${{ secrets.VISE_CI_TOKEN }}
          min-severity: high
          exclude: "**/test/**,**/node_modules/**,**/bin/**"
          upload-sarif: true
      # The action already fails the job on Critical/High. For a custom message
      # instead, set fail-on-findings: false and branch on steps.scan.outputs.exit-code.

Without the Action (manual install)

If you prefer not to use the Action, the same canonical install snippet works in any GitHub job — see Manual install below, then run the scan with VISE_CI_TOKEN in the environment.


Manual install (any CI)

Use this canonical snippet on any Linux runner. It pins the version and verifies the checksum — copy it verbatim:

# Pin the version — never float to "latest" in CI.
VISE_VERSION="1.0.0"
BASE="https://download.visesec.com/cli/${VISE_VERSION}"

# Download the single-file binary + its checksum manifest, then verify before use.
curl -fsSL --retry 3 -o vise-scan-linux-x64 "${BASE}/vise-scan-linux-x64"
curl -fsSL --retry 3 -o SHA256SUMS          "${BASE}/SHA256SUMS"
grep ' vise-scan-linux-x64$' SHA256SUMS | sha256sum -c -    # aborts on mismatch
chmod +x vise-scan-linux-x64 && mv vise-scan-linux-x64 vise-scan

For macOS runners use vise-scan-osx-arm64 and shasum -a 256 -c -. For Windows use vise-scan-win-x64.exe and CertUtil -hashfile.

Then scan with the Enterprise CI token in the environment:

export VISE_CI_TOKEN="$VISE_CI_TOKEN"      # from your CI secret store
./vise-scan . --edition enterprise --format sarif --output results.sarif --min-severity medium --quiet

GitLab CI

security-scan:
  stage: test
  image: ubuntu:22.04
  variables:
    VISE_VERSION: "1.0.0"
    # Set VISE_CI_TOKEN as a masked CI/CD variable (Settings -> CI/CD -> Variables).
  before_script:
    - apt-get update && apt-get install -y curl
    - BASE="https://download.visesec.com/cli/${VISE_VERSION}"
    - curl -fsSL --retry 3 -o vise-scan-linux-x64 "${BASE}/vise-scan-linux-x64"
    - curl -fsSL --retry 3 -o SHA256SUMS "${BASE}/SHA256SUMS"
    - grep ' vise-scan-linux-x64$' SHA256SUMS | sha256sum -c -
    - chmod +x vise-scan-linux-x64 && mv vise-scan-linux-x64 vise-scan
  script:
    - ./vise-scan . --edition enterprise --format sarif --output gl-sast-report.sarif --quiet
  artifacts:
    reports:
      sast: gl-sast-report.sarif
    paths:
      - gl-sast-report.sarif
    when: always
  allow_failure: false

Azure DevOps

trigger:
  branches:
    include:
      - main
      - develop

pool:
  vmImage: 'ubuntu-latest'

variables:
  VISE_VERSION: '1.0.0'
  # Add VISE_CI_TOKEN as a secret pipeline variable (do not echo it).

steps:
  - task: Bash@3
    displayName: 'Install vise-scan'
    inputs:
      targetType: inline
      script: |
        BASE="https://download.visesec.com/cli/$(VISE_VERSION)"
        curl -fsSL --retry 3 -o vise-scan-linux-x64 "${BASE}/vise-scan-linux-x64"
        curl -fsSL --retry 3 -o SHA256SUMS "${BASE}/SHA256SUMS"
        grep ' vise-scan-linux-x64$' SHA256SUMS | sha256sum -c -
        chmod +x vise-scan-linux-x64 && mv vise-scan-linux-x64 vise-scan

  - task: Bash@3
    displayName: 'Run Security Scan'
    env:
      VISE_CI_TOKEN: $(VISE_CI_TOKEN)
    inputs:
      targetType: inline
      script: |
        ./vise-scan . \
          --edition enterprise \
          --format sarif \
          --output $(Build.ArtifactStagingDirectory)/results.sarif \
          --quiet

  - task: PublishBuildArtifacts@1
    displayName: 'Publish SARIF Report'
    condition: always()
    inputs:
      PathtoPublish: $(Build.ArtifactStagingDirectory)/results.sarif
      ArtifactName: security-report

Jenkins

pipeline {
    agent any

    environment {
        VISE_VERSION  = '1.0.0'
        VISE_CI_TOKEN = credentials('vise-ci-token')   // Enterprise CI token
    }

    stages {
        stage('Install Scanner') {
            steps {
                sh '''
                    BASE="https://download.visesec.com/cli/${VISE_VERSION}"
                    curl -fsSL --retry 3 -o vise-scan-linux-x64 "${BASE}/vise-scan-linux-x64"
                    curl -fsSL --retry 3 -o SHA256SUMS "${BASE}/SHA256SUMS"
                    grep ' vise-scan-linux-x64$' SHA256SUMS | sha256sum -c -
                    chmod +x vise-scan-linux-x64 && mv vise-scan-linux-x64 vise-scan
                '''
            }
        }

        stage('Security Scan') {
            steps {
                sh '''
                    ./vise-scan . \
                        --edition enterprise \
                        --format sarif \
                        --format json \
                        --output results.sarif \
                        --min-severity medium \
                        --quiet
                '''
            }
            post {
                always {
                    archiveArtifacts artifacts: 'results.*', fingerprint: true
                    recordIssues tool: sarif(pattern: 'results.sarif')
                }
            }
        }
    }

    post {
        failure {
            echo 'Security scan found Critical/High vulnerabilities!'
        }
    }
}

Bitbucket Pipelines

pipelines:
  default:
    - step:
        name: Security Scan
        image: ubuntu:22.04
        # Set VISE_CI_TOKEN as a secured repository variable.
        script:
          - apt-get update && apt-get install -y curl
          - export VISE_VERSION="1.0.0"
          - BASE="https://download.visesec.com/cli/${VISE_VERSION}"
          - curl -fsSL --retry 3 -o vise-scan-linux-x64 "${BASE}/vise-scan-linux-x64"
          - curl -fsSL --retry 3 -o SHA256SUMS "${BASE}/SHA256SUMS"
          - grep ' vise-scan-linux-x64$' SHA256SUMS | sha256sum -c -
          - chmod +x vise-scan-linux-x64 && mv vise-scan-linux-x64 vise-scan
          - ./vise-scan . --edition enterprise --format sarif --output results.sarif --quiet
        artifacts:
          - results.sarif

Docker

Build a self-contained scanner image with the binary baked in and verified:

FROM ubuntu:22.04
ARG VISE_VERSION=1.0.0
RUN apt-get update && apt-get install -y curl ca-certificates && rm -rf /var/lib/apt/lists/* && \
    BASE="https://download.visesec.com/cli/${VISE_VERSION}" && \
    curl -fsSL --retry 3 -o vise-scan-linux-x64 "${BASE}/vise-scan-linux-x64" && \
    curl -fsSL --retry 3 -o SHA256SUMS "${BASE}/SHA256SUMS" && \
    grep ' vise-scan-linux-x64$' SHA256SUMS | sha256sum -c - && \
    chmod +x vise-scan-linux-x64 && mv vise-scan-linux-x64 /usr/local/bin/vise-scan && rm SHA256SUMS
ENTRYPOINT ["vise-scan"]
# Build
docker build -t vise-scan .

# Scan a local project (pass the Enterprise CI token through)
docker run --rm -e VISE_CI_TOKEN -v "$(pwd)":/project vise-scan \
  /project --edition enterprise --format sarif --output /project/results.sarif --quiet

CLI Reference

Options

Option Description Default
<path> Directory to scan (required) -
--edition basic, pro, enterprise (CI requires enterprise) basic
--format sarif, json, text (repeatable; SARIF is Enterprise) sarif
--output, -o Output file path vise-report.{format}
--languages Comma-separated language filter all detected
--exclude Glob exclusion patterns none
--min-severity info, low, medium, high, critical info
--baseline Baseline report for delta comparison none
--max-vulns Maximum vulnerabilities to report 10000
--license-key License key for local Pro/Enterprise (machine-bound; not for CI) none
--nvd-api-key NVD API key (or use NVD_API_KEY env) none
--no-secrets Disable secret detection enabled
--no-deps Disable dependency scanning enabled
--no-config Disable configuration scanning enabled
--no-iac Disable IaC scanning enabled
--no-live-cve Disable live CVE lookup enabled
--quiet, -q Suppress progress output verbose

Environment Variables

Variable Purpose
VISE_CI_TOKEN Enterprise CI token (machine-unbound) — the supported way to authenticate in CI
VISE_LICENSE_KEY Local license key (machine-bound; alternative to --license-key for non-CI use)
NVD_API_KEY NVD API key for higher CVE lookup rate limits

Best Practices

  1. Store the CI token as a secret named VISE_CI_TOKEN — never hardcode it in pipeline files
  2. Pin the version — set VISE_VERSION / the Action's version; never float to "latest" in CI
  3. Verify the checksum — every recipe here does; don't strip it out
  4. Use --quiet in CI — cleaner logs, only summary output
  5. Use --min-severity medium — ignore Info/Low to reduce noise
  6. Upload SARIF — enables GitHub Code Scanning, IDE annotations, PR comments
  7. Use --exclude — skip node_modules, bin, obj, vendor, test fixtures
  8. Cache the binary — key the cache on VISE_VERSION to avoid re-downloading
  9. Gate on exit code ≥ 2 — Critical/High fail the build; errors (≥3) fail loudly

SARIF Integration

The --format sarif output is OASIS SARIF 2.1.0 compliant, includes partialFingerprints for stable cross-run dedup, and integrates with:

  • GitHub Code Scanninggithub/codeql-action/upload-sarif@v3
  • GitLab SAST — via artifacts.reports.sast
  • Azure DevOps — SARIF Viewer extension
  • VS Code — SARIF Viewer extension
  • Visual Studio — built-in SARIF support
  • JetBrains IDEs — SARIF support via plugin

Vise CLI v1.0.0 · Generated 2026-06-22