Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Eljakani/ward/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Ward uses standard Unix exit codes to indicate scan results. This is essential for CI/CD pipeline integration where the exit code determines whether a build passes or fails.

Exit Code Reference

0
Success
The scan completed successfully with no errors.This exit code is returned when:
  • No --fail-on threshold is specified (regardless of findings)
  • A threshold is specified but no findings meet or exceed it
  • The scan found no security issues at all
$ ward scan . --output json
# Scan completes, 5 Low findings discovered
$ echo $?
0
1
Failure
The scan failed or findings exceeded the severity threshold.This exit code is returned when:
  • Findings at or above the --fail-on threshold were discovered
  • The scan encountered an error (missing config, invalid path, etc.)
$ ward scan . --output json --fail-on high
# Scan finds 2 Critical and 3 High findings
findings exceed --fail-on high threshold: 2 critical, 3 high
$ echo $?
1

Fail-On Threshold Behavior

The --fail-on flag sets a severity threshold that triggers exit code 1 when met or exceeded.

Severity Hierarchy

Severities are ordered from lowest to highest:
  1. Info (lowest)
  2. Low
  3. Medium
  4. High
  5. Critical (highest)

Threshold Is Inclusive

When you set a threshold, Ward exits with code 1 if any finding at that severity level or higher is discovered.
ward scan . --fail-on info
# Exits 1 if ANY findings exist (Info, Low, Medium, High, or Critical)

Implementation Details

Ward’s exit code logic is implemented in the checkFailOn function: Source: cmd/scan.go:177
func checkFailOn(report *models.ScanReport) error {
    if failOn == "" || report == nil {
        return nil
    }

    threshold := models.ParseSeverity(failOn)

    for _, f := range report.Findings {
        if f.Severity >= threshold {
            counts := report.CountBySeverity()
            var parts []string
            for _, sev := range []models.Severity{
                models.SeverityCritical, 
                models.SeverityHigh, 
                models.SeverityMedium, 
                models.SeverityLow, 
                models.SeverityInfo,
            } {
                if sev >= threshold {
                    if c := counts[sev]; c > 0 {
                        parts = append(parts, 
                            fmt.Sprintf("%d %s", c, sev))
                    }
                }
            }
            return fmt.Errorf(
                "findings exceed --fail-on %s threshold: %s", 
                failOn, 
                strings.Join(parts, ", "))
        }
    }

    return nil
}

CI/CD Examples

GitHub Actions

- name: Run Ward Security Scan
  run: |
    ward scan . \
      --output json,sarif \
      --fail-on high
  # Job fails if High or Critical findings exist

- name: Upload SARIF (runs even if previous step fails)
  if: always()
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: ward-report.sarif

GitLab CI

ward-scan:
  script:
    - ward scan . --output json --fail-on high
  # Pipeline fails if exit code is 1
  artifacts:
    paths:
      - ward-report.json
    when: always  # Save report even on failure

Conditional Failure

You can use shell logic to customize exit behavior:
# Allow the scan to fail but continue the pipeline
ward scan . --output json --fail-on high || true

# Only fail on Critical findings, warn on High
ward scan . --output json --fail-on critical
if [ $? -eq 1 ]; then
  echo "CRITICAL findings detected - failing build"
  exit 1
fi

ward scan . --output json --fail-on high
if [ $? -eq 1 ]; then
  echo "WARNING: High findings detected but not blocking"
fi

Error Messages

Findings Exceed Threshold

findings exceed --fail-on high threshold: 2 critical, 3 high
This message shows:
  • The threshold that was set (high)
  • Count of findings at each severity level that met or exceeded the threshold

Configuration Errors

If Ward encounters configuration issues, it exits with code 1 and displays an error:
Error: loading config: failed to read ~/.ward/config.yaml: no such file or directory
Run ward init to create the default configuration if you see config-related errors.

Baseline Errors

Error: loading baseline: failed to read baseline.json: no such file or directory
Baseline file must exist when specified with --baseline.

Best Practices

Start Permissive

Begin with --fail-on high in CI to avoid blocking on minor issues while you remediate existing findings.

Use Baselines

Generate a baseline to suppress known findings, then use --fail-on to prevent new issues.

Gradual Strictness

Over time, lower the threshold from highmediumlow as you improve security posture.

Always Save Reports

Use if: always() or when: always to save reports even when scans fail, for debugging.

Build docs developers (and LLMs) love