CtrlK
BlogDocsLog inGet started
Tessl Logo

pantheon-ai/jenkinsfile-validator

Comprehensive toolkit for validating, linting, testing, and automating Jenkinsfile pipelines (both Declarative and Scripted). Use this skill when working with Jenkins pipeline files, validating pipeline syntax, checking best practices, debugging pipeline issues, or working with custom plugins.

Overall
score

93%

Does it follow best practices?

Validation for skill structure

Overview
Skills
Evals
Files

validate_jenkinsfile.shscripts/

#!/bin/bash

# Jenkinsfile Validator - Main Orchestrator Script
# Runs all validators in sequence with unified output
#
# Usage: validate_jenkinsfile.sh [OPTIONS] <jenkinsfile>
#
# Options:
#   --syntax-only       Run only syntax validation
#   --security-only     Run only security checks
#   --best-practices    Run only best practices check
#   --no-security       Skip security checks
#   --no-best-practices Skip best practices check
#   --strict            Fail on warnings
#   -h, --help          Show this help message
#
# Exit codes:
#   0 - Validation passed
#   1 - Validation failed
#   2 - Usage error

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Colors for output
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NC='\033[0m' # No Color

# Symbols
PASS_SYMBOL="✓"
FAIL_SYMBOL="✗"
WARN_SYMBOL="⚠"
SKIP_SYMBOL="○"

# Default options
RUN_SYNTAX=true
RUN_SECURITY=true
RUN_BEST_PRACTICES=true
STRICT_MODE=false

# Counters
TOTAL_ERRORS=0
TOTAL_WARNINGS=0
TOTAL_INFO=0

usage() {
    cat << EOF
Usage: $(basename "$0") [OPTIONS] <jenkinsfile>

Validates Jenkins pipeline files (Declarative and Scripted).

Options:
  --syntax-only       Run only syntax validation
  --security-only     Run only security checks
  --best-practices    Run only best practices check
  --no-security       Skip security checks
  --no-best-practices Skip best practices check
  --strict            Fail on warnings (treat warnings as errors)
  -h, --help          Show this help message

Examples:
  $(basename "$0") Jenkinsfile                    # Full validation
  $(basename "$0") --syntax-only Jenkinsfile      # Syntax only
  $(basename "$0") --strict Jenkinsfile           # Fail on warnings
  $(basename "$0") --no-security Jenkinsfile      # Skip security scan

Exit codes:
  0 - Validation passed
  1 - Validation failed (errors found, or warnings in strict mode)
  2 - Usage error
EOF
    exit 2
}

print_header() {
    echo ""
    echo -e "${BLUE}${BOLD}════════════════════════════════════════════════════════════════${NC}"
    echo -e "${BLUE}${BOLD}  Jenkinsfile Validator v1.2.1${NC}"
    echo -e "${BLUE}${BOLD}════════════════════════════════════════════════════════════════${NC}"
    echo ""
}

print_section() {
    local title=$1
    echo ""
    echo -e "${BLUE}┌──────────────────────────────────────────────────────────────┐${NC}"
    echo -e "${BLUE}│ ${BOLD}$title${NC}"
    echo -e "${BLUE}└──────────────────────────────────────────────────────────────┘${NC}"
    echo ""
}

# Detect pipeline type (Declarative or Scripted)
detect_pipeline_type() {
    local file=$1

    # Remove comments and check for pipeline block
    local first_meaningful
    first_meaningful=$(grep -v '^\s*//' "$file" | grep -v '^\s*$' | grep -v '^\s*\*' | grep -v '^\s*/\*' | head -20)

    if echo "$first_meaningful" | grep -q '^\s*pipeline\s*{'; then
        echo "declarative"
    elif echo "$first_meaningful" | grep -q '^\s*node\s*[({]'; then
        echo "scripted"
    elif grep -q 'pipeline\s*{' "$file"; then
        echo "declarative"
    elif grep -q 'node\s*[({]' "$file"; then
        echo "scripted"
    else
        echo "unknown"
    fi
}

