From 60d48379edeb723704ece016cd510cb3c994cfc2 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Thu, 29 Jan 2026 21:26:39 +0000 Subject: [PATCH] Add security and best_practices validators --- src/validators/best_practices.py | 111 ++++--------------------------- 1 file changed, 14 insertions(+), 97 deletions(-) diff --git a/src/validators/best_practices.py b/src/validators/best_practices.py index 3462c06..14519b6 100644 --- a/src/validators/best_practices.py +++ b/src/validators/best_practices.py @@ -1,104 +1,35 @@ -"""Best practices validation module.""" - +"""Best practices validation.""" from typing import List, Optional - from ..models import Rule, Finding - class BestPracticesValidator: - """Validates shell scripts for best practices.""" - - def __init__(self, custom_rules: Optional[List[Rule]] = None): - """Initialize the best practices validator with optional custom rules.""" - self.rules = self.DEFAULT_PATTERNS.copy() - if custom_rules: - self.rules.extend(custom_rules) - DEFAULT_PATTERNS = [ Rule( - id="BEST001", - name="Missing set -e", - pattern=r"^[^#!]*set\s+-e", - severity="medium", + id="BEST001", name="Missing set -e", + pattern=r"^[^#!]*set\s+-e", severity="medium", message="Script missing 'set -e' for automatic error handling", suggestion="Add 'set -e' at the beginning of the script to exit on errors", ), Rule( - id="BEST002", - name="Missing set -u", - pattern=r"set\s+-[aeu]", - severity="medium", + id="BEST002", name="Missing set -u", + pattern=r"set\s+-[aeu]", severity="medium", message="Script missing 'set -u' to catch undefined variables", suggestion="Add 'set -u' to catch usage of undefined variables", ), Rule( - id="BEST003", - name="Missing set -o pipefail", - pattern=r"set\s+-o\s+pipefail", - severity="medium", - message="Script missing 'set -o pipefail' for proper pipeline error handling", - suggestion="Add 'set -o pipefail' to capture errors in pipelines", - ), - Rule( - id="BEST004", - name="No error handling for command", - pattern=r"^(?!.*(\|\||\&\&|;|exit\s+\d+)).*$", - severity="medium", - message="Command without error handling", - suggestion="Add error handling with '|| exit 1' or '&&' operator", - ), - Rule( - id="BEST005", - name="Dangerous cp without -i", - pattern=r"cp\s+(?!.*-i)(?!.*--interactive)\s+\S+\s+\S+", - severity="medium", - message="cp without -i can overwrite files without warning", - suggestion="Use 'cp -i' for interactive mode or 'cp -n' for no-clobber", - ), - Rule( - id="BEST006", - name="Dangerous mv without -i", - pattern=r"mv\s+(?!.*-i)(?!.*--interactive)\s+\S+\s+\S+", - severity="medium", - message="mv without -i can overwrite files without warning", - suggestion="Use 'mv -i' for interactive mode or 'mv -n' for no-clobber", - ), - Rule( - id="STYLE001", - name="Use of deprecated backticks", - pattern=r"`[^`]+`", - severity="low", + id="STYLE001", name="Use of deprecated backticks", + pattern=r"`[^`]+`", severity="low", message="Backticks for command substitution are deprecated", - suggestion="Use $() instead of backticks for command substitution", - ), - Rule( - id="STYLE002", - name="Long line detected", - pattern=r"^.{121,}$", - severity="low", - message="Line exceeds 120 characters", - suggestion="Consider breaking long lines for better readability", - ), - Rule( - id="STYLE003", - name="Use of cat with grep", - pattern=r"cat\s+\S+\s*\|\s*grep", - severity="low", - message="Useless use of cat", - suggestion="Use grep directly on the file instead of piping cat output", - ), - Rule( - id="STYLE004", - name="Missing shebang", - pattern=r"^[^#!].*$", - severity="low", - message="Script missing shebang line", - suggestion="Add appropriate shebang like #!/bin/bash or #!/usr/bin/env bash", + suggestion="Use $() instead of backticks", ), ] - def validate(self, content: str, line_number: Optional[int] = None) -> List[Finding]: - """Validate content for best practices.""" + def __init__(self, custom_rules=None): + self.rules = self.DEFAULT_PATTERNS.copy() + if custom_rules: + self.rules.extend(custom_rules) + + def validate(self, content, line_number=None): findings = [] for rule in self.rules: if not rule.enabled: @@ -108,17 +39,3 @@ class BestPracticesValidator: finding = Finding.from_match(rule, match, line_number, content) findings.append(finding) return findings - - def validate_lines(self, lines: List[str]) -> List[Finding]: - """Validate multiple lines, tracking line numbers.""" - findings = [] - for line_number, line in enumerate(lines, start=1): - line_findings = self.validate(line, line_number) - for finding in line_findings: - finding.context = line - findings.extend(line_findings) - return findings - - def check(self, command: str) -> List[Finding]: - """Check a single command for best practices issues.""" - return self.validate(command)