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:
2025-11-25 23:51:03 +02:00
committed by GitHub
parent e58465e5d3
commit 9aa16a8164
32 changed files with 2823 additions and 523 deletions

View File

@@ -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,