feat(credentials): /ops:credentials audit + plugin.json field hints (v2.0.6)#184
feat(credentials): /ops:credentials audit + plugin.json field hints (v2.0.6)#184auroracapital merged 1 commit intomainfrom
Conversation
…v2.0.6)
Claude Code's plugin settings UI cannot introspect external credential
stores. If a user has STRIPE_SECRET_KEY in macOS Keychain or
klaviyo_api_key in Doppler, the settings panel shows those fields as
empty even when configured. The user can't tell at a glance which
integrations are wired up.
Adds:
- bin/ops-credentials — credential audit CLI. Scans shell env,
preferences.json, Doppler (with doppler:KEY resolution), Keychain,
and Dashlane. Reports configured-vs-missing with first6•••last4
masking. Output: human table | --json | --service <name>. Compact
mode on SSH/mobile per Rule 7.
- skills/ops-credentials/SKILL.md — /ops:credentials slash command
wrapping the bin script with follow-up actions (configure missing,
re-audit, JSON export).
- Description hints on all 22 sensitive fields in plugin.json:
"If already configured via /ops:setup or stored in keychain/Doppler,
leave blank — runtime resolves automatically."
Privacy: never prints raw values. JSON export contains only
{service, label, configured, masked, source}, never the raw secret.
Read-only — does not write to keychain/Doppler/preferences.
Bumps marketplace.json + plugin.json to 2.0.6.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 0/1 reviews remaining, refill in 16 minutes and 25 seconds.Comment |
| results_json=$(jq -c --arg s "$service" --arg l "$label" --arg m "$masked" --arg src "$src" \ | ||
| '. + [{service:$s, label:$l, configured:true, masked:$m, source:$src}]' <<<"$results_json") | ||
| else | ||
| missing=$((missing+1)) | ||
| missing_lines+=("$(printf ' ✗ %-32s — run /ops:setup %s' "$label" "$service")") | ||
| results_json=$(jq -c --arg s "$service" --arg l "$label" \ | ||
| '. + [{service:$s, label:$l, configured:false}]' <<<"$results_json") |
There was a problem hiding this comment.
Bug: The script calls jq without first checking if it is installed, which will cause the script to crash if jq is not in the PATH.
Severity: MEDIUM
Suggested Fix
Before the main loop, add a check to ensure jq is installed and exit with an informative error if it is not. For example: if ! command -v jq &> /dev/null; then echo "jq is not installed. Please install it to continue." >&2; exit 1; fi.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: claude-ops/bin/ops-credentials#L147-L153
Potential issue: The script has `set -e` enabled, which causes it to exit immediately if
a command fails. In the main scan loop, the `jq` command is used on lines 147-153
without a prior check to ensure it is installed. If `jq` is not present in the system's
`PATH`, the command will fail, and the script will terminate prematurely. This is
inconsistent with other parts of the script that correctly use `command -v jq` to verify
its existence before use.
Did we get this right? 👍 / 👎 to inform future reviews.
| while [[ $# -gt 0 ]]; do | ||
| case "$1" in | ||
| --json) OUTPUT_MODE="json"; shift ;; | ||
| --service) SERVICE_FILTER="$2"; shift 2 ;; |
There was a problem hiding this comment.
Bug: Providing the --service flag without a corresponding value causes the script to crash with an "unbound variable" error due to set -u.
Severity: MEDIUM
Suggested Fix
Before accessing $2 for the --service flag, check if it is set. If $2 is empty or starts with a -, it indicates a missing value. In this case, print a usage error and exit. For example: if [[ -z "$2" || "$2" == -* ]]; then echo "Error: --service requires an argument." >&2; exit 1; fi.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: claude-ops/bin/ops-credentials#L29
Potential issue: The script enables `set -u`, which treats attempts to access unset
variables as errors. The argument parsing for the `--service` flag on line 29 assigns
`$2` to `SERVICE_FILTER`. If a user provides `--service` as the last argument on the
command line, `$2` will be unset. This will trigger an "unbound variable" error and
cause the script to exit, rather than providing a more user-friendly error message about
the missing value.
Did we get this right? 👍 / 👎 to inform future reviews.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Missing
|| truecrashes script on malformed preferences- Added
|| trueto the preferencesjqcommand substitution so invalid JSON yields an empty value and resolution continues underset -e.
- Added
- ✅ Fixed: Unconditional jq usage crashes text mode without jq
- Incremental
results_jsonupdates now run only whenOUTPUT_MODEisjson, so the default text path no longer invokesjq.
- Incremental
You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit 209ea5b. Configure here.
| # 2. preferences.json | ||
| if [[ -n "$prefs_path" && -f "$PREFS" ]] && command -v jq >/dev/null 2>&1; then | ||
| local v | ||
| v=$(jq -r "${prefs_path} // empty" "$PREFS" 2>/dev/null) |
There was a problem hiding this comment.
Missing || true crashes script on malformed preferences
Medium Severity
The jq call reading preferences.json on line 94 is the only external command in resolve() that lacks || true. Under set -euo pipefail, a malformed or empty prefs file causes jq to exit non-zero, terminating the entire audit script. The three other backends (Doppler, Keychain, Dashlane) all guard their commands with || true and degrade gracefully.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 209ea5b. Configure here.
| missing=$((missing+1)) | ||
| missing_lines+=("$(printf ' ✗ %-32s — run /ops:setup %s' "$label" "$service")") | ||
| results_json=$(jq -c --arg s "$service" --arg l "$label" \ | ||
| '. + [{service:$s, label:$l, configured:false}]' <<<"$results_json") |
There was a problem hiding this comment.
Unconditional jq usage crashes text mode without jq
Medium Severity
The scan loop unconditionally builds results_json via jq on lines 147–148 and 152–153 for every credential, even when the output mode is "text". The script explicitly guards against missing jq on line 92 with command -v jq, showing awareness it may be absent — but the JSON-building calls in the loop body have no such guard. Under set -euo pipefail, running bin/ops-credentials (text mode, no --json) on a system without jq crashes the script with a command-not-found error.
Reviewed by Cursor Bugbot for commit 209ea5b. Configure here.
…release (#199) The v2.0.5 → v2.0.9 patch series shipped meaningful features (multi-workspace Slack #195, /ops:credentials audit #184, ops-ci current-state filter #196, telegram preflight #185, userConfig schema upgrades #182). Per semver these should have been a minor bump. This release retroactively rolls them up into v2.1.0 with a single coherent CHANGELOG entry. No code changes — only: - plugin.json: 2.0.9 → 2.1.0 - CHANGELOG.md: new [2.1.0] entry consolidating Added/Fixed/Notes for the patch series - README header + What's-new section: refer to v2.1.0 - 11 docs/*.md badges + agents-reference subtitle + migration latest-stable note: v2.0.9 → v2.1.0 Marketplace pin (.claude-plugin/marketplace.json) bumped in follow-up PR. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>


Summary
Claude Code's plugin settings UI cannot introspect external credential stores. If a user has
STRIPE_SECRET_KEYin macOS Keychain orklaviyo_api_keyin Doppler, the settings panel shows those fields as empty — even when those integrations are working. This PR ships a separate audit surface so users can see configured-vs-missing at a glance.Adds:
bin/ops-credentials— credential audit CLI. Scans shell env,preferences.json, Doppler (resolvesdoppler:KEYreferences live), macOS Keychain, and Dashlane. Reports configured-vs-missing withfirst6•••last4masking. Output: human table |--json|--service <name>. Compact mode on SSH/mobile per Rule 7.skills/ops-credentials/SKILL.md—/ops:credentialsslash command wrapping the bin with follow-up actions (configure missing, re-audit, JSON export).plugin.json: "If already configured via /ops:setup or stored in keychain/Doppler, leave blank — runtime resolves automatically."Smoke test result
Run on dev machine — detected 21/27 tracked credentials across 4 sources (env, keychain, Dashlane, Doppler). 6 missing flagged for
/ops:setup.Privacy
{service, label, configured, masked, source}Test plan
bash -npassesfirst6•••last4for 12+ char values,•••for shorter--jsonoutput shape stableNote
Medium Risk
Adds a new credential-auditing CLI/skill that reads from env, prefs, Doppler, macOS Keychain, and Dashlane; while secrets are masked and read-only, it touches sensitive credential-resolution paths and external CLIs.
Overview
Introduces a new
/ops:credentialsskill backed bybin/ops-credentialsto audit which integration credentials are configured vs missing across shell env,preferences.json, Doppler refs (live-resolved), macOS Keychain, and Dashlane, with masked output plus--jsonand--servicefiltering.Updates
plugin.jsoncredential field descriptions to explicitly tell users they can leave fields blank when credentials are already available via/ops:setupor external stores, and bumps the marketplace/plugin version to2.0.6with an accompanying changelog entry.Reviewed by Cursor Bugbot for commit 209ea5b. Bugbot is set up for automated code reviews on this repo. Configure here.