# Run syntax validation based on pipeline type
run_syntax_validation() {
    local file=$1
    local type=$2
    local errors=0
    local warnings=0

    print_section "1. Syntax Validation"

    if [ "$type" == "declarative" ]; then
        echo -e "Pipeline type: ${GREEN}Declarative${NC}"
        echo ""

        if [ -f "$SCRIPT_DIR/validate_declarative.sh" ]; then
            # Capture output and exit code
            local output
            output=$("$SCRIPT_DIR/validate_declarative.sh" "$file" 2>&1) || true
            echo "$output"

            # Count errors and warnings from output (strip ANSI codes first for accurate counting)
            local clean_output
            clean_output=$(echo "$output" | sed 's/\x1b\[[0-9;]*m//g')
            errors=$(echo "$clean_output" | grep -c "^ERROR\|^ERROR \[" || true)
            warnings=$(echo "$clean_output" | grep -c "^WARNING\|^WARNING \[" || true)
        else
            echo -e "${RED}Error: validate_declarative.sh not found${NC}"
            errors=1
        fi
    elif [ "$type" == "scripted" ]; then
        echo -e "Pipeline type: ${GREEN}Scripted${NC}"
        echo ""

        if [ -f "$SCRIPT_DIR/validate_scripted.sh" ]; then
            local output
            output=$("$SCRIPT_DIR/validate_scripted.sh" "$file" 2>&1) || true
            echo "$output"

            # Count errors and warnings from output (strip ANSI codes first for accurate counting)
            local clean_output
            clean_output=$(echo "$output" | sed 's/\x1b\[[0-9;]*m//g')
            errors=$(echo "$clean_output" | grep -c "^ERROR\|^ERROR \[" || true)
            warnings=$(echo "$clean_output" | grep -c "^WARNING\|^WARNING \[" || true)
        else
            echo -e "${RED}Error: validate_scripted.sh not found${NC}"
            errors=1
        fi
    else
        echo -e "${YELLOW}Warning: Could not determine pipeline type${NC}"
        echo "Attempting both validators..."
        echo ""

        # Try declarative first
        if [ -f "$SCRIPT_DIR/validate_declarative.sh" ]; then
            echo -e "${BLUE}Trying Declarative validation:${NC}"
            local output
            output=$("$SCRIPT_DIR/validate_declarative.sh" "$file" 2>&1) || true
            echo "$output"

            # Count errors and warnings from output (strip ANSI codes first for accurate counting)
            local clean_output
            clean_output=$(echo "$output" | sed 's/\x1b\[[0-9;]*m//g')
            errors=$(echo "$clean_output" | grep -c "^ERROR\|^ERROR \[" || true)
            warnings=$(echo "$clean_output" | grep -c "^WARNING\|^WARNING \[" || true)
        fi
    fi

    TOTAL_ERRORS=$((TOTAL_ERRORS + errors))
    TOTAL_WARNINGS=$((TOTAL_WARNINGS + warnings))

    if [ "$errors" -eq 0 ]; then
        echo ""
        echo -e "${GREEN}${PASS_SYMBOL} Syntax validation passed${NC}"
        return 0
    else
        echo ""
        echo -e "${RED}${FAIL_SYMBOL} Syntax validation failed with $errors error(s)${NC}"
        return 1
    fi
}

