github-actions-maintainer 0.4.2

General-purpose GitHub Actions maintenance toolkit with secure workflow pinning
Documentation

GitHub Actions Maintainer

CI Security License: MIT Rust

General-purpose dependency maintenance in Rust, built from the ThreatFlux Rust CI/CD template. The shipped capabilities cover secure GitHub Action pinning plus latest-version reporting and updates for both GitHub Actions and cargo packages.

What It Does

github-actions-maintainer pin scans workflow files, finds floating GitHub Action refs such as:

- uses: actions/checkout@v4

and rewrites them to immutable commit SHAs while keeping the original ref as a comment:

- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v4

That preserves operator intent while eliminating runtime drift from moving tags and branches.

Current Features

  • Pins the ref already declared in the workflow instead of upgrading to a newer major automatically
  • Supports GitHub-hosted actions with nested paths such as github/codeql-action/init@v3
  • Skips local actions, Docker actions, and dynamic expressions like ${{ matrix.action }}
  • Offers --dry-run for previewing rewrites before touching files
  • Can update actions to the latest GitHub release, with tag fallback when releases are absent
  • Can report current tracked versions versus latest upstream versions without rewriting files
  • Can scan Cargo.toml manifests, find the latest stable crates.io versions, and update supported cargo dependency requirements
  • Reports unmanaged cargo dependency shapes such as path, git, and workspace = true entries instead of rewriting them
  • Can create a remote branch and pull request with labels instead of rewriting the checked-out repo
  • Retries GitHub API calls with exponential backoff and respects Retry-After plus rate-limit reset headers
  • Validates token scopes before remote PR creation so missing repo or workflow permissions fail early

CLI

cargo run -- pin --dry-run
cargo run -- update --dry-run
cargo run -- update --cargo --dry-run
cargo run -- update --all
cargo run -- update
cargo run -- status
cargo run -- status --cargo
cargo run -- pin --repo /path/to/repo --workflows-path .github/workflows

Options:

  • --repo: repository root to scan, defaults to .
  • --workflows-path: relative workflow directory, defaults to .github/workflows
  • --token: optional GitHub token, also read from GITHUB_TOKEN
  • --dry-run: report rewrites without applying them
  • --cargo: target cargo package dependencies
  • --github-actions: target GitHub Actions updates explicitly
  • --all: target both GitHub Actions and cargo package dependencies
  • --create-pr: create a remote branch and pull request instead of editing files locally
  • --owner and --repo-name: remote repository coordinates for PR creation
  • --labels, --title, --commit-message, --base-branch, --branch-name: control remote PR creation

Command behavior:

  • pin: pin the ref already declared in the workflow
  • update: move selected dependencies to the latest upstream version. By default it targets GitHub Actions; add --cargo or --all for cargo support
  • status: report current tracked versions, latest upstream versions, and whether a change is needed for the selected target set
  • update without --create-pr: apply changes locally in the checked-out repository, which is the equivalent of the original tool's stage mode
  • release: bump the Cargo version from conventional commits, then create the release commit, tag, and GitHub Release through the API (see below)

Cargo update support currently manages registry-backed dependencies that declare a direct version requirement such as:

  • reqwest = "0.12.13"
  • serde = { version = "^1.0.200", features = ["derive"] }
  • regex = { version = "~1.10.0" }

The updater preserves the existing requirement operator where possible and skips unsupported forms such as multi-range requirements, path dependencies, git dependencies, and workspace = true references.

Remote update mode:

cargo run -- update \
  --cargo \
  --create-pr \
  --owner ThreatFlux \
  --repo-name githubWorkFlowChecker \
  --token "$GITHUB_TOKEN"

Remote update mode will:

  • validate the token before mutating repository state
  • resolve the default branch when --base-branch is not provided
  • create a tree/commit/branch through the GitHub API
  • open a pull request and attach any requested labels

Release mode:

# Outside GitHub Actions, pass --owner/--repo-name (or set GITHUB_REPOSITORY).
cargo run -- release --dry-run \
  --owner ThreatFlux \
  --repo-name github_actions \
  --token "$GITHUB_TOKEN"
