Loading...
Validates Kubernetes YAML manifests for syntax and best practices when modified
{
"hookConfig": {
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/kubernetes-manifest-validator.sh",
"matchers": [
"write",
"edit"
]
}
}
},
"scriptContent": "#!/usr/bin/env bash\n\n# Read the tool input from stdin\nINPUT=$(cat)\nTOOL_NAME=$(echo \"$INPUT\" | jq -r '.tool_name')\nFILE_PATH=$(echo \"$INPUT\" | jq -r '.tool_input.file_path // .tool_input.path // \"\"')\n\nif [ -z \"$FILE_PATH\" ]; then\n exit 0\nfi\n\n# Check if this is a YAML file that might be a Kubernetes manifest\nif [[ \"$FILE_PATH\" == *.yaml ]] || [[ \"$FILE_PATH\" == *.yml ]]; then\n # Check if it's a Kubernetes manifest by looking for apiVersion and kind\n if grep -q 'apiVersion:\\|kind:' \"$FILE_PATH\" 2>/dev/null; then\n echo \"βΈοΈ Kubernetes Manifest Validation for: $(basename \"$FILE_PATH\")\" >&2\n \n # Initialize validation counters\n ERRORS=0\n WARNINGS=0\n VALIDATIONS_PASSED=0\n KUBECTL_AVAILABLE=false\n \n # Function to report validation results\n report_validation() {\n local level=\"$1\"\n local message=\"$2\"\n \n case \"$level\" in\n \"ERROR\")\n echo \"β ERROR: $message\" >&2\n ERRORS=$((ERRORS + 1))\n ;;\n \"WARNING\")\n echo \"β οΈ WARNING: $message\" >&2\n WARNINGS=$((WARNINGS + 1))\n ;;\n \"PASS\")\n echo \"β
PASS: $message\" >&2\n VALIDATIONS_PASSED=$((VALIDATIONS_PASSED + 1))\n ;;\n \"INFO\")\n echo \"βΉοΈ INFO: $message\" >&2\n ;;\n esac\n }\n \n # Check if file exists and is readable\n if [ ! -f \"$FILE_PATH\" ]; then\n report_validation \"ERROR\" \"Manifest file not found: $FILE_PATH\"\n exit 1\n fi\n \n if [ ! -r \"$FILE_PATH\" ]; then\n report_validation \"ERROR\" \"Manifest file is not readable: $FILE_PATH\"\n exit 1\n fi\n \n # Get file information\n FILE_NAME=\"$(basename \"$FILE_PATH\")\"\n FILE_SIZE=$(wc -c < \"$FILE_PATH\" 2>/dev/null || echo \"0\")\n \n echo \"π Kubernetes manifest: $FILE_NAME ($(( FILE_SIZE / 1024 ))KB)\" >&2\n \n # 1. Basic YAML Syntax Validation\n echo \"π Checking YAML syntax...\" >&2\n \n # Use Python YAML parser for syntax validation\n if command -v python3 &> /dev/null; then\n if python3 -c \"import yaml; yaml.safe_load_all(open('$FILE_PATH'))\" 2>/dev/null; then\n report_validation \"PASS\" \"Valid YAML syntax\"\n else\n report_validation \"ERROR\" \"Invalid YAML syntax detected\"\n python3 -c \"import yaml; yaml.safe_load_all(open('$FILE_PATH'))\" 2>&1 | head -3 >&2\n exit 1\n fi\n else\n report_validation \"WARNING\" \"Python not available for YAML validation\"\n fi\n \n # 2. Kubernetes Manifest Structure Analysis\n echo \"π Analyzing Kubernetes manifest structure...\" >&2\n \n # Extract resource information\n API_VERSION=$(grep '^apiVersion:' \"$FILE_PATH\" | head -1 | cut -d':' -f2 | xargs 2>/dev/null || echo \"unknown\")\n KIND=$(grep '^kind:' \"$FILE_PATH\" | head -1 | cut -d':' -f2 | xargs 2>/dev/null || echo \"unknown\")\n RESOURCE_NAME=$(grep 'name:' \"$FILE_PATH\" | head -1 | cut -d':' -f2 | xargs 2>/dev/null || echo \"unnamed\")\n NAMESPACE=$(grep 'namespace:' \"$FILE_PATH\" | head -1 | cut -d':' -f2 | xargs 2>/dev/null || echo \"default\")\n \n echo \" π Resource: $KIND/$RESOURCE_NAME\" >&2\n echo \" π§ API Version: $API_VERSION\" >&2\n echo \" π Namespace: $NAMESPACE\" >&2\n \n # Check for multiple resources in single file\n RESOURCE_COUNT=$(grep -c '^apiVersion:' \"$FILE_PATH\" 2>/dev/null || echo \"1\")\n if [ \"$RESOURCE_COUNT\" -gt 1 ]; then\n echo \" π Multi-resource file: $RESOURCE_COUNT resources\" >&2\n fi\n \n # 3. kubectl Validation (if available)\n echo \"βΈοΈ Running kubectl validation...\" >&2\n \n if command -v kubectl &> /dev/null; then\n KUBECTL_AVAILABLE=true\n echo \" π§ kubectl found - running dry-run validation\" >&2\n \n # Check kubectl connection (but don't fail if no cluster)\n KUBECTL_OUTPUT_FILE=\"/tmp/kubectl_output_$$\"\n if kubectl apply --dry-run=client -f \"$FILE_PATH\" > \"$KUBECTL_OUTPUT_FILE\" 2>&1; then\n report_validation \"PASS\" \"kubectl dry-run validation successful\"\n \n # Show what would be created/updated\n grep -E 'created|configured|unchanged' \"$KUBECTL_OUTPUT_FILE\" 2>/dev/null | head -3 | while read line; do\n echo \" $line\" >&2\n done\n \n else\n # Check if it's a connection error or manifest error\n if grep -q 'connection refused\\|unable to connect' \"$KUBECTL_OUTPUT_FILE\" 2>/dev/null; then\n report_validation \"WARNING\" \"kubectl validation skipped - no cluster connection\"\n else\n report_validation \"ERROR\" \"kubectl dry-run validation failed\"\n echo \" π kubectl error details:\" >&2\n head -5 \"$KUBECTL_OUTPUT_FILE\" | while read line; do\n echo \" $line\" >&2\n done\n fi\n fi\n \n rm -f \"$KUBECTL_OUTPUT_FILE\"\n else\n report_validation \"WARNING\" \"kubectl not available - install for comprehensive validation\"\n fi\n \n # 4. Additional Validation Tools\n echo \"π Running additional validation tools...\" >&2\n \n # kubeval validation\n if command -v kubeval &> /dev/null; then\n echo \" π Running kubeval validation...\" >&2\n \n KUBEVAL_OUTPUT_FILE=\"/tmp/kubeval_output_$$\"\n if kubeval \"$FILE_PATH\" > \"$KUBEVAL_OUTPUT_FILE\" 2>&1; then\n report_validation \"PASS\" \"kubeval validation successful\"\n else\n report_validation \"WARNING\" \"kubeval found issues\"\n head -5 \"$KUBEVAL_OUTPUT_FILE\" | while read line; do\n echo \" $line\" >&2\n done\n fi\n rm -f \"$KUBEVAL_OUTPUT_FILE\"\n else\n echo \" π‘ kubeval not installed - consider installing for schema validation\" >&2\n fi\n \n # kube-score validation (best practices)\n if command -v kube-score &> /dev/null; then\n echo \" π Running kube-score best practices check...\" >&2\n \n KUBESCORE_OUTPUT_FILE=\"/tmp/kubescore_output_$$\"\n if kube-score score \"$FILE_PATH\" > \"$KUBESCORE_OUTPUT_FILE\" 2>&1; then\n # kube-score shows recommendations, not just pass/fail\n CRITICAL_COUNT=$(grep -c 'CRITICAL' \"$KUBESCORE_OUTPUT_FILE\" 2>/dev/null || echo \"0\")\n WARNING_COUNT=$(grep -c 'WARNING' \"$KUBESCORE_OUTPUT_FILE\" 2>/dev/null || echo \"0\")\n \n if [ \"$CRITICAL_COUNT\" -eq 0 ]; then\n report_validation \"PASS\" \"kube-score validation passed (no critical issues)\"\n else\n report_validation \"WARNING\" \"kube-score found $CRITICAL_COUNT critical issues\"\n fi\n \n if [ \"$WARNING_COUNT\" -gt 0 ]; then\n echo \" β οΈ kube-score warnings: $WARNING_COUNT\" >&2\n fi\n fi\n rm -f \"$KUBESCORE_OUTPUT_FILE\"\n else\n echo \" π‘ kube-score not installed - consider installing for best practices validation\" >&2\n fi\n \n # 5. Resource-Specific Validation\n echo \"π§ Performing resource-specific validation...\" >&2\n \n case \"$KIND\" in\n \"Deployment\")\n echo \" π Deployment-specific checks...\" >&2\n \n # Check for resource limits\n if grep -q 'resources:' \"$FILE_PATH\" 2>/dev/null; then\n if grep -q 'limits:\\|requests:' \"$FILE_PATH\" 2>/dev/null; then\n report_validation \"PASS\" \"Resource limits/requests defined\"\n else\n report_validation \"WARNING\" \"Resource limits/requests not fully specified\"\n fi\n else\n report_validation \"WARNING\" \"No resource limits defined - consider adding for production\"\n fi\n \n # Check for replicas\n REPLICAS=$(grep 'replicas:' \"$FILE_PATH\" | head -1 | cut -d':' -f2 | xargs 2>/dev/null || echo \"1\")\n if [ \"$REPLICAS\" -eq 1 ]; then\n report_validation \"WARNING\" \"Single replica deployment - consider multiple replicas for HA\"\n else\n echo \" π Replicas: $REPLICAS\" >&2\n fi\n \n # Check for readiness/liveness probes\n if grep -q 'livenessProbe:\\|readinessProbe:' \"$FILE_PATH\" 2>/dev/null; then\n report_validation \"PASS\" \"Health probes configured\"\n else\n report_validation \"WARNING\" \"No health probes defined - consider adding for reliability\"\n fi\n ;;\n \n \"Service\")\n echo \" π Service-specific checks...\" >&2\n \n # Check service type\n SERVICE_TYPE=$(grep 'type:' \"$FILE_PATH\" | head -1 | cut -d':' -f2 | xargs 2>/dev/null || echo \"ClusterIP\")\n echo \" π§ Service type: $SERVICE_TYPE\" >&2\n \n if [ \"$SERVICE_TYPE\" = \"LoadBalancer\" ]; then\n report_validation \"WARNING\" \"LoadBalancer service - ensure cloud provider support\"\n fi\n \n # Check for selector\n if grep -q 'selector:' \"$FILE_PATH\" 2>/dev/null; then\n report_validation \"PASS\" \"Service selector defined\"\n else\n report_validation \"ERROR\" \"Service missing selector - will not route traffic\"\n fi\n ;;\n \n \"ConfigMap\"|\"Secret\")\n echo \" π Configuration resource checks...\" >&2\n \n # Check for data section\n if grep -q 'data:' \"$FILE_PATH\" 2>/dev/null; then\n DATA_KEYS=$(grep -A 10 'data:' \"$FILE_PATH\" | grep -c '^ [^:]*:' || echo \"0\")\n echo \" π Data keys: $DATA_KEYS\" >&2\n report_validation \"PASS\" \"Configuration data present\"\n else\n report_validation \"WARNING\" \"No data section found in $KIND\"\n fi\n ;;\n \n \"Ingress\")\n echo \" π Ingress-specific checks...\" >&2\n \n # Check for rules\n if grep -q 'rules:' \"$FILE_PATH\" 2>/dev/null; then\n report_validation \"PASS\" \"Ingress rules defined\"\n else\n report_validation \"ERROR\" \"Ingress missing rules section\"\n fi\n \n # Check for TLS\n if grep -q 'tls:' \"$FILE_PATH\" 2>/dev/null; then\n report_validation \"PASS\" \"TLS configuration present\"\n else\n report_validation \"WARNING\" \"No TLS configuration - consider HTTPS\"\n fi\n ;;\n esac\n \n # 6. Security and Best Practices\n echo \"π Security and best practices check...\" >&2\n \n # Check for security context\n if grep -q 'securityContext:' \"$FILE_PATH\" 2>/dev/null; then\n report_validation \"PASS\" \"Security context defined\"\n \n # Check for non-root user\n if grep -q 'runAsNonRoot: true\\|runAsUser:' \"$FILE_PATH\" 2>/dev/null; then\n report_validation \"PASS\" \"Non-root security configuration\"\n else\n report_validation \"WARNING\" \"Consider running as non-root user\"\n fi\n else\n report_validation \"WARNING\" \"No security context defined - consider adding for security\"\n fi\n \n # Check for privileged containers\n if grep -q 'privileged: true' \"$FILE_PATH\" 2>/dev/null; then\n report_validation \"WARNING\" \"Privileged container detected - security risk\"\n fi\n \n # Check for host network/PID\n if grep -q 'hostNetwork: true\\|hostPID: true' \"$FILE_PATH\" 2>/dev/null; then\n report_validation \"WARNING\" \"Host network/PID access detected - security risk\"\n fi\n \n # Check for latest tag usage\n if grep -q 'image:.*:latest' \"$FILE_PATH\" 2>/dev/null; then\n report_validation \"WARNING\" \"Using 'latest' tag - consider specific version tags\"\n fi\n \n # 7. Generate Validation Summary\n echo \"\" >&2\n echo \"π Kubernetes Manifest Validation Summary:\" >&2\n echo \"==========================================\" >&2\n echo \" π File: $FILE_NAME\" >&2\n echo \" βΈοΈ Resource: $KIND/$RESOURCE_NAME\" >&2\n echo \" π§ API Version: $API_VERSION\" >&2\n echo \" π Namespace: $NAMESPACE\" >&2\n echo \" β
Validations passed: $VALIDATIONS_PASSED\" >&2\n echo \" β οΈ Warnings: $WARNINGS\" >&2\n echo \" β Errors: $ERRORS\" >&2\n \n if [ \"$ERRORS\" -eq 0 ]; then\n if [ \"$WARNINGS\" -eq 0 ]; then\n echo \" π Status: EXCELLENT - Manifest is valid and follows best practices\" >&2\n else\n echo \" β
Status: GOOD - Manifest is valid with minor recommendations\" >&2\n fi\n else\n echo \" β Status: ERRORS - Manifest has critical issues that must be fixed\" >&2\n fi\n \n echo \"\" >&2\n echo \"π‘ Kubernetes Best Practices:\" >&2\n echo \" β’ Use specific image tags instead of 'latest'\" >&2\n echo \" β’ Define resource limits and requests\" >&2\n echo \" β’ Configure health probes for applications\" >&2\n echo \" β’ Use security contexts and non-root users\" >&2\n echo \" β’ Implement RBAC for access control\" >&2\n echo \" β’ Use multiple replicas for high availability\" >&2\n \n # Exit with error if there are critical validation issues\n if [ \"$ERRORS\" -gt 0 ]; then\n echo \"β οΈ Kubernetes manifest validation completed with errors\" >&2\n exit 1\n fi\n \n else\n # YAML file but not a Kubernetes manifest\n exit 0\n fi\nelse\n # Not a YAML file\n exit 0\nfi\n\nexit 0"
}.claude/hooks/~/.claude/hooks/{
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/kubernetes-manifest-validator.sh",
"matchers": [
"write",
"edit"
]
}
}
}#!/usr/bin/env bash
# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# Check if this is a YAML file that might be a Kubernetes manifest
if [[ "$FILE_PATH" == *.yaml ]] || [[ "$FILE_PATH" == *.yml ]]; then
# Check if it's a Kubernetes manifest by looking for apiVersion and kind
if grep -q 'apiVersion:\|kind:' "$FILE_PATH" 2>/dev/null; then
echo "βΈοΈ Kubernetes Manifest Validation for: $(basename "$FILE_PATH")" >&2
# Initialize validation counters
ERRORS=0
WARNINGS=0
VALIDATIONS_PASSED=0
KUBECTL_AVAILABLE=false
# Function to report validation results
report_validation() {
local level="$1"
local message="$2"
case "$level" in
"ERROR")
echo "β ERROR: $message" >&2
ERRORS=$((ERRORS + 1))
;;
"WARNING")
echo "β οΈ WARNING: $message" >&2
WARNINGS=$((WARNINGS + 1))
;;
"PASS")
echo "β
PASS: $message" >&2
VALIDATIONS_PASSED=$((VALIDATIONS_PASSED + 1))
;;
"INFO")
echo "βΉοΈ INFO: $message" >&2
;;
esac
}
# Check if file exists and is readable
if [ ! -f "$FILE_PATH" ]; then
report_validation "ERROR" "Manifest file not found: $FILE_PATH"
exit 1
fi
if [ ! -r "$FILE_PATH" ]; then
report_validation "ERROR" "Manifest file is not readable: $FILE_PATH"
exit 1
fi
# Get file information
FILE_NAME="$(basename "$FILE_PATH")"
FILE_SIZE=$(wc -c < "$FILE_PATH" 2>/dev/null || echo "0")
echo "π Kubernetes manifest: $FILE_NAME ($(( FILE_SIZE / 1024 ))KB)" >&2
# 1. Basic YAML Syntax Validation
echo "π Checking YAML syntax..." >&2
# Use Python YAML parser for syntax validation
if command -v python3 &> /dev/null; then
if python3 -c "import yaml; yaml.safe_load_all(open('$FILE_PATH'))" 2>/dev/null; then
report_validation "PASS" "Valid YAML syntax"
else
report_validation "ERROR" "Invalid YAML syntax detected"
python3 -c "import yaml; yaml.safe_load_all(open('$FILE_PATH'))" 2>&1 | head -3 >&2
exit 1
fi
else
report_validation "WARNING" "Python not available for YAML validation"
fi
# 2. Kubernetes Manifest Structure Analysis
echo "π Analyzing Kubernetes manifest structure..." >&2
# Extract resource information
API_VERSION=$(grep '^apiVersion:' "$FILE_PATH" | head -1 | cut -d':' -f2 | xargs 2>/dev/null || echo "unknown")
KIND=$(grep '^kind:' "$FILE_PATH" | head -1 | cut -d':' -f2 | xargs 2>/dev/null || echo "unknown")
RESOURCE_NAME=$(grep 'name:' "$FILE_PATH" | head -1 | cut -d':' -f2 | xargs 2>/dev/null || echo "unnamed")
NAMESPACE=$(grep 'namespace:' "$FILE_PATH" | head -1 | cut -d':' -f2 | xargs 2>/dev/null || echo "default")
echo " π Resource: $KIND/$RESOURCE_NAME" >&2
echo " π§ API Version: $API_VERSION" >&2
echo " π Namespace: $NAMESPACE" >&2
# Check for multiple resources in single file
RESOURCE_COUNT=$(grep -c '^apiVersion:' "$FILE_PATH" 2>/dev/null || echo "1")
if [ "$RESOURCE_COUNT" -gt 1 ]; then
echo " π Multi-resource file: $RESOURCE_COUNT resources" >&2
fi
# 3. kubectl Validation (if available)
echo "βΈοΈ Running kubectl validation..." >&2
if command -v kubectl &> /dev/null; then
KUBECTL_AVAILABLE=true
echo " π§ kubectl found - running dry-run validation" >&2
# Check kubectl connection (but don't fail if no cluster)
KUBECTL_OUTPUT_FILE="/tmp/kubectl_output_$$"
if kubectl apply --dry-run=client -f "$FILE_PATH" > "$KUBECTL_OUTPUT_FILE" 2>&1; then
report_validation "PASS" "kubectl dry-run validation successful"
# Show what would be created/updated
grep -E 'created|configured|unchanged' "$KUBECTL_OUTPUT_FILE" 2>/dev/null | head -3 | while read line; do
echo " $line" >&2
done
else
# Check if it's a connection error or manifest error
if grep -q 'connection refused\|unable to connect' "$KUBECTL_OUTPUT_FILE" 2>/dev/null; then
report_validation "WARNING" "kubectl validation skipped - no cluster connection"
else
report_validation "ERROR" "kubectl dry-run validation failed"
echo " π kubectl error details:" >&2
head -5 "$KUBECTL_OUTPUT_FILE" | while read line; do
echo " $line" >&2
done
fi
fi
rm -f "$KUBECTL_OUTPUT_FILE"
else
report_validation "WARNING" "kubectl not available - install for comprehensive validation"
fi
# 4. Additional Validation Tools
echo "π Running additional validation tools..." >&2
# kubeval validation
if command -v kubeval &> /dev/null; then
echo " π Running kubeval validation..." >&2
KUBEVAL_OUTPUT_FILE="/tmp/kubeval_output_$$"
if kubeval "$FILE_PATH" > "$KUBEVAL_OUTPUT_FILE" 2>&1; then
report_validation "PASS" "kubeval validation successful"
else
report_validation "WARNING" "kubeval found issues"
head -5 "$KUBEVAL_OUTPUT_FILE" | while read line; do
echo " $line" >&2
done
fi
rm -f "$KUBEVAL_OUTPUT_FILE"
else
echo " π‘ kubeval not installed - consider installing for schema validation" >&2
fi
# kube-score validation (best practices)
if command -v kube-score &> /dev/null; then
echo " π Running kube-score best practices check..." >&2
KUBESCORE_OUTPUT_FILE="/tmp/kubescore_output_$$"
if kube-score score "$FILE_PATH" > "$KUBESCORE_OUTPUT_FILE" 2>&1; then
# kube-score shows recommendations, not just pass/fail
CRITICAL_COUNT=$(grep -c 'CRITICAL' "$KUBESCORE_OUTPUT_FILE" 2>/dev/null || echo "0")
WARNING_COUNT=$(grep -c 'WARNING' "$KUBESCORE_OUTPUT_FILE" 2>/dev/null || echo "0")
if [ "$CRITICAL_COUNT" -eq 0 ]; then
report_validation "PASS" "kube-score validation passed (no critical issues)"
else
report_validation "WARNING" "kube-score found $CRITICAL_COUNT critical issues"
fi
if [ "$WARNING_COUNT" -gt 0 ]; then
echo " β οΈ kube-score warnings: $WARNING_COUNT" >&2
fi
fi
rm -f "$KUBESCORE_OUTPUT_FILE"
else
echo " π‘ kube-score not installed - consider installing for best practices validation" >&2
fi
# 5. Resource-Specific Validation
echo "π§ Performing resource-specific validation..." >&2
case "$KIND" in
"Deployment")
echo " π Deployment-specific checks..." >&2
# Check for resource limits
if grep -q 'resources:' "$FILE_PATH" 2>/dev/null; then
if grep -q 'limits:\|requests:' "$FILE_PATH" 2>/dev/null; then
report_validation "PASS" "Resource limits/requests defined"
else
report_validation "WARNING" "Resource limits/requests not fully specified"
fi
else
report_validation "WARNING" "No resource limits defined - consider adding for production"
fi
# Check for replicas
REPLICAS=$(grep 'replicas:' "$FILE_PATH" | head -1 | cut -d':' -f2 | xargs 2>/dev/null || echo "1")
if [ "$REPLICAS" -eq 1 ]; then
report_validation "WARNING" "Single replica deployment - consider multiple replicas for HA"
else
echo " π Replicas: $REPLICAS" >&2
fi
# Check for readiness/liveness probes
if grep -q 'livenessProbe:\|readinessProbe:' "$FILE_PATH" 2>/dev/null; then
report_validation "PASS" "Health probes configured"
else
report_validation "WARNING" "No health probes defined - consider adding for reliability"
fi
;;
"Service")
echo " π Service-specific checks..." >&2
# Check service type
SERVICE_TYPE=$(grep 'type:' "$FILE_PATH" | head -1 | cut -d':' -f2 | xargs 2>/dev/null || echo "ClusterIP")
echo " π§ Service type: $SERVICE_TYPE" >&2
if [ "$SERVICE_TYPE" = "LoadBalancer" ]; then
report_validation "WARNING" "LoadBalancer service - ensure cloud provider support"
fi
# Check for selector
if grep -q 'selector:' "$FILE_PATH" 2>/dev/null; then
report_validation "PASS" "Service selector defined"
else
report_validation "ERROR" "Service missing selector - will not route traffic"
fi
;;
"ConfigMap"|"Secret")
echo " π Configuration resource checks..." >&2
# Check for data section
if grep -q 'data:' "$FILE_PATH" 2>/dev/null; then
DATA_KEYS=$(grep -A 10 'data:' "$FILE_PATH" | grep -c '^ [^:]*:' || echo "0")
echo " π Data keys: $DATA_KEYS" >&2
report_validation "PASS" "Configuration data present"
else
report_validation "WARNING" "No data section found in $KIND"
fi
;;
"Ingress")
echo " π Ingress-specific checks..." >&2
# Check for rules
if grep -q 'rules:' "$FILE_PATH" 2>/dev/null; then
report_validation "PASS" "Ingress rules defined"
else
report_validation "ERROR" "Ingress missing rules section"
fi
# Check for TLS
if grep -q 'tls:' "$FILE_PATH" 2>/dev/null; then
report_validation "PASS" "TLS configuration present"
else
report_validation "WARNING" "No TLS configuration - consider HTTPS"
fi
;;
esac
# 6. Security and Best Practices
echo "π Security and best practices check..." >&2
# Check for security context
if grep -q 'securityContext:' "$FILE_PATH" 2>/dev/null; then
report_validation "PASS" "Security context defined"
# Check for non-root user
if grep -q 'runAsNonRoot: true\|runAsUser:' "$FILE_PATH" 2>/dev/null; then
report_validation "PASS" "Non-root security configuration"
else
report_validation "WARNING" "Consider running as non-root user"
fi
else
report_validation "WARNING" "No security context defined - consider adding for security"
fi
# Check for privileged containers
if grep -q 'privileged: true' "$FILE_PATH" 2>/dev/null; then
report_validation "WARNING" "Privileged container detected - security risk"
fi
# Check for host network/PID
if grep -q 'hostNetwork: true\|hostPID: true' "$FILE_PATH" 2>/dev/null; then
report_validation "WARNING" "Host network/PID access detected - security risk"
fi
# Check for latest tag usage
if grep -q 'image:.*:latest' "$FILE_PATH" 2>/dev/null; then
report_validation "WARNING" "Using 'latest' tag - consider specific version tags"
fi
# 7. Generate Validation Summary
echo "" >&2
echo "π Kubernetes Manifest Validation Summary:" >&2
echo "==========================================" >&2
echo " π File: $FILE_NAME" >&2
echo " βΈοΈ Resource: $KIND/$RESOURCE_NAME" >&2
echo " π§ API Version: $API_VERSION" >&2
echo " π Namespace: $NAMESPACE" >&2
echo " β
Validations passed: $VALIDATIONS_PASSED" >&2
echo " β οΈ Warnings: $WARNINGS" >&2
echo " β Errors: $ERRORS" >&2
if [ "$ERRORS" -eq 0 ]; then
if [ "$WARNINGS" -eq 0 ]; then
echo " π Status: EXCELLENT - Manifest is valid and follows best practices" >&2
else
echo " β
Status: GOOD - Manifest is valid with minor recommendations" >&2
fi
else
echo " β Status: ERRORS - Manifest has critical issues that must be fixed" >&2
fi
echo "" >&2
echo "π‘ Kubernetes Best Practices:" >&2
echo " β’ Use specific image tags instead of 'latest'" >&2
echo " β’ Define resource limits and requests" >&2
echo " β’ Configure health probes for applications" >&2
echo " β’ Use security contexts and non-root users" >&2
echo " β’ Implement RBAC for access control" >&2
echo " β’ Use multiple replicas for high availability" >&2
# Exit with error if there are critical validation issues
if [ "$ERRORS" -gt 0 ]; then
echo "β οΈ Kubernetes manifest validation completed with errors" >&2
exit 1
fi
else
# YAML file but not a Kubernetes manifest
exit 0
fi
else
# Not a YAML file
exit 0
fi
exit 0kubectl dry-run fails with 'no configuration found' error
Check kubectl context: kubectl config current-context. Set context if missing: kubectl config use-context <context-name>. For validation without cluster, use --dry-run=client instead of --dry-run=server.
Validation detects Kubernetes manifest in non-k8s YAML files
Strengthen detection logic: grep -q '^apiVersion:.*v1' && grep -q '^kind: (Pod|Deployment|Service)'. Skip YAML files in non-k8s directories: [[ "$FILE_PATH" =~ /k8s/|/manifests/|/deploy/ ]] || exit 0.
Multi-document YAML causes validation to check only first resource
Use kubectl apply --dry-run for all documents. Split YAML: csplit -z "$FILE_PATH" '/^---$/' '{*}' && for f in xx*; do kubectl apply --dry-run=client -f $f; done. Handle --- document separators properly.
Security context warnings trigger on valid init containers
Check container type before warning: grep -A5 'initContainers:' to identify init containers. Init containers may legitimately need privileged access. Add context-aware checks for runAsNonRoot based on container type.
Hook exits with error preventing further operations after validation
Change exit strategy: collect validation errors but exit 0 for warnings. Use: [ "$ERRORS" -gt 0 ] && echo 'Validation errors' >&2 || exit 0. Only fail on critical errors, warn on best practices.
Loading reviews...
Join our community of Claude power users. No spam, unsubscribe anytime.
Automated accessibility testing and compliance checking for web applications following WCAG guidelines
Automatically generates or updates API documentation when endpoint files are modified
Automatically formats code files after Claude writes or edits them using Prettier, Black, or other formatters