diff --git a/Cargo.lock b/Cargo.lock index bbf2511..9ee2059 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -593,7 +593,7 @@ checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "uphold" -version = "1.6.0" +version = "1.7.0" dependencies = [ "encoding_rs", "globset", diff --git a/Cargo.toml b/Cargo.toml index 18ccd78..625e830 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uphold" -version = "1.6.0" +version = "1.7.0" edition = "2021" # 1.88, not 1.85: the ripgrep stack this crate embeds -- globset 0.4.20 and # ignore 0.4.33 in Cargo.lock -- refuses anything older. The 1.85 that stood here diff --git a/README.md b/README.md index ae4b1c0..1022ae5 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ bootstraps). default_install_hook_types: [pre-commit, commit-msg, pre-merge-commit, pre-push] repos: - repo: https://github.com/HackingGate/uphold - rev: v1.6.0 + rev: v1.7.0 hooks: - id: uphold-check # the claims still hold - id: uphold-scan # the content policy @@ -48,13 +48,13 @@ the binary must be on PATH. # lefthook.yml remotes: - git_url: https://github.com/HackingGate/uphold - ref: v1.6.0 + ref: v1.7.0 configs: - hooks/lefthook.yml ``` ```sh -cargo install --git https://github.com/HackingGate/uphold --tag v1.6.0 +cargo install --git https://github.com/HackingGate/uphold --tag v1.7.0 ``` That `ref:` is the one version a lefthook consumer pins, and **Dependabot does diff --git a/docs/REFERENCE.md b/docs/REFERENCE.md index c8267ea..103ca66 100644 --- a/docs/REFERENCE.md +++ b/docs/REFERENCE.md @@ -72,6 +72,46 @@ every git hook, and a repository whose own prose cites its issues would have every one of those citations refused — so the seam it belongs at is the command that publishes text to a forge, and only that one. +### A rule may not be about its own declaration + +A policy file is a tracked file, so a rule's `regexp` and `require_regexp` are +inside the corpus that rule scans. An unanchored literal therefore matches the +line it is written on, and both fields reach the same accident from opposite +directions: + +| field | must find | a self-match is | +|---|---|---| +| `regexp` | nothing | a finding that is always there, naming the rule instead of the tree | +| `require_regexp` | something | a pass that is always there, exempting the policy file forever | + +**A rule that matches its own declaration *and* selects the file that +declaration is in is refused at load.** Both halves are required. Most rules +never select the policy file — an `include` of `["cmd", "internal"]` with a +`glob` of `["*.go"]` cannot reach `policy/` — and a pattern matching its own +text under such a rule is harmless, so the scope test comes first. + +Three cures, and the refusal names all of them: + +```toml +[rule.no-yubikey-mentions] +regexp = '\bYubiKey\b' +[rule.no-yubikey-mentions.files] +include = ["."] +exclude = ["policy/**"] # 1. exclude the policy file +``` + +2. narrow `files.include` to what the rule is actually about; +3. anchor the pattern, so it cannot match the key it is written under. + +The third is worth knowing before reaching for the first. `^Status:` does not +match `regexp = '^Status:...'`, because that line begins with `regexp` — so an +anchored pattern needs nothing, and a one-character class written to dodge a +self-match it never had (`^Sta[t]us:`) is a defensive edit that can be deleted. + +Own rules only. A bundled set's rule is declared inside the binary and an +`inherit.paths` rule in a file the rule may not select; neither has a +declaration in this policy file to match. + Exit codes: `0` clean, `1` violations, `2` the check could not be made. There is no fourth. A reader that closes a pipe — `uphold scan | head` — is a diff --git a/hooks/lefthook.yml b/hooks/lefthook.yml index 0abdbe0..ad6de32 100644 --- a/hooks/lefthook.yml +++ b/hooks/lefthook.yml @@ -10,7 +10,7 @@ # # lefthook.yml, in the consuming repository # remotes: # - git_url: https://github.com/HackingGate/uphold -# ref: v1.6.0 +# ref: v1.7.0 # configs: # - hooks/lefthook.yml # @@ -21,7 +21,7 @@ # their manifest contract; lefthook runs commands and has no such contract, so # `uphold` must be on PATH: # -# cargo install --git https://github.com/HackingGate/uphold --tag v1.6.0 +# cargo install --git https://github.com/HackingGate/uphold --tag v1.7.0 # # The names below are prefixed `uphold-` on purpose. A remote config is # merged into the consumer's own, and two commands sharing a name under one hook