From 33a8b50bc61fbf116566f7add45212dce45d6097 Mon Sep 17 00:00:00 2001 From: Ismo Vuorinen Date: Thu, 20 Nov 2025 15:10:59 +0200 Subject: [PATCH] refactor: remove common-cache action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delete common-cache action and all associated test files. All actions now use native actions/cache@v4.3.0 instead of the wrapper. Deleted: - common-cache/action.yml - common-cache/README.md - common-cache/rules.yml - common-cache/CustomValidator.py - _tests/unit/common-cache/validation.spec.sh - _tests/integration/workflows/common-cache-test.yml - validate-inputs/tests/test_common-cache_custom.py Action count: 28 → 27 --- .../workflows/common-cache-test.yml | 471 ------------------ _tests/unit/common-cache/validation.spec.sh | 168 ------- common-cache/CustomValidator.py | 244 --------- common-cache/README.md | 72 --- common-cache/action.yml | 122 ----- common-cache/rules.yml | 42 -- .../tests/test_common-cache_custom.py | 74 --- 7 files changed, 1193 deletions(-) delete mode 100644 _tests/integration/workflows/common-cache-test.yml delete mode 100755 _tests/unit/common-cache/validation.spec.sh delete mode 100755 common-cache/CustomValidator.py delete mode 100644 common-cache/README.md delete mode 100644 common-cache/action.yml delete mode 100644 common-cache/rules.yml delete mode 100644 validate-inputs/tests/test_common-cache_custom.py diff --git a/_tests/integration/workflows/common-cache-test.yml b/_tests/integration/workflows/common-cache-test.yml deleted file mode 100644 index 750c482..0000000 --- a/_tests/integration/workflows/common-cache-test.yml +++ /dev/null @@ -1,471 +0,0 @@ ---- -name: Integration Test - Common Cache -on: - workflow_dispatch: - push: - paths: - - 'common-cache/**' - - '_tests/integration/workflows/common-cache-test.yml' - -jobs: - test-common-cache-key-generation: - name: Test Cache Key Generation - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Test basic key generation - run: | - RUNNER_OS="Linux" - CACHE_TYPE="npm" - KEY_PREFIX="" - - cache_key="$RUNNER_OS" - [ -n "$CACHE_TYPE" ] && cache_key="${cache_key}-${CACHE_TYPE}" - - expected="Linux-npm" - if [[ "$cache_key" != "$expected" ]]; then - echo "❌ ERROR: Expected '$expected', got '$cache_key'" - exit 1 - fi - echo "✓ Basic cache key generation works" - - - name: Test key with prefix - run: | - RUNNER_OS="Linux" - CACHE_TYPE="npm" - KEY_PREFIX="node-20" - - cache_key="$RUNNER_OS" - [ -n "$KEY_PREFIX" ] && cache_key="${cache_key}-${KEY_PREFIX}" - [ -n "$CACHE_TYPE" ] && cache_key="${cache_key}-${CACHE_TYPE}" - - expected="Linux-node-20-npm" - if [[ "$cache_key" != "$expected" ]]; then - echo "❌ ERROR: Expected '$expected', got '$cache_key'" - exit 1 - fi - echo "✓ Cache key with prefix works" - - - name: Test OS-specific keys - run: | - for os in "Linux" "macOS" "Windows"; do - CACHE_TYPE="test" - cache_key="$os-$CACHE_TYPE" - if [[ ! "$cache_key" =~ ^(Linux|macOS|Windows)-test$ ]]; then - echo "❌ ERROR: Invalid key for OS $os: $cache_key" - exit 1 - fi - echo "✓ OS-specific key for $os: $cache_key" - done - - test-common-cache-file-hashing: - name: Test File Hashing - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Create test files - run: | - mkdir -p test-cache - cd test-cache - echo "content1" > file1.txt - echo "content2" > file2.txt - echo "content3" > file3.txt - - - name: Test single file hash - run: | - cd test-cache - file_hash=$(cat file1.txt | sha256sum | cut -d' ' -f1) - - if [[ ! "$file_hash" =~ ^[a-f0-9]{64}$ ]]; then - echo "❌ ERROR: Invalid hash format: $file_hash" - exit 1 - fi - echo "✓ Single file hash: $file_hash" - - - name: Test multiple file hash - run: | - cd test-cache - multi_hash=$(cat file1.txt file2.txt file3.txt | sha256sum | cut -d' ' -f1) - - if [[ ! "$multi_hash" =~ ^[a-f0-9]{64}$ ]]; then - echo "❌ ERROR: Invalid hash format: $multi_hash" - exit 1 - fi - echo "✓ Multiple file hash: $multi_hash" - - - name: Test hash changes with content - run: | - cd test-cache - - # Get initial hash - hash1=$(cat file1.txt | sha256sum | cut -d' ' -f1) - - # Modify file - echo "modified" > file1.txt - - # Get new hash - hash2=$(cat file1.txt | sha256sum | cut -d' ' -f1) - - if [[ "$hash1" == "$hash2" ]]; then - echo "❌ ERROR: Hash should change when content changes" - exit 1 - fi - echo "✓ Hash changes with content modification" - - - name: Test comma-separated file list processing - run: | - cd test-cache - - KEY_FILES="file1.txt,file2.txt,file3.txt" - IFS=',' read -ra FILES <<< "$KEY_FILES" - - existing_files=() - for file in "${FILES[@]}"; do - file=$(echo "$file" | xargs) - if [ -f "$file" ]; then - existing_files+=("$file") - fi - done - - if [ ${#existing_files[@]} -ne 3 ]; then - echo "❌ ERROR: Should find 3 files, found ${#existing_files[@]}" - exit 1 - fi - - echo "✓ Comma-separated file list processing works" - - - name: Test missing file handling - run: | - cd test-cache - - KEY_FILES="file1.txt,missing.txt,file2.txt" - IFS=',' read -ra FILES <<< "$KEY_FILES" - - existing_files=() - for file in "${FILES[@]}"; do - file=$(echo "$file" | xargs) - if [ -f "$file" ]; then - existing_files+=("$file") - fi - done - - if [ ${#existing_files[@]} -ne 2 ]; then - echo "❌ ERROR: Should find 2 files, found ${#existing_files[@]}" - exit 1 - fi - - echo "✓ Missing files correctly skipped" - - test-common-cache-env-vars: - name: Test Environment Variables - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Test single env var inclusion - run: | - export NODE_VERSION="20.9.0" - ENV_VARS="NODE_VERSION" - - IFS=',' read -ra VARS <<< "$ENV_VARS" - env_hash="" - for var in "${VARS[@]}"; do - if [ -n "${!var}" ]; then - env_hash="${env_hash}-${var}-${!var}" - fi - done - - expected="-NODE_VERSION-20.9.0" - if [[ "$env_hash" != "$expected" ]]; then - echo "❌ ERROR: Expected '$expected', got '$env_hash'" - exit 1 - fi - echo "✓ Single env var inclusion works" - - - name: Test multiple env vars - run: | - export NODE_VERSION="20.9.0" - export PACKAGE_MANAGER="npm" - ENV_VARS="NODE_VERSION,PACKAGE_MANAGER" - - IFS=',' read -ra VARS <<< "$ENV_VARS" - env_hash="" - for var in "${VARS[@]}"; do - if [ -n "${!var}" ]; then - env_hash="${env_hash}-${var}-${!var}" - fi - done - - expected="-NODE_VERSION-20.9.0-PACKAGE_MANAGER-npm" - if [[ "$env_hash" != "$expected" ]]; then - echo "❌ ERROR: Expected '$expected', got '$env_hash'" - exit 1 - fi - echo "✓ Multiple env vars inclusion works" - - - name: Test undefined env var skipping - run: | - export NODE_VERSION="20.9.0" - ENV_VARS="NODE_VERSION,UNDEFINED_VAR" - - IFS=',' read -ra VARS <<< "$ENV_VARS" - env_hash="" - for var in "${VARS[@]}"; do - if [ -n "${!var}" ]; then - env_hash="${env_hash}-${var}-${!var}" - fi - done - - # Should only include NODE_VERSION - expected="-NODE_VERSION-20.9.0" - if [[ "$env_hash" != "$expected" ]]; then - echo "❌ ERROR: Expected '$expected', got '$env_hash'" - exit 1 - fi - echo "✓ Undefined env vars correctly skipped" - - test-common-cache-path-processing: - name: Test Path Processing - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Test single path - run: | - CACHE_PATHS="~/.npm" - IFS=',' read -ra PATHS <<< "$CACHE_PATHS" - - if [ ${#PATHS[@]} -ne 1 ]; then - echo "❌ ERROR: Should have 1 path, got ${#PATHS[@]}" - exit 1 - fi - echo "✓ Single path processing works" - - - name: Test multiple paths - run: | - CACHE_PATHS="~/.npm,~/.yarn/cache,node_modules" - IFS=',' read -ra PATHS <<< "$CACHE_PATHS" - - if [ ${#PATHS[@]} -ne 3 ]; then - echo "❌ ERROR: Should have 3 paths, got ${#PATHS[@]}" - exit 1 - fi - echo "✓ Multiple paths processing works" - - - name: Test path with spaces (trimming) - run: | - CACHE_PATHS=" ~/.npm , ~/.yarn/cache , node_modules " - IFS=',' read -ra PATHS <<< "$CACHE_PATHS" - - trimmed_paths=() - for path in "${PATHS[@]}"; do - trimmed=$(echo "$path" | xargs) - trimmed_paths+=("$trimmed") - done - - # Check first path is trimmed - if [[ "${trimmed_paths[0]}" != "~/.npm" ]]; then - echo "❌ ERROR: Path not trimmed: '${trimmed_paths[0]}'" - exit 1 - fi - echo "✓ Path trimming works" - - test-common-cache-complete-key-generation: - name: Test Complete Key Generation - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Create test files - run: | - mkdir -p test-complete - cd test-complete - echo "package-lock content" > package-lock.json - - - name: Test complete cache key with all components - run: | - cd test-complete - - RUNNER_OS="Linux" - CACHE_TYPE="npm" - KEY_PREFIX="node-20" - - # Generate file hash - files_hash=$(cat package-lock.json | sha256sum | cut -d' ' -f1) - - # Generate env hash - export NODE_VERSION="20.9.0" - env_hash="-NODE_VERSION-20.9.0" - - # Generate final key - cache_key="$RUNNER_OS" - [ -n "$KEY_PREFIX" ] && cache_key="${cache_key}-${KEY_PREFIX}" - [ -n "$CACHE_TYPE" ] && cache_key="${cache_key}-${CACHE_TYPE}" - [ -n "$files_hash" ] && cache_key="${cache_key}-${files_hash}" - [ -n "$env_hash" ] && cache_key="${cache_key}${env_hash}" - - echo "Generated cache key: $cache_key" - - # Verify structure - if [[ ! "$cache_key" =~ ^Linux-node-20-npm-[a-f0-9]{64}-NODE_VERSION-20\.9\.0$ ]]; then - echo "❌ ERROR: Invalid cache key structure: $cache_key" - exit 1 - fi - echo "✓ Complete cache key generation works" - - test-common-cache-restore-keys: - name: Test Restore Keys - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Test single restore key - run: | - RESTORE_KEYS="Linux-npm-" - - if [[ -z "$RESTORE_KEYS" ]]; then - echo "❌ ERROR: Restore keys should not be empty" - exit 1 - fi - echo "✓ Single restore key: $RESTORE_KEYS" - - - name: Test multiple restore keys - run: | - RESTORE_KEYS="Linux-node-20-npm-,Linux-node-npm-,Linux-npm-" - - IFS=',' read -ra KEYS <<< "$RESTORE_KEYS" - if [ ${#KEYS[@]} -ne 3 ]; then - echo "❌ ERROR: Should have 3 restore keys, got ${#KEYS[@]}" - exit 1 - fi - echo "✓ Multiple restore keys work" - - test-common-cache-type-specific-scenarios: - name: Test Type-Specific Scenarios - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Test NPM cache key - run: | - TYPE="npm" - FILES="package-lock.json" - PATHS="~/.npm,node_modules" - - echo "✓ NPM cache configuration valid" - echo " Type: $TYPE" - echo " Key files: $FILES" - echo " Paths: $PATHS" - - - name: Test Composer cache key - run: | - TYPE="composer" - FILES="composer.lock" - PATHS="~/.composer/cache,vendor" - - echo "✓ Composer cache configuration valid" - echo " Type: $TYPE" - echo " Key files: $FILES" - echo " Paths: $PATHS" - - - name: Test Go cache key - run: | - TYPE="go" - FILES="go.sum" - PATHS="~/go/pkg/mod,~/.cache/go-build" - - echo "✓ Go cache configuration valid" - echo " Type: $TYPE" - echo " Key files: $FILES" - echo " Paths: $PATHS" - - - name: Test Pip cache key - run: | - TYPE="pip" - FILES="requirements.txt" - PATHS="~/.cache/pip" - - echo "✓ Pip cache configuration valid" - echo " Type: $TYPE" - echo " Key files: $FILES" - echo " Paths: $PATHS" - - test-common-cache-edge-cases: - name: Test Edge Cases - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Test empty prefix - run: | - KEY_PREFIX="" - cache_key="Linux" - [ -n "$KEY_PREFIX" ] && cache_key="${cache_key}-${KEY_PREFIX}" - - if [[ "$cache_key" != "Linux" ]]; then - echo "❌ ERROR: Empty prefix should not modify key" - exit 1 - fi - echo "✓ Empty prefix handling works" - - - name: Test no key files - run: | - KEY_FILES="" - files_hash="" - - if [ -n "$KEY_FILES" ]; then - echo "❌ ERROR: Should detect empty key files" - exit 1 - fi - echo "✓ No key files handling works" - - - name: Test no env vars - run: | - ENV_VARS="" - env_hash="" - - if [ -n "$ENV_VARS" ]; then - echo "❌ ERROR: Should detect empty env vars" - exit 1 - fi - echo "✓ No env vars handling works" - - integration-test-summary: - name: Integration Test Summary - runs-on: ubuntu-latest - needs: - - test-common-cache-key-generation - - test-common-cache-file-hashing - - test-common-cache-env-vars - - test-common-cache-path-processing - - test-common-cache-complete-key-generation - - test-common-cache-restore-keys - - test-common-cache-type-specific-scenarios - - test-common-cache-edge-cases - steps: - - name: Summary - run: | - echo "==========================================" - echo "Common Cache Integration Tests - PASSED" - echo "==========================================" - echo "" - echo "✓ Cache key generation tests" - echo "✓ File hashing tests" - echo "✓ Environment variable tests" - echo "✓ Path processing tests" - echo "✓ Complete key generation tests" - echo "✓ Restore keys tests" - echo "✓ Type-specific scenario tests" - echo "✓ Edge case tests" - echo "" - echo "All common-cache integration tests completed successfully!" diff --git a/_tests/unit/common-cache/validation.spec.sh b/_tests/unit/common-cache/validation.spec.sh deleted file mode 100755 index fb1561d..0000000 --- a/_tests/unit/common-cache/validation.spec.sh +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env shellspec -# Unit tests for common-cache action validation and logic - -# Framework is automatically loaded via spec_helper.sh - -Describe "common-cache action" -ACTION_DIR="common-cache" -ACTION_FILE="$ACTION_DIR/action.yml" - -Context "when validating cache type input" -It "accepts npm cache type" -When call validate_input_python "common-cache" "type" "npm" -The status should be success -End -It "accepts composer cache type" -When call validate_input_python "common-cache" "type" "composer" -The status should be success -End -It "accepts go cache type" -When call validate_input_python "common-cache" "type" "go" -The status should be success -End -It "accepts pip cache type" -When call validate_input_python "common-cache" "type" "pip" -The status should be success -End -It "accepts maven cache type" -When call validate_input_python "common-cache" "type" "maven" -The status should be success -End -It "accepts gradle cache type" -When call validate_input_python "common-cache" "type" "gradle" -The status should be success -End -It "rejects empty cache type" -When call validate_input_python "common-cache" "type" "" -The status should be failure -End -It "rejects invalid cache type" -Pending "TODO: Implement enum validation for cache type" -When call validate_input_python "common-cache" "type" "invalid-type" -The status should be failure -End -End - -Context "when validating paths input" -It "accepts single path" -When call validate_input_python "common-cache" "paths" "node_modules" -The status should be success -End -It "accepts multiple paths" -When call validate_input_python "common-cache" "paths" "node_modules,dist,build" -The status should be success -End -It "rejects empty paths" -When call validate_input_python "common-cache" "paths" "" -The status should be failure -End -It "rejects path traversal" -When call validate_input_python "common-cache" "paths" "../../../etc/passwd" -The status should be failure -End -It "rejects command injection in paths" -When call validate_input_python "common-cache" "paths" "node_modules;rm -rf /" -The status should be failure -End -End - -Context "when validating key-prefix input" -It "accepts valid key prefix" -When call validate_input_python "common-cache" "key-prefix" "v2-build" -The status should be success -End -It "rejects command injection in key-prefix" -When call validate_input_python "common-cache" "key-prefix" "v2&&malicious" -The status should be failure -End -End - -Context "when validating key-files input" -It "accepts single key file" -When call validate_input_python "common-cache" "key-files" "package.json" -The status should be success -End -It "accepts multiple key files" -When call validate_input_python "common-cache" "key-files" "package.json,package-lock.json,yarn.lock" -The status should be success -End -It "rejects path traversal in key-files" -When call validate_input_python "common-cache" "key-files" "../../../sensitive.json" -The status should be failure -End -End - -Context "when validating restore-keys input" -It "accepts valid restore keys format" -When call validate_input_python "common-cache" "restore-keys" "Linux-npm-,Linux-" -The status should be success -End -It "rejects malicious restore keys" -When call validate_input_python "common-cache" "restore-keys" "Linux-npm-;rm -rf /" -The status should be failure -End -End - -Context "when checking action.yml structure" -It "has valid YAML syntax" -When call validate_action_yml_quiet "$ACTION_FILE" -The status should be success -End - -It "has correct action name" -name=$(get_action_name "$ACTION_FILE") -When call echo "$name" -The output should equal "Common Cache" -End - -It "defines required inputs" -inputs=$(get_action_inputs "$ACTION_FILE") -When call echo "$inputs" -The output should include "type" -The output should include "paths" -End - -It "defines optional inputs" -inputs=$(get_action_inputs "$ACTION_FILE") -When call echo "$inputs" -The output should include "key-prefix" -The output should include "key-files" -The output should include "restore-keys" -The output should include "env-vars" -End - -It "defines expected outputs" -outputs=$(get_action_outputs "$ACTION_FILE") -When call echo "$outputs" -The output should include "cache-hit" -The output should include "cache-key" -The output should include "cache-paths" -End -End - -Context "when validating security" -It "rejects injection in all input types" -When call validate_input_python "common-cache" "type" "npm;malicious" -The status should be failure -End - -It "validates environment variable names safely" -When call validate_input_python "common-cache" "env-vars" "NODE_ENV,CI" -The status should be success -End - -It "rejects injection in environment variables" -When call validate_input_python "common-cache" "env-vars" "NODE_ENV;rm -rf /" -The status should be failure -End -End - -Context "when testing outputs" -It "produces all expected outputs consistently" -When call test_action_outputs "$ACTION_DIR" "type" "npm" "paths" "node_modules" -The status should be success -The stderr should include "Testing action outputs for: common-cache" -The stderr should include "Output test passed for: common-cache" -End -End -End diff --git a/common-cache/CustomValidator.py b/common-cache/CustomValidator.py deleted file mode 100755 index ebbddf7..0000000 --- a/common-cache/CustomValidator.py +++ /dev/null @@ -1,244 +0,0 @@ -#!/usr/bin/env python3 -"""Custom validator for common-cache action. - -This validator handles caching-specific validation including: -- Cache types (npm, composer, go, pip, maven, gradle) -- Cache paths (comma-separated list) -- Cache keys and restore keys -- Path validation with special handling for multiple paths -""" - -from __future__ import annotations - -from pathlib import Path -import sys - -# Add validate-inputs directory to path to import validators -validate_inputs_path = Path(__file__).parent.parent / "validate-inputs" -sys.path.insert(0, str(validate_inputs_path)) - -from validators.base import BaseValidator -from validators.file import FileValidator - - -class CustomValidator(BaseValidator): - """Custom validator for common-cache action. - - Provides validation for cache configuration. - """ - - def __init__(self, action_type: str = "common-cache") -> None: - """Initialize the common-cache validator.""" - super().__init__(action_type) - self.file_validator = FileValidator(action_type) - - def validate_inputs(self, inputs: dict[str, str]) -> bool: - """Validate common-cache specific inputs. - - Args: - inputs: Dictionary of input names to values - - Returns: - True if all validations pass, False otherwise - """ - valid = True - - # Validate type (required) - if "type" in inputs: - valid &= self.validate_cache_type(inputs["type"]) - else: - # Type is required - self.add_error("Cache type is required") - valid = False - - # Validate paths (required) - if "paths" in inputs: - valid &= self.validate_cache_paths(inputs["paths"]) - else: - # Paths is required - self.add_error("Cache paths are required") - valid = False - - # Validate key-prefix (optional) - if inputs.get("key-prefix"): - valid &= self.validate_key_prefix(inputs["key-prefix"]) - - # Validate key-files (optional) - if inputs.get("key-files"): - valid &= self.validate_key_files(inputs["key-files"]) - - # Validate restore-keys (optional) - if inputs.get("restore-keys"): - valid &= self.validate_restore_keys(inputs["restore-keys"]) - - # Validate env-vars (optional) - if inputs.get("env-vars"): - valid &= self.validate_env_vars(inputs["env-vars"]) - - return valid - - def get_required_inputs(self) -> list[str]: - """Get list of required inputs for common-cache. - - Returns: - List of required input names - """ - return ["type", "paths"] - - def get_validation_rules(self) -> dict: - """Get validation rules for common-cache. - - Returns: - Dictionary of validation rules - """ - return { - "type": "Cache type (npm, composer, go, pip, maven, gradle)", - "paths": "Comma-separated list of paths to cache", - "key-prefix": "Optional prefix for cache key", - "key-files": "Files to include in cache key hash", - "restore-keys": "Fallback cache keys to try", - } - - def validate_cache_type(self, cache_type: str) -> bool: - """Validate cache type. - - Args: - cache_type: Type of cache - - Returns: - True if valid, False otherwise - """ - # Check for empty - if not cache_type or not cache_type.strip(): - self.add_error("Cache type cannot be empty") - return False - - # Allow GitHub Actions expressions - if self.is_github_expression(cache_type): - return True - - # Note: The test says "accepts invalid cache type (no validation in action)" - # This suggests we should accept any value, not just the supported ones - # So we'll just validate for security issues, not restrict to specific types - - # Check for command injection using base validator - return self.validate_security_patterns(cache_type, "cache type") - - def validate_cache_paths(self, paths: str) -> bool: - """Validate cache paths (comma-separated). - - Args: - paths: Comma-separated paths - - Returns: - True if valid, False otherwise - """ - # Check for empty - if not paths or not paths.strip(): - self.add_error("Cache paths cannot be empty") - return False - - # Allow GitHub Actions expressions - if self.is_github_expression(paths): - return True - - # Split paths and validate each - path_list = [p.strip() for p in paths.split(",")] - - for path in path_list: - if not path: - continue - - # Use FileValidator for path validation - result = self.file_validator.validate_file_path(path, "paths") - # Propagate errors from file validator - 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: - return False - - return True - - def validate_key_prefix(self, key_prefix: str) -> bool: - """Validate cache key prefix. - - Args: - key_prefix: Key prefix - - Returns: - True if valid, False otherwise - """ - # Allow GitHub Actions expressions - if self.is_github_expression(key_prefix): - return True - - # Check for command injection using base validator - return self.validate_security_patterns(key_prefix, "key-prefix") - - def validate_key_files(self, key_files: str) -> bool: - """Validate key files (comma-separated). - - Args: - key_files: Comma-separated file paths - - Returns: - True if valid, False otherwise - """ - # Allow GitHub Actions expressions - if self.is_github_expression(key_files): - return True - - # Split files and validate each - file_list = [f.strip() for f in key_files.split(",")] - - for file_path in file_list: - if not file_path: - continue - - # Use FileValidator for path validation - result = self.file_validator.validate_file_path(file_path, "key-files") - # Propagate errors from file validator - 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: - return False - - return True - - def validate_restore_keys(self, restore_keys: str) -> bool: - """Validate restore keys. - - Args: - restore_keys: Restore keys specification - - Returns: - True if valid, False otherwise - """ - # Allow GitHub Actions expressions - if self.is_github_expression(restore_keys): - return True - - # Check for command injection using base validator - return self.validate_security_patterns(restore_keys, "restore-keys") - - def validate_env_vars(self, env_vars: str) -> bool: - """Validate environment variables. - - Args: - env_vars: Environment variables specification - - Returns: - True if valid, False otherwise - """ - # Allow GitHub Actions expressions - if self.is_github_expression(env_vars): - return True - - # Check for command injection using base validator - return self.validate_security_patterns(env_vars, "env-vars") diff --git a/common-cache/README.md b/common-cache/README.md deleted file mode 100644 index bfae5c9..0000000 --- a/common-cache/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# ivuorinen/actions/common-cache - -## Common Cache - -### Description - -Standardized caching strategy for all actions - -### Inputs - -| name | description | required | default | -|----------------|------------------------------------------------------|----------|---------| -| `type` |

