chore(release): v8.1.2 — node_modules and plugin dir foreign, posture credit honest

Version sync: package.json, .claude-plugin/plugin.json, README badge +
Recent versions row, CLAUDE.md header + v8.1.2 highlights, CHANGELOG
[8.1.2]. The own-working-tree header and CHANGELOG no longer claim that
node_modules and the plugin dir are the only install locations foreign
code lands in (independent review: Python venv, vendor/ still own) —
listed as Known open instead.

Gates on the staged tree: suite 2328 / 2322 pass / 0 fail / 6 skipped,
hooks 370/0, golden 109/7/4 61/61, av-surface 6/6, claude plugin
validate pass (1 known CLAUDE.md warning).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-22 21:39:19 +02:00
commit 0bc4c8a6be
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
6 changed files with 70 additions and 10 deletions

View file

@ -6,6 +6,63 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased]
## [8.1.2] - 2026-09-22
Patch that closes both items v8.1.1 left open. Detection tables, golden
baseline and hooks are unchanged. Windows/Defender quarantine is still not
measured. 2328 tests, 2322 pass, 6 skipped, 0 fail.
### Fixed
- **An installed package and a Claude Code plugin copy are no longer "own
working tree".** A target without a `.git` of its own shares the working
directory's git root, so v8.1.1 still read its `.llm-security-ignore` and
`.llm-security/policy.json` (including `sig.custom_rules_path`). A target is
now also foreign when the path from the working directory down to it has a
`node_modules` folder in it, or when it lies under Claude Code's plugin
directory — `$CLAUDE_CONFIG_DIR/plugins`, or `~/.claude/plugins` when the
variable is unset (`cache/` and `marketplaces/` alike)
(`scanners/lib/own-working-tree.mjs`). These are the two install locations
the rule names; it does not cover every place foreign code can land (see
Known open). A general "has no `.git` of its own" rule was not taken,
because it would also ignore the configuration of ordinary folders inside
your own repository.
**Behaviour change:** scanning a package under `node_modules/`, or a plugin
under the plugin directory, no longer applies that folder's ignore file or
policy; it gets the defaults and one stderr line per ignored file. Only the
path *below* the working directory is checked for `node_modules`, so a
package you have `cd`'d into and scan as `.` is still your own tree. A target
under the plugin directory is foreign even from inside it. Scanning your
repository or a plain folder inside it is unchanged, and so are hooks, which
read the policy from the project root.
- **The posture scanner no longer gives NIST "Govern" credit for a
`policy.json` the scan would not honour.** The credit used to follow the
file's existence; it now also requires the target to be your own working
tree (`scanners/posture-scanner.mjs`).
### Known open
- **A `git archive` export or an unpacked tarball under the working
directory still counts as your own tree.** It has no `.git`, no
`node_modules` folder and no plugin-directory path, so nothing tells it apart
from a folder of your own; its ignore file and policy are read.
- **Other install locations still count as your own tree:** a package in a
Python virtual environment (`.venv/lib/…/site-packages/`), a composer or
bundler `vendor/` folder, and skills copied into `~/.claude/skills` when you
scan from inside a git-tracked `~/.claude`. Only `node_modules` and the
plugin directory are named by the rule.
- The plugin-directory check knows one config directory: the one
`CLAUDE_CONFIG_DIR` points at, or `~/.claude` when it is unset. With the
variable pointing at another profile, a copy under `~/.claude/plugins` counts
as own again.
- Two cases stay foreign on purpose (safe direction, more findings, not
fewer): a git worktree of your repository checked out inside it, scanned
from the main checkout; and a target path typed with different letter case
than the folder on disk (macOS APFS is case-insensitive, but the path check
compares exactly).
## [8.1.1] - 2026-09-22
Patch that closes the v8.1.0 follow-up list. Detection tables, golden baseline