fix(deps): replace step-security/retry and update action pins (#468)

* fix(deps): replace step-security/retry with nick-fields/retry

* chore(deps): update github action sha pins via pinact

* refactor: remove common-retry references from tests and validators

* chore: simplify description fallback and update action count

* docs: remove hardcoded test counts from memory and docs

Replace exact "769 tests" references with qualitative language
so these files don't go stale as test count grows.
This commit is contained in:
2026-03-02 02:31:26 +02:00
committed by GitHub
parent d919327c7e
commit bd59245cd7
18 changed files with 29 additions and 127 deletions

View File

@@ -80,7 +80,7 @@ jobs:
category: github-actions-tests category: github-actions-tests
- name: Upload unit test results - name: Upload unit test results
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
if: always() if: always()
with: with:
name: unit-test-results name: unit-test-results
@@ -133,7 +133,7 @@ jobs:
fi fi
- name: Upload integration test results - name: Upload integration test results
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
if: always() && steps.check-integration-reports.outputs.reports-found == 'true' if: always() && steps.check-integration-reports.outputs.reports-found == 'true'
with: with:
name: integration-test-results name: integration-test-results
@@ -167,7 +167,7 @@ jobs:
run: make test-coverage run: make test-coverage
- name: Upload coverage report - name: Upload coverage report
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: coverage-report name: coverage-report
path: _tests/coverage/ path: _tests/coverage/
@@ -263,7 +263,7 @@ jobs:
steps: steps:
- name: Download test results - name: Download test results
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with: with:
pattern: '*-test-results' pattern: '*-test-results'
merge-multiple: true merge-multiple: true

View File

@@ -5,28 +5,28 @@
- **Path**: /Users/ivuorinen/Code/ivuorinen/actions - **Path**: /Users/ivuorinen/Code/ivuorinen/actions
- **Branch**: main - **Branch**: main
- **External Usage**: `ivuorinen/actions/<action-name>@main` - **External Usage**: `ivuorinen/actions/<action-name>@main`
- **Total Actions**: 44 self-contained actions - **Total Actions**: 43 self-contained actions
- **Dogfooding**: Workflows use local actions (pr-lint, codeql-analysis, security-scan) - **Dogfooding**: Workflows use local actions (pr-lint, codeql-analysis, security-scan)
## Structure ## Structure
```text ```text
/ /
├── <action-dirs>/ # 44 self-contained actions ├── <action-dirs>/ # 43 self-contained actions
│ ├── action.yml # Action definition │ ├── action.yml # Action definition
│ ├── README.md # Auto-generated │ ├── README.md # Auto-generated
│ └── CustomValidator.py # Optional validator │ └── CustomValidator.py # Optional validator
├── validate-inputs/ # Centralized validation ├── validate-inputs/ # Centralized validation
│ ├── validators/ # 9 specialized modules │ ├── validators/ # 9 specialized modules
│ ├── scripts/ # Rule/test generators │ ├── scripts/ # Rule/test generators
│ └── tests/ # 769 pytest tests │ └── tests/ # pytest tests
├── _tests/ # ShellSpec framework ├── _tests/ # ShellSpec framework
├── _tools/ # Development utilities ├── _tools/ # Development utilities
├── .github/workflows/ # CI/CD workflows ├── .github/workflows/ # CI/CD workflows
└── Makefile # Build automation └── Makefile # Build automation
``` ```
## Action Categories (44 total) ## Action Categories (43 total)
**Setup (7)**: node-setup, set-git-config, php-version-detect, python-version-detect, python-version-detect-v2, go-version-detect, dotnet-version-detect **Setup (7)**: node-setup, set-git-config, php-version-detect, python-version-detect, python-version-detect-v2, go-version-detect, dotnet-version-detect
@@ -40,7 +40,7 @@
**Testing (3)**: php-tests, php-laravel-phpunit, php-composer **Testing (3)**: php-tests, php-laravel-phpunit, php-composer
**Repository (9)**: github-release, release-monthly, sync-labels, stale, compress-images, common-cache, common-file-check, common-retry, codeql-analysis **Repository (8)**: github-release, release-monthly, sync-labels, stale, compress-images, common-cache, common-file-check, codeql-analysis
**Utilities (3)**: version-file-parser, version-validator, validate-inputs **Utilities (3)**: version-file-parser, version-validator, validate-inputs
@@ -77,12 +77,12 @@ make test # All tests (pytest + ShellSpec)
## Testing Framework ## Testing Framework
- **ShellSpec**: GitHub Actions and shell scripts - **ShellSpec**: GitHub Actions and shell scripts
- **pytest**: Python validators (769 tests, 100% pass rate) - **pytest**: Python validators (100% pass rate)
- **Test Generator**: Automatic scaffolding for new actions - **Test Generator**: Automatic scaffolding for new actions
## Current Status ## Current Status
- ✅ All tests passing (769/769) - ✅ All tests passing
- ✅ Zero linting issues - ✅ Zero linting issues
- ✅ Modular validator architecture - ✅ Modular validator architecture
- ✅ Convention-based validation - ✅ Convention-based validation

View File

@@ -2,7 +2,7 @@
## Status: PRODUCTION READY ✅ ## Status: PRODUCTION READY ✅
- 769 tests passing (100%) - All tests passing (100%)
- Zero linting issues - Zero linting issues
- Modular architecture complete - Modular architecture complete
@@ -60,7 +60,7 @@ validate-inputs/
├── scripts/ ├── scripts/
│ ├── update-validators.py # Rule generator │ ├── update-validators.py # Rule generator
│ └── generate-tests.py # Test generator │ └── generate-tests.py # Test generator
└── tests/ # 769 pytest tests └── tests/ # pytest tests
<action>/CustomValidator.py # Action-specific validators <action>/CustomValidator.py # Action-specific validators
``` ```

View File

@@ -183,9 +183,6 @@ validate_input_python "docker-build" "tag" "v1.0.0" # success
validate_input_python "pre-commit" "config-file" "config.yml" # success validate_input_python "pre-commit" "config-file" "config.yml" # success
validate_input_python "pre-commit" "config-file" "../etc/pass" # failure validate_input_python "pre-commit" "config-file" "../etc/pass" # failure
# Injection detection
validate_input_python "common-retry" "command" "echo test" # success
validate_input_python "common-retry" "command" "rm -rf /; " # failure
``` ```
### Helper Functions from spec_helper.sh ### Helper Functions from spec_helper.sh
@@ -482,11 +479,6 @@ End
✅ **Always include**: ✅ **Always include**:
```bash ```bash
It "rejects command injection"
When call validate_input_python "common-retry" "command" "rm -rf /; "
The status should be failure
End
It "rejects path traversal" It "rejects path traversal"
When call validate_input_python "pre-commit" "config-file" "../etc/passwd" When call validate_input_python "pre-commit" "config-file" "../etc/passwd"
The status should be failure The status should be failure

View File

@@ -264,7 +264,7 @@ def get_input_property(action_file: str, input_name: str, property_check: str) -
if property_check == "description": if property_check == "description":
description = input_data.get("description", "") description = input_data.get("description", "")
return description if description else "no-description" return description or "no-description"
if property_check == "all_optional": if property_check == "all_optional":
# Check if all inputs are optional (none are required) # Check if all inputs are optional (none are required)

View File

@@ -337,7 +337,7 @@ class ValidationCore:
""" """
if not value: # Empty values are generally allowed, except for specific cases if not value: # Empty values are generally allowed, except for specific cases
# Some inputs should not be empty even if they're optional # Some inputs should not be empty even if they're optional
if action_name == "php-composer" and input_name in ["composer-version"]: if action_name == "php-composer" and input_name == "composer-version":
return False, f"Empty {input_name} is not allowed" return False, f"Empty {input_name} is not allowed"
return None, "" return None, ""
@@ -552,7 +552,7 @@ class ActionFileParser:
def _get_description_property(input_data: dict) -> str: def _get_description_property(input_data: dict) -> str:
"""Get the description property.""" """Get the description property."""
description = input_data.get("description", "") description = input_data.get("description", "")
return description if description else "no-description" return description or "no-description"
@staticmethod @staticmethod
def _get_all_optional_property(inputs: dict) -> str: def _get_all_optional_property(inputs: dict) -> str:

View File

@@ -92,9 +92,6 @@ setup_default_inputs() {
"go-build" | "go-lint") "go-build" | "go-lint")
[[ "$input_name" != "go-version" ]] && export INPUT_GO_VERSION="1.21" [[ "$input_name" != "go-version" ]] && export INPUT_GO_VERSION="1.21"
;; ;;
"common-retry")
[[ "$input_name" != "command" ]] && export INPUT_COMMAND="echo test"
;;
"dotnet-version-detect") "dotnet-version-detect")
[[ "$input_name" != "default-version" ]] && export INPUT_DEFAULT_VERSION="8.0" [[ "$input_name" != "default-version" ]] && export INPUT_DEFAULT_VERSION="8.0"
;; ;;
@@ -154,9 +151,6 @@ cleanup_default_inputs() {
"go-build" | "go-lint") "go-build" | "go-lint")
[[ "$input_name" != "go-version" ]] && unset INPUT_GO_VERSION [[ "$input_name" != "go-version" ]] && unset INPUT_GO_VERSION
;; ;;
"common-retry")
[[ "$input_name" != "command" ]] && unset INPUT_COMMAND
;;
"dotnet-version-detect") "dotnet-version-detect")
[[ "$input_name" != "default-version" ]] && unset INPUT_DEFAULT_VERSION [[ "$input_name" != "default-version" ]] && unset INPUT_DEFAULT_VERSION
;; ;;
@@ -239,12 +233,6 @@ shellspec_mock_action_run() {
"common-file-check") "common-file-check")
echo "found=true" >>"$GITHUB_OUTPUT" echo "found=true" >>"$GITHUB_OUTPUT"
;; ;;
"common-retry")
echo "success=true" >>"$GITHUB_OUTPUT"
echo "attempts=1" >>"$GITHUB_OUTPUT"
echo "exit-code=0" >>"$GITHUB_OUTPUT"
echo "duration=5" >>"$GITHUB_OUTPUT"
;;
"compress-images") "compress-images")
echo "images_compressed=true" >>"$GITHUB_OUTPUT" echo "images_compressed=true" >>"$GITHUB_OUTPUT"
printf "compression_report=## Compression Results\n- 3 images compressed\n- 25%% size reduction\n" >>"$GITHUB_OUTPUT" printf "compression_report=## Compression Results\n- 3 images compressed\n- 25%% size reduction\n" >>"$GITHUB_OUTPUT"

