gha-workflow-linter


Namegha-workflow-linter JSON
Version 0.1.7 PyPI version JSON
download
home_pageNone
SummaryGitHub Actions workflow linter for validating action and workflow calls
upload_time2025-10-30 18:39:01
maintainerNone
docs_urlNone
authorNone
requires_python<3.14,>=3.10
licenseApache-2.0
keywords actions github linting validation workflows
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <!--
SPDX-License-Identifier: Apache-2.0
SPDX-FileCopyrightText: 2025 The Linux Foundation
-->

# ๐Ÿ” GHA Workflow Linter

[![GitHub Actions](https://github.com/modeseven-lfit/gha-workflow-linter/actions/workflows/build-test.yaml/badge.svg)](https://github.com/modeseven-lfit/gha-workflow-linter/actions/workflows/build-test.yaml)
[![PyPI version](https://img.shields.io/pypi/v/gha-workflow-linter.svg)](https://pypi.org/project/gha-workflow-linter/)
[![Python Support](https://img.shields.io/pypi/pyversions/gha-workflow-linter.svg)](https://devguide.python.org/versions/)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

A comprehensive GitHub Actions workflow linter that validates action and
workflow calls against remote repositories. GHA Workflow Linter ensures your GitHub
Actions workflows reference valid repositories, branches, tags, and commit SHAs.

## Features

<!-- markdownlint-disable MD013 -->

- **๐Ÿ”’ SHA Pinning Enforcement**: Requires actions using commit SHAs for security (configurable)
- **๐Ÿ”‘ Automatic Authentication**: Auto-detects GitHub tokens from GitHub CLI when available
- **๐Ÿ“ฆ Local Caching**: Stores validation results locally to improve performance and reduce API calls
- **Multi-format Support**: Works as CLI tool, pre-commit hook, and GitHub Action
- **Comprehensive Validation**: Validates repositories, references, and syntax
- **Parallel Processing**: Multi-threaded validation for faster execution
- **Flexible Configuration**: YAML/JSON config files with environment overrides
- **Rich Output**: Clear error reporting with file paths and line numbers
- **SSH Support**: Respects SSH configuration and agent for private repositories
- **Rate Limiting**: Built-in throttling to respect API limits

<!-- markdownlint-enable MD013 -->

## Installation

### From PyPI

```bash
uv add gha-workflow-linter
```

### From Source

```bash
git clone https://github.com/modeseven-lfit/gha-workflow-linter.git
cd gha-workflow-linter
uv pip install -e .
```

### Development Installation

```bash
git clone https://github.com/modeseven-lfit/gha-workflow-linter.git
cd gha-workflow-linter
uv pip install -e ".[dev]"
```

## Authentication

GHA Workflow Linter uses the GitHub GraphQL API for efficient validation. Authentication
is **optional** but **highly recommended** to avoid rate limiting.

### Automatic Authentication (Recommended)

If you have [GitHub CLI](https://cli.github.com/) installed and authenticated,
the linter will **automatically** get a token when needed:

```bash
# No token setup required if GitHub CLI has authentication!
gha-workflow-linter lint
```

When no token exists, you'll see:

```text
โš ๏ธ No GitHub token found; attempting to get using GitHub CLI
โœ… GitHub token retrieved from GitHub CLI
```

### Manual Token Setup

If you don't use GitHub CLI or prefer manual setup:

1. **Create a Personal Access Token:**

   <!-- markdownlint-disable MD013 -->

   - Go to [GitHub Settings > Developer settings > Personal access tokens](https://github.com/settings/tokens)
   - Click "Generate new token (classic)"
   - Select scopes: `public_repo` (for public repositories) or `repo` (for
     private repositories)
   - Copy the generated token

   <!-- markdownlint-enable MD013 -->

2. **Set the token via environment variable:**

   ```bash
   export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx
   gha-workflow-linter lint
   ```

3. **Or pass the token via CLI flag:**

   ```bash
   gha-workflow-linter lint --github-token ghp_xxxxxxxxxxxxxxxxxxxx
   ```

### Authentication Priority

The linter uses the following priority order:

1. **CLI flag** (`--github-token`)
2. **Environment variable** (`GITHUB_TOKEN`)
3. **GitHub CLI fallback** (`gh auth token`)

### Rate Limits

<!-- markdownlint-disable MD013 -->

| Authentication | Requests/Hour | Recommended Use |
|---------------|---------------|-----------------|
| **With Token** | 5,000 | โœ… Production, CI/CD, large repositories |
| **Without Token** | 60 | โš ๏ธ Small repositories, testing purposes |

<!-- markdownlint-enable MD013 -->

**Without any authentication, you'll see:**
`โš ๏ธ No GitHub token available; API requests may be rate-limited`

## Usage

### Command Line Interface

```bash
# Show help with version
gha-workflow-linter --help

# Scan current directory (automatic authentication via GitHub CLI)
gha-workflow-linter lint

# Scan with environment token
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx
gha-workflow-linter lint

# Scan specific path with CLI token
gha-workflow-linter lint /path/to/project --github-token ghp_xxxxxxxxxxxxxxxxxxxx

# Use custom configuration
gha-workflow-linter lint --config config.yaml

# JSON output format
gha-workflow-linter lint --format json

# Verbose output with 8 parallel workers
gha-workflow-linter lint --verbose --workers 8

# Exclude patterns
gha-workflow-linter lint --exclude "**/test/**" --exclude "**/docs/**"

# Disable SHA pinning policy (allow tags/branches)
gha-workflow-linter lint --no-require-pinned-sha

# Run without any authentication (limited to 60 requests/hour)
# This happens when GitHub CLI is not installed/authenticated AND no token exists
# Shows: โš ๏ธ No GitHub token available; API requests may be rate-limited
gha-workflow-linter lint
```

### As a Pre-commit Hook

Add to your `.pre-commit-config.yaml`:

```yaml
repos:
  - repo: https://github.com/modeseven-lfit/gha-workflow-linter
    rev: d86993e21bbcddcfa9dac63cd43213b6a58fa6fb  # frozen: v0.1.1
    hooks:
      - id: gha-workflow-linter
```

### As a GitHub Action

```yaml
name: Check GitHub Actions
on: [push, pull_request]

jobs:
  check-actions:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a
      - name: Check action calls (strict SHA pinning)
        uses: modeseven-lfit/gha-workflow-linter@d86993e21bbcddcfa9dac63cd43213b6a58fa6fb
        with:
          path: .
          fail-on-error: true
          parallel: true
          workers: 4
          require-pinned-sha: true  # Default: require SHA pinning
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  check-actions-allow-tags:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4  # This would fail in strict mode above
      - name: Check action calls (allow tags/branches)
        uses: modeseven-lfit/gha-workflow-linter@d86993e21bbcddcfa9dac63cd43213b6a58fa6fb
        with:
          path: .
          require-pinned-sha: false  # Allow @v4, @main, etc.
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

## Configuration

GHA Workflow Linter is configurable via YAML files, environment variables, or
command-line arguments. Configuration loads in this order:

1. Command-line arguments (highest priority)
2. Environment variables with `GHA_WORKFLOW_LINTER_` prefix
3. Configuration file (lowest priority)

### Configuration File

Create `~/.config/gha-workflow-linter/config.yaml` or use `--config`:

```yaml
# Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
log_level: INFO

# Number of parallel workers (1-32)
parallel_workers: 4

# File extensions to scan
scan_extensions:
  - ".yml"
  - ".yaml"

# Patterns to exclude from scanning
exclude_patterns:
  - "**/node_modules/**"
  - "**/vendor/**"

# Require actions using commit SHAs (default: true)
require_pinned_sha: true

# Git configuration
git:
  timeout_seconds: 30
  use_ssh_agent: true

# Network configuration
network:
  timeout_seconds: 30
  max_retries: 3
  retry_delay_seconds: 1.0
  rate_limit_delay_seconds: 0.1

# Local caching configuration
cache:
  enabled: true
  cache_dir: ~/.cache/gha-workflow-linter
  cache_file: validation_cache.json
  default_ttl_seconds: 604800  # 7 days
  max_cache_size: 10000
  cleanup_on_startup: true
```

### Environment Variables

```bash
export GHA_WORKFLOW_LINTER_LOG_LEVEL=DEBUG
export GHA_WORKFLOW_LINTER_PARALLEL_WORKERS=8
export GHA_WORKFLOW_LINTER_REQUIRE_PINNED_SHA=false
export GHA_WORKFLOW_LINTER_GIT__TIMEOUT_SECONDS=60
export GHA_WORKFLOW_LINTER_CACHE__ENABLED=true
export GHA_WORKFLOW_LINTER_CACHE__DEFAULT_TTL_SECONDS=86400
```

## Local Caching

GHA Workflow Linter includes a local caching system that stores validation
results to improve performance and reduce API calls for later runs.

### Cache Features

- **Automatic Caching**: Validation results are automatically cached locally
- **Version-Based Invalidation**: Tool purges cache when version changes
- **Configurable TTL**: Cache entries expire after seven days by default
- **Size Limits**: Cache size limits prevent excessive disk usage
- **Persistence**: Cache survives between CLI invocations and system restarts
- **Smart Cleanup**: Expired entries are automatically removed

### Cache Commands

```bash
# Show cache information
gha-workflow-linter cache --info

# Remove expired cache entries
gha-workflow-linter cache --cleanup

# Clear all cache entries
gha-workflow-linter cache --purge
```

### Cache Options

```bash
# Bypass cache for a single run
gha-workflow-linter lint --no-cache

# Clear cache and exit
gha-workflow-linter lint --purge-cache

# Override default cache TTL (in seconds)
gha-workflow-linter lint --cache-ttl 3600  # 1 hour
```

### Cache Benefits

- **Performance**: Later runs are faster for validated actions
- **API Efficiency**: Reduces GitHub API calls and respects rate limits better
- **Offline Support**: Validated actions work without network access
- **Bandwidth Savings**: Useful in CI/CD environments with repeated workflows

### Cache Location

By default, cache files go in:

- **Linux/macOS**: `~/.cache/gha-workflow-linter/validation_cache.json`
- **Windows**: `%LOCALAPPDATA%\gha-workflow-linter\validation_cache.json`

You can customize the cache location via configuration file or environment variables.

### Version-Based Cache Invalidation

The cache system automatically detects when you've upgraded to a new version of
the tool and purges all cached entries to ensure consistency. This prevents
issues where validation logic changes between versions could result in stale
cached data.

When the tool detects a version mismatch, you'll see a message like:

```text
INFO Cache version mismatch (cache: 0.1.3, current: 0.1.4). Purging cache.
```

This ensures that:

- Validation logic improvements are always applied
- Bug fixes in validation don't get masked by old cache entries
- New validation features work properly from the first run

**Note**: Caching works for CLI and pre-commit hook usage. GitHub Actions
runners use ephemeral containers, so caching provides no benefit in that
environment.

## Validation Rules

GHA Workflow Linter validates GitHub Actions workflow calls using these rules:

### Action Call Format

Valid action call patterns:

```yaml
# Standard action with version tag
- uses: actions/checkout@v4

# Action with commit SHA
- uses: actions/checkout@8f4d7d2c3f1b2a9d8e5c6a7b4f3e2d1c0b9a8f7e

# Action with branch reference
- uses: actions/checkout@main

# Reusable workflow call
- uses: org/repo/.github/workflows/workflow.yaml@v1.0.0

# With trailing comment
- uses: actions/setup-python@v5.0.0  # Latest stable
```

### Repository Validation

- Organization names: 1-39 characters, alphanumeric and hyphens
- Cannot start/end with hyphen or contain consecutive hyphens
- Repository names: alphanumeric, dots, underscores, hyphens, slashes

### Reference Validation

GHA Workflow Linter validates that references exist using GitHub's GraphQL API:

- **Commit SHAs**: 40-character hexadecimal strings
- **Tags**: Semantic versions (v1.0.0) and other tag formats
- **Branches**: main, master, develop, feature branches

### Supported Reference Types

<!-- markdownlint-disable MD013 -->

| Type | Example | Validation Method | SHA Pinning |
|------|---------|-------------------|-------------|
| Commit SHA | `f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a` | GitHub GraphQL API | โœ… **Required by default** |
| Semantic Version | `v1.2.3`, `1.0.0` | GitHub GraphQL API | โŒ Fails unless `--no-require-pinned-sha` |
| Branch | `main`, `develop` | GitHub GraphQL API | โŒ Fails unless `--no-require-pinned-sha` |

<!-- markdownlint-enable MD013 -->

### SHA Pinning Enforcement

By default, gha-workflow-linter **requires all action calls use commit SHAs** for
security best practices. This helps prevent supply chain attacks and ensures
reproducible builds.

```bash
# Default behavior - fails on non-SHA references
gha-workflow-linter lint  # Fails on @v4, @main, etc.

# Disable SHA pinning policy
gha-workflow-linter lint --no-require-pinned-sha  # Allows @v4, @main, etc.
```

**Security Recommendation**: Keep SHA pinning enabled in production environments
and use automated tools like Dependabot to keep SHA references updated.

## Security Considerations

### SHA Pinning Benefits

- **Supply Chain Security**: Prevents malicious code injection through
compromised action versions
- **Reproducible Builds**: Ensures consistent behavior across builds and environments
- **Immutable References**: SHA references stay fixed, unlike tags and branches
- **Audit Trail**: Clear tracking of exact code versions used in workflows

### Migration Strategy

```bash
# Step 1: Identify unpinned actions
gha-workflow-linter lint --format json | jq '.errors[] | \
  select(.validation_result == "not_pinned_to_sha")'

# Step 2: Temporarily allow unpinned actions during migration
gha-workflow-linter lint --no-require-pinned-sha

# Step 3: Use tools like Dependabot to pin and update SHA references automatically
```

### Dependabot Configuration

Add to `.github/dependabot.yml`:

```yaml
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
    commit-message:
      prefix: "ci"
      include: "scope"
```

## Output Formats

### Text Output (Default)

```text
๐Ÿท๏ธ gha-workflow-linter version 1.0.0

                                     Scan Summary
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”“
โ”ƒ Metric                โ”ƒ Count โ”ƒ
โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”ฉ
โ”‚ Workflow files        โ”‚    12 โ”‚
โ”‚ Total action calls    โ”‚    45 โ”‚
โ”‚ Action calls          โ”‚    38 โ”‚
โ”‚ Workflow calls        โ”‚     7 โ”‚
โ”‚ SHA references        โ”‚    35 โ”‚
โ”‚ Tag references        โ”‚     8 โ”‚
โ”‚ Branch references     โ”‚     2 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โŒ Found 8 validation errors

  - 8 actions not pinned to SHA

Validation Errors:
โŒ Invalid action call in workflow: .github/workflows/test.yaml
      - uses: actions/checkout@v4 [not_pinned_to_sha]

โŒ Invalid action call in workflow: .github/workflows/test.yaml
      - uses: actions/setup-python@v5 [not_pinned_to_sha]
```

### JSON Output

```bash
gha-workflow-linter lint --format json
```

```json
{
  "scan_summary": {
    "total_files": 12,
    "total_calls": 45,
    "action_calls": 38,
    "workflow_calls": 7,
    "sha_references": 42,
    "tag_references": 2,
    "branch_references": 1
  },
  "validation_summary": {
    "total_errors": 8,
    "invalid_repositories": 0,
    "invalid_references": 0,
    "syntax_errors": 0,
    "network_errors": 0,
    "timeouts": 0,
    "not_pinned_to_sha": 8
  },
  "errors": [
    {
      "file_path": ".github/workflows/test.yaml",
      "line_number": 8,
      "raw_line": "      - uses: actions/checkout@v4",
      "organization": "actions",
      "repository": "checkout",
      "reference": "v4",
      "call_type": "action",
      "reference_type": "tag",
      "validation_result": "not_pinned_to_sha",
      "error_message": "Action not pinned to commit SHA"
    }
  ]
}
```

## GitHub Action Inputs

<!-- markdownlint-disable MD013 -->

| Input | Description | Required | Default |
|-------|-------------|----------|---------|
| `path` | Path to scan for workflows | No | `.` |
| `config-file` | Path to configuration file | No | |
| `github-token` | GitHub API token | No | |
| `log-level` | Logging level | No | `INFO` |
| `output-format` | Output format (text, json) | No | `text` |
| `fail-on-error` | Exit with error on failures | No | `true` |
| `parallel` | Enable parallel processing | No | `true` |
| `workers` | Number of parallel workers | No | `4` |
| `exclude` | Comma-separated exclude patterns | No | |
| `require-pinned-sha` | Require actions pinned to commit SHAs | No | `true` |

<!-- markdownlint-enable MD013 -->

## GitHub Action Outputs

<!-- markdownlint-disable MD013 -->

| Output | Description |
|--------|-------------|
| `errors-found` | Number of validation errors |
| `total-calls` | Total action calls scanned |
| `scan-summary` | JSON summary of results |

<!-- markdownlint-enable MD013 -->

## CLI Options

```text
Usage: gha-workflow-linter lint [OPTIONS] [PATH]

  Scan GitHub Actions workflows for invalid action and workflow calls.

Arguments:
  [PATH]  Path to scan for workflows (default: current directory)

Options:
  -c, --config FILE          Configuration file path
  --github-token TEXT        GitHub API token (auto-detects from GitHub CLI)
  -v, --verbose              Enable verbose output
  -q, --quiet                Suppress all output except errors
  --log-level LEVEL          Set logging level
  -f, --format FORMAT        Output format (text, json)
  --fail-on-error            Exit with error code if failures found
  --no-fail-on-error         Don't exit with error code
  --parallel                 Enable parallel processing
  --no-parallel              Disable parallel processing
  -j, --workers INTEGER      Number of parallel workers (1-32)
  -e, --exclude PATTERN      Patterns to exclude (multiples accepted)
  --require-pinned-sha       Require actions pinned to commit SHAs (default)
  --no-require-pinned-sha    Allow actions with tags/branches
  --version                  Show version and exit
  --help                     Show this message and exit
```

## Integration Examples

### Jenkins Pipeline

```groovy
pipeline {
    agent any
    stages {
        stage('Check Actions') {
            steps {
                sh 'pip install gha-workflow-linter'
                sh 'gha-workflow-linter lint --format json > results.json'
                archiveArtifacts artifacts: 'results.json'
            }
        }
    }
}
```

### Docker Usage

```bash
# Using published image
docker run --rm -v "$(pwd):/workspace" \
  -e GITHUB_TOKEN=$GITHUB_TOKEN \
  ghcr.io/modeseven-lfit/gha-workflow-linter:latest lint /workspace

# Build local image
docker build -t gha-workflow-linter .
docker run --rm -v "$(pwd):/workspace" \
  -e GITHUB_TOKEN=$GITHUB_TOKEN \
  gha-workflow-linter lint /workspace
```

## Error Types

<!-- markdownlint-disable MD013 -->

| Error Type | Description | Resolution |
|------------|-------------|------------|
| `invalid_repository` | Repository not found | Check org/repo name spelling |
| `invalid_reference` | Branch/tag/SHA not found | Verify reference exists |
| `invalid_syntax` | Malformed action call | Fix YAML syntax |
| `network_error` | Connection failed | Check network/credentials |
| `timeout` | Validation timed out | Increase timeout settings |
| `not_pinned_to_sha` | Action not using SHA | Pin to commit SHA or use `--no-require-pinned-sha` |

<!-- markdownlint-enable MD013 -->

## Development

### Setup Development Environment

```bash
git clone https://github.com/modeseven-lfit/gha-workflow-linter.git
cd gha-workflow-linter
uv pip install -e ".[dev]"
```

### Running Tests

```bash
# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov=gha_workflow_linter

# Run specific test categories
uv run pytest -m unit
uv run pytest -m integration
uv run pytest -m "not slow"
```

### Code Quality

```bash
# Format code
ruff format .

# Lint code
ruff check .

# Type checking
mypy src/gha_workflow_linter

# Pre-commit hooks
pre-commit run --all-files
```

### Building and Publishing

**Local Builds:**

```bash
uv build
```

This project uses automated CI/CD workflows for building and publishing:

**Development/Testing:**

- Pull requests trigger the `build-test.yaml` workflow
- Automatically runs tests, audits, linting
- Validates the package builds without errors

**Releases:**

- The `build-test-release.yaml` workflow performs publishing/releasing
- Triggered by pushing a git tag to the repository
- Automatically builds, tests and publishes the package

## Architecture

GHA Workflow Linter follows a modular architecture with clear separation of
concerns:

- **CLI Interface**: Typer-based command-line interface
- **Configuration**: Pydantic models with YAML/env support
- **Scanner**: Workflow file discovery and parsing
- **Patterns**: Regex-based action call extraction
- **Validator**: Git-based remote validation
- **Models**: Type-safe data structures

## Performance

GHA Workflow Linter performance optimizations:

- **Parallel Processing**: Multi-threaded validation
- **Caching**: Repository and reference validation caching
- **Rate Limiting**: Configurable delays to respect API limits
- **Efficient API Operations**: Uses GitHub GraphQL API

Typical performance on a repository with 50 workflows and 200 action calls:

- **Serial**: ~60 seconds
- **Parallel (4 workers)**: ~15 seconds
- **Cached**: ~2 seconds (follow-up runs)

## Security Notes

- **Token Security**: Tokens are never logged or stored permanently
- **Environment Variables**: Recommended method for token management
- **Private Repositories**: Requires appropriate token permissions
- **Rate Limiting**: Proactive management prevents API abuse
- **API Efficiency**: Batch queries reduce API surface area

### Pre-commit Hook

The repository includes a pre-commit hook that runs gha-workflow-linter
on its own workflows:

```yaml
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/modeseven-lfit/gha-workflow-linter
    rev: d86993e21bbcddcfa9dac63cd43213b6a58fa6fb  # frozen: v0.1.1
    hooks:
      - id: gha-workflow-linter
```

### Development Setup

For contributors, use the development setup script:

```bash
# Install development environment with self-linting
./scripts/setup-dev.sh

# This sets up:
# - Development dependencies
# - Pre-commit hooks (including gha-workflow-linter)
# - GitHub authentication (GitHub CLI recommended)
# - Self-linting test
```

## Troubleshooting

### Authentication Issues

**GitHub CLI not found:**

```text
โŒ Unable to get GitHub token from any source
๐Ÿ’ก Authentication options:
   โ€ข Install GitHub CLI: https://cli.github.com/
   โ€ข Or set environment variable: export GITHUB_TOKEN=ghp_xxx
   โ€ข Or use --github-token flag with your personal access token
```

**GitHub CLI not authenticated:**

```bash
# Check authentication status
gh auth status

# Login if not authenticated
gh auth login
```

**Token permissions:**

- Ensure your token has `public_repo` scope for public repositories
- Use `repo` scope for private repositories
- Check token validity: `gh auth token` should return a valid token

**Rate limiting:**

- Without authentication: 60 requests/hour
- With GitHub token: 5,000 requests/hour
- Large repositories may require authentication to avoid limits

## Contributing

We welcome contributions! Please see our contributing guidelines:

1. Fork the repository
2. Create a feature branch
3. Make your changes with tests
4. Run the test suite and linting (including self-linting)
5. Submit a pull request

## License

Licensed under the Apache License 2.0. See the LICENSE file for details.

## Support

- **Issues**: [GitHub Issues](https://github.com/modeseven-lfit/gha-workflow-linter/issues)
- **Discussions**: [GitHub Discussions](https://github.com/modeseven-lfit/gha-workflow-linter/discussions)
- **Documentation**: [Read the Docs](https://gha-workflow-linter.readthedocs.io)

## Acknowledgments

Built with modern Python tooling:

- [Typer](https://typer.tiangolo.com/) for CLI interface
- [Pydantic](https://docs.pydantic.dev/) for data validation
- [Rich](https://rich.readthedocs.io/) for beautiful terminal output
- [uv](https://docs.astral.sh/uv/) for dependency management
- [pytest](https://pytest.org/) for testing

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "gha-workflow-linter",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<3.14,>=3.10",
    "maintainer_email": null,
    "keywords": "actions, github, linting, validation, workflows",
    "author": null,
    "author_email": "The Linux Foundation <releng@linuxfoundation.org>",
    "download_url": "https://files.pythonhosted.org/packages/04/ba/54391be2cc79c1aa93c43d11762ede01d534c87a096f6dd2c448a940925c/gha_workflow_linter-0.1.7.tar.gz",
    "platform": null,
    "description": "<!--\nSPDX-License-Identifier: Apache-2.0\nSPDX-FileCopyrightText: 2025 The Linux Foundation\n-->\n\n# \ud83d\udd0d GHA Workflow Linter\n\n[![GitHub Actions](https://github.com/modeseven-lfit/gha-workflow-linter/actions/workflows/build-test.yaml/badge.svg)](https://github.com/modeseven-lfit/gha-workflow-linter/actions/workflows/build-test.yaml)\n[![PyPI version](https://img.shields.io/pypi/v/gha-workflow-linter.svg)](https://pypi.org/project/gha-workflow-linter/)\n[![Python Support](https://img.shields.io/pypi/pyversions/gha-workflow-linter.svg)](https://devguide.python.org/versions/)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n\nA comprehensive GitHub Actions workflow linter that validates action and\nworkflow calls against remote repositories. GHA Workflow Linter ensures your GitHub\nActions workflows reference valid repositories, branches, tags, and commit SHAs.\n\n## Features\n\n<!-- markdownlint-disable MD013 -->\n\n- **\ud83d\udd12 SHA Pinning Enforcement**: Requires actions using commit SHAs for security (configurable)\n- **\ud83d\udd11 Automatic Authentication**: Auto-detects GitHub tokens from GitHub CLI when available\n- **\ud83d\udce6 Local Caching**: Stores validation results locally to improve performance and reduce API calls\n- **Multi-format Support**: Works as CLI tool, pre-commit hook, and GitHub Action\n- **Comprehensive Validation**: Validates repositories, references, and syntax\n- **Parallel Processing**: Multi-threaded validation for faster execution\n- **Flexible Configuration**: YAML/JSON config files with environment overrides\n- **Rich Output**: Clear error reporting with file paths and line numbers\n- **SSH Support**: Respects SSH configuration and agent for private repositories\n- **Rate Limiting**: Built-in throttling to respect API limits\n\n<!-- markdownlint-enable MD013 -->\n\n## Installation\n\n### From PyPI\n\n```bash\nuv add gha-workflow-linter\n```\n\n### From Source\n\n```bash\ngit clone https://github.com/modeseven-lfit/gha-workflow-linter.git\ncd gha-workflow-linter\nuv pip install -e .\n```\n\n### Development Installation\n\n```bash\ngit clone https://github.com/modeseven-lfit/gha-workflow-linter.git\ncd gha-workflow-linter\nuv pip install -e \".[dev]\"\n```\n\n## Authentication\n\nGHA Workflow Linter uses the GitHub GraphQL API for efficient validation. Authentication\nis **optional** but **highly recommended** to avoid rate limiting.\n\n### Automatic Authentication (Recommended)\n\nIf you have [GitHub CLI](https://cli.github.com/) installed and authenticated,\nthe linter will **automatically** get a token when needed:\n\n```bash\n# No token setup required if GitHub CLI has authentication!\ngha-workflow-linter lint\n```\n\nWhen no token exists, you'll see:\n\n```text\n\u26a0\ufe0f No GitHub token found; attempting to get using GitHub CLI\n\u2705 GitHub token retrieved from GitHub CLI\n```\n\n### Manual Token Setup\n\nIf you don't use GitHub CLI or prefer manual setup:\n\n1. **Create a Personal Access Token:**\n\n   <!-- markdownlint-disable MD013 -->\n\n   - Go to [GitHub Settings > Developer settings > Personal access tokens](https://github.com/settings/tokens)\n   - Click \"Generate new token (classic)\"\n   - Select scopes: `public_repo` (for public repositories) or `repo` (for\n     private repositories)\n   - Copy the generated token\n\n   <!-- markdownlint-enable MD013 -->\n\n2. **Set the token via environment variable:**\n\n   ```bash\n   export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx\n   gha-workflow-linter lint\n   ```\n\n3. **Or pass the token via CLI flag:**\n\n   ```bash\n   gha-workflow-linter lint --github-token ghp_xxxxxxxxxxxxxxxxxxxx\n   ```\n\n### Authentication Priority\n\nThe linter uses the following priority order:\n\n1. **CLI flag** (`--github-token`)\n2. **Environment variable** (`GITHUB_TOKEN`)\n3. **GitHub CLI fallback** (`gh auth token`)\n\n### Rate Limits\n\n<!-- markdownlint-disable MD013 -->\n\n| Authentication | Requests/Hour | Recommended Use |\n|---------------|---------------|-----------------|\n| **With Token** | 5,000 | \u2705 Production, CI/CD, large repositories |\n| **Without Token** | 60 | \u26a0\ufe0f Small repositories, testing purposes |\n\n<!-- markdownlint-enable MD013 -->\n\n**Without any authentication, you'll see:**\n`\u26a0\ufe0f No GitHub token available; API requests may be rate-limited`\n\n## Usage\n\n### Command Line Interface\n\n```bash\n# Show help with version\ngha-workflow-linter --help\n\n# Scan current directory (automatic authentication via GitHub CLI)\ngha-workflow-linter lint\n\n# Scan with environment token\nexport GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx\ngha-workflow-linter lint\n\n# Scan specific path with CLI token\ngha-workflow-linter lint /path/to/project --github-token ghp_xxxxxxxxxxxxxxxxxxxx\n\n# Use custom configuration\ngha-workflow-linter lint --config config.yaml\n\n# JSON output format\ngha-workflow-linter lint --format json\n\n# Verbose output with 8 parallel workers\ngha-workflow-linter lint --verbose --workers 8\n\n# Exclude patterns\ngha-workflow-linter lint --exclude \"**/test/**\" --exclude \"**/docs/**\"\n\n# Disable SHA pinning policy (allow tags/branches)\ngha-workflow-linter lint --no-require-pinned-sha\n\n# Run without any authentication (limited to 60 requests/hour)\n# This happens when GitHub CLI is not installed/authenticated AND no token exists\n# Shows: \u26a0\ufe0f No GitHub token available; API requests may be rate-limited\ngha-workflow-linter lint\n```\n\n### As a Pre-commit Hook\n\nAdd to your `.pre-commit-config.yaml`:\n\n```yaml\nrepos:\n  - repo: https://github.com/modeseven-lfit/gha-workflow-linter\n    rev: d86993e21bbcddcfa9dac63cd43213b6a58fa6fb  # frozen: v0.1.1\n    hooks:\n      - id: gha-workflow-linter\n```\n\n### As a GitHub Action\n\n```yaml\nname: Check GitHub Actions\non: [push, pull_request]\n\njobs:\n  check-actions:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a\n      - name: Check action calls (strict SHA pinning)\n        uses: modeseven-lfit/gha-workflow-linter@d86993e21bbcddcfa9dac63cd43213b6a58fa6fb\n        with:\n          path: .\n          fail-on-error: true\n          parallel: true\n          workers: 4\n          require-pinned-sha: true  # Default: require SHA pinning\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n  check-actions-allow-tags:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4  # This would fail in strict mode above\n      - name: Check action calls (allow tags/branches)\n        uses: modeseven-lfit/gha-workflow-linter@d86993e21bbcddcfa9dac63cd43213b6a58fa6fb\n        with:\n          path: .\n          require-pinned-sha: false  # Allow @v4, @main, etc.\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n```\n\n## Configuration\n\nGHA Workflow Linter is configurable via YAML files, environment variables, or\ncommand-line arguments. Configuration loads in this order:\n\n1. Command-line arguments (highest priority)\n2. Environment variables with `GHA_WORKFLOW_LINTER_` prefix\n3. Configuration file (lowest priority)\n\n### Configuration File\n\nCreate `~/.config/gha-workflow-linter/config.yaml` or use `--config`:\n\n```yaml\n# Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)\nlog_level: INFO\n\n# Number of parallel workers (1-32)\nparallel_workers: 4\n\n# File extensions to scan\nscan_extensions:\n  - \".yml\"\n  - \".yaml\"\n\n# Patterns to exclude from scanning\nexclude_patterns:\n  - \"**/node_modules/**\"\n  - \"**/vendor/**\"\n\n# Require actions using commit SHAs (default: true)\nrequire_pinned_sha: true\n\n# Git configuration\ngit:\n  timeout_seconds: 30\n  use_ssh_agent: true\n\n# Network configuration\nnetwork:\n  timeout_seconds: 30\n  max_retries: 3\n  retry_delay_seconds: 1.0\n  rate_limit_delay_seconds: 0.1\n\n# Local caching configuration\ncache:\n  enabled: true\n  cache_dir: ~/.cache/gha-workflow-linter\n  cache_file: validation_cache.json\n  default_ttl_seconds: 604800  # 7 days\n  max_cache_size: 10000\n  cleanup_on_startup: true\n```\n\n### Environment Variables\n\n```bash\nexport GHA_WORKFLOW_LINTER_LOG_LEVEL=DEBUG\nexport GHA_WORKFLOW_LINTER_PARALLEL_WORKERS=8\nexport GHA_WORKFLOW_LINTER_REQUIRE_PINNED_SHA=false\nexport GHA_WORKFLOW_LINTER_GIT__TIMEOUT_SECONDS=60\nexport GHA_WORKFLOW_LINTER_CACHE__ENABLED=true\nexport GHA_WORKFLOW_LINTER_CACHE__DEFAULT_TTL_SECONDS=86400\n```\n\n## Local Caching\n\nGHA Workflow Linter includes a local caching system that stores validation\nresults to improve performance and reduce API calls for later runs.\n\n### Cache Features\n\n- **Automatic Caching**: Validation results are automatically cached locally\n- **Version-Based Invalidation**: Tool purges cache when version changes\n- **Configurable TTL**: Cache entries expire after seven days by default\n- **Size Limits**: Cache size limits prevent excessive disk usage\n- **Persistence**: Cache survives between CLI invocations and system restarts\n- **Smart Cleanup**: Expired entries are automatically removed\n\n### Cache Commands\n\n```bash\n# Show cache information\ngha-workflow-linter cache --info\n\n# Remove expired cache entries\ngha-workflow-linter cache --cleanup\n\n# Clear all cache entries\ngha-workflow-linter cache --purge\n```\n\n### Cache Options\n\n```bash\n# Bypass cache for a single run\ngha-workflow-linter lint --no-cache\n\n# Clear cache and exit\ngha-workflow-linter lint --purge-cache\n\n# Override default cache TTL (in seconds)\ngha-workflow-linter lint --cache-ttl 3600  # 1 hour\n```\n\n### Cache Benefits\n\n- **Performance**: Later runs are faster for validated actions\n- **API Efficiency**: Reduces GitHub API calls and respects rate limits better\n- **Offline Support**: Validated actions work without network access\n- **Bandwidth Savings**: Useful in CI/CD environments with repeated workflows\n\n### Cache Location\n\nBy default, cache files go in:\n\n- **Linux/macOS**: `~/.cache/gha-workflow-linter/validation_cache.json`\n- **Windows**: `%LOCALAPPDATA%\\gha-workflow-linter\\validation_cache.json`\n\nYou can customize the cache location via configuration file or environment variables.\n\n### Version-Based Cache Invalidation\n\nThe cache system automatically detects when you've upgraded to a new version of\nthe tool and purges all cached entries to ensure consistency. This prevents\nissues where validation logic changes between versions could result in stale\ncached data.\n\nWhen the tool detects a version mismatch, you'll see a message like:\n\n```text\nINFO Cache version mismatch (cache: 0.1.3, current: 0.1.4). Purging cache.\n```\n\nThis ensures that:\n\n- Validation logic improvements are always applied\n- Bug fixes in validation don't get masked by old cache entries\n- New validation features work properly from the first run\n\n**Note**: Caching works for CLI and pre-commit hook usage. GitHub Actions\nrunners use ephemeral containers, so caching provides no benefit in that\nenvironment.\n\n## Validation Rules\n\nGHA Workflow Linter validates GitHub Actions workflow calls using these rules:\n\n### Action Call Format\n\nValid action call patterns:\n\n```yaml\n# Standard action with version tag\n- uses: actions/checkout@v4\n\n# Action with commit SHA\n- uses: actions/checkout@8f4d7d2c3f1b2a9d8e5c6a7b4f3e2d1c0b9a8f7e\n\n# Action with branch reference\n- uses: actions/checkout@main\n\n# Reusable workflow call\n- uses: org/repo/.github/workflows/workflow.yaml@v1.0.0\n\n# With trailing comment\n- uses: actions/setup-python@v5.0.0  # Latest stable\n```\n\n### Repository Validation\n\n- Organization names: 1-39 characters, alphanumeric and hyphens\n- Cannot start/end with hyphen or contain consecutive hyphens\n- Repository names: alphanumeric, dots, underscores, hyphens, slashes\n\n### Reference Validation\n\nGHA Workflow Linter validates that references exist using GitHub's GraphQL API:\n\n- **Commit SHAs**: 40-character hexadecimal strings\n- **Tags**: Semantic versions (v1.0.0) and other tag formats\n- **Branches**: main, master, develop, feature branches\n\n### Supported Reference Types\n\n<!-- markdownlint-disable MD013 -->\n\n| Type | Example | Validation Method | SHA Pinning |\n|------|---------|-------------------|-------------|\n| Commit SHA | `f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a` | GitHub GraphQL API | \u2705 **Required by default** |\n| Semantic Version | `v1.2.3`, `1.0.0` | GitHub GraphQL API | \u274c Fails unless `--no-require-pinned-sha` |\n| Branch | `main`, `develop` | GitHub GraphQL API | \u274c Fails unless `--no-require-pinned-sha` |\n\n<!-- markdownlint-enable MD013 -->\n\n### SHA Pinning Enforcement\n\nBy default, gha-workflow-linter **requires all action calls use commit SHAs** for\nsecurity best practices. This helps prevent supply chain attacks and ensures\nreproducible builds.\n\n```bash\n# Default behavior - fails on non-SHA references\ngha-workflow-linter lint  # Fails on @v4, @main, etc.\n\n# Disable SHA pinning policy\ngha-workflow-linter lint --no-require-pinned-sha  # Allows @v4, @main, etc.\n```\n\n**Security Recommendation**: Keep SHA pinning enabled in production environments\nand use automated tools like Dependabot to keep SHA references updated.\n\n## Security Considerations\n\n### SHA Pinning Benefits\n\n- **Supply Chain Security**: Prevents malicious code injection through\ncompromised action versions\n- **Reproducible Builds**: Ensures consistent behavior across builds and environments\n- **Immutable References**: SHA references stay fixed, unlike tags and branches\n- **Audit Trail**: Clear tracking of exact code versions used in workflows\n\n### Migration Strategy\n\n```bash\n# Step 1: Identify unpinned actions\ngha-workflow-linter lint --format json | jq '.errors[] | \\\n  select(.validation_result == \"not_pinned_to_sha\")'\n\n# Step 2: Temporarily allow unpinned actions during migration\ngha-workflow-linter lint --no-require-pinned-sha\n\n# Step 3: Use tools like Dependabot to pin and update SHA references automatically\n```\n\n### Dependabot Configuration\n\nAdd to `.github/dependabot.yml`:\n\n```yaml\nversion: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    commit-message:\n      prefix: \"ci\"\n      include: \"scope\"\n```\n\n## Output Formats\n\n### Text Output (Default)\n\n```text\n\ud83c\udff7\ufe0f gha-workflow-linter version 1.0.0\n\n                                     Scan Summary\n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Metric                \u2503 Count \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 Workflow files        \u2502    12 \u2502\n\u2502 Total action calls    \u2502    45 \u2502\n\u2502 Action calls          \u2502    38 \u2502\n\u2502 Workflow calls        \u2502     7 \u2502\n\u2502 SHA references        \u2502    35 \u2502\n\u2502 Tag references        \u2502     8 \u2502\n\u2502 Branch references     \u2502     2 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\n\u274c Found 8 validation errors\n\n  - 8 actions not pinned to SHA\n\nValidation Errors:\n\u274c Invalid action call in workflow: .github/workflows/test.yaml\n      - uses: actions/checkout@v4 [not_pinned_to_sha]\n\n\u274c Invalid action call in workflow: .github/workflows/test.yaml\n      - uses: actions/setup-python@v5 [not_pinned_to_sha]\n```\n\n### JSON Output\n\n```bash\ngha-workflow-linter lint --format json\n```\n\n```json\n{\n  \"scan_summary\": {\n    \"total_files\": 12,\n    \"total_calls\": 45,\n    \"action_calls\": 38,\n    \"workflow_calls\": 7,\n    \"sha_references\": 42,\n    \"tag_references\": 2,\n    \"branch_references\": 1\n  },\n  \"validation_summary\": {\n    \"total_errors\": 8,\n    \"invalid_repositories\": 0,\n    \"invalid_references\": 0,\n    \"syntax_errors\": 0,\n    \"network_errors\": 0,\n    \"timeouts\": 0,\n    \"not_pinned_to_sha\": 8\n  },\n  \"errors\": [\n    {\n      \"file_path\": \".github/workflows/test.yaml\",\n      \"line_number\": 8,\n      \"raw_line\": \"      - uses: actions/checkout@v4\",\n      \"organization\": \"actions\",\n      \"repository\": \"checkout\",\n      \"reference\": \"v4\",\n      \"call_type\": \"action\",\n      \"reference_type\": \"tag\",\n      \"validation_result\": \"not_pinned_to_sha\",\n      \"error_message\": \"Action not pinned to commit SHA\"\n    }\n  ]\n}\n```\n\n## GitHub Action Inputs\n\n<!-- markdownlint-disable MD013 -->\n\n| Input | Description | Required | Default |\n|-------|-------------|----------|---------|\n| `path` | Path to scan for workflows | No | `.` |\n| `config-file` | Path to configuration file | No | |\n| `github-token` | GitHub API token | No | |\n| `log-level` | Logging level | No | `INFO` |\n| `output-format` | Output format (text, json) | No | `text` |\n| `fail-on-error` | Exit with error on failures | No | `true` |\n| `parallel` | Enable parallel processing | No | `true` |\n| `workers` | Number of parallel workers | No | `4` |\n| `exclude` | Comma-separated exclude patterns | No | |\n| `require-pinned-sha` | Require actions pinned to commit SHAs | No | `true` |\n\n<!-- markdownlint-enable MD013 -->\n\n## GitHub Action Outputs\n\n<!-- markdownlint-disable MD013 -->\n\n| Output | Description |\n|--------|-------------|\n| `errors-found` | Number of validation errors |\n| `total-calls` | Total action calls scanned |\n| `scan-summary` | JSON summary of results |\n\n<!-- markdownlint-enable MD013 -->\n\n## CLI Options\n\n```text\nUsage: gha-workflow-linter lint [OPTIONS] [PATH]\n\n  Scan GitHub Actions workflows for invalid action and workflow calls.\n\nArguments:\n  [PATH]  Path to scan for workflows (default: current directory)\n\nOptions:\n  -c, --config FILE          Configuration file path\n  --github-token TEXT        GitHub API token (auto-detects from GitHub CLI)\n  -v, --verbose              Enable verbose output\n  -q, --quiet                Suppress all output except errors\n  --log-level LEVEL          Set logging level\n  -f, --format FORMAT        Output format (text, json)\n  --fail-on-error            Exit with error code if failures found\n  --no-fail-on-error         Don't exit with error code\n  --parallel                 Enable parallel processing\n  --no-parallel              Disable parallel processing\n  -j, --workers INTEGER      Number of parallel workers (1-32)\n  -e, --exclude PATTERN      Patterns to exclude (multiples accepted)\n  --require-pinned-sha       Require actions pinned to commit SHAs (default)\n  --no-require-pinned-sha    Allow actions with tags/branches\n  --version                  Show version and exit\n  --help                     Show this message and exit\n```\n\n## Integration Examples\n\n### Jenkins Pipeline\n\n```groovy\npipeline {\n    agent any\n    stages {\n        stage('Check Actions') {\n            steps {\n                sh 'pip install gha-workflow-linter'\n                sh 'gha-workflow-linter lint --format json > results.json'\n                archiveArtifacts artifacts: 'results.json'\n            }\n        }\n    }\n}\n```\n\n### Docker Usage\n\n```bash\n# Using published image\ndocker run --rm -v \"$(pwd):/workspace\" \\\n  -e GITHUB_TOKEN=$GITHUB_TOKEN \\\n  ghcr.io/modeseven-lfit/gha-workflow-linter:latest lint /workspace\n\n# Build local image\ndocker build -t gha-workflow-linter .\ndocker run --rm -v \"$(pwd):/workspace\" \\\n  -e GITHUB_TOKEN=$GITHUB_TOKEN \\\n  gha-workflow-linter lint /workspace\n```\n\n## Error Types\n\n<!-- markdownlint-disable MD013 -->\n\n| Error Type | Description | Resolution |\n|------------|-------------|------------|\n| `invalid_repository` | Repository not found | Check org/repo name spelling |\n| `invalid_reference` | Branch/tag/SHA not found | Verify reference exists |\n| `invalid_syntax` | Malformed action call | Fix YAML syntax |\n| `network_error` | Connection failed | Check network/credentials |\n| `timeout` | Validation timed out | Increase timeout settings |\n| `not_pinned_to_sha` | Action not using SHA | Pin to commit SHA or use `--no-require-pinned-sha` |\n\n<!-- markdownlint-enable MD013 -->\n\n## Development\n\n### Setup Development Environment\n\n```bash\ngit clone https://github.com/modeseven-lfit/gha-workflow-linter.git\ncd gha-workflow-linter\nuv pip install -e \".[dev]\"\n```\n\n### Running Tests\n\n```bash\n# Run all tests\nuv run pytest\n\n# Run with coverage\nuv run pytest --cov=gha_workflow_linter\n\n# Run specific test categories\nuv run pytest -m unit\nuv run pytest -m integration\nuv run pytest -m \"not slow\"\n```\n\n### Code Quality\n\n```bash\n# Format code\nruff format .\n\n# Lint code\nruff check .\n\n# Type checking\nmypy src/gha_workflow_linter\n\n# Pre-commit hooks\npre-commit run --all-files\n```\n\n### Building and Publishing\n\n**Local Builds:**\n\n```bash\nuv build\n```\n\nThis project uses automated CI/CD workflows for building and publishing:\n\n**Development/Testing:**\n\n- Pull requests trigger the `build-test.yaml` workflow\n- Automatically runs tests, audits, linting\n- Validates the package builds without errors\n\n**Releases:**\n\n- The `build-test-release.yaml` workflow performs publishing/releasing\n- Triggered by pushing a git tag to the repository\n- Automatically builds, tests and publishes the package\n\n## Architecture\n\nGHA Workflow Linter follows a modular architecture with clear separation of\nconcerns:\n\n- **CLI Interface**: Typer-based command-line interface\n- **Configuration**: Pydantic models with YAML/env support\n- **Scanner**: Workflow file discovery and parsing\n- **Patterns**: Regex-based action call extraction\n- **Validator**: Git-based remote validation\n- **Models**: Type-safe data structures\n\n## Performance\n\nGHA Workflow Linter performance optimizations:\n\n- **Parallel Processing**: Multi-threaded validation\n- **Caching**: Repository and reference validation caching\n- **Rate Limiting**: Configurable delays to respect API limits\n- **Efficient API Operations**: Uses GitHub GraphQL API\n\nTypical performance on a repository with 50 workflows and 200 action calls:\n\n- **Serial**: ~60 seconds\n- **Parallel (4 workers)**: ~15 seconds\n- **Cached**: ~2 seconds (follow-up runs)\n\n## Security Notes\n\n- **Token Security**: Tokens are never logged or stored permanently\n- **Environment Variables**: Recommended method for token management\n- **Private Repositories**: Requires appropriate token permissions\n- **Rate Limiting**: Proactive management prevents API abuse\n- **API Efficiency**: Batch queries reduce API surface area\n\n### Pre-commit Hook\n\nThe repository includes a pre-commit hook that runs gha-workflow-linter\non its own workflows:\n\n```yaml\n# .pre-commit-config.yaml\nrepos:\n  - repo: https://github.com/modeseven-lfit/gha-workflow-linter\n    rev: d86993e21bbcddcfa9dac63cd43213b6a58fa6fb  # frozen: v0.1.1\n    hooks:\n      - id: gha-workflow-linter\n```\n\n### Development Setup\n\nFor contributors, use the development setup script:\n\n```bash\n# Install development environment with self-linting\n./scripts/setup-dev.sh\n\n# This sets up:\n# - Development dependencies\n# - Pre-commit hooks (including gha-workflow-linter)\n# - GitHub authentication (GitHub CLI recommended)\n# - Self-linting test\n```\n\n## Troubleshooting\n\n### Authentication Issues\n\n**GitHub CLI not found:**\n\n```text\n\u274c Unable to get GitHub token from any source\n\ud83d\udca1 Authentication options:\n   \u2022 Install GitHub CLI: https://cli.github.com/\n   \u2022 Or set environment variable: export GITHUB_TOKEN=ghp_xxx\n   \u2022 Or use --github-token flag with your personal access token\n```\n\n**GitHub CLI not authenticated:**\n\n```bash\n# Check authentication status\ngh auth status\n\n# Login if not authenticated\ngh auth login\n```\n\n**Token permissions:**\n\n- Ensure your token has `public_repo` scope for public repositories\n- Use `repo` scope for private repositories\n- Check token validity: `gh auth token` should return a valid token\n\n**Rate limiting:**\n\n- Without authentication: 60 requests/hour\n- With GitHub token: 5,000 requests/hour\n- Large repositories may require authentication to avoid limits\n\n## Contributing\n\nWe welcome contributions! Please see our contributing guidelines:\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes with tests\n4. Run the test suite and linting (including self-linting)\n5. Submit a pull request\n\n## License\n\nLicensed under the Apache License 2.0. See the LICENSE file for details.\n\n## Support\n\n- **Issues**: [GitHub Issues](https://github.com/modeseven-lfit/gha-workflow-linter/issues)\n- **Discussions**: [GitHub Discussions](https://github.com/modeseven-lfit/gha-workflow-linter/discussions)\n- **Documentation**: [Read the Docs](https://gha-workflow-linter.readthedocs.io)\n\n## Acknowledgments\n\nBuilt with modern Python tooling:\n\n- [Typer](https://typer.tiangolo.com/) for CLI interface\n- [Pydantic](https://docs.pydantic.dev/) for data validation\n- [Rich](https://rich.readthedocs.io/) for beautiful terminal output\n- [uv](https://docs.astral.sh/uv/) for dependency management\n- [pytest](https://pytest.org/) for testing\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "GitHub Actions workflow linter for validating action and workflow calls",
    "version": "0.1.7",
    "project_urls": {
        "Bug Tracker": "https://github.com/lfit/gha-workflow-linter/issues",
        "Changelog": "https://github.com/lfit/gha-workflow-linter/releases",
        "Documentation": "https://gha-workflow-linter.readthedocs.io",
        "Homepage": "https://github.com/lfit/gha-workflow-linter",
        "Repository": "https://github.com/lfit/gha-workflow-linter.git"
    },
    "split_keywords": [
        "actions",
        " github",
        " linting",
        " validation",
        " workflows"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2315777226fcc1f57410c4259362adc1a7d38ededa24e3acef4d5175dd23d3ba",
                "md5": "50c25d7a5b8abe78c4fddb0d42831a40",
                "sha256": "1157889fd15e95011560427555be1589a295b281a453f3855e4487b0df9dec54"
            },
            "downloads": -1,
            "filename": "gha_workflow_linter-0.1.7-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "50c25d7a5b8abe78c4fddb0d42831a40",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<3.14,>=3.10",
            "size": 64843,
            "upload_time": "2025-10-30T18:38:59",
            "upload_time_iso_8601": "2025-10-30T18:38:59.774479Z",
            "url": "https://files.pythonhosted.org/packages/23/15/777226fcc1f57410c4259362adc1a7d38ededa24e3acef4d5175dd23d3ba/gha_workflow_linter-0.1.7-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "04ba54391be2cc79c1aa93c43d11762ede01d534c87a096f6dd2c448a940925c",
                "md5": "ec392199dafb49b70751bab0b132109f",
                "sha256": "7ffaa6565b071c218a7f501b6c0814400d0991d93d4a6613d2dd60cb9f8fe36e"
            },
            "downloads": -1,
            "filename": "gha_workflow_linter-0.1.7.tar.gz",
            "has_sig": false,
            "md5_digest": "ec392199dafb49b70751bab0b132109f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<3.14,>=3.10",
            "size": 174832,
            "upload_time": "2025-10-30T18:39:01",
            "upload_time_iso_8601": "2025-10-30T18:39:01.359675Z",
            "url": "https://files.pythonhosted.org/packages/04/ba/54391be2cc79c1aa93c43d11762ede01d534c87a096f6dd2c448a940925c/gha_workflow_linter-0.1.7.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-30 18:39:01",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "lfit",
    "github_project": "gha-workflow-linter",
    "github_not_found": true,
    "lcname": "gha-workflow-linter"
}
        
Elapsed time: 2.39073s