Skip to content

v0.2.0

Released on 2026-03-15. Full changelog

Breaking: * inside quotes is now treated as a glob pattern (#157)

Section titled “Breaking: * inside quotes is now treated as a glob pattern (#157)”

Previously, "*" in a pattern was treated as a literal asterisk. Starting with v0.2.0, * inside quotes is treated as a glob wildcard, matching the same way as an unquoted *. To match a literal * character, use the \* escape sequence.

What should I do?

If your rules use "*" intending to match a literal asterisk, update them to use \*:

runok.yml
# Before (v0.1.x): matched a literal * character
rules:
- allow: 'echo "*"'
# After (v0.2.0): use \* to match a literal * character
rules:
- allow: 'echo \*'

If your rules use "*" intending it as a wildcard (matching any arguments), no changes are needed — it now works as you’d expect.

See Wildcards for details.

A new runok test subcommand lets you write test cases for your rules and verify they behave as intended. Test cases can be defined in two ways.

Inline tests attach directly to a rule:

runok.yml
rules:
- allow: 'git status'
tests:
- allow: 'git status'
- allow: 'git status --short'
- deny: 'git push -f|--force *'
tests:
- deny: 'git push --force origin main'

Top-level tests validate across multiple rules:

runok.yml
tests:
cases:
- allow: 'git push origin main'
- deny: 'git push --force origin main'
Terminal window
$ runok test -c runok.yml
PASS: git status => allow
PASS: git status --short => allow
PASS: git push --force origin main => deny
3 passed, 0 failed, 3 total

Global config is excluded during test execution to guarantee reproducible results.

See runok test for details.

Rules can now define typed variables using definitions.vars and reference them with <var:name> in patterns. Variables support per-value types for more precise matching, and can also be used in command position:

runok.yml
definitions:
vars:
branch:
values:
- main
- develop
- 'feature/*'
rules:
- allow: 'git checkout <var:branch>'

See Placeholders and Configuration Schema for details.

The new runok audit subcommand provides logging and inspection of command evaluation results. It displays results in a table format with colors, making it easy to review how rules evaluate commands across your configuration.

Use --dir to filter audit results by directory.

See runok audit for details.

A new command to refresh and upgrade cached remote presets. It detects version tag precision (@v1, @v1.0, @v1.0.0) and automatically finds the latest compatible version. For branch references, it shows SHA changes; for version tag upgrades, it displays a config file diff.

Terminal window
$ runok update-presets

See runok update-presets for details.

Two new context variables are available in when expressions for conditional rule evaluation based on shell I/O:

  • redirects: list of redirect operators present in the command (e.g., >, >>, 2>&1)
  • pipe: the command’s position in a pipeline (stdin, stdout, or empty)
runok.yml
rules:
# Block piping curl output to sh
- deny: 'sh'
when: 'pipe.stdin'

See when clause for details.

Fused short flags like -n3 (where the flag and value are joined without a space) are now matched by FlagWithValue patterns. This allows patterns like [-n *] to match both git tag -n 3 and git tag -n3:

runok.yml
rules:
# Matches: git tag -n3, git tag -n 3, git tag -n100
- allow: 'git tag [-n *] *'

Only flags declared as value-bearing in the pattern are split, so -rf (combined boolean flags) is not incorrectly separated.

See Matching Behavior for details.

Unknown flags before -- in exec/check subcommands were silently absorbed and the command exited with code 0. They are now properly rejected with an error message:

Terminal window
# Before: silently ignored, exit 0
runok check --unknown-flag -- git status
# After: error message, non-zero exit
runok check --unknown-flag -- git status # → error: unknown flag '--unknown-flag'

The runok exec --dry-run option has been removed. Use runok check instead, which provides the same functionality:

Terminal window
# Before
runok exec --dry-run -- git status
# After
runok check -- git status

<cmd> placeholder no longer captures flag-starting tokens (#206)

Section titled “<cmd> placeholder no longer captures flag-starting tokens (#206)”

The <cmd> placeholder in wrapper patterns was incorrectly capturing token sequences starting with -, causing explicitly allowed commands to be downgraded to ask:

runok.yml
definitions:
wrappers:
- 'command <cmd>'
rules:
- allow: 'command -v|-V *'
Terminal window
# Before: <cmd> captured [-v, a], inner "-v a" matched no rules → ask
command -v git # → ask (wrong)
# After: <cmd> skips flag-starting sequences, direct rule applies → allow
command -v git # → allow (correct)