Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions plugins/guardrails/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ All notable changes to the `guardrails` plugin are documented here. Format follo
stringified `"true"` / `"false"` values the jq filter produces; any other shape skips
verification rather than proceeding on the permissive branch.

### Changed

- **Eight prose references still named 0.26.0 as the release that made `block-hook-bypass`'s
exemptions operand-keyed. It is 0.27.0.** No behaviour changes, no assertions moved. The #2226 work
was written against 0.26.0 and renumbered when `main` took that version for the
`block-dangerous-git` / `block-no-verify` `jq` fail-closed change (#2146) while the branch was
open. The renumber reached the CHANGELOG heading, the manifest version and the entry's own
comparison table; it did not reach the narrative around them, so the README caveat paragraph (2),
the note above `scratch_target_exempt` (1), three comments in the contract test, and the erratum
inside the 0.25.1 entry (2) each pointed a reader at a release that documents something else
entirely. 0.26.0's own heading and entry are untouched — that is the one 0.26.0 reference in this
plugin that is correct.

## [0.27.1]

### Fixed
Expand Down
4 changes: 2 additions & 2 deletions plugins/guardrails/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@ out of scope until such a signal exists.
fails closed rather than being documented: the quote strip drops a kept
target's quotes, and the segment split would then read a `;`, `|`, `&` or space
*inside* the operand as syntax, so `> "/tmp/scratch/a;/../../etc/passwd"` —
one pathname to bash — would be judged on `/tmp/scratch/a`. Since **0.26.0**
one pathname to bash — would be judged on `/tmp/scratch/a`. Since **0.27.0**
the operand is **marked** wherever that would happen, so it reaches the compare
as one word and the decision is made on the whole thing: an operand carrying
whitespace, `;`, `|`, `&`, `(`, `)`, a newline or a backslash escape exempts
nothing, and a merely quoted operand is refused by this axis on its shipped
floor. **Quotes and backslashes elsewhere in the command no longer matter.**
Before 0.26.0 this test read the whole raw command tail after the first `>`
Before 0.27.0 this test read the whole raw command tail after the first `>`
*character*, so a quote in an unrelated later segment, or a `>` inside quoted
content, cancelled the exemption for an earlier plain write. Both were friction
rather than protection and both are gone — `echo x > /tmp/scratch/f && grep foo
Expand Down
2 changes: 1 addition & 1 deletion plugins/guardrails/hooks/block-hook-bypass.sh
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ devnull_target_exempt() {
# root only in case is therefore also exempt.
#
# A QUOTED OR ESCAPED redirect operand is never exempt — see the fail-closed
# tests at the top of scratch_target_exempt. Since 0.26.0 that decision is made
# tests at the top of scratch_target_exempt. Since 0.27.0 that decision is made
# on the OPERAND, from the marks strip_literals attaches to it, not on the raw
# command: an operand carrying whitespace, `;`, `|`, `&`, `(`, `)`, a newline or
# a backslash escape is OPAQUE and exempts nothing, and a merely quoted one is
Expand Down
6 changes: 3 additions & 3 deletions plugins/guardrails/hooks/block-hook-bypass.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,7 @@ run "scratch: case-insensitive compare (documented residual, allowed)" \
"echo hello > /tmp/SCRATCH/f" 0 "$SCRATCH_ENV=/tmp/scratch"

# TRUNCATED-OPERAND FAIL-CLOSED. strip_literals keeps a quoted write target but
# drops its quotes, and before 0.26.0 normalize_segments then resolved a `;`,
# drops its quotes, and before 0.27.0 normalize_segments then resolved a `;`,
# `|`, `&`, newline or space inside that operand as SYNTAX — so a quoted pathname
# reached the compare as a safe-looking prefix of itself. bash treats the whole
# quoted word as one pathname, so exempting the prefix would be a one-token
Expand All @@ -897,7 +897,7 @@ run "scratch: even a benign quoted target is not exempted (blocked)" \
run "scratch: quoted content, unquoted target (allowed)" \
"echo \"hello world\" > /tmp/scratch/f" 0 "$SCRATCH_ENV=/tmp/scratch"
# THE BREADTH THAT WAS, still pinned on both sides — but the verdicts moved in
# 0.26.0 and these four cases are where that is visible. 0.25.x could not tell
# 0.27.0 and these four cases are where that is visible. 0.25.x could not tell
# operand quotes from content quotes, so it read `${COMMAND#*>}` and refused the
# exemption on ANY quote or backslash after the first `>` CHARACTER anywhere in
# the command (#2236). The operand marks supply that association, so the test is
Expand Down Expand Up @@ -925,7 +925,7 @@ run "scratch: > inside single-quoted content keeps it (allowed)" \
"echo 'x > y' > /tmp/scratch/f" 0 "$SCRATCH_ENV=/tmp/scratch"
# --- Redirect-operand marking (#2226) ---------------------------------------
# THE REPORTED BYPASS AND ITS FAMILY. A quoted redirect operand is one pathname
# to bash. Until 0.26.0 the exemptions were decided on its first whitespace- or
# to bash. Until 0.27.0 the exemptions were decided on its first whitespace- or
# separator-delimited fragment, so `> "/dev/null ../../etc/pw"` was exempted on
# the word `/dev/null` while nothing named `/dev/null` was the destination. The
# operand now carries an opaque mark over every character whose literal value
Expand Down
Loading