← Back to Docs

Output Formats

vigil supports 4 output formats to adapt to different workflows: interactive terminal, automation, CI dashboards, and security platforms.

Format selection

# Human format (default)
vigil scan src/

# JSON format
vigil scan src/ -f json

# JUnit XML format
vigil scan src/ -f junit

# SARIF 2.1.0 format
vigil scan src/ -f sarif

Human

Default format, optimized for reading in the terminal. Includes ANSI colors, severity icons, and a final summary.

Severity icons

IconSeverityColor
CRITICALRed
HIGHRed
MEDIUMYellow
~LOWBlue
iINFOCyan

Example output

  vigil v0.5.0 — scanning 42 files...

  ✗ CRITICAL  DEP-001  requirements.txt:14
    Package 'python-jwt-utils' does not exist in pypi.
    → Suggestion: Remove 'python-jwt-utils' and find the correct package name.
    | python-jwt-utils==1.0.0

  ✗ HIGH      AUTH-005  src/main.py:8
    CORS configured with '*' allowing requests from any origin.
    → Suggestion: Restrict CORS to specific trusted origins.

  ─────────────────────────────────────────────────
  42 files scanned in 1.2s
  2 findings: 1 critical, 1 high
  2 analyzers: dependency ✓, auth ✓

Clean output (no findings)

  vigil v0.5.0 — scanning 42 files...

  No findings.

  ─────────────────────────────────────────────────
  42 files scanned in 0.5s
  0 findings
  2 analyzers: dependency ✓, auth ✓

Colors

  • Colors are automatically enabled when stdout is a TTY (interactive terminal).
  • If stdout is a pipe or a file, colors are automatically disabled.
  • You can control this with the output.colors config.

Snippets

If a finding includes a snippet (code fragment), it is displayed below the suggestion with the | prefix.

Quiet mode

With output.quiet: true (or the equivalent config), the human format suppresses the header and summary, showing only the findings and errors. Useful for integrations that only need the list of issues.

Behavior with --output

When --output is used with the human format, the report is written to both the file and the terminal. This allows saving the report without losing immediate feedback.


JSON

Structured format for programmatic processing, integration with other tools, or storage.

Structure

{
  "version": "0.5.0",
  "files_scanned": 42,
  "duration_seconds": 1.2,
  "analyzers_run": ["dependency", "auth"],
  "findings_count": 2,
  "findings": [
    {
      "rule_id": "DEP-001",
      "category": "dependency",
      "severity": "critical",
      "message": "Package 'python-jwt-utils' does not exist in pypi.",
      "location": {
        "file": "requirements.txt",
        "line": 14,
        "column": null,
        "end_line": null,
        "snippet": "python-jwt-utils==1.0.0"
      },
      "suggestion": "Remove 'python-jwt-utils' and find the correct package name.",
      "metadata": {}
    }
  ],
  "summary": {
    "files_scanned": 42,
    "total_findings": 2,
    "duration_seconds": 1.2,
    "analyzers_run": ["dependency", "auth"],
    "by_severity": {
      "critical": 1,
      "high": 1
    },
    "by_category": {
      "dependency": 1,
      "auth": 1
    },
    "by_rule": {
      "DEP-001": 1,
      "AUTH-005": 1
    },
    "by_file": {
      "requirements.txt": 1,
      "src/main.py": 1
    },
    "has_blocking": true,
    "errors": []
  },
  "errors": []
}

Fields

FieldTypeDescription
versionstringvigil version
files_scannedintNumber of files analyzed
duration_secondsfloatScan duration in seconds
analyzers_runarrayList of analyzers executed
findings_countintTotal number of findings
findingsarrayList of findings (empty if no issues)
summaryobjectStatistical summary (severity, category, rule, top 10 files)
errorsarrayAnalyzer execution errors

Each finding

FieldTypeDescription
rule_idstringUnique rule ID (e.g., DEP-001)
categorystringCategory: dependency, auth, secrets, test-quality
severitystringcritical, high, medium, low, info
messagestringDescription of the problem
locationobjectLocation in the code (includes snippet only if present)
suggestionstring|nullFix suggestion
metadataobjectAdditional rule-specific data

Typical usage

# Generate and process with jq
vigil scan src/ -f json | jq '.findings[] | select(.severity == "critical")'

# Save to file
vigil scan src/ -f json -o report.json

# Integrate with scripts
vigil scan src/ -f json | python process_results.py

JUnit XML

Format compatible with CI/CD dashboards (Jenkins, GitLab CI, Azure DevOps, etc.). Each finding is represented as a failed test case.

Structure

<?xml version="1.0" encoding="utf-8"?>
<testsuites>
  <testsuite name="vigil" tests="2" failures="2" errors="0" time="1.200">
    <properties>
      <property name="vigil.version" value="0.5.0" />
      <property name="vigil.files_scanned" value="42" />
      <property name="vigil.analyzers" value="dependency,auth" />
    </properties>
    <testcase name="DEP-001: requirements.txt:14" classname="vigil.dependency">
      <failure type="error" message="Package 'python-jwt-utils' does not exist in pypi.">
