mirror of
https://github.com/ivuorinen/actions.git
synced 2026-01-26 03:23:59 +00:00
* docs: update documentation * feat: validate-inputs has it's own pyproject * security: mask DOCKERHUB_PASSWORD * chore: add tokens, checkout, recrete docs, integration tests * fix: add `statuses: write` permission to pr-lint
113 lines
4.2 KiB
Python
Executable File
113 lines
4.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Custom validator for validate-inputs action."""
|
|
# pylint: disable=invalid-name # Module name matches class name for clarity
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add validate-inputs directory to path to import validators
|
|
validate_inputs_path = Path(__file__).parent
|
|
sys.path.insert(0, str(validate_inputs_path))
|
|
|
|
# pylint: disable=wrong-import-position
|
|
from validators.base import BaseValidator
|
|
from validators.boolean import BooleanValidator
|
|
from validators.file import FileValidator
|
|
|
|
|
|
class CustomValidator(BaseValidator):
|
|
"""Custom validator for validate-inputs action."""
|
|
|
|
def __init__(self, action_type: str = "validate-inputs") -> None:
|
|
"""Initialize validate-inputs validator."""
|
|
super().__init__(action_type)
|
|
self.boolean_validator = BooleanValidator()
|
|
self.file_validator = FileValidator()
|
|
|
|
def validate_inputs(self, inputs: dict[str, str]) -> bool: # pylint: disable=too-many-branches
|
|
"""Validate validate-inputs action inputs."""
|
|
valid = True
|
|
|
|
# Validate action/action-type input
|
|
if "action" in inputs or "action-type" in inputs:
|
|
action_input = inputs.get("action") or inputs.get("action-type", "")
|
|
# Check for empty action
|
|
if action_input == "":
|
|
self.add_error("Action name cannot be empty")
|
|
valid = False
|
|
# Allow GitHub expressions
|
|
elif action_input.startswith("${{") and action_input.endswith("}}"):
|
|
pass # GitHub expressions are valid
|
|
# Check for dangerous characters
|
|
elif any(
|
|
char in action_input
|
|
for char in [";", "`", "$", "&", "|", ">", "<", "\n", "\r", "/"]
|
|
):
|
|
self.add_error(f"Invalid characters in action name: {action_input}")
|
|
valid = False
|
|
# Validate action name format (should be lowercase with hyphens or underscores)
|
|
elif action_input and not re.match(r"^[a-z][a-z0-9_-]*[a-z0-9]$", action_input):
|
|
self.add_error(f"Invalid action name format: {action_input}")
|
|
valid = False
|
|
|
|
# Validate rules-file if provided
|
|
if inputs.get("rules-file"):
|
|
result = self.file_validator.validate_file_path(inputs["rules-file"], "rules-file")
|
|
for error in self.file_validator.errors:
|
|
if error not in self.errors:
|
|
self.add_error(error)
|
|
self.file_validator.clear_errors()
|
|
if not result:
|
|
valid = False
|
|
|
|
# Validate fail-on-error boolean
|
|
if "fail-on-error" in inputs:
|
|
value = inputs["fail-on-error"]
|
|
# Reject empty string
|
|
if value == "":
|
|
self.add_error("fail-on-error cannot be empty")
|
|
valid = False
|
|
elif value:
|
|
result = self.boolean_validator.validate_boolean(value, "fail-on-error")
|
|
for error in self.boolean_validator.errors:
|
|
if error not in self.errors:
|
|
self.add_error(error)
|
|
self.boolean_validator.clear_errors()
|
|
if not result:
|
|
valid = False
|
|
|
|
return valid
|
|
|
|
def get_required_inputs(self) -> list[str]:
|
|
"""Get list of required inputs."""
|
|
# action/action-type is required
|
|
return []
|
|
|
|
def get_validation_rules(self) -> dict:
|
|
"""Get validation rules."""
|
|
return {
|
|
"action": {
|
|
"type": "string",
|
|
"required": False,
|
|
"description": "Action name to validate",
|
|
},
|
|
"action-type": {
|
|
"type": "string",
|
|
"required": False,
|
|
"description": "Action type to validate (alias for action)",
|
|
},
|
|
"rules-file": {
|
|
"type": "file",
|
|
"required": False,
|
|
"description": "Rules file path",
|
|
},
|
|
"fail-on-error": {
|
|
"type": "boolean",
|
|
"required": False,
|
|
"description": "Whether to fail on validation error",
|
|
},
|
|
}
|