Skill 安装
多 Agent 安装npx skills add https://github.com/bitwarden/ai-plugins --skill reviewing-claude-config
使用 npx skills 快速安装,支持将 Skill 添加到多个兼容的 AI Agent。
Skill 调研报告
bitwarden/ai-plugins#reviewing-claude-config
Skill 更新日志
版本列表
无版本号
fix(claude-config-validator): close three false negatives in security-scan.sh (#203)
* fix(claude-config-validator): close three false negatives in check 1 and the permission checks
Rebased onto the current #201, which absorbed the secret-filter and verdict work
this branch previously carried. #201 anchors placeholder patterns to value
position and adds the INCOMPLETE verdict with exit 2, both better than what was
here, so only the gaps it does not cover remain.
Check 1 still piped git ls-files into grep -q. Under pipefail a match makes grep
exit first, git dies of SIGPIPE with 141, and the pipeline reports failure, so a
committed settings.local.json read as absent. Reproduced against #201 at 20k
tracked files. It also ran without -C, so the check read whatever repository the
shell was in and reported a pass for a target outside one.
The two permission checks still printed "(OK)" when there was no settings.json to
read, which #201's own skipped accounting then did not see.
Add security-scan.test.sh. Eight of its fifteen assertions fail against #201 as it
stands. Credential fixtures are assembled at run time so the file holds no string
a secret scanner should flag, which keeps the scanner's exclusion list from having
to grow to accommodate its own tests.
* fix(claude-config-validator): answer the open review threads on the scanner
An absent settings.json is a determinate answer rather than a check that could
not run: no file means no rules are set in the scanned directory. Marking it
skipped drove a common .claude shape to INCOMPLETE and exit 2, overstating the
doubt in the direction opposite to the false negatives this branch closes. It
reports the result plainly now, and the README states that rules reaching the
session from elsewhere are outside what the scan sees.
Correct the README sentence saying the settings.local.json check does not report
itself as skipped, which check 1 now does outside a git repository.
Make the clean-configuration case jq-aware. Check 3's rule tests need jq, so
without it the run is legitimately incomplete and the old assertion failed on any
machine lacking it, which contradicted the no-new-dependency claim.
Document the suite and how to run it in the scanner section, including that
nothing runs it automatically.
* fix(claude-config-validator): make case 1 actually reproduce the pipeline failure
The fillers sat in the repository root, outside the scanned directory, so with
-C and a pathspec git wrote one line and the pipe never filled. The case caught
the -C fix but not the no-pipe half: reintroducing `| grep -q` still passed.
Moving the fillers under the scanned directory and matching the pathspec puts
roughly 500 KB past the 64 KB buffer, and reintroducing the pipe now fails the
case. Dropping xargs -n1 collapses 20k process spawns, so the suite runs in
about six seconds.
security-patterns.md documented check 1 as the pre-fix command, teaching the
false pass this branch removes and contradicting the file's own note that only
the check 3 and check 4 blocks mirror the script. The manual form now guards the
repository first and asks git with a pathspec, and the duplicated script block
points at the shipped script instead.
* chore(claude-config-validator): renumber to 2.0.2 above the merged 2.0.1
marketplace.json, plugin.json, and the README catalog row, with the changelog
section retitled so it sits above #208's entry rather than replacing it.
* fix(claude-config-validator): scope check 1 to the repository, not the scanned subtree
The -C fix targeted CLAUDE_DIR, which narrowed the check from the repository to
the .claude subtree: a committed settings.local.json anywhere else reported as
absent, and the paths listed no longer matched the remediation printed below
them. Reproduced with apps/foo/.claude/settings.local.json in a monorepo. It
resolves the scanned directory's worktree root first, which keeps the original
coverage while still targeting the target's repository rather than the shell's.
Route an ls-files failure to skipped rather than the OK branch, so a genuine
error cannot read as a pass.
Give case 5 a positive assertion. Built only from reject assertions, it passed
whenever the scanner produced no output at all, including an early exit, which
made it the one case where a broken scanner still showed green. Add a case for
the repository-wide coverage; reverting to subtree scope fails it.
* fix(claude-config-validator): widen the documented check to the worktree root
5f5d126 widened the script but left the reference's manual command asking git
from .claude, so a human following it on a monorepo got the pass this branch
removes. Same drift class as the README sentence and the Automated Detection
block already corrected here, in a third place.
Verified against a monorepo fixture: the old form returns nothing, the new form
returns apps/foo/.claude/settings.local.json.
无版本号
fix(claude-config-validator): stop two skills failing to load on quoted shell syntax (#208)
Claude Code expands a bash-execution block on the raw text of any file it
loads, so a skill that quotes the syntax to teach it runs the quoted
fragment as a shell command and fails. reviewing-claude-config carried one
in an inline code span; reviewing-command-definitions carried four plus a
fenced example.
Fenced blocks are not a safe haven: plugin-dev:command-development fails to
load for the same reason, from a fenced block.
无版本号
feat(claude-config-validator)!: fence findings to the changeset, split the review skill, and stop guessing at commands (#201)
* feat(claude-config-validator)!: fence findings to the changeset and split the review skill
Report only what a changeset introduced or worsened, fail only on CRITICAL, and
replace the checklist tree with four targeted review skills.
BREAKING CHANGE: reviewing-claude-config is now a router. The checklists/ and
examples/ directories are removed, and SKILL.md review belongs to
plugin-dev:skill-reviewer.
* fix(claude-config-validator): close review findings in the guardrail change
Restore the hook credential-access check dropped in the checklist split, add a
security floor to the verdict so a widened permission or tool grant fails the run
regardless of tier, exempt CRITICAL and security findings from the filter, add a
fallback routing row for skill support files, and carry the CWE-1427 boundary into
each targeted skill.
Also realign the READMEs and the marketplace escalation with the new structure.
* fix(claude-config-validator): gate the frontmatter skip on actual coverage
Skip agent frontmatter review only where plugin-dev:plugin-validator ran, rather
than wherever the file sits inside a plugin, so an uninstalled plugin-dev cannot
silence a CRITICAL band. Restore the permission-example wildcards, and align both
READMEs with the security floor and the coverage the targeted skills actually have.
* fix(claude-config-validator): correct the permission schema the skills teach
Permission rules are Tool(specifier) under permissions.allow/deny; the skills and
both references taught a top-level autoApprovedTools array with bare Tool:specifier
rules, which Claude Code does not read, so a reviewer following them would grep for
a key that never appears and report an over-broad settings file clean.
Also qualify the routing table's four skill names, cover shell execution and argument
interpolation in command review, gate the command frontmatter skip on actual coverage,
and carry the verdict's security floor into the remaining statements of it.
* fix(claude-config-validator): correct the permission rule grammar and the detectors
A bare Tool rule is valid and is the broadest grant available, so instructing
reviewers that every rule is Tool(specifier) filed a CRITICAL against a working
deny: ["WebFetch"] while calibrating them past the real unbounded grant. Scope that
finding to the two forms Claude Code genuinely does not read.
The detection greps, detect-broad-permissions.sh, and the shipped security-scan.sh
still matched the old notation, so all three reported a filesystem-wide grant as
scoped. Also settle // as absolute against a single leading slash as settings-relative,
give command review a real frontmatter pass, and gate the hook carve-out on actual
coverage like its two siblings.
* fix(claude-config-validator): use low-entropy placeholders for the secret examples
The example credentials had to match the quantifiers in the regexes the skill
points at, but a realistic-looking string of that length reads as a live secret to
a scanner. Repeated EXAMPLE text satisfies the length the regexes require without
the entropy that makes it look real.
* fix(claude-config-validator): stop telling reviewers that quoting closes shell injection
Pass 7 said quoting $ARGUMENTS inside a !`cmd` block closes the hole and is not a
finding. Substitution is textual and happens before the shell parses the line, so
$(rm -rf ~) still executes inside double quotes and 1" ; rm -rf ~ ; " closes the
author's quote outright. Both verified. Interpolation is now a finding either way,
with stdin or a validated allowlist as the remedy.
Also correlate the bare-tool-rule detector against permissions.allow so a bare rule
in deny no longer fails the scan, exclude placeholder text from secret detection now
that the teaching examples live inline, and correct the command frontmatter severity:
frontmatter is optional for commands, so a missing description does not stop loading.
* docs(claude-config-validator): drop the superseded quoting claim from the changelog
* fix(claude-config-validator): guard the documented detector and scope frontmatter severity
The bare-rule detector in security-patterns.md had no jq guard, so with jq absent the
branch was skipped, ISSUES stayed 0, and it printed "Permissions appropriately
scoped" for a check that never ran. The shipped script already guarded this; both
copies now agree.
Frontmatter severity is stated per file type, since commands do not require it and an
unqualified CRITICAL row failed a valid frontmatter-less command. The model-value
correction now reaches all four statements in the reference, including the detection
table a reviewer classifies from.
* fix(claude-config-validator): extend the security floor to shell-execution findings
The floor enumerated permissions, tool grants, and hook capabilities, so a changeset
adding a quoted $ARGUMENTS interpolation inside a !`cmd` block produced one IMPORTANT
finding, widened nothing enumerated, and reported Pass with a live injection vector
listed underneath. It now covers any new path from contributor-controlled input to a
shell, in all three copies of the clause.
Also annotate the Grep-path bare-rule pattern as candidate-only, since it cannot tell
allow from deny and the router has no Bash to reach the jq version, and carry the
model-identifier correction to the last two of six statements.
* fix(claude-config-validator): bring hook input guidance to parity with commands
reviewing-command-definitions asserted that the sibling applied the same rule to
hook input. It did not, and it should not: verified by execution, a quoted value in
a shell variable used directly is safe, the same value handed to a nested shell such
as bash -c is not, and slash-command substitution has no safe quoted form at all.
Both skills now state the three cases rather than one claiming agreement.
Also add a settings pass for the fields that execute or bypass, since defaultMode:
bypassPermissions disables prompting wholesale and matched no rule-shaped check; give
priority-framework hook and settings severity tables, which it had none of while a
skill delegated hook classification to it; settle the command tier in one place; and
write the report rather than asking which PR to validate when nobody can answer.
* fix(claude-config-validator): stop the secret scanner dropping keys by file path
The placeholder filter added in 47ea728 ran over the whole grep -r record, which
begins with the path, so a real key in any file under an example-named path was
discarded and the scan reported a pass. Verified by execution both ways: an identical
40-char sk- key in example-agent.md and prod-agent.md is now reported for both, and
the plugin's own teaching examples still produce no finding.
Also reconcile hook severity, which contradicted itself four lines apart: a quoted
value consumed directly by the command is not a finding, unquoted is CRITICAL, and a
nested shell is CRITICAL either way. Drop the blanket permission elevation in Security
Context, which overrode the per-field tables and falsified the security floor's own
rationale, and extend agent tool-access review to Skill alongside Task.
* fix(claude-config-validator): anchor the third secret filter to the value
e5d374f narrowed the OpenAI and GitHub token filters from the whole grep record to
the value and did not bring the generic-credential check along, so it still discarded
any match whose file path contained example or xxx. Reproduced the reported fixture:
three identical credentials, one reported. All three are reported now, and the
plugin's own teaching examples still produce no finding.
Also take acceptEdits out of the block whose closing sentence makes every item
CRITICAL, since the framework rates it IMPORTANT and asks why rather than blocking,
and state in the verdict that a widening the changeset justifies is not a finding at
all, which is what makes asking possible. Move the Migration heading below the five
Fixed entries it had captured.
* fix(claude-config-validator): close three false negatives in security-scan.sh
Verified by execution before and after. A raw sk- key under any examples/ directory
reported "All security checks passed", because the path exclusion on the two token
filters dropped it and the generic filter cannot see a key with no apiKey: prefix.
Both filters are anchored to the value now, as the generic one already was.
The sensitive-path loop grepped the whole settings file, so a config whose only
entries are hardening denies failed the scan, contradicting the framework row this PR
adds saying such a rule is the control. It reads permissions.allow via jq and records
itself skipped without jq.
Also drop additionalDirectories from the block that tiers every item CRITICAL, hoist
the agent scope exclusion ahead of Pass 1, and reword a CRITICAL checkbox that read as
a platform guarantee rather than a condition to confirm.
Per review: cut the 2.0.0 changelog entry from 78 bullets to 17, and remove the
skill-level README, moving the scanner usage it uniquely held to the plugin root.
* fix(claude-config-validator): make skipped checks reach the verdict and scope check 4
Regressions from 88a366c, all reproduced before and after. With jq absent, a settings
file granting bare Bash and Read(//Users/x/.ssh/**) printed "All security checks
passed" while the same commit added a README line promising skipped checks are never
reported as passed. Skips are counted now and a clean-but-incomplete run exits 2.
That rewrite also dropped /etc from the sensitive-path list, which two other
statements still said was reported, and left the documented twin grepping the whole
settings file so a hardening deny failed it.
Check 4 had the same whole-file problem plus four patterns whose unescaped pipe made
them ERE alternations, so any quoted string containing curl tripped them. Both fixed
in the script and the documented copy, which now share one path list.
* fix(claude-config-validator): anchor .config and finish the skipped-check sweep
484fe38 unified the two sensitive-path lists and moved .config from a whole-file grep
into a contains() loop, where it matches vite.config.ts, jest.config.js, and a
Bash(npx jest --config ...) rule. Reproduced: the scan exited 1 on a benign edit rule.
Anchored to .config/, which still matches Read(//Users/x/.config/**).
The same commit added a skip branch to detect-dangerous-commands.sh without the
counter its sibling block already had, so it printed SKIPPED and then exited 0 while
the changelog claimed both copies gate their verdict. Every skip branch in both files
is now checked to increment: six of six.
Also annotate the reviewer-facing dangerous-command grep as candidates-only and anchor
dd as dd if=. That is the block two skills tell reviewers to reuse, and it read as
allow-only while being file-wide.
* fix(claude-config-validator): report a settings.json that does not parse
jq exits non-zero on a parse error exactly as it does on no-match, and the jq
conversion in this PR swallowed both. A malformed settings.json holding a bare Bash
grant, an ssh read grant, and Bash(rm -rf:*) produced "All security checks passed"
and exit 0. Before the conversion those three checks were greps that fired
regardless of whether the file parsed, so this is a regression the PR introduced.
Invalid JSON is now CRITICAL, matching what reviewing-runtime-configuration already
rates it, in the script and both documented detectors. Verified that valid files
still report all three grants and that the jq-absent path still exits 2.
Also reconcile two pairs of contradicting instructions: whether the agent frontmatter
pass runs by default, and whether a quoted $ARGUMENTS interpolation is CRITICAL when
the same file demonstrates it is arbitrary command execution.
* fix(claude-config-validator): stop checks that did not run reporting as passed
* fix(claude-config-validator): detect the colon-form permission rule it rates CRITICAL
* fix(claude-config-validator): list what a configuration runs instead of classifying it
* docs(claude-config-validator): scope the scanner's coverage claim to the check that makes it
无版本号
fix(claude-config-validator): match the skill's documented behavior to its tool grants (#199)
* fix(claude-config-validator): make the skill's documented behavior match its grants
The skill's allowed-tools is Read, Grep, Glob, but its output section made inline
pull request comments the required mode and exempted only the two commands, so the
default path could not be carried out on a direct invocation. Findings are now
per-issue text by default; comment posting and the single-document report contract
are what an invoking context can supply.
The cross-plugin secret-detection enrichment called Skill(detecting-secrets)
without holding Skill. Conditioned on the grant rather than widening allowed-tools,
since a validator that preaches least privilege should not grant itself the ability
to invoke arbitrary skills to reach one optional enrichment.
Narrow Bash(git fetch:*) to origin, which is all step 1 fetches, and record the
shared-host caveat for the fixed /tmp report path.
* fix(claude-config-validator): finish the README coherence pass and order the output cases
The first pass left the same capability claim in five more places: the skill
README's process step and Review Output Format section, and the plugin README's
feedback heading and two output descriptions.
Order the three output cases specific to general with a first-match rule. /validate-ai
holds a comment-posting grant, so it matched two bullets in an unordered list.
* fix(claude-config-validator): retire the inline-comment instruction on the routing path
checklists/agents.md carried the retired instruction under its Process heading,
and SKILL.md step 3 loads checklists into context, so a direct invocation still
received it. The occurrences in checklists/prompts.md and under examples/ are
sample content rather than reviewer instructions and are left alone.
Finish the skill README: the always-first security list claimed the git-tracking
check runs unconditionally and dropped the finish-remaining-checks half of the
rule, the feature list and tree still advertised executable automation, and
Requirements listed Git and Bash as the skill's rather than the helper's.
Also fold in the duplicated priority-level block, which had drifted to contradict
its own earlier copy, point Troubleshooting at /plugin list for plugin installs,
drop an unsourced statistic, and repair a sentence that inverted its own subject.
Thin the 1.2.2 changelog entries to one line each.
* fix(claude-config-validator): finish retiring the inline-comment mode in the output templates
SKILL.md step 5 loads examples/ as the format template for the file type under
review, so the retired instruction in example-prompts-review.md, the two other
examples, and the prompts checklist exemplar still propagated. Reworded all four.
Correct the shared-host caveat: an allow rule applies only when the symlink and
its target both match, so Edit(//tmp/validation-summary.md) prompts rather than
following a hostile symlink. World-readability is the real exposure.
Mirror the git-tracking correction into the plugin README, replace SKILL.md's
"mental checks" with the Grep mechanism the same step prescribes, and drop the
remaining unsourced statistics from the checklists, examples, and plugin README.
* fix(claude-config-validator): drop the never-update rule from the comment branch
The branch carried "Create new comments rather than updating existing ones"
verbatim from the inline mode this PR retires, and it contradicts the plugin's
only comment-posting caller: /validate-ai upserts a single sticky comment keyed
on its marker. Defer to the invoking context's convention instead.
State the precedence ordering in the skill README too, which presented the three
destinations as co-equal.
* fix(claude-config-validator): return findings to the caller instead of posting them
The comment-posting branch had no caller that wanted it. bitwarden-code-reviewer
holds an inline-comment tool but tells the skill to "fold its findings into your
own classification and validation", and the multi-agent config subagent expects
findings per its Finding Shape schema. Posting directly would bypass both
pipelines, plus the false-positive gate and the low-severity cap. Step 5 is now
two cases: the validate-ai report contract, or return the findings as text.
State the grant-composition rule once at the top. The file previously reasoned
from the skill's own allowed-tools in one place and the caller's grants in
another, which cannot both be the ceiling.
Carry the settings.local.json qualification up into both Features lists and the
frontmatter description, scope the CRITICAL CHECKS line to the pattern checks it
actually covers, give the direct-invocation path a defined scope source, note
that only origin is fetched, record that the Edit grant covers the Write tool,
and finish the vocabulary rename across the examples and priority framework.
* fix(claude-config-validator): align the checklists and skill README with step 5
Round-2 validation caught the skill README still documenting the three-case
routing order, including the posting case, and citing the SKILL.md section that
now forbids it.
checklists/settings.md told the reviewer to stop the review on a security
finding, reversing a fix 1.2.0 already shipped, and stated the settings.local.json
check as a git-tracking fact ten lines before stating it correctly.
Harmonize the wording everywhere on "appears in the changeset", and scope the
/validate-ai description to what it does in CI.
* fix(claude-config-validator): close the last capability claims from round-3 validation
The direct-invocation list still opened with detecting recently modified files,
which needs a changed-files list the skill has no way to obtain. Check 1 of the
security patterns reference still framed the settings.local.json check as git
tracking with no changeset alternative, and two headings kept the old vocabulary.
* fix(claude-config-validator): drop review-event vocabulary and repair broken references
The output format still ended in APPROVE / REQUEST CHANGES, which are GitHub
review-event values from the posting mode this release retires, and which the
report contract cannot consume. The verdict is now Pass or Issues found, with the
caller mapping to its own vocabulary, updated across the README and four examples.
Nine relative references were broken: six checklists cited SKILL.md as a sibling,
and two examples cited reference/ and checklists/ as if they sat alongside. This
is the plugin's own broken-file-reference finding class.
Scope the marketplace use case to the component files the skill can review and
point manifest checks at the command that delegates them. Align the skills
pass list with the checklist's five passes, restate the strategy list as the
five actual steps, add checklists/ to the disclosure criteria both commands
pass to the skill reviewer, and finish the changeset wording in the settings and
skills checklists.
Also from the notes: hooks.md licensed abandoning the review on a finding, and a
heading's globs were being eaten by markdown emphasis. Trim both command
descriptions, which are what /help renders.
* fix(claude-config-validator): finish the verdict sweep and tighten step 2
The settings example kept a third verdict spelling, BLOCK, so the earlier sweep for
APPROVE and REQUEST CHANGES missed it. All seven verdict lines now read Pass or
Issues found, which is what the report contract consumes.
Step 2 listed the same credential check twice and omitted the dangerous
auto-approval check that both the README and the security reference advertise as
always run. Step 5 stated the per-issue rule twice; the Per-Issue Rules block is
the more complete of the two.
Note that a changeset touching only skill support files lands in no component
bucket, so the configuration and security row does not fire for it. Widening the
pattern would put the reference out of step with the action it mirrors.
State the 2.1.210 floor in the plugin README's Installation section, convert the
new grant section to imperative bullets to match the rest of the file, and drop a
step number that collided with this skill's own numbering.
* fix(claude-config-validator): correct the scope gloss and repair security-scan.sh
The skill-bucket gloss was written for plugin-hosted skills and inverted for a
repo-level one: .claude/skills/foo/reference/bar.md matches the config bucket, so
components-changed is true and the configuration row does fire, while changed-plugins
is empty so plugin validation does not. A reviewer following it would have skipped
the one review that applied. Qualified both paths, mirroring the hook-files bullet.
security-scan.sh had two silent-pass paths and one false positive. git ls-files ran
against whatever repository the shell was in, and outside a repository the error was
swallowed and the check printed a pass it never performed; it now runs with -C and
reports a non-repository as skipped. grep -v "example" discarded any line containing
that substring, including real credentials; the anchored path exclusions already
cover the fixtures. checklists/ was missing from those exclusions, so the script
reported the plugin's own teaching material as a critical finding. Verified all
three by running it before and after.
security-patterns.md embedded a copy of the script that had drifted 134 lines from
the shipped file, including a different directory resolution that would silently
find nothing; it now points at the file.
Also finish the verdict and finish-remaining-checks sweeps, document allowed-tools
in the frontmatter reference, bridge the two meanings of a changed skill, and record
the omitted changes in the changelog.
* fix(claude-config-validator): close a load-dependent false negative in check 1
Under pipefail, `git ls-files | grep -q` fails when grep matches early: grep exits,
git dies of SIGPIPE with 141, and pipefail makes that the pipeline's status, so the
branch went false and the script printed "OK: settings.local.json not in git" for a
file that was committed. Reproduced at 20k tracked files with a match that sorts
early; a small .claude/ never shows it. Ask git directly instead of piping.
Carry the skipped state into the summary. The branch added in 6017574 left
ISSUES_FOUND at 0, so a non-repository still printed "All security checks passed"
and "No committed local settings" for a check that never ran.
* fix(claude-config-validator): give the verdict a threshold rule
Pass and Issues found were defined as the two values without saying which
findings flip one to the other, so two reviewers with identical findings could
return opposite verdicts and a SUGGESTED-only review was ambiguous.
* refactor(claude-config-validator): move the security-scan.sh fixes out of scope
Those fixes belong in a change where shell behaviour is the subject and can carry
regression coverage. Three consecutive review rounds found the same false-negative
class in that file, each time in code a previous fix was meant to close, and the
script has no tests. They are preserved on fix-security-scan-false-negatives.
Restore the troubleshooting note that described the reverted exclusions, and drop
the changelog bullet that claimed them. The security-patterns.md changes stay:
pointing at the shipped script instead of a copy that had drifted 134 lines is
true regardless of what that script contains.
Attribute the report to the caller in the security-scan step, the last place the
skill still spoke as though it owned one.
* fix(claude-config-validator): correct three defects in this change's own edits
The reworded settings.local.json check fired CRITICAL on any changeset where the
file appeared, including the one that deletes it, which is the remediation the same
section prescribes. Scope it to additions and modifications.
The enrichment section said a direct invocation "cannot invoke another skill",
which contradicts the allowed-tools note added to the requirements reference in
this same change: the field pre-approves rather than restricts. The call prompts,
which makes it unavailable in a non-interactive run, and that is what matters.
The settings example closed by counting three CRITICAL findings where it has two
CRITICAL and one IMPORTANT.
* fix(claude-config-validator): group the settings example's bullets by severity
The CRITICAL heading covered all three bullets, one of which maps to the IMPORTANT
finding at line 62, so the section claimed three CRITICAL findings twelve lines
above a closing line that correctly says two. Regrouped on the shape the skill
example already uses, one sub-heading per severity, which also folds the separate
risk list into the bullets it describes.
无版本号
feat(claude-config-validator): write local validation reports to plugin data dir (#198)
* feat(claude-config-validator): write local validation reports to plugin data dir
/validate-ai-local runs against any checkout, so a report written to the
working directory meant every repository it was pointed at needed a
.gitignore entry to keep it out of a commit. Writing to
${CLAUDE_PLUGIN_DATA}/ai-validation/ removes that requirement, and naming
reports by repo and timestamp keeps runs against different checkouts from
overwriting each other.
Addresses https://github.com/bitwarden/ai-plugins/pull/197#discussion_r3785900171
* fix(claude-config-validator): correct the report Write grant and report docs
The grant read Write(${CLAUDE_PLUGIN_DATA}/ai-validation/*). The variable is
substituted in command frontmatter, but it expands with a single leading slash,
and a permission pattern is filesystem-absolute only in its ~/ or // form. The
rule anchored at the current directory and never matched, so the mandatory final
write prompted and two documents claimed a scope that did not hold.
Use the home-relative form, which the permission engine handles on every
platform, and document what it gives up: it spans any plugin's ai-validation
directory, and it does not follow CLAUDE_CODE_PLUGIN_CACHE_DIR.
Also restore the .gitignore entry for one release cycle so installs still on
1.2.0 cannot commit a working-directory report, name the report location in the
command description, and note that uninstall drops the data directory without
--keep-data.
* chore(claude-config-validator): release as 1.2.1 and condense the changelog
* fix(claude-config-validator): tighten the report Write glob and correct two doc claims
Narrow the grant from ** to *: the plugin data directory is a single path
segment, so ** additionally pre-approved any ai-validation/ directory at
arbitrary depth under data/.
Name CLAUDE_CONFIG_DIR as the variable that relocates the tree the grant is
written against. CLAUDE_CODE_PLUGIN_CACHE_DIR governs plugins/cache/, not
plugins/data/, so it would not have moved the report.
Attribute --keep-data to `claude plugin uninstall`, the CLI subcommand that
documents it, rather than the interactive /plugin manager.
* fix(claude-config-validator): scope the report Write grant to this plugin
A permission pattern allows partial-segment globs, so the plugin can be named
without pinning the marketplace: the trailing -* globs the install-id suffix.
The previous /*/ wildcard covered every installed plugin's ai-validation
directory.
Name CLAUDE_CODE_PLUGIN_CACHE_DIR alongside CLAUDE_CONFIG_DIR in the caveat.
It relocates the plugins root independently, so dropping it left the caveat
incomplete.
* fix(claude-config-validator): declare report grants as Edit rules
Claude Code checks file permissions against Edit(path) and Read(path) rules
only. A path rule written for Write is accepted, never consulted, and warned
about at startup, so both commands' mandatory final write was unapproved
despite the declared scope. /validate-ai carried the higher impact, running
non-interactively in CI where no prompt can be answered.
An Edit rule applies to every built-in tool that edits files, and allowed-tools
pre-approves rather than restricting availability, so the Write tool stays
callable under the Edit rule's path.
Drop Bash(ls:*) from both commands; neither body invokes ls.
* fix(claude-config-validator): restore Bash(ls:*) and loosen the install-id glob
Restoring Bash(ls:*) on both commands. Calling it unexercised was wrong: step 3
probes $BW_GH_ACTIONS_PATH/validate-ai/scripts, and ls was the only granted tool
that could resolve a path behind an environment variable. Dropping it cost a
permission prompt on the script-location lookup.
Drop the required hyphen from the install-id glob. A marketplace install yields
claude-config-validator-bitwarden-marketplace, but a local --plugin-dir load
yields the bare id, which claude-config-validator-* could not match, leaving the
mandatory write unapproved in exactly the case this change set out to fix.
Record the 2.1.210 floor the Edit-covers-Write behavior needs, cite where the
data-directory layout and --keep-data are documented, stop reusing the // rule
syntax as if it were part of the /tmp path, and drop the stale Write-grant
wording from the skill.
* chore(claude-config-validator): drop the dead validation-summary.md ignore entry
Nothing writes that filename into a working directory any more: /validate-ai-local
writes under the plugin data directory and /validate-ai writes /tmp. Installs still
on 1.2.0 can surface the file until they upgrade, which is an accepted risk.
Note the Linux sandbox startup warning about glob patterns in permission rules, so
a user who sees it knows the report is still written.
* fix(claude-config-validator): correct the literal-path rationale and add a fallback
The stated reason for writing the data path literally was that substitution in
allowed-tools is documented for Bash rules only. That is true of the docs but not
of the CLI, which substitutes the whole allowed-tools value regardless of rule
type. The real reason is that substitution is guarded on the plugin having a
marketplace source, so a local --plugin-dir load can leave the variable unexpanded.
Give step 7 an explicit fallback for that case, pointing at the bare-id directory
the Edit glob already covers, and rule out falling back to the working directory.
无版本号
feat(claude-config-validator): add /validate-ai and /validate-ai-local commands (#197)
* feat(claude-config-validator): add /validate-ai and /validate-ai-local commands
Port the review prompt and logic from the bitwarden/gh-actions validate-ai
action into two commands: /validate-ai for pull requests (the action will
eventually call it) and /validate-ai-local for a local checkout.
Shared scope rules, gating, and the report contract live in
reference/validate-ai-scope.md so the commands and the action cannot drift.
* fix(claude-config-validator): scope Write grants and document the scripts-only case
Address review feedback on #197:
- Scope Write to the single report path each command produces
- Explain why `^scripts/validate-` feeds no bucket, and have the report say so
- Drop `mktemp` from the dictionary; the frontmatter no longer uses it
* fix(claude-config-validator): align commands with the validate-ai completion contract
bitwarden/gh-actions#867 made report completeness a marker check rather than a
file-existence check, forbade interim writes, and required synchronous
subagents. Carry all three into both commands and the shared reference.
* fix(claude-config-validator): let independent subagents overlap
bitwarden/gh-actions#868 split synchronous from sequential: subagent calls
still may not detach, but independent ones are dispatched together in one
message so they run concurrently. Drop the 'in order' framing that serialized
them, and say the numbering is the report's order, not an execution order.
* fix(claude-config-validator): treat reviewed config as data, not instructions
Both reviewers on #197 flagged the same gap: the review reads
contributor-authored config, which is text written to instruct Claude, with
nothing telling the model not to obey it. Add that boundary to the command,
the shared reference, and subagent prompts (CWE-1427).
Also from review: scope the Step 5 inline-comment mandate so the changeset
report contract does not contradict it, fix the priority-framework link for
callers outside the skill directory, drop unused grants, and correct the
stale structure block and agent-detection glob.
* fix(claude-config-validator): close the hook and command review gaps
Validator findings on #197. Both commands routed hook files and plugin
command files into reviewing-claude-config, which had no hook coverage at
all and a command detection rule that stopped at .claude/commands/*.md —
so this plugin's own command files matched nothing and went unreviewed.
Adds checklists/hooks.md, widens the command rule to plugin layouts, keys
the changeset report exception to the invoking command rather than the
review's shape, and corrects documentation drift in both READMEs.
* fix(claude-config-validator): make hook review reachable and correct
Validator findings on #197. The hook coverage added last commit was only
partly reachable and partly wrong:
- Detection keyed on hooks.json alone, missing the hooks block in a
settings file, which is where repositories usually declare them
- The event list was presented as exhaustive but omitted
UserPromptExpansion, which bitwarden-ai-telemetry ships, so a reviewer
following it would file a false positive against a shipping plugin
- All four passes assumed command hooks, leaving prompt hooks with no
applicable criteria despite their own injection surface
- The skill description never mentioned hooks, so natural-language
invocation had no trigger to match
Also sweeps 20 lowercase skill.md references and the skill README's stale
counts, dead paths, and version claim.
* fix(claude-config-validator): make the untrusted-input boundary unconditional
The CWE-1427 boundary lived only in reference/validate-ai-scope.md, which
SKILL.md gates behind 'reviewing a whole changeset'. Direct skill invocation
— the mode the skill's own README documents first, and what this repo's
CLAUDE.md prescribes — never loaded it, so the changelog claimed a control
that entry point did not have. It is now a preamble ahead of Step 1.
Also adds a hooks review example, trims the description under the length
guideline, resolves the skill README's install-layout contradiction, and
fixes security-scan.sh's default directory under a plugin install.
* docs(claude-config-validator): sync example counts and coverage lists
Adding the hooks example in 3f73773 made three counts stale that the same
release claims to have fixed. Corrects them, adds the file to both listings,
and brings the skill README's use-when list and review-process summary in
line with the agents and hooks coverage added earlier in this PR.
* docs(claude-config-validator): drop the drift-prone counts and fix runnable paths
Counts of checklists, references, and examples went stale twice in this
release, so they are gone rather than corrected again. The lists say the
same thing and cannot drift.
Also from review: CLAUDE_PLUGIN_ROOT is unset in a user's shell, so the
snippets that told people to paste it were not runnable, and the
substitution rule they relied on doubled the path. Both README layouts now
use real paths. Anchors the local report at the repository root to match its
Write grant, settles the 500-line figure as a guideline, and ignores
.claude-pr/.
* fix(claude-config-validator): correct example citations and split the oversized one
Validator warnings on #197, all in material this PR added or touched:
- The hooks example cited two anchors off by one, in the exemplar that
teaches file:line precision, and its summary undercounted its own findings
- Line ranges into claude-code-requirements.md had drifted; cite sections by
name, which cannot go stale
- example-agent-review.md was 559 lines against the 500-line guideline this
plugin applies to others; split out agent composition reviews
- Route every checklist back to the Step 5 output contract, not just hooks.md
- Scope the subagent and Bash-reference advice to callers that can act on it
Reverts the local report path to the current working directory: a bare Write
pattern anchors at cwd, so the previous 'repository root' wording described
a path the grant does not cover.
* docs(claude-config-validator): clear the drift this PR created
Validator warnings on #197, all documentation consistency:
- Three checklists had doubled thematic breaks where the output-format
section was appended after a rule they already ended with
- The split composition example kept its old Example 4/5 numbering in a file
that now starts at the beginning
- Two coverage claims still said one example per configuration type after a
second agent example was added
- The skill README's troubleshooting steps omitted the scripts/ prefix
- Both commands described the skill-reviewer convention as references/ while
this plugin's own skill uses reference/
无版本号
Cross-reference skills in plugins (#55)
无版本号
Apply validator fixes (#23)
* Apply validator fixes
* Simplify changelogs
无版本号
Fix file formatting (#19)
无版本号
Claude Config Validator (#7)
暂无评论...