Rule: DEP-001
Severity: critical
Category: dependency
File: requirements.txt:14
Suggestion: Remove 'python-jwt-utils' and find the correct package name.
Snippet: python-jwt-utils==1.0.0
      </failure>
    </testcase>
    <testcase name="AUTH-005: src/main.py:8" classname="vigil.auth">
      <failure type="error" message="CORS configured with '*' allowing requests from any origin.">
Rule: AUTH-005
Severity: high
Category: auth
File: src/main.py:8
Suggestion: Restrict CORS to specific trusted origins.
      </failure>
    </testcase>
  </testsuite>
</testsuites>

Severity mapping

vigil severityJUnit failure type
CRITICALerror
HIGHerror
MEDIUMwarning
LOWwarning
INFOwarning

Typical usage

# Generate JUnit report
vigil scan src/ -f junit -o report.xml

In GitLab CI, the report can be published as a test artifact:

vigil:
  script:
    - vigil scan src/ -f junit -o report.xml
  artifacts:
    reports:
      junit: report.xml

In Jenkins, it can be used with the JUnit plugin:

stage('Security Scan') {
    steps {
        sh 'vigil scan src/ -f junit -o report.xml'
    }
    post {
        always {
            junit 'report.xml'
        }
    }
}

SARIF 2.1.0

Static Analysis Results Interchange Format. Industry-standard format for static analysis results. Compatible with GitHub Code Scanning, VS Code SARIF Viewer, and other platforms.

Structure

{
  "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
  "version": "2.1.0",
  "runs": [
    {
      "tool": {
        "driver": {
          "name": "vigil",
          "version": "0.5.0",
          "semanticVersion": "0.5.0",
          "informationUri": "https://github.com/org/vigil",
          "rules": [
            {
              "id": "DEP-001",
              "name": "HallucinatedDependency",
              "shortDescription": {
                "text": "Package declared as dependency does not exist in the public registry."
              },
              "defaultConfiguration": {
                "level": "error"
              },
              "helpUri": "https://github.com/org/vigil/docs/rules/DEP-001",
              "properties": {
                "cwe": "CWE-829",
                "owasp": "LLM03"
              }
            }
          ]
        }
      },
      "results": [
        {
          "ruleId": "DEP-001",
          "ruleIndex": 0,
          "level": "error",
          "message": {
            "text": "Package 'python-jwt-utils' does not exist in pypi."
          },
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "requirements.txt"
                },
                "region": {
                  "startLine": 14,
                  "snippet": {
                    "text": "python-jwt-utils==1.0.0"
                  }
                }
              }
            }
          ],
          "fixes": [
            {
              "description": {
                "text": "Remove 'python-jwt-utils' and find the correct package name."
              }
            }
          ]
        }
      ],
      "invocations": [
        {
          "executionSuccessful": true,
          "toolExecutionNotifications": []
        }
      ]
    }
  ]
}

Severity mapping

vigil severitySARIF level
CRITICALerror
HIGHerror
MEDIUMwarning
LOWnote
INFOnote

SARIF elements

  • tool.driver.rules: Only includes rules that generated findings (not all 26 rules).
  • tool.driver.semanticVersion: Semantic version of vigil.
  • defaultConfiguration: Default level of the rule (error, warning, note).
  • helpUri: URL to the rule documentation.
  • ruleIndex: Numeric index referencing the rule’s position in tool.driver.rules.
  • results: Each finding as an individual result with physical location.
  • region.snippet: Code fragment, included if the finding has a snippet.
  • fixes: If the finding has a suggestion, it is included as fixes[].description.
  • invocations: Execution status and analyzer error notifications.
  • properties.cwe: CWE reference if the rule has one.
  • properties.owasp: OWASP reference if the rule has one.

Usage with GitHub Code Scanning

# Generate SARIF
vigil scan src/ -f sarif -o vigil.sarif

In GitHub Actions:

- name: Run vigil
  run: vigil scan src/ -f sarif -o vigil.sarif
  continue-on-error: true

- name: Upload SARIF
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: vigil.sarif

Findings appear directly in the repository’s “Security” tab and as annotations on pull requests.


Format comparison

FeatureHumanJSONJUnitSARIF
Terminal readingYesNoNoNo
Programmatic processingNoYesPartialYes
ColorsYes (TTY)NoNoNo
GitHub Code ScanningNoNoNoYes
CI dashboardsNoNoYesYes
Fix suggestionsYesYesYesYes
CWE referencesNoNoNoYes
Rule definitionsNoNoNoYes

Combining formats

It is possible to generate multiple reports in a single execution using scripts:

# Generate JSON and SARIF in one pass
vigil scan src/ -f json -o report.json
vigil scan src/ -f sarif -o vigil.sarif
vigil scan src/ -f junit -o report.xml

Since vigil uses a cache for registry responses, successive executions are fast because they don’t repeat HTTP requests.