View File

@@ -83,7 +83,7 @@ runs:
- name: Install ansible-lint - name: Install ansible-lint
id: install-ansible-lint id: install-ansible-lint
if: steps.check-files.outputs.files_found == 'true' if: steps.check-files.outputs.files_found == 'true'
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4 uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
with: with:
timeout_minutes: 5 timeout_minutes: 5
max_attempts: ${{ inputs.max-retries }} max_attempts: ${{ inputs.max-retries }}

View File

@@ -155,7 +155,7 @@ runs:
cache-dependency-path: '**/packages.lock.json' cache-dependency-path: '**/packages.lock.json'
- name: Restore Dependencies - name: Restore Dependencies
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4 uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
with: with:
timeout_minutes: 10 timeout_minutes: 10
max_attempts: ${{ inputs.max-retries }} max_attempts: ${{ inputs.max-retries }}
@@ -203,7 +203,7 @@ runs:
- name: Upload Test Results - name: Upload Test Results
if: always() if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: csharp-test-results name: csharp-test-results
path: | path: |

View File

@@ -169,7 +169,7 @@ runs:
cache-dependency-path: '**/packages.lock.json' cache-dependency-path: '**/packages.lock.json'
- name: Restore Dependencies - name: Restore Dependencies
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4 uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
with: with:
timeout_minutes: 10 timeout_minutes: 10
max_attempts: ${{ inputs.max-retries }} max_attempts: ${{ inputs.max-retries }}

