mirror of
https://github.com/ivuorinen/actions.git
synced 2026-01-26 11:34:00 +00:00
feat: use our own actions in our workflows (#377)
* feat: use our own actions in our workflows * fix: add missing inputs to validate-inputs, refactor node * chore: cr comment fixes * fix: update-validators formatting * chore: update validators, add tests, conventions * feat: validate severity with severity_enum * feat: add 10 generic validators to improve input validation coverage Add comprehensive validation system improvements across multiple phases: Phase 2A - Quick Wins: - Add multi_value_enum validator for 2-10 value enumerations - Add exit_code_list validator for Unix/Linux exit codes (0-255) - Refactor coverage_driver to use multi_value_enum Phase 2B - High-Value Validators: - Add key_value_list validator with shell injection prevention - Add path_list validator with path traversal and glob support Quick Wins - Additional Enums: - Add network_mode validator for Docker network modes - Add language_enum validator for language detection - Add framework_mode validator for PHP framework modes - Update boolean pattern to include 'push' Phase 2C - Specialized Validators: - Add json_format validator for JSON syntax validation - Add cache_config validator for Docker BuildKit cache configs Improvements: - All validators include comprehensive security checks - Pattern-based validation with clear error messages - 23 new test methods with edge case coverage - Update special case mappings for 20+ inputs - Fix build-args mapping test expectation Coverage impact: 22 actions now at 100% validation (88% → 92%) Test suite: 762 → 785 tests (+23 tests, all passing) * chore: regenerate rules.yml with improved validator coverage Regenerate validation rules for all actions with new validators: - compress-images: 86% → 100% (+1 input: ignore-paths) - docker-build: 63% → 100% (+4 inputs: cache configs, platform-build-args) - docker-publish: 73% → 100% (+1 input: build-args) - language-version-detect: 67% → 100% (+1 input: language) - php-tests: 89% (fixed framework→framework_mode mapping) - prettier-lint: 86% → 100% (+2 inputs: file-pattern, plugins) - security-scan: 86% (maintained coverage) Overall: 23 of 25 actions now at 100% validation coverage (92%) * fix: address PR #377 review comments - Add | None type annotations to 6 optional parameters (PEP 604) - Standardize injection pattern: remove @# from comma_separated_list validator (@ and # are not shell injection vectors, allows npm scoped packages) - Remove dead code: unused value expression in key_value_list validator - Update tests to reflect injection pattern changes
This commit is contained in:
@@ -114,7 +114,7 @@ class ValidationRuleGenerator:
|
||||
"prefix": re.compile(r"\b(prefix|tag[_-]?prefix)\b", re.IGNORECASE),
|
||||
# Boolean patterns (broad, should be lower priority)
|
||||
"boolean": re.compile(
|
||||
r"\b(dry-?run|verbose|enable|disable|auto|skip|force|cache|provenance|sbom|scan|sign|fail[_-]?on[_-]?error|nightly)\b",
|
||||
r"\b(dry-?run|verbose|enable|disable|auto|skip|force|cache|provenance|sbom|scan|sign|push|fail[_-]?on[_-]?error|nightly)\b",
|
||||
re.IGNORECASE,
|
||||
),
|
||||
# File extensions pattern
|
||||
@@ -160,36 +160,36 @@ class ValidationRuleGenerator:
|
||||
"npm_token": "github_token",
|
||||
"password": "github_token",
|
||||
# Complex fields that should skip validation
|
||||
"build-args": None, # Can be empty
|
||||
"context": None, # Default handled
|
||||
"cache-from": None, # Complex cache syntax
|
||||
"cache-export": None, # Complex cache syntax
|
||||
"cache-import": None, # Complex cache syntax
|
||||
"build-contexts": None, # Complex syntax
|
||||
"secrets": None, # Complex syntax
|
||||
"platform-build-args": None, # JSON format
|
||||
"extensions": None, # PHP extensions list
|
||||
"tools": None, # PHP tools list
|
||||
"build-args": "key_value_list", # Docker build arguments (KEY=VALUE format)
|
||||
"context": "file_path", # Build context path
|
||||
"cache-from": "cache_config", # Docker cache configuration
|
||||
"cache-export": "cache_config", # Docker cache configuration
|
||||
"cache-import": "cache_config", # Docker cache configuration
|
||||
"build-contexts": "key_value_list", # Docker build contexts (KEY=VALUE format)
|
||||
"secrets": "key_value_list", # Docker secrets (KEY=VALUE format)
|
||||
"platform-build-args": "json_format", # JSON format for platform-specific args
|
||||
"extensions": "php_extensions", # PHP extensions list
|
||||
"tools": "linter_list", # PHP tools list - same pattern as linters
|
||||
"framework": "framework_mode", # PHP framework mode (auto, laravel, generic)
|
||||
"args": None, # Composer args
|
||||
"stability": None, # Composer stability
|
||||
"registry-url": "url", # URL format
|
||||
"scope": "scope", # NPM scope
|
||||
"plugins": None, # Prettier plugins
|
||||
"plugins": "linter_list", # Prettier plugins - same pattern as linters
|
||||
"file-extensions": "file_extensions", # File extension list
|
||||
"file-pattern": None, # Glob pattern
|
||||
"enable-linters": None, # Linter list
|
||||
"disable-linters": None, # Linter list
|
||||
"success-codes": None, # Exit code list
|
||||
"retry-codes": None, # Exit code list
|
||||
"ignore-paths": None, # Path patterns
|
||||
"key-files": None, # Cache key files
|
||||
"restore-keys": None, # Cache restore keys
|
||||
"env-vars": None, # Environment variables
|
||||
"file-pattern": "path_list", # Glob pattern for file paths
|
||||
"enable-linters": "linter_list", # Linter list
|
||||
"disable-linters": "linter_list", # Linter list
|
||||
"success-codes": "exit_code_list", # Exit code list
|
||||
"retry-codes": "exit_code_list", # Exit code list
|
||||
"ignore-paths": "path_list", # Path patterns to ignore
|
||||
"key-files": "path_list", # Cache key files (paths)
|
||||
"restore-keys": "path_list", # Cache restore keys (paths)
|
||||
"env-vars": "key_value_list", # Environment variables (KEY=VALUE format)
|
||||
# Action-specific fields that need special handling
|
||||
"type": None, # Cache type enum (npm, composer, go, etc.) - complex enum,
|
||||
# skip validation
|
||||
"paths": None, # File paths for caching (comma-separated) - complex format,
|
||||
# skip validation
|
||||
"paths": "path_list", # File paths for caching (comma-separated)
|
||||
"command": None, # Shell command - complex format, skip validation for safety
|
||||
"backoff-strategy": None, # Retry strategy enum - complex enum, skip validation
|
||||
"shell": None, # Shell type enum - simple enum, skip validation
|
||||
@@ -199,10 +199,13 @@ class ValidationRuleGenerator:
|
||||
"retry-delay": "numeric_range_1_300", # Retry delay should support higher values
|
||||
"max-warnings": "numeric_range_0_10000",
|
||||
# version-file-parser specific fields
|
||||
"language": None, # Simple enum (node, php, python, go, dotnet)
|
||||
"tool-versions-key": None, # Simple string (nodejs, python, php, golang, dotnet)
|
||||
"dockerfile-image": None, # Simple string (node, python, php, golang, dotnet)
|
||||
"validation-regex": "regex_pattern", # Regex pattern - validate for ReDoS
|
||||
# Docker network mode
|
||||
"network": "network_mode", # Docker network mode (host, none, default)
|
||||
# Language enum for version detection
|
||||
"language": "language_enum", # Language type (php, python, go, dotnet)
|
||||
}
|
||||
|
||||
def get_action_directories(self) -> list[str]:
|
||||
@@ -314,7 +317,6 @@ class ValidationRuleGenerator:
|
||||
"docker-publish": {
|
||||
"registry": "registry_enum",
|
||||
"cache-mode": "cache_mode",
|
||||
"platforms": None, # Skip validation - complex platform format
|
||||
},
|
||||
"docker-publish-hub": {
|
||||
"password": "docker_password",
|
||||
@@ -354,26 +356,28 @@ class ValidationRuleGenerator:
|
||||
"prettier-lint": {
|
||||
"mode": "mode_enum",
|
||||
},
|
||||
"security-scan": {
|
||||
"gitleaks-config": "file_path",
|
||||
"trivy-severity": "severity_enum",
|
||||
"trivy-scanners": "scanner_list",
|
||||
"trivy-timeout": "timeout_with_unit",
|
||||
"actionlint-enabled": "boolean",
|
||||
"token": "github_token",
|
||||
},
|
||||
}
|
||||
|
||||
if action_name in action_overrides:
|
||||
# Apply overrides for existing conventions
|
||||
overrides.update(
|
||||
{
|
||||
input_name: override_value
|
||||
for input_name, override_value in action_overrides[action_name].items()
|
||||
if input_name in conventions
|
||||
},
|
||||
)
|
||||
# Add missing inputs from overrides to conventions
|
||||
for input_name, override_value in action_overrides[action_name].items():
|
||||
if input_name not in conventions and input_name in action_data["inputs"]:
|
||||
if input_name in action_data["inputs"]:
|
||||
overrides[input_name] = override_value
|
||||
# Update conventions to match override (or set to None if skipped)
|
||||
conventions[input_name] = override_value
|
||||
|
||||
# Calculate statistics
|
||||
total_inputs = len(action_data["inputs"])
|
||||
validated_inputs = len(conventions)
|
||||
skipped_inputs = sum(1 for v in overrides.values() if v is None)
|
||||
validated_inputs = sum(1 for v in conventions.values() if v is not None)
|
||||
skipped_inputs = sum(1 for v in conventions.values() if v is None)
|
||||
coverage = round((validated_inputs / total_inputs) * 100) if total_inputs > 0 else 0
|
||||
|
||||
# Generate rules object with enhanced metadata
|
||||
@@ -432,8 +436,20 @@ class ValidationRuleGenerator:
|
||||
|
||||
# Use a custom yaml dumper to ensure proper indentation
|
||||
class CustomYamlDumper(yaml.SafeDumper):
|
||||
def increase_indent(self, flow: bool = False, *, indentless: bool = False) -> None: # noqa: FBT001, FBT002
|
||||
return super().increase_indent(flow, indentless=indentless)
|
||||
def increase_indent(self, flow: bool = False, *, indentless: bool = False) -> None: # noqa: FBT001, FBT002, ARG002 # type: ignore[override]
|
||||
return super().increase_indent(flow, False)
|
||||
|
||||
def choose_scalar_style(self):
|
||||
"""Choose appropriate quote style based on string content."""
|
||||
if hasattr(self, "event") and hasattr(self.event, "value") and self.event.value: # type: ignore[attr-defined]
|
||||
value = self.event.value # type: ignore[attr-defined]
|
||||
# Use literal block style for multiline strings
|
||||
if "\n" in value:
|
||||
return "|"
|
||||
# Use double quotes for strings with single quotes
|
||||
if "'" in value:
|
||||
return '"'
|
||||
return super().choose_scalar_style()
|
||||
|
||||
yaml_content = yaml.dump(
|
||||
rules,
|
||||
|
||||
Reference in New Issue
Block a user