A configuration file is optional.
pinact supports a configuration file .pinact.yaml, .github/pinact.yaml, .pinact.yml or .github/pinact.yml.
You can also specify the configuration file path by the environment variable PINACT_CONFIG or command line option -c.
You can generate a configuration file by pinact init.
pinact init [<configuration file path>]As of pinact v2.2.0, pinact configuration file has a schema version.
version: 3In general, you should use the latest schema version.
pinact migrate command migrates your configuration file to the latest schema version.
pinact migrate- pinact.json
- https://raw.githubusercontent.com/suzuki-shunsuke/pinact/refs/heads/main/json-schema/pinact.json
If you look for a CLI tool to validate configuration with JSON Schema, ajv-cli is useful.
ajv --spec=draft2020 -s json-schema/pinact.json -d pinact.yamlVersion: main
# yaml-language-server: $schema=https://raw.githubusercontent.com/suzuki-shunsuke/pinact/main/json-schema/pinact.jsonOr pinning version:
# yaml-language-server: $schema=https://raw.githubusercontent.com/suzuki-shunsuke/pinact/v1.1.2/json-schema/pinact.jsonpinact supports a global configuration file for user-wide defaults.
Global Configuration File Paths (highest precedence first):
$PINACT_GLOBAL_CONFIGif set (any absolute or relative path; no~or$VARexpansion is performed)- Linux, macOS:
$XDG_CONFIG_HOME/pinact/pinact.yamlif$XDG_CONFIG_HOMEis set~/.config/pinact/pinact.yaml
- Windows:
%APPDATA%\pinact\pinact.yaml
When both a project-level configuration (e.g. .pinact.yaml) and a global configuration exist, they are merged field-by-field. Project values win for scalars and the min_age / ghes blocks; list fields (rules, ignore_actions) are concatenated as [global..., project...]. Each file's schema version is validated independently; if either file uses an unsupported or abandoned version, pinact aborts with an error that names the offending path.
| Field | Merge behavior |
|---|---|
version |
project if non-zero, otherwise global (both are validated independently) |
files |
project if non-empty, otherwise global |
separator |
project if non-empty, otherwise global |
ghes |
project if set (whole-object replace), otherwise global |
min_age.value |
project if set, otherwise global |
min_age.always |
project if set, otherwise global (so a global always: true survives when the project doesn't mention it) |
ignore_actions |
concatenated as [global..., project...] |
rules |
concatenated as [global..., project...] (later rules win per-field under the existing rule resolution semantics) |
pinact init -g creates a global configuration file if it doesn't exist (and honors $PINACT_GLOBAL_CONFIG for the target path).
pinact init -gpinact v2.2.0 or later supports this version.
.pinact.yaml
e.g.
version: 3
files:
- pattern: .github/workflows/*.yml
- pattern: .github/workflows/*.yaml
- pattern: .github/actions/*/action.yml
- pattern: .github/actions/*/action.yaml
ignore_actions:
# slsa-framework/slsa-github-generator doesn't support pinning version
# > Invalid ref: 68bad40844440577b33778c9f29077a3388838e9. Expected ref of the form refs/tags/vX.Y.Z
# https://github.com/slsa-framework/slsa-github-generator/issues/722
- name: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml
ref: "v\\d+\\.\\d+\\.\\d+"
- name: suzuki-shunsuke/.*
ref: main
# GitHub Enterprise Server Support
ghes:
api_url: https://ghes.example.com
fallback: true # optional, default is false
# Separator between version and tag comment (optional, default is " # ")
# pinact >= v3.9.0
separator: " # "
# Default min-age in days (optional)
# pinact >= v4.0.0
min_age:
value: 7
always: true
rules:
- ignore: true
conditions:
- expr: |
ActionName == "slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml" && ActionVersion matches "v\\d+\\.\\d+\\.\\d+"
- expr: |
ActionName matches "suzuki-shunsuke/.*" && ActionVersion == "main"
- min_age: 0
conditions:
- expr: |
ActionName matches "suzuki-shunsuke/.*" && ActionVersion == "main"This is optional. A list of target files.
This is required. A glob pattern of target files. Go's path/filepath#Glob is used. A relative path from pinact's configuration file. If files are passed via positional command line arguments, the configuration is ignored.
e.g.
files:
- pattern: .github/workflows/*.yml
- pattern: .github/workflows/*.yaml
- pattern: README.mdpinact >= v4.0.0
This is optional. A list of rules that override per-action settings for actions matching expression conditions.
Each rule has match conditions and one or more override fields (ignore, min_age). When pinact processes an action, every rule's conditions are evaluated in declaration order. For each rule that matches, its override fields are merged on top of previous matches: later rules override earlier ones, but only for the fields they explicitly set.
For new configurations, prefer rules with ignore: true over ignore_actions for more flexibility (rules can match on owner, repo, version comment, etc.).
e.g.
rules:
# Skip actions whose ref is a branch name in our own repos.
- ignore: true
conditions:
- expr: |
ActionRepoOwner == "suzuki-shunsuke" && ActionVersion == "main"
# Lower the min-age threshold for trusted actions.
- min_age: 0
conditions:
- expr: |
ActionRepoFullName == "actions/checkout"This is optional. If true, pinact skips pin/update/error reporting for the matched action.
This is optional. Overrides the min-age threshold (in days) for the matched action. Setting it to 0 disables the min-age check for the action.
The effective min-age for an action is resolved in this order: CLI flag -min-age > matching rules > top-level min_age.
This is required. A list of match conditions. The rule matches if any of its conditions evaluates to true (OR semantics). Each rule must have at least one condition.
This is required. A boolean expression evaluated against the action being processed. The expr language is used.
The following variables are available:
| Variable | Description | Example |
|---|---|---|
ActionName |
Full action name | slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml |
ActionRepoOwner |
Repository owner | slsa-framework |
ActionRepoName |
Repository name | slsa-github-generator |
ActionRepoFullName |
<owner>/<repo> |
slsa-framework/slsa-github-generator |
ActionVersion |
The action's ref (commit SHA, tag, or branch) | v1.10.0, main, 68bad40... |
VersionComment |
Existing # <tag> comment on the line, if any |
v1.10.0 |
Expressions are validated and compiled at startup. Syntax errors, references to undefined variables, and non-boolean expressions are surfaced as configuration errors.
pinact >= v4.0.0
This is optional. The default min-age in days for the min-age check. When set, pinact checks that every action's pinned commit is at least this many days old, and exits with code 2 on violation.
The top-level value can be overridden by the CLI flag -min-age (highest precedence) or per-action by rules[].min_age.
This is optional. A list of ignored actions and reusable workflows.
Note
For new configurations, consider using rules with ignore: true instead. rules can match on the repository owner, full name, version comment, and arbitrary expressions, while ignore_actions only matches on name and ref regexps.
This is required. A regular expression of ignored actions and reusable workflows.
ignore_actions:
- name: actions/.*
ref: mainWarning
Regular expressions must match with action names exactly.
For instance, name: actions/ doesn't match with actions/checkout
Regarding regular expressions, Go's regexp package is used.
This is required. A regular expression of ignored action versions (branch, tag, or commit hash).
Warning
Regular expressions must match with action versions exactly.
For instance, ref: main doesn't match with malicious-main
See GitHub Enterprise Support.
This is optional. Default is #.
The separator between the action version (commit SHA) and the version tag comment.
It must include #.
You can also configure the separator by command line option --separator (-sep) or environment variable PINACT_SEPARATOR.
e.g.
# Default separator " # "
separator: " # "
# Results in: uses: actions/checkout@abc123... # v3.5.0
# Custom separator " # tag="
separator: " # tag="
# Results in: uses: actions/checkout@abc123... # tag=v3.5.0
# Custom separator with double space before #
separator: " # "
# Results in: uses: actions/checkout@abc123... # v3.5.0Please see here.