<!--
SPDX-License-Identifier: Apache-2.0
SPDX-FileCopyrightText: 2025 The Linux Foundation
-->
# ๐ GHA Workflow Linter
[](https://github.com/modeseven-lfit/gha-workflow-linter/actions/workflows/build-test.yaml)
[](https://pypi.org/project/gha-workflow-linter/)
[](https://devguide.python.org/versions/)
[](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[](https://github.com/modeseven-lfit/gha-workflow-linter/actions/workflows/build-test.yaml)\n[](https://pypi.org/project/gha-workflow-linter/)\n[](https://devguide.python.org/versions/)\n[](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"
}