View File

@@ -159,13 +159,13 @@ runs:
echo "Final detected Go version: $detected_version" >&2 echo "Final detected Go version: $detected_version" >&2
- name: Setup Go - name: Setup Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with: with:
go-version: ${{ steps.detect-go-version.outputs.detected-version }} go-version: ${{ steps.detect-go-version.outputs.detected-version }}
cache: true cache: true
- name: Download Dependencies - name: Download Dependencies
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4 uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
with: with:
timeout_minutes: 10 timeout_minutes: 10
max_attempts: ${{ inputs.max-retries }} max_attempts: ${{ inputs.max-retries }}
@@ -253,7 +253,7 @@ runs:
- name: Upload Build Artifacts - name: Upload Build Artifacts
if: always() if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: go-build-artifacts name: go-build-artifacts
path: | path: |

View File

@@ -205,7 +205,7 @@ runs:
validate_linter_list "$DISABLE_LINTERS" "disable-linters" validate_linter_list "$DISABLE_LINTERS" "disable-linters"
- name: Setup Go - name: Setup Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with: with:
go-version: ${{ inputs.go-version }} go-version: ${{ inputs.go-version }}
cache: true cache: true

View File

@@ -376,7 +376,7 @@ runs:
composer clear-cache composer clear-cache
- name: Install Composer Dependencies - name: Install Composer Dependencies
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4 uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
with: with:
timeout_minutes: 10 timeout_minutes: 10
max_attempts: ${{ inputs.max-retries }} max_attempts: ${{ inputs.max-retries }}