# Run security scan
run_security_scan() {
    local file=$1
    local errors=0
    local warnings=0
    local info=0

    print_section "2. Security Scan"

    if [ -f "$SCRIPT_DIR/common_validation.sh" ]; then
        # Run credential check via script (not sourced, to get proper output)
        echo -e "${BLUE}Scanning for hardcoded credentials...${NC}"
        echo ""

        local output
        output=$(bash "$SCRIPT_DIR/common_validation.sh" check_credentials "$file" 2>&1) || true
        echo "$output"

        # Count issues - look for ERROR in the output (may have ANSI codes)
        errors=$(echo "$output" | grep -c "ERROR \[" || true)
        warnings=$(echo "$output" | grep -c "WARNING \[" || true)
        info=$(echo "$output" | grep -c "INFO \[" || true)
    else
        echo -e "${YELLOW}Warning: common_validation.sh not found, skipping security scan${NC}"
    fi

    TOTAL_ERRORS=$((TOTAL_ERRORS + errors))
    TOTAL_WARNINGS=$((TOTAL_WARNINGS + warnings))
    TOTAL_INFO=$((TOTAL_INFO + info))

    if [ "$errors" -eq 0 ] && [ "$warnings" -eq 0 ]; then
        echo ""
        echo -e "${GREEN}${PASS_SYMBOL} Security scan passed - no credentials detected${NC}"
        return 0
    elif [ "$errors" -eq 0 ]; then
        echo ""
        echo -e "${YELLOW}${WARN_SYMBOL} Security scan completed with $warnings warning(s)${NC}"
        return 0
    else
        echo ""
        echo -e "${RED}${FAIL_SYMBOL} Security scan failed with $errors error(s)${NC}"
        return 1
    fi
}

# Run best practices check
run_best_practices() {
    local file=$1
    local errors=0
    local warnings=0

    print_section "3. Best Practices Check"

    if [ -f "$SCRIPT_DIR/best_practices.sh" ]; then
        local output
        output=$("$SCRIPT_DIR/best_practices.sh" "$file" 2>&1) || true
        echo "$output"

        # Count from output
        errors=$(echo "$output" | grep -c "^ERROR\|CRITICAL ISSUES" || true)
        warnings=$(echo "$output" | grep -c "^WARNING\|IMPROVEMENTS RECOMMENDED" || true)
    else
        echo -e "${YELLOW}Warning: best_practices.sh not found, skipping best practices check${NC}"
    fi

    # Don't add to totals - best practices has its own scoring

    if [ "$errors" -eq 0 ]; then
        return 0
    else
        return 1
    fi
}

# Print final summary
print_summary() {
    local file=$1
    local syntax_result=$2
    local security_result=$3
    local practices_result=$4

    echo ""
    echo -e "${BLUE}${BOLD}════════════════════════════════════════════════════════════════${NC}"
    echo -e "${BLUE}${BOLD}  Validation Summary${NC}"
    echo -e "${BLUE}${BOLD}════════════════════════════════════════════════════════════════${NC}"
    echo ""
    echo -e "File: ${BOLD}$file${NC}"
    echo ""

    # Syntax result
    if [ "$RUN_SYNTAX" == true ]; then
        if [ "$syntax_result" == "0" ]; then
            echo -e "  ${GREEN}${PASS_SYMBOL}${NC} Syntax Validation    : ${GREEN}PASSED${NC}"
        else
            echo -e "  ${RED}${FAIL_SYMBOL}${NC} Syntax Validation    : ${RED}FAILED${NC}"
        fi
    else
        echo -e "  ${BLUE}${SKIP_SYMBOL}${NC} Syntax Validation    : ${BLUE}SKIPPED${NC}"
    fi

    # Security result
    if [ "$RUN_SECURITY" == true ]; then
        if [ "$security_result" == "0" ]; then
            echo -e "  ${GREEN}${PASS_SYMBOL}${NC} Security Scan        : ${GREEN}PASSED${NC}"
        else
            echo -e "  ${RED}${FAIL_SYMBOL}${NC} Security Scan        : ${RED}FAILED${NC}"
        fi
    else
        echo -e "  ${BLUE}${SKIP_SYMBOL}${NC} Security Scan        : ${BLUE}SKIPPED${NC}"
    fi

    # Best practices result
    if [ "$RUN_BEST_PRACTICES" == true ]; then
        if [ "$practices_result" == "0" ]; then
            echo -e "  ${GREEN}${PASS_SYMBOL}${NC} Best Practices       : ${GREEN}PASSED${NC}"
        else
            echo -e "  ${YELLOW}${WARN_SYMBOL}${NC} Best Practices       : ${YELLOW}REVIEW NEEDED${NC}"
        fi
    else
        echo -e "  ${BLUE}${SKIP_SYMBOL}${NC} Best Practices       : ${BLUE}SKIPPED${NC}"
    fi

    echo ""
    echo -e "${BLUE}────────────────────────────────────────────────────────────────${NC}"

    # Overall result
    local overall_pass=true

    if [ "$RUN_SYNTAX" == true ] && [ "$syntax_result" != "0" ]; then
        overall_pass=false
    fi

    if [ "$RUN_SECURITY" == true ] && [ "$security_result" != "0" ]; then
        overall_pass=false
    fi

    # In strict mode, warnings also cause failure
    if [ "$STRICT_MODE" == true ] && [ "$TOTAL_WARNINGS" -gt 0 ]; then
        overall_pass=false
    fi

    echo ""
    if [ "$overall_pass" == true ]; then
        echo -e "  ${GREEN}${BOLD}${PASS_SYMBOL} VALIDATION PASSED${NC}"
        if [ "$TOTAL_WARNINGS" -gt 0 ]; then
            echo -e "    (with $TOTAL_WARNINGS warning(s) - review recommended)"
        fi
        echo ""
        return 0
    else
        echo -e "  ${RED}${BOLD}${FAIL_SYMBOL} VALIDATION FAILED${NC}"
        if [ "$STRICT_MODE" == true ] && [ "$TOTAL_WARNINGS" -gt 0 ]; then
            echo -e "    (strict mode: $TOTAL_WARNINGS warning(s) treated as errors)"
        fi
        echo ""
        return 1
    fi
}

