Files
actions/validate-inputs
Ismo Vuorinen ab371bdebf feat: simplify actions (#353)
* feat: first pass simplification

* refactor: simplify actions repository structure

Major simplification reducing actions from 44 to 30:

Consolidations:
- Merge biome-check + biome-fix → biome-lint (mode: check/fix)
- Merge eslint-check + eslint-fix → eslint-lint (mode: check/fix)
- Merge prettier-check + prettier-fix → prettier-lint (mode: check/fix)
- Merge 5 version-detect actions → language-version-detect (language param)

Removals:
- common-file-check, common-retry (better served by external tools)
- docker-publish-gh, docker-publish-hub (consolidated into docker-publish)
- github-release (redundant with existing tooling)
- set-git-config (no longer needed)
- version-validator (functionality moved to language-version-detect)

Fixes:
- Rewrite docker-publish to use official Docker actions directly
- Update validate-inputs example (eslint-fix → eslint-lint)
- Update tests and documentation for new structure

Result: ~6,000 lines removed, cleaner action catalog, maintained functionality.

* refactor: complete action simplification and cleanup

Remove deprecated actions and update remaining actions:

Removed:
- common-file-check, common-retry: utility actions
- docker-publish-gh, docker-publish-hub: replaced by docker-publish wrapper
- github-release, version-validator, set-git-config: no longer needed
- Various version-detect actions: replaced by language-version-detect

Updated:
- docker-publish: rewrite as simple wrapper using official Docker actions
- validate-inputs: update example (eslint-fix → eslint-lint)
- Multiple actions: update configurations and remove deprecated dependencies
- Tests: update integration/unit tests for new structure
- Documentation: update README, remove test for deleted actions

Configuration updates:
- Linter configs, ignore files for new structure
- Makefile, pyproject.toml updates

* fix: enforce POSIX compliance in GitHub workflows

Convert all workflow shell scripts to POSIX-compliant sh:

Critical fixes:
- Replace bash with sh in all shell declarations
- Replace [[ with [ for test conditions
- Replace == with = for string comparisons
- Replace set -euo pipefail with set -eu
- Split compound AND conditions into separate [ ] tests

Files updated:
- .github/workflows/test-actions.yml (7 shell declarations, 10 test operators)
- .github/workflows/security-suite.yml (set -eu)
- .github/workflows/action-security.yml (2 shell declarations)
- .github/workflows/pr-lint.yml (3 shell declarations)
- .github/workflows/issue-stats.yml (1 shell declaration)

Ensures compatibility with minimal sh implementations and aligns with
CLAUDE.md standards requiring POSIX shell compliance across all scripts.

All tests pass: 764 pytest tests, 100% coverage.

* fix: add missing permissions for private repository support

Add critical permissions to pr-lint workflow for private repositories:

Workflow-level permissions:
+ packages: read - Access private npm/PyPI/Composer packages

Job-level permissions:
+ packages: read - Access private packages during dependency installation
+ checks: write - Create and update check runs

Fixes failures when:
- Installing private npm packages from GitHub Packages
- Installing private Composer dependencies
- Installing private Python packages
- Creating status checks with github-script

Valid permission scopes per actionlint:
actions, attestations, checks, contents, deployments, discussions,
id-token, issues, models, packages, pages, pull-requests,
repository-projects, security-events, statuses

Note: "workflows" and "metadata" are NOT valid permission scopes
(they are PAT-only scopes or auto-granted respectively).

* docs: update readmes

* fix: replace bash-specific 'source' with POSIX '.' command

Replace all occurrences of 'source' with '.' (dot) for POSIX compliance:

Changes in python-lint-fix/action.yml:
- Line 165: source .venv/bin/activate → . .venv/bin/activate
- Line 179: source .venv/bin/activate → . .venv/bin/activate
- Line 211: source .venv/bin/activate → . .venv/bin/activate

Also fixed bash-specific test operator:
- Line 192: [[ "$FAIL_ON_ERROR" == "true" ]] → [ "$FAIL_ON_ERROR" = "true" ]

The 'source' command is bash-specific. POSIX sh uses '.' (dot) to source files.
Both commands have identical functionality but '.' is portable across all
POSIX-compliant shells.

* security: fix code injection vulnerability in docker-publish

Fix CodeQL code injection warning (CWE-094, CWE-095, CWE-116):

Issue: inputs.context was used directly in GitHub Actions expression
without sanitization at line 194, allowing potential code injection
by external users.

Fix: Use environment variable indirection to prevent expression injection:
- Added env.BUILD_CONTEXT to capture inputs.context
- Changed context parameter to use ${{ env.BUILD_CONTEXT }}

Environment variables are evaluated after expression compilation,
preventing malicious code execution during workflow parsing.

Security Impact: Medium severity (CVSS 5.0)
Identified by: GitHub Advanced Security (CodeQL)
Reference: https://github.com/ivuorinen/actions/pull/353#pullrequestreview-3481935924

* security: prevent credential persistence in pr-lint checkout

Add persist-credentials: false to checkout step to mitigate untrusted
checkout vulnerability. This prevents GITHUB_TOKEN from being accessible
to potentially malicious PR code.

Fixes: CodeQL finding CWE-829 (untrusted checkout on privileged workflow)

* fix: prevent security bot from overwriting unrelated comments

Replace broad string matching with unique HTML comment marker for
identifying bot-generated comments. Previously, any comment containing
'Security Analysis' or '🔐 GitHub Actions Permissions' would be
overwritten, causing data loss.

Changes:
- Add unique marker: <!-- security-analysis-bot-comment -->
- Prepend marker to generated comment body
- Update comment identification to use marker only
- Add defensive null check for comment.body

This fixes critical data loss bug where user comments could be
permanently overwritten by the security analysis bot.

Follows same proven pattern as test-actions.yml coverage comments.

* improve: show concise permissions diff instead of full blocks

Replace verbose full-block permissions diff with line-by-line changes.
Now shows only added/removed permissions, making output much more
readable.

Changes:
- Parse permissions into individual lines
- Compare old vs new to identify actual changes
- Show only removed (-) and added (+) lines in diff
- Collapse unchanged permissions into details section (≤3 items)
- Show count summary for many unchanged permissions (>3 items)

Example output:
  Before: 30+ lines showing entire permissions block
  After: 3-5 lines showing only what changed

This addresses user feedback that permissions changes were too verbose.

* security: add input validation and trust model documentation

Add comprehensive security validation for docker-publish action to prevent
code injection attacks (CWE-094, CWE-116).

Changes:
- Add validation for context input (reject absolute paths, warn on URLs)
- Add validation for dockerfile input (reject absolute/URL paths)
- Document security trust model in README
- Add best practices for secure usage
- Explain validation rules and threat model

Prevents malicious actors from:
- Building from arbitrary file system locations
- Fetching Dockerfiles from untrusted remote sources
- Executing code injection through build context manipulation

Addresses: CodeRabbit review comments #2541434325, #2541549615
Fixes: GitHub Advanced Security code injection findings

* security: replace unmaintained nick-fields/retry with step-security/retry

Replace nick-fields/retry with step-security/retry across all 4 actions:
- csharp-build/action.yml
- php-composer/action.yml
- go-build/action.yml
- ansible-lint-fix/action.yml

The nick-fields/retry action has security vulnerabilities and low maintenance.
step-security/retry is a drop-in replacement with full API compatibility.

All inputs (timeout_minutes, max_attempts, command, retry_wait_seconds) are
compatible. Using SHA-pinned version for security.

Addresses CodeRabbit review comment #2541549598

* test: add is_input_required() helper function

Add helper function to check if an action input is required, reducing
duplication across test suites.

The function:
- Takes action_file and input_name as parameters
- Uses validation_core.py to query the 'required' property
- Returns 0 (success) if input is required
- Returns 1 (failure) if input is optional

This DRY improvement addresses CodeRabbit review comment #2541549572

* feat: add mode validation convention mapping

Add "mode" to the validation conventions mapping for lint actions
(eslint-lint, biome-lint, prettier-lint).

Note: The update-validators script doesn't currently recognize "string"
as a validator type, so mode validation coverage remains at 93%. The
actions already have inline validation for mode (check|fix), so this is
primarily for improving coverage metrics.

Addresses part of CodeRabbit review comment #2541549570
(validation coverage improvement)

* docs: fix CLAUDE.md action counts and add missing action

- Update action count from 31 to 29 (line 42)
- Add missing 'action-versioning' to Utilities category (line 74)

Addresses CodeRabbit review comments #2541553130 and #2541553110

* docs: add security considerations to docker-publish

Add security documentation to both action.yml header and README.md:
- Trust model explanation
- Input validation details for context and dockerfile
- Attack prevention information
- Best practices for secure usage

The documentation was previously removed when README was autogenerated.
Now documented in both places to ensure it persists.

* fix: correct step ID reference in docker-build

Fix incorrect step ID reference in platforms output:
- Changed steps.platforms.outputs.built to steps.detect-platforms.outputs.platforms
- The step is actually named 'detect-platforms' not 'platforms'
- Ensures output correctly references the detect-platforms step defined at line 188

* fix: ensure docker-build platforms output is always available

Make detect-platforms step unconditional to fix broken output contract.

The platforms output (line 123) references steps.detect-platforms.outputs.platforms,
but the step only ran when auto-detect-platforms was true (default: false).
This caused undefined output in most cases.

Changes:
- Remove 'if' condition from detect-platforms step
- Step now always runs and always produces platforms output
- When auto-detect is false: outputs configured architectures
- When auto-detect is true: outputs detected platforms or falls back to architectures
- Add '|| true' to grep to prevent errors when no platforms detected

Fixes CodeRabbit review comment #2541824904

* security: remove env var indirection in docker-publish BUILD_CONTEXT

Remove BUILD_CONTEXT env var indirection to address GitHub Advanced Security alert.

The inputs.context is validated at lines 137-147 (rejects absolute paths, warns on URLs)
before being used, so the env var indirection is unnecessary and triggers false positive
code injection warnings.

Changes:
- Remove BUILD_CONTEXT env var (line 254)
- Use inputs.context directly (line 256 → 254)
- Input validation remains in place (lines 137-147)

Fixes GitHub Advanced Security code injection alerts (comments #2541405269, #2541522320)

* feat: implement mode_enum validator for lint actions

Add mode_enum validator to validate mode inputs in linting actions.

Changes to conventions.py:
- Add 'mode_enum' to exact_matches mapping (line 215)
- Add 'mode_enum' to PHP-specific validators list (line 560)
- Implement _validate_mode_enum() method (lines 642-660)
  - Validates mode values against ['check', 'fix']
  - Returns clear error messages for invalid values

Updated rules.yml files:
- biome-lint: Add mode: mode_enum convention
- eslint-lint: Add mode: mode_enum convention
- prettier-lint: Add mode: mode_enum convention
- All rules.yml: Fix YAML formatting with yamlfmt

This addresses PR #353 comment #2541522326 which reported that mode validation
was being skipped due to unrecognized 'string' type, reducing coverage to 93%.

Tested with biome-lint action - correctly rejects invalid values and accepts
valid 'check' and 'fix' values.

* docs: update action count from 29 to 30 in CLAUDE.md

Update two references to action count in CLAUDE.md:
- Line 42: repository_overview memory description
- Line 74: Repository Structure section header

The repository has 30 actions total (29 listed + validate-inputs).

Addresses PR #353 comment #2541549588.

* docs: use pinned version ref in language-version-detect README

Change usage example from @main to @v2025 for security best practices.

Using pinned version refs (instead of @main) ensures:
- Predictable behavior across workflow runs
- Protection against breaking changes
- Better security through immutable references

Follows repository convention documented in main README and CLAUDE.md.

Addresses PR #353 comment #2541549588.

* refactor: remove deprecated add-snippets input from codeql-analysis

Remove add-snippets input which has been deprecated by GitHub's CodeQL action
and no longer has any effect.

Changes:
- Remove add-snippets input definition (lines 93-96)
- Remove reference in init step (line 129)
- Remove reference in analyze step (line 211)
- Regenerate README and rules.yml

This is a non-breaking change since:
- Default was 'false' (minimal usage expected)
- GitHub's action already ignores this parameter
- Aligns with recent repository simplification efforts

* feat: add mode_enum validator and update rules

Add mode_enum validator support for lint actions and regenerate all validation rules:

Validator Changes:
- Add mode_enum to action_overrides for biome-lint, eslint-lint, prettier-lint
- Remove deprecated add-snippets from codeql-analysis overrides

Rules Updates:
- All 29 action rules.yml files regenerated with consistent YAML formatting
- biome-lint, eslint-lint, prettier-lint now validate mode input (check/fix)
- Improved coverage for lint actions (79% → 83% for biome, 93% for eslint, 79% for prettier)

Documentation:
- Fix language-version-detect README to use @v2025 (not @main)
- Remove outdated docker-publish security docs (now handled by official actions)

This completes PR #353 review feedback implementation.

* fix: replace bash-specific $'\n' with POSIX-compliant printf

Replace non-POSIX $'\n' syntax in tag building loop with printf-based
approach that works in any POSIX shell.

Changed:
- Line 216: tags="${tags}"$'\n'"${image}:${tag}"
+ Line 216: tags="$(printf '%s\n%s' "$tags" "${image}:${tag}")"

This ensures docker-publish/action.yml runs correctly on systems using
/bin/sh instead of bash.
2025-11-19 15:42:06 +02:00
..
2025-11-19 15:42:06 +02:00
2025-11-19 15:42:06 +02:00
2025-11-19 15:42:06 +02:00
2025-11-19 15:42:06 +02:00
2025-11-19 15:42:06 +02:00

ivuorinen/actions/validate-inputs

Validate Inputs

Description

Centralized Python-based input validation for GitHub Actions with PCRE regex support

Inputs

name description required default
action

Action name to validate (alias for action-type)

false ""
action-type

Type of action to validate (e.g., csharp-publish, docker-build, eslint-lint)

false ""
rules-file

Path to validation rules file

false ""
fail-on-error

Whether to fail on validation errors

false true
token

GitHub token for authentication

false ""
namespace

Namespace/username for validation

false ""
email

Email address for validation

false ""
username

Username for validation

false ""
dotnet-version

.NET version string

false ""
terraform-version

Terraform version string

false ""
tflint-version

TFLint version string

false ""
node-version

Node.js version string

false ""
force-version

Force version override

false ""
default-version

Default version fallback

false ""
image-name

Docker image name

false ""
tag

Docker image tag

false ""
architectures

Target architectures

false ""
dockerfile

Dockerfile path

false ""
context

Docker build context

false ""
build-args

Docker build arguments

false ""
buildx-version

Docker Buildx version

false ""
max-retries

Maximum retry attempts

false ""
image-quality

Image quality percentage

false ""
png-quality

PNG quality percentage

false ""
parallel-builds

Number of parallel builds

false ""
days-before-stale

Number of days before marking as stale

false ""
days-before-close

Number of days before closing stale items

false ""
pre-commit-config

Pre-commit configuration file path

false ""
base-branch

Base branch name

false ""
dry-run

Dry run mode

false ""
is_fiximus

Use Fiximus bot

false ""
prefix

Release tag prefix

false ""
language

Language to analyze (for CodeQL)

false ""
queries

CodeQL queries to run

false ""
packs

CodeQL query packs

false ""
config-file

CodeQL configuration file path

false ""
config

CodeQL configuration YAML string

false ""
build-mode

Build mode for compiled languages

false ""
source-root

Source code root directory

false ""
category

Analysis category

false ""
checkout-ref

Git reference to checkout

false ""
working-directory

Working directory for analysis

false ""
upload-results

Upload results to GitHub Security

false ""
ram

Memory in MB for CodeQL

false ""
threads

Number of threads for CodeQL

false ""
output

Output path for SARIF results

false ""
skip-queries

Skip running queries

false ""
add-snippets

Add code snippets to SARIF

false ""

Outputs

name description
validation-status

Overall validation status (success/failure)

error-message

Validation error message if failed

validation-result

Detailed validation result

errors-found

Number of validation errors found

rules-applied

Number of validation rules applied

Runs

This action is a composite action.

Usage

- uses: ivuorinen/actions/validate-inputs@main
  with:
    action:
    # Action name to validate (alias for action-type)
    #
    # Required: false
    # Default: ""

    action-type:
    # Type of action to validate (e.g., csharp-publish, docker-build, eslint-lint)
    #
    # Required: false
    # Default: ""

    rules-file:
    # Path to validation rules file
    #
    # Required: false
    # Default: ""

    fail-on-error:
    # Whether to fail on validation errors
    #
    # Required: false
    # Default: true

    token:
    # GitHub token for authentication
    #
    # Required: false
    # Default: ""

    namespace:
    # Namespace/username for validation
    #
    # Required: false
    # Default: ""

    email:
    # Email address for validation
    #
    # Required: false
    # Default: ""

    username:
    # Username for validation
    #
    # Required: false
    # Default: ""

    dotnet-version:
    # .NET version string
    #
    # Required: false
    # Default: ""

    terraform-version:
    # Terraform version string
    #
    # Required: false
    # Default: ""

    tflint-version:
    # TFLint version string
    #
    # Required: false
    # Default: ""

    node-version:
    # Node.js version string
    #
    # Required: false
    # Default: ""

    force-version:
    # Force version override
    #
    # Required: false
    # Default: ""

    default-version:
    # Default version fallback
    #
    # Required: false
    # Default: ""

    image-name:
    # Docker image name
    #
    # Required: false
    # Default: ""

    tag:
    # Docker image tag
    #
    # Required: false
    # Default: ""

    architectures:
    # Target architectures
    #
    # Required: false
    # Default: ""

    dockerfile:
    # Dockerfile path
    #
    # Required: false
    # Default: ""

    context:
    # Docker build context
    #
    # Required: false
    # Default: ""

    build-args:
    # Docker build arguments
    #
    # Required: false
    # Default: ""

    buildx-version:
    # Docker Buildx version
    #
    # Required: false
    # Default: ""

    max-retries:
    # Maximum retry attempts
    #
    # Required: false
    # Default: ""

    image-quality:
    # Image quality percentage
    #
    # Required: false
    # Default: ""

    png-quality:
    # PNG quality percentage
    #
    # Required: false
    # Default: ""

    parallel-builds:
    # Number of parallel builds
    #
    # Required: false
    # Default: ""

    days-before-stale:
    # Number of days before marking as stale
    #
    # Required: false
    # Default: ""

    days-before-close:
    # Number of days before closing stale items
    #
    # Required: false
    # Default: ""

    pre-commit-config:
    # Pre-commit configuration file path
    #
    # Required: false
    # Default: ""

    base-branch:
    # Base branch name
    #
    # Required: false
    # Default: ""

    dry-run:
    # Dry run mode
    #
    # Required: false
    # Default: ""

    is_fiximus:
    # Use Fiximus bot
    #
    # Required: false
    # Default: ""

    prefix:
    # Release tag prefix
    #
    # Required: false
    # Default: ""

    language:
    # Language to analyze (for CodeQL)
    #
    # Required: false
    # Default: ""

    queries:
    # CodeQL queries to run
    #
    # Required: false
    # Default: ""

    packs:
    # CodeQL query packs
    #
    # Required: false
    # Default: ""

    config-file:
    # CodeQL configuration file path
    #
    # Required: false
    # Default: ""

    config:
    # CodeQL configuration YAML string
    #
    # Required: false
    # Default: ""

    build-mode:
    # Build mode for compiled languages
    #
    # Required: false
    # Default: ""

    source-root:
    # Source code root directory
    #
    # Required: false
    # Default: ""

    category:
    # Analysis category
    #
    # Required: false
    # Default: ""

    checkout-ref:
    # Git reference to checkout
    #
    # Required: false
    # Default: ""

    working-directory:
    # Working directory for analysis
    #
    # Required: false
    # Default: ""

    upload-results:
    # Upload results to GitHub Security
    #
    # Required: false
    # Default: ""

    ram:
    # Memory in MB for CodeQL
    #
    # Required: false
    # Default: ""

    threads:
    # Number of threads for CodeQL
    #
    # Required: false
    # Default: ""

    output:
    # Output path for SARIF results
    #
    # Required: false
    # Default: ""

    skip-queries:
    # Skip running queries
    #
    # Required: false
    # Default: ""

    add-snippets:
    # Add code snippets to SARIF
    #
    # Required: false
    # Default: ""