pinner 0.0.10

Secure CI/CD workflows by pinning mutable tags to immutable SHA-1 hashes. A high-performance Rust CLI that preserves YAML formatting and comments. Supports GitHub, GitLab, Bitbucket, Forgejo, and Docker image pinning.
Documentation
name: 'Pinner Actions Pinning'
description: 'Secure CI/CD workflows by hash-pinning mutable action tags and container images to immutable commit SHAs/digests.'
author: 'Fabio Falcinelli'
branding:
  icon: 'shield'
  color: 'blue'

inputs:
  command:
    description: 'The pinner subcommand to run: verify (default), pin, upgrade, set, export-sbom, scan, init.'
    required: false
    default: 'verify'
  workflows:
    description: 'Workflow files or directories to process (comma-separated or single directory).'
    required: false
  yes:
    description: 'Automatically confirm all replacements (default: true).'
    required: false
    default: 'true'
  dry-run:
    description: 'Print what would be changed without modifying any files.'
    required: false
    default: 'false'
  offline:
    description: 'Force offline mode, preventing any network requests (default: false).'
    required: false
    default: 'false'
  github-token:
    description: 'GitHub token for authentication/rate limits (defaults to github.token).'
    required: false
    default: '${{ github.token }}'
  gitlab-token:
    description: 'GitLab token for authentication.'
    required: false
  bitbucket-token:
    description: 'Bitbucket token for authentication.'
    required: false
  forgejo-token:
    description: 'Forgejo token for authentication.'
    required: false
  circleci-token:
    description: 'CircleCI token for authentication.'
    required: false
  format:
    description: 'Output results in the specified format: text, json, markdown.'
    required: false
    default: 'text'
  upgrade-strategy:
    description: 'Strategy to use when upgrading actions: latest, major, minor, commit.'
    required: false
    default: 'latest'
  concurrency:
    description: 'Number of concurrent API requests.'
    required: false
  ignore:
    description: 'Comma-separated list of actions or images to ignore.'
    required: false

runs:
  using: 'composite'
  steps:
    - name: Install Pinner
      shell: bash
      run: |
        if ! command -v pinner &> /dev/null; then
          echo "Installing pinner..."
          curl -LsSf https://raw.githubusercontent.com/ffalcinelli/pinner/main/install.sh | sh
        else
          echo "pinner is already installed."
        fi

    - name: Run Pinner
      shell: bash
      env:
        GITHUB_TOKEN: ${{ inputs.github-token }}
        GITLAB_TOKEN: ${{ inputs.gitlab-token }}
        BITBUCKET_TOKEN: ${{ inputs.bitbucket-token }}
        FORGEJO_TOKEN: ${{ inputs.forgejo-token }}
        CIRCLECI_TOKEN: ${{ inputs.circleci-token }}
      run: |
        ARGS=""
        
        if [ "${{ inputs.yes }}" = "true" ]; then
          ARGS="$ARGS --yes"
        fi
        
        if [ "${{ inputs.dry-run }}" = "true" ]; then
          ARGS="$ARGS --dry-run"
        fi
        
        if [ "${{ inputs.offline }}" = "true" ]; then
          ARGS="$ARGS --offline"
        fi
        
        if [ -n "${{ inputs.workflows }}" ]; then
          # Split by comma if multiple workflows provided, otherwise pass directly
          IFS=',' read -ra ADDR <<< "${{ inputs.workflows }}"
          for path in "${ADDR[@]}"; do
            ARGS="$ARGS --workflows $path"
          done
        fi
        
        if [ -n "${{ inputs.format }}" ]; then
          ARGS="$ARGS --format ${{ inputs.format }}"
        fi
        
        if [ -n "${{ inputs.upgrade-strategy }}" ]; then
          ARGS="$ARGS --upgrade-strategy ${{ inputs.upgrade-strategy }}"
        fi
        
        if [ -n "${{ inputs.concurrency }}" ]; then
          ARGS="$ARGS --concurrency ${{ inputs.concurrency }}"
        fi
        
        if [ -n "${{ inputs.ignore }}" ]; then
          ARGS="$ARGS --ignore ${{ inputs.ignore }}"
        fi
        
        echo "Running: pinner $ARGS ${{ inputs.command }}"
        pinner $ARGS ${{ inputs.command }}