GitHub Actions Maintainer
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-runfor 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.tomlmanifests, find the latest stable crates.io versions, and update supported cargo dependency requirements - Reports unmanaged cargo dependency shapes such as
path,git, andworkspace = trueentries 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-Afterplus rate-limit reset headers - Validates token scopes before remote PR creation so missing
repoorworkflowpermissions fail early
CLI
Options:
--repo: repository root to scan, defaults to.--workflows-path: relative workflow directory, defaults to.github/workflows--token: optional GitHub token, also read fromGITHUB_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--ownerand--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 workflowupdate: move selected dependencies to the latest upstream version. By default it targets GitHub Actions; add--cargoor--allfor cargo supportstatus: report current tracked versions, latest upstream versions, and whether a change is needed for the selected target setupdatewithout--create-pr: apply changes locally in the checked-out repository, which is the equivalent of the original tool's stage moderelease: 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:
Remote update mode will:
- validate the token before mutating repository state
- resolve the default branch when
--base-branchis 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).
release runs entirely through the GitHub REST API — no git, gh, or cargo binaries are needed at runtime — so it works inside minimal containers:
- Reads the current version from
Cargo.toml([package].version, falling back to[workspace.package].version). - Finds the latest
--tag-prefixsemver 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 withreleased=false;--bump major|minor|patchforces a release. - Rewrites the version across workspace member manifests, internal dependency pins, and
Cargo.lock. - 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.Ztag, an optional moving major alias tag (--update-major-alias), and the GitHub Release with grouped release notes. - Writes release notes to
--notes-fileandreleased/version/tag/release-url/notes-fileoutputs to$GITHUB_OUTPUTwhen 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:
repoorpublic_repoworkflow
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 Requests403 Forbiddenresponses that carry rate-limit exhaustion headers- server-side
5xxresponses - 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:
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
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.