cargo run -- release \
  --owner ThreatFlux \
  --repo-name github_actions \
  --update-major-alias \
  --token "$GITHUB_TOKEN"

release runs entirely through the GitHub REST API — no git, gh, or cargo binaries are needed at runtime — so it works inside minimal containers:

  1. Reads the current version from Cargo.toml ([package].version, falling back to [workspace.package].version).
  2. Finds the latest --tag-prefix semver tag and classifies the conventional commits since it (feat: → minor, fix: → patch, !/BREAKING CHANGE → major). Merge commits are skipped. When no commit warrants a release it exits successfully with released=false; --bump major|minor|patch forces a release.
  3. Rewrites the version across workspace member manifests, internal dependency pins, and Cargo.lock.
  4. Creates the release commit directly on the base branch (fast-forward only — if the branch advanced past the analyzed head, the run skips cleanly), the vX.Y.Z tag, an optional moving major alias tag (--update-major-alias), and the GitHub Release with grouped release notes.
  5. Writes release notes to --notes-file and released/version/tag/release-url/notes-file outputs to $GITHUB_OUTPUT when set.

Release mode requires a token with contents: write on the target repository. The workflow scope is not required because release commits only touch Cargo manifests.

Token Permissions

Remote PR mode requires a GitHub token with the equivalent of:

  • repo or public_repo
  • workflow

pin, update --dry-run, and status can run without a token. Authenticated requests are still recommended for GitHub-backed operations to raise API rate limits.

Rate Limits

The GitHub client retries transient failures and rate-limited responses. The crates.io client also retries 429 and 5xx responses with Retry-After handling.

GitHub handling includes:

  • 429 Too Many Requests
  • 403 Forbidden responses that carry rate-limit exhaustion headers
  • server-side 5xx responses
  • connection and timeout errors from the HTTP client

When GitHub returns reset metadata, the client sleeps until the reset window instead of blindly retrying.

GitHub Action Usage

name: Maintain Dependencies

on:
  workflow_dispatch:
  pull_request:
    paths:
      - ".github/workflows/**"

jobs:
  pin-actions:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Update workflow and cargo dependencies
        uses: ThreatFlux/github-actions-maintainer@main
        with:
          command: update
          all: "true"
          token: ${{ secrets.GITHUB_TOKEN }}
          owner: ${{ github.repository_owner }}
          repo-name: ${{ github.event.repository.name }}
          create-pr: "true"
          dry-run: "false"

The repository also ships an action.yml wrapper so the binary can run as a container action.

Auto Release Action

The release/ sub-action gives any Cargo-based repository automatic releases on merge to main: it bumps the version from conventional commits, rewrites Cargo.toml/Cargo.lock, and creates the release commit, tag, and GitHub Release with generated notes — entirely through the GitHub API, from a prebuilt image that starts in seconds.

name: Auto Release
on:
  push:
    branches: [main]
concurrency:
  group: auto-release-${{ github.ref }}
permissions:
  contents: write
jobs:
  release:
    uses: ThreatFlux/github_actions/.github/workflows/reusable-auto-release.yml@v0 # pin to a SHA in production
    with:
      bump: auto

Two actions live in this repository: ThreatFlux/github_actions@<ref> (dependency maintainer, root action.yml) and ThreatFlux/github_actions/release@<ref> (auto release). See release/README.md for inputs, outputs, token guidance, and branch-protection notes.

Development

make dev-setup
cargo fmt --all
cargo clippy --all-features --all-targets -- -D warnings
cargo test --all-features

Architecture

The Go-based githubWorkFlowChecker concept was narrowed for the initial Rust implementation:

  • keep the repo general-purpose for future GitHub Actions maintenance features
  • ship secure pinning first, then add version-aware updates and authenticated PR publishing
  • separate scanning, GitHub resolution, and rewrite orchestration into small modules

See docs/ARCHITECTURE.md for the current design.