Source code for ralph.guidelines.go

"""Go-specific review guidelines.

Ported from the canonical Rust implementation in
``ralph-workflow/src/guidelines/go.rs`` and adapted for the Python port.
Includes core Go checks plus framework-specific additions for Gin, Chi,
Fiber, and Echo projects.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from collections.abc import Iterable


[docs] class GoGuidelines: """Review guidelines for Go codebases. Args: frameworks: Optional framework names used to add stack-specific guidance. """ __slots__ = ( "anti_patterns", "api_design_checks", "concurrency_checks", "documentation_checks", "frameworks", "idioms", "observability_checks", "performance_checks", "quality_checks", "resource_checks", "secrets_checks", "security_checks", "testing_checks", ) frameworks: tuple[str, ...] quality_checks: list[str] security_checks: list[str] performance_checks: list[str] testing_checks: list[str] documentation_checks: list[str] idioms: list[str] anti_patterns: list[str] concurrency_checks: list[str] resource_checks: list[str] observability_checks: list[str] secrets_checks: list[str] api_design_checks: list[str] def __init__(self, frameworks: Iterable[str] = ()) -> None: normalized_frameworks = tuple(frameworks) self.frameworks = normalized_frameworks self.quality_checks = [ "Run go fmt and golint.", "Check all error returns.", "Use defer for cleanup.", "Keep functions short and focused.", ] self.security_checks = [ "Validate input bounds before slice operations.", "Use crypto/rand for security-sensitive random numbers.", "Check for SQL injection in database queries.", ] self.performance_checks = [ "Pre-allocate slices when size is known.", "Use sync.Pool for frequently allocated objects.", "Consider goroutine leaks.", ] self.testing_checks = [ "Use table-driven tests.", "Test error paths explicitly.", "Use testify or similar for assertions when it improves clarity.", ] self.documentation_checks = [ "Document exported types, functions, and packages with Go-style comments.", "Explain concurrency expectations, ownership, and side effects in non-obvious code.", "Keep README and API examples aligned with actual package behavior.", ] self.idioms = [ "Accept interfaces, return structs.", "Make the zero value useful.", "Don't communicate by sharing memory.", ] self.anti_patterns = [ "Don't ignore returned errors.", "Avoid init() when possible.", "Don't use panic for normal error handling.", ] self.concurrency_checks = [ "Use context propagation and cancellation for goroutines and I/O boundaries.", "Protect shared state with clear synchronization strategy and avoid race-prone access.", "Ensure goroutines terminate cleanly on shutdown, timeout, or caller cancellation.", ] self.resource_checks = [ "Close files, response bodies, and other resources on every path.", "Use defer near acquisition sites so cleanup is obvious and reliable.", "Check cleanup-related errors when they can change user-visible behavior.", ] self.observability_checks = [ "Log errors with enough context to diagnose request, job, or goroutine failures.", "Avoid noisy logs inside hot paths and tight retry loops.", "Expose meaningful metrics or traces for latency-critical and concurrent operations.", ] self.secrets_checks = [ "Load secrets from environment or configuration, not source code.", "Do not log credentials, tokens, or sensitive request data.", "Review default configuration values for accidental secret exposure.", ] self.api_design_checks = [ "Keep package APIs small, consistent, and idiomatic for Go consumers.", "Return errors as the final result value and make failure modes explicit.", "Pass context.Context explicitly at request and I/O boundaries.", ] for framework in normalized_frameworks: self._apply_framework(framework) def _apply_framework(self, framework: str) -> None: """Add framework-specific guideline extensions.""" framework_name = framework.casefold() if framework_name in {"gin", "chi", "fiber", "echo"}: self.quality_checks.extend( [ "Use proper error handling in handlers.", "Use context for cancellation.", "Structure handlers and middleware properly.", ] ) self.security_checks.extend( [ "Set proper CORS headers.", "Validate input in handlers.", ] )
[docs] def summary(self) -> str: """Return a short human-readable summary.""" return ( f"{len(self.quality_checks)} quality checks, " f"{len(self.security_checks)} security checks, " f"{len(self.anti_patterns)} anti-patterns" )
[docs] def total_checks(self) -> int: """Return the total number of configured checks.""" return sum( [ len(self.quality_checks), len(self.security_checks), len(self.performance_checks), len(self.testing_checks), len(self.documentation_checks), len(self.idioms), len(self.anti_patterns), len(self.concurrency_checks), len(self.resource_checks), len(self.observability_checks), len(self.secrets_checks), len(self.api_design_checks), ] )
__all__ = ["GoGuidelines"]