View File

@@ -621,7 +621,7 @@ runs:
- name: Setup Go - name: Setup Go
if: steps.detect-go.outputs.found == 'true' if: steps.detect-go.outputs.found == 'true'
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with: with:
go-version: ${{ steps.go-version.outputs.detected-version }} go-version: ${{ steps.go-version.outputs.detected-version }}
cache: true cache: true
@@ -677,7 +677,7 @@ runs:
# Upload MegaLinter artifacts # Upload MegaLinter artifacts
- name: Archive production artifacts - name: Archive production artifacts
if: success() || failure() if: success() || failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: MegaLinter reports name: MegaLinter reports
include-hidden-files: 'true' include-hidden-files: 'true'

View File

@@ -175,7 +175,7 @@ runs:
- name: Archive security reports - name: Archive security reports
if: always() if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: security-reports-${{ github.run_id }} name: security-reports-${{ github.run_id }}
path: | path: |

View File

@@ -332,7 +332,7 @@ class CustomValidator(BaseValidator):
## Quality Metrics ## Quality Metrics
- **Test Coverage**: 100% (769 tests) - **Test Coverage**: 100%
- **Validators**: 9 specialized + unlimited custom - **Validators**: 9 specialized + unlimited custom
- **Performance**: < 10ms typical validation time - **Performance**: < 10ms typical validation time
- **Zero Dependencies**: Uses only Python stdlib + PyYAML - **Zero Dependencies**: Uses only Python stdlib + PyYAML

View File

@@ -310,10 +310,6 @@ class ValidationRuleGenerator:
"common-file-check": { "common-file-check": {
"file-pattern": "file_path", "file-pattern": "file_path",
}, },
"common-retry": {
"backoff-strategy": "backoff_strategy",
"shell": "shell_type",
},
"docker-publish": { "docker-publish": {
"registry": "registry_enum", "registry": "registry_enum",
"cache-mode": "cache_mode", "cache-mode": "cache_mode",

View File

@@ -1,74 +0,0 @@
"""Tests for common-retry 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-retry"
sys.path.insert(0, str(action_path))
# pylint: disable=wrong-import-position
from CustomValidator import CustomValidator
class TestCustomCommonRetryValidator:
"""Test cases for common-retry custom validator."""
def setup_method(self):
"""Set up test fixtures."""
self.validator = CustomValidator("common-retry")
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-retry
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-retry
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-retry
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-retry
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