mirror of
https://github.com/ivuorinen/actions.git
synced 2026-03-02 22:54:03 +00:00
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:
8
.github/workflows/test-actions.yml
vendored
8
.github/workflows/test-actions.yml
vendored
@@ -80,7 +80,7 @@ jobs:
|
||||
category: github-actions-tests
|
||||
|
||||
- name: Upload unit test results
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
if: always()
|
||||
with:
|
||||
name: unit-test-results
|
||||
@@ -133,7 +133,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- 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'
|
||||
with:
|
||||
name: integration-test-results
|
||||
@@ -167,7 +167,7 @@ jobs:
|
||||
run: make test-coverage
|
||||
|
||||
- name: Upload coverage report
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: coverage-report
|
||||
path: _tests/coverage/
|
||||
@@ -263,7 +263,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Download test results
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
||||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
pattern: '*-test-results'
|
||||
merge-multiple: true
|
||||
|
||||
@@ -5,28 +5,28 @@
|
||||
- **Path**: /Users/ivuorinen/Code/ivuorinen/actions
|
||||
- **Branch**: 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)
|
||||
|
||||
## Structure
|
||||
|
||||
```text
|
||||
/
|
||||
├── <action-dirs>/ # 44 self-contained actions
|
||||
├── <action-dirs>/ # 43 self-contained actions
|
||||
│ ├── action.yml # Action definition
|
||||
│ ├── README.md # Auto-generated
|
||||
│ └── CustomValidator.py # Optional validator
|
||||
├── validate-inputs/ # Centralized validation
|
||||
│ ├── validators/ # 9 specialized modules
|
||||
│ ├── scripts/ # Rule/test generators
|
||||
│ └── tests/ # 769 pytest tests
|
||||
│ └── tests/ # pytest tests
|
||||
├── _tests/ # ShellSpec framework
|
||||
├── _tools/ # Development utilities
|
||||
├── .github/workflows/ # CI/CD workflows
|
||||
└── 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
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
**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
|
||||
|
||||
@@ -77,12 +77,12 @@ make test # All tests (pytest + ShellSpec)
|
||||
## Testing Framework
|
||||
|
||||
- **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
|
||||
|
||||
## Current Status
|
||||
|
||||
- ✅ All tests passing (769/769)
|
||||
- ✅ All tests passing
|
||||
- ✅ Zero linting issues
|
||||
- ✅ Modular validator architecture
|
||||
- ✅ Convention-based validation
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Status: PRODUCTION READY ✅
|
||||
|
||||
- 769 tests passing (100%)
|
||||
- All tests passing (100%)
|
||||
- Zero linting issues
|
||||
- Modular architecture complete
|
||||
|
||||
@@ -60,7 +60,7 @@ validate-inputs/
|
||||
├── scripts/
|
||||
│ ├── update-validators.py # Rule generator
|
||||
│ └── generate-tests.py # Test generator
|
||||
└── tests/ # 769 pytest tests
|
||||
└── tests/ # pytest tests
|
||||
|
||||
<action>/CustomValidator.py # Action-specific validators
|
||||
```
|
||||
|
||||
@@ -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" "../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
|
||||
@@ -482,11 +479,6 @@ End
|
||||
✅ **Always include**:
|
||||
|
||||
```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"
|
||||
When call validate_input_python "pre-commit" "config-file" "../etc/passwd"
|
||||
The status should be failure
|
||||
|
||||
@@ -264,7 +264,7 @@ def get_input_property(action_file: str, input_name: str, property_check: str) -
|
||||
|
||||
if property_check == "description":
|
||||
description = input_data.get("description", "")
|
||||
return description if description else "no-description"
|
||||
return description or "no-description"
|
||||
|
||||
if property_check == "all_optional":
|
||||
# Check if all inputs are optional (none are required)
|
||||
|
||||
@@ -337,7 +337,7 @@ class ValidationCore:
|
||||
"""
|
||||
if not value: # Empty values are generally allowed, except for specific cases
|
||||
# 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 None, ""
|
||||
|
||||
@@ -552,7 +552,7 @@ class ActionFileParser:
|
||||
def _get_description_property(input_data: dict) -> str:
|
||||
"""Get the description property."""
|
||||
description = input_data.get("description", "")
|
||||
return description if description else "no-description"
|
||||
return description or "no-description"
|
||||
|
||||
@staticmethod
|
||||
def _get_all_optional_property(inputs: dict) -> str:
|
||||
|
||||
@@ -92,9 +92,6 @@ setup_default_inputs() {
|
||||
"go-build" | "go-lint")
|
||||
[[ "$input_name" != "go-version" ]] && export INPUT_GO_VERSION="1.21"
|
||||
;;
|
||||
"common-retry")
|
||||
[[ "$input_name" != "command" ]] && export INPUT_COMMAND="echo test"
|
||||
;;
|
||||
"dotnet-version-detect")
|
||||
[[ "$input_name" != "default-version" ]] && export INPUT_DEFAULT_VERSION="8.0"
|
||||
;;
|
||||
@@ -154,9 +151,6 @@ cleanup_default_inputs() {
|
||||
"go-build" | "go-lint")
|
||||
[[ "$input_name" != "go-version" ]] && unset INPUT_GO_VERSION
|
||||
;;
|
||||
"common-retry")
|
||||
[[ "$input_name" != "command" ]] && unset INPUT_COMMAND
|
||||
;;
|
||||
"dotnet-version-detect")
|
||||
[[ "$input_name" != "default-version" ]] && unset INPUT_DEFAULT_VERSION
|
||||
;;
|
||||
@@ -239,12 +233,6 @@ shellspec_mock_action_run() {
|
||||
"common-file-check")
|
||||
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")
|
||||
echo "images_compressed=true" >>"$GITHUB_OUTPUT"
|
||||
printf "compression_report=## Compression Results\n- 3 images compressed\n- 25%% size reduction\n" >>"$GITHUB_OUTPUT"
|
||||
|
||||
@@ -83,7 +83,7 @@ runs:
|
||||
- name: Install ansible-lint
|
||||
id: install-ansible-lint
|
||||
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:
|
||||
timeout_minutes: 5
|
||||
max_attempts: ${{ inputs.max-retries }}
|
||||
|
||||
@@ -155,7 +155,7 @@ runs:
|
||||
cache-dependency-path: '**/packages.lock.json'
|
||||
|
||||
- name: Restore Dependencies
|
||||
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4
|
||||
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
|
||||
with:
|
||||
timeout_minutes: 10
|
||||
max_attempts: ${{ inputs.max-retries }}
|
||||
@@ -203,7 +203,7 @@ runs:
|
||||
|
||||
- name: Upload Test Results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: csharp-test-results
|
||||
path: |
|
||||
|
||||
@@ -169,7 +169,7 @@ runs:
|
||||
cache-dependency-path: '**/packages.lock.json'
|
||||
|
||||
- name: Restore Dependencies
|
||||
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4
|
||||
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
|
||||
with:
|
||||
timeout_minutes: 10
|
||||
max_attempts: ${{ inputs.max-retries }}
|
||||
|
||||
@@ -159,13 +159,13 @@ runs:
|
||||
echo "Final detected Go version: $detected_version" >&2
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
with:
|
||||
go-version: ${{ steps.detect-go-version.outputs.detected-version }}
|
||||
cache: true
|
||||
|
||||
- name: Download Dependencies
|
||||
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4
|
||||
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
|
||||
with:
|
||||
timeout_minutes: 10
|
||||
max_attempts: ${{ inputs.max-retries }}
|
||||
@@ -253,7 +253,7 @@ runs:
|
||||
|
||||
- name: Upload Build Artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: go-build-artifacts
|
||||
path: |
|
||||
|
||||
@@ -205,7 +205,7 @@ runs:
|
||||
validate_linter_list "$DISABLE_LINTERS" "disable-linters"
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
with:
|
||||
go-version: ${{ inputs.go-version }}
|
||||
cache: true
|
||||
|
||||
@@ -376,7 +376,7 @@ runs:
|
||||
composer clear-cache
|
||||
|
||||
- name: Install Composer Dependencies
|
||||
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4
|
||||
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
|
||||
with:
|
||||
timeout_minutes: 10
|
||||
max_attempts: ${{ inputs.max-retries }}
|
||||
|
||||
@@ -621,7 +621,7 @@ runs:
|
||||
|
||||
- name: Setup Go
|
||||
if: steps.detect-go.outputs.found == 'true'
|
||||
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.detected-version }}
|
||||
cache: true
|
||||
@@ -677,7 +677,7 @@ runs:
|
||||
# Upload MegaLinter artifacts
|
||||
- name: Archive production artifacts
|
||||
if: success() || failure()
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: MegaLinter reports
|
||||
include-hidden-files: 'true'
|
||||
|
||||
@@ -175,7 +175,7 @@ runs:
|
||||
|
||||
- name: Archive security reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: security-reports-${{ github.run_id }}
|
||||
path: |
|
||||
|
||||
@@ -332,7 +332,7 @@ class CustomValidator(BaseValidator):
|
||||
|
||||
## Quality Metrics
|
||||
|
||||
- **Test Coverage**: 100% (769 tests)
|
||||
- **Test Coverage**: 100%
|
||||
- **Validators**: 9 specialized + unlimited custom
|
||||
- **Performance**: < 10ms typical validation time
|
||||
- **Zero Dependencies**: Uses only Python stdlib + PyYAML
|
||||
|
||||
@@ -310,10 +310,6 @@ class ValidationRuleGenerator:
|
||||
"common-file-check": {
|
||||
"file-pattern": "file_path",
|
||||
},
|
||||
"common-retry": {
|
||||
"backoff-strategy": "backoff_strategy",
|
||||
"shell": "shell_type",
|
||||
},
|
||||
"docker-publish": {
|
||||
"registry": "registry_enum",
|
||||
"cache-mode": "cache_mode",
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user