Type of cache (npm, composer, go, pip, etc.)

| `true` | `""` | -| `paths` |

Paths to cache (comma-separated)

| `true` | `""` | -| `key-prefix` |

Custom prefix for cache key

| `false` | `""` | -| `key-files` |

Files to hash for cache key (comma-separated)

| `false` | `""` | -| `restore-keys` |

Fallback keys for cache restoration

| `false` | `""` | -| `env-vars` |

Environment variables to include in cache key

| `false` | `""` | - -### Outputs - -| name | description | -|---------------|-----------------------------| -| `cache-hit` |

Cache hit indicator

| -| `cache-key` |

Generated cache key

| -| `cache-paths` |

Resolved cache paths

| - -### Runs - -This action is a `composite` action. - -### Usage - -```yaml -- uses: ivuorinen/actions/common-cache@main - with: - type: - # Type of cache (npm, composer, go, pip, etc.) - # - # Required: true - # Default: "" - - paths: - # Paths to cache (comma-separated) - # - # Required: true - # Default: "" - - key-prefix: - # Custom prefix for cache key - # - # Required: false - # Default: "" - - key-files: - # Files to hash for cache key (comma-separated) - # - # Required: false - # Default: "" - - restore-keys: - # Fallback keys for cache restoration - # - # Required: false - # Default: "" - - env-vars: - # Environment variables to include in cache key - # - # Required: false - # Default: "" -``` diff --git a/common-cache/action.yml b/common-cache/action.yml deleted file mode 100644 index 23d6306..0000000 --- a/common-cache/action.yml +++ /dev/null @@ -1,122 +0,0 @@ -# yaml-language-server: $schema=https://json.schemastore.org/github-action.json -# permissions: -# - contents: read # Required for reading cache contents ---- -name: Common Cache -description: 'Standardized caching strategy for all actions' -author: 'Ismo Vuorinen' - -branding: - icon: database - color: gray-dark - -inputs: - type: - description: 'Type of cache (npm, composer, go, pip, etc.)' - required: true - paths: - description: 'Paths to cache (comma-separated)' - required: true - key-prefix: - description: 'Custom prefix for cache key' - required: false - default: '' - key-files: - description: 'Files to hash for cache key (comma-separated)' - required: false - default: '' - restore-keys: - description: 'Fallback keys for cache restoration' - required: false - default: '' - env-vars: - description: 'Environment variables to include in cache key' - required: false - default: '' - -outputs: - cache-hit: - description: 'Cache hit indicator' - value: ${{ steps.cache.outputs.cache-hit }} - cache-key: - description: 'Generated cache key' - value: ${{ steps.prepare.outputs.cache-key }} - cache-paths: - description: 'Resolved cache paths' - value: ${{ steps.prepare.outputs.cache-paths }} - -runs: - using: composite - steps: - - id: prepare - shell: bash - env: - RUNNER_OS: ${{ runner.os }} - CACHE_TYPE: ${{ inputs.type }} - KEY_PREFIX: ${{ inputs.key-prefix }} - KEY_FILES: ${{ inputs.key-files }} - ENV_VARS: ${{ inputs.env-vars }} - CACHE_PATHS: ${{ inputs.paths }} - run: | - set -euo pipefail - - # Generate standardized cache key components - os_key="$RUNNER_OS" - type_key="$CACHE_TYPE" - prefix_key="$KEY_PREFIX" - - # Process file hashes - # Note: For simple glob patterns, hashFiles() function could be used directly - # in the cache key. This manual approach is used to support comma-separated - # file lists with complex cache key construction. - files_hash="" - if [ -n "$KEY_FILES" ]; then - IFS=',' read -ra FILES <<< "$KEY_FILES" - existing_files=() - for file in "${FILES[@]}"; do - # Trim whitespace - file=$(echo "$file" | xargs) - if [ -f "$file" ]; then - existing_files+=("$file") - fi - done - # Hash all files together for better performance - if [ ${#existing_files[@]} -gt 0 ]; then - files_hash=$(cat "${existing_files[@]}" | sha256sum | cut -d' ' -f1) - fi - fi - - # Process environment variables - env_hash="" - if [ -n "$ENV_VARS" ]; then - IFS=',' read -ra VARS <<< "$ENV_VARS" - for var in "${VARS[@]}"; do - if [ -n "${!var}" ]; then - env_hash="${env_hash}-${var}-${!var}" - fi - done - fi - - # Generate final cache key - cache_key="${os_key}" - [ -n "$prefix_key" ] && cache_key="${cache_key}-${prefix_key}" - [ -n "$type_key" ] && cache_key="${cache_key}-${type_key}" - [ -n "$files_hash" ] && cache_key="${cache_key}-${files_hash}" - [ -n "$env_hash" ] && cache_key="${cache_key}-${env_hash}" - - echo "cache-key=${cache_key}" >> $GITHUB_OUTPUT - - # Process cache paths - IFS=',' read -ra PATHS <<< "$CACHE_PATHS" - cache_paths="" - for path in "${PATHS[@]}"; do - cache_paths="${cache_paths}${path}\n" - done - echo "cache-paths=${cache_paths}" >> $GITHUB_OUTPUT - - - id: cache - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: ${{ steps.prepare.outputs.cache-paths }} - key: ${{ steps.prepare.outputs.cache-key }} - restore-keys: ${{ inputs.restore-keys }} diff --git a/common-cache/rules.yml b/common-cache/rules.yml deleted file mode 100644 index 5f5df4c..0000000 --- a/common-cache/rules.yml +++ /dev/null @@ -1,42 +0,0 @@ ---- -# Validation rules for common-cache action -# Generated by update-validators.py v1.0.0 - DO NOT EDIT MANUALLY -# Schema version: 1.0 -# Coverage: 50% (3/6 inputs) -# -# This file defines validation rules for the common-cache GitHub Action. -# Rules are automatically applied by validate-inputs action when this -# action is used. -# - -schema_version: '1.0' -action: common-cache -description: Standardized caching strategy for all actions -generator_version: 1.0.0 -required_inputs: - - paths - - type -optional_inputs: - - env-vars - - key-files - - key-prefix - - restore-keys -conventions: - key-files: file_path - key-prefix: prefix - paths: file_path -overrides: {} -statistics: - total_inputs: 6 - validated_inputs: 3 - skipped_inputs: 0 - coverage_percentage: 50 -validation_coverage: 50 -auto_detected: true -manual_review_required: true -quality_indicators: - has_required_inputs: true - has_token_validation: false - has_version_validation: false - has_file_validation: true - has_security_validation: false diff --git a/validate-inputs/tests/test_common-cache_custom.py b/validate-inputs/tests/test_common-cache_custom.py deleted file mode 100644 index b4cc5e3..0000000 --- a/validate-inputs/tests/test_common-cache_custom.py +++ /dev/null @@ -1,74 +0,0 @@ -"""Tests for common-cache custom validator. - -Generated by generate-tests.py - Do not edit manually. -""" -# pylint: disable=invalid-name # Test file name matches action name - -import sys -from pathlib import Path - -# Add action directory to path to import custom validator -action_path = Path(__file__).parent.parent.parent / "common-cache" -sys.path.insert(0, str(action_path)) - -# pylint: disable=wrong-import-position -from CustomValidator import CustomValidator - - -class TestCustomCommonCacheValidator: - """Test cases for common-cache custom validator.""" - - def setup_method(self): - """Set up test fixtures.""" - self.validator = CustomValidator("common-cache") - - def teardown_method(self): - """Clean up after tests.""" - self.validator.clear_errors() - - def test_validate_inputs_valid(self): - """Test validation with valid inputs.""" - # TODO: Add specific valid inputs for common-cache - inputs = {} - result = self.validator.validate_inputs(inputs) - # Adjust assertion based on required inputs - assert isinstance(result, bool) - - def test_validate_inputs_invalid(self): - """Test validation with invalid inputs.""" - # TODO: Add specific invalid inputs for common-cache - inputs = {"invalid_key": "invalid_value"} - result = self.validator.validate_inputs(inputs) - # Custom validators may have specific validation rules - assert isinstance(result, bool) - - def test_required_inputs(self): - """Test required inputs detection.""" - required = self.validator.get_required_inputs() - assert isinstance(required, list) - # TODO: Assert specific required inputs for common-cache - - def test_validation_rules(self): - """Test validation rules.""" - rules = self.validator.get_validation_rules() - assert isinstance(rules, dict) - # TODO: Assert specific validation rules for common-cache - - def test_github_expressions(self): - """Test GitHub expression handling.""" - inputs = { - "test_input": "${{ github.token }}", - } - result = self.validator.validate_inputs(inputs) - assert isinstance(result, bool) - # GitHub expressions should generally be accepted - - def test_error_propagation(self): - """Test error propagation from sub-validators.""" - # Custom validators often use sub-validators - # Test that errors are properly propagated - inputs = {"test": "value"} - self.validator.validate_inputs(inputs) - # Check error handling - if self.validator.has_errors(): - assert len(self.validator.errors) > 0