# Parse command line arguments
parse_args() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            --syntax-only)
                RUN_SECURITY=false
                RUN_BEST_PRACTICES=false
                shift
                ;;
            --security-only)
                RUN_SYNTAX=false
                RUN_BEST_PRACTICES=false
                shift
                ;;
            --best-practices)
                RUN_SYNTAX=false
                RUN_SECURITY=false
                shift
                ;;
            --no-security)
                RUN_SECURITY=false
                shift
                ;;
            --no-best-practices)
                RUN_BEST_PRACTICES=false
                shift
                ;;
            --strict)
                STRICT_MODE=true
                shift
                ;;
            -h|--help)
                usage
                ;;
            -*)
                echo -e "${RED}Error: Unknown option: $1${NC}"
                usage
                ;;
            *)
                JENKINSFILE="$1"
                shift
                ;;
        esac
    done
}

# Main execution
main() {
    parse_args "$@"

    # Validate input
    if [ -z "${JENKINSFILE:-}" ]; then
        echo -e "${RED}Error: No Jenkinsfile specified${NC}"
        usage
    fi

    if [ ! -f "$JENKINSFILE" ]; then
        echo -e "${RED}Error: File '$JENKINSFILE' not found${NC}"
        exit 2
    fi

    print_header
    echo -e "Validating: ${BOLD}$JENKINSFILE${NC}"

    # Detect pipeline type
    local pipeline_type
    pipeline_type=$(detect_pipeline_type "$JENKINSFILE")

    # Track results
    local syntax_result=0
    local security_result=0
    local practices_result=0

    # Run validations based on options
    if [ "$RUN_SYNTAX" == true ]; then
        run_syntax_validation "$JENKINSFILE" "$pipeline_type" || syntax_result=$?
    fi

    if [ "$RUN_SECURITY" == true ]; then
        run_security_scan "$JENKINSFILE" || security_result=$?
    fi

    if [ "$RUN_BEST_PRACTICES" == true ]; then
        run_best_practices "$JENKINSFILE" || practices_result=$?
    fi

    # Print summary and exit with appropriate code
    print_summary "$JENKINSFILE" "$syntax_result" "$security_result" "$practices_result"
}

main "$@"

Install with Tessl CLI

npx tessl i pantheon-ai/jenkinsfile-validator@0.1.0

SKILL.md

tile.json