You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix: address Claude plugin directory review findings - #87
Fix the findings from the Claude plugin directory review of abc472f, so the plugin can be resubmitted with plugin as the plugin path.
That review ran against the repository root, which has .claude-plugin/marketplace.json but no plugin.json ("Couldn't confirm what the plugin runs or connects to"). With plugin as the plugin path, the pre-submission checklist would also block on the inline node -e launcher and the missing README in the plugin folder. This PR fixes those too.
The directory doesn't need a dedicated repository: "If the plugin is one folder in a larger repository, give that folder as the plugin path" (Submit your plugin). So the plugin stays in plugin/.
MCP server launch
plugin/.mcp.json now runs node ${CLAUDE_PLUGIN_ROOT}/scripts/bundle.js. The directory blocks inline programs such as node -e when the plugin is a subfolder of the repository.
Codex doesn't expand ${CLAUDE_PLUGIN_ROOT} (openai/codex#19582). So plugin/.codex-plugin/plugin.json now points to a new plugin/.codex-mcp.json, which runs node ./scripts/bundle.js with cwd: ".". That is the same resolution the old resolver used on Codex after 8cd00db.
Skill allowed-tools
MCP tool names now carry the plugin scope (mcp__plugin_deploygate_deploygate__<tool>). The unscoped mcp__deploygate__* names never matched the tools of the installed plugin, so those pre-approvals had no effect.
No MCP wildcard. With working names, setup's wildcard would pre-approve all 58 tools, including delete_project and update_saml_certificate. setup now names its Phase 1 onboarding tools only. Tools that invite people or grant app access (add_member, create_shared_team, assign_shared_team_to_app) keep a per-call approval.
Removed broad shell access, which held the version for review: ./gradlew, xcodebuild, fastlane, plus cp, cd, zip, and mkdir in setup. Users now approve these commands when the skill runs them. which, ls, git rev-parse, and security find-identity stay.
Scoped file edits. In ci-setup, Write Edit became Edit(.github/workflows/**) Edit(bitrise.yml) Edit(.circleci/config.yml). In sdk-setup, Edit became Edit(build.gradle), Edit(build.gradle.kts), Edit(settings.gradle), and Edit(settings.gradle.kts). Claude Code checks only Edit(path) rules for writes, and ignores path rules on Write (permissions).
Listing assets
New plugin/README.md. The directory uses it as the listing description, and it must be in the plugin folder. It covers install, the skills, and what the plugin runs, sends (only https://deploygate.com), stores (the device-flow token), and reads on request (the keystore and passwords given to update_keystore). It also explains how scripts/bundle.js is built and checked.
New plugin/.claude-plugin/icon.png (512×512 PNG). The directory takes the listing icon from the first save or submission, so it has to be on main before the new submission.
Tests and docs
skills.test.ts checks the allowed-tools constraints for every skill. Pre-approved MCP tools must be in an explicit allowlist (PRE_APPROVABLE_MCP_TOOLS), so wildcards and destructive or access-granting tools fail the test.
plugin.test.ts checks both MCP configs, the README word count, and the icon dimensions.
CLAUDE.md documents the two MCP configs and the allowed-tools rules.
The root README.md now describes the token path accurately (XDG_CONFIG_HOME is honored, and 0600 applies on macOS and Linux only).
Findings left for the reviewer
scripts/bundle.js. The bundle is over the 256 KiB per-file limit, and the security scan flagged it as code it can't read. A Node server in a subfolder is also always held ("Scripts the validator couldn't follow"). The README now explains how the bundle is built.
"Uses a credential from the user's machine". Each case is a DeployGate token sent only to deploygate.com, which the checklist lets a reviewer confirm. The token in plugin.json is the plugin's own device-flow token. The references/ and templates/ cases are CI secrets on the user's CI provider.
Local stdio MCP not available on claude.ai. This is informational.
Test plan
npm run build && npm test (489 tests pass)
claude plugin validate ./plugin and claude plugin validate . pass
scripts/smoke-bundle.mjs passes when the bundle is started by absolute path (Claude) and by ./scripts/bundle.js from plugin/ (Codex)
Install from this branch in Claude Code and confirm that the MCP server starts and the skills' MCP calls are pre-approved
Install from this branch in Codex and confirm that the MCP server starts
After merge, withdraw the current submission, submit again with plugin path plugin, and run Validate
Prepare the plugin folder for resubmission to the Claude plugin
directory with `plugin` as the plugin path.
- Start the MCP server with `node ${CLAUDE_PLUGIN_ROOT}/scripts/bundle.js`
in plugin/.mcp.json. The directory blocks inline programs such as
`node -e` when the plugin is a subfolder of the repository. Codex does
not expand ${CLAUDE_PLUGIN_ROOT}, so it gets its own
plugin/.codex-mcp.json that runs the bundle relative to the plugin root.
- Name MCP tools in skill allowed-tools with the plugin scope
(mcp__plugin_deploygate_deploygate__*). The unscoped names never
matched, so the pre-approvals had no effect.
- Stop pre-approving build tools (./gradlew, xcodebuild, fastlane) and
file-mutating shell commands, which the directory holds as broad shell
access. Limit file edits to Edit(<path>) rules for CI configs and
Gradle build scripts.
- Add plugin/README.md for the listing, describing what the plugin runs,
sends, and stores, and how bundle.js is built.
- Add the listing icon at plugin/.claude-plugin/icon.png.
- Add tests that keep these invariants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Scoping the MCP tool names turned the setup skill's wildcard, which
never matched before, into a pre-approval of every tool the server
exposes, including delete_project, delete_keystore, remove_* and
update_saml_certificate. Name the Phase 1 onboarding tools instead, and
leave tools that invite people or grant app access (add_member,
create_shared_team, assign_shared_team_to_app) to a per-call approval.
A new test rejects MCP wildcards and destructive or access-granting
tools in every skill's allowed-tools.
Also describe the token path accurately in both READMEs: it honors
XDG_CONFIG_HOME, and the 0600 mode applies on macOS and Linux only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Disclose transient keystore credentials read by update_keystore
plugin/README.md:39
The credential disclosure is incomplete: update_keystore reads a local signing keystore and accepts its keystore/key passwords (src/tools/keystores.ts:33-48), so the statement that no other credentials are read is false. This is material to the directory security review; disclose these transient credentials and clarify that they are sent to DeployGate but not persisted.
The policy test matched destructive tool names with a pattern, which
let create_shared_team through although the setup skill leaves it to a
per-call approval. Check every pre-approved MCP tool against an explicit
allowlist instead, so any other tool, including ones added to the
server later, needs a deliberate change to be pre-approved.
The plugin README said the plugin reads no credentials besides its
token, but update_keystore reads the keystore file and passwords the
user gives it and sends them to DeployGate. Disclose that, and that
nothing is stored locally.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@copilot On the previously missed finding about update_keystore (plugin/README.md): fixed in a8dfd3f. The README now says that update_keystore reads the keystore file at the path you give it and takes the keystore and key passwords you provide, sends them to https://deploygate.com, and doesn't store them locally. Keystores are also listed among the data sent to DeployGate.
Validate the complete PNG signature and IHDR chunk
src/__tests__/plugin.test.ts:195
This checks only bytes 1–3, so a non-PNG file with arbitrary byte 0 and PNG next would pass and the offsets below could be interpreted as dimensions without an IHDR chunk. Validate the complete eight-byte PNG signature and the first chunk type so this test actually protects the listing asset.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fix the findings from the Claude plugin directory review of
abc472f, so the plugin can be resubmitted withpluginas the plugin path.That review ran against the repository root, which has
.claude-plugin/marketplace.jsonbut noplugin.json("Couldn't confirm what the plugin runs or connects to"). Withpluginas the plugin path, the pre-submission checklist would also block on the inlinenode -elauncher and the missing README in the plugin folder. This PR fixes those too.The directory doesn't need a dedicated repository: "If the plugin is one folder in a larger repository, give that folder as the plugin path" (Submit your plugin). So the plugin stays in
plugin/.MCP server launch
plugin/.mcp.jsonnow runsnode ${CLAUDE_PLUGIN_ROOT}/scripts/bundle.js. The directory blocks inline programs such asnode -ewhen the plugin is a subfolder of the repository.${CLAUDE_PLUGIN_ROOT}(openai/codex#19582). Soplugin/.codex-plugin/plugin.jsonnow points to a newplugin/.codex-mcp.json, which runsnode ./scripts/bundle.jswithcwd: ".". That is the same resolution the old resolver used on Codex after 8cd00db.Skill
allowed-toolsmcp__plugin_deploygate_deploygate__<tool>). The unscopedmcp__deploygate__*names never matched the tools of the installed plugin, so those pre-approvals had no effect.setup's wildcard would pre-approve all 58 tools, includingdelete_projectandupdate_saml_certificate.setupnow names its Phase 1 onboarding tools only. Tools that invite people or grant app access (add_member,create_shared_team,assign_shared_team_to_app) keep a per-call approval../gradlew,xcodebuild,fastlane, pluscp,cd,zip, andmkdirinsetup. Users now approve these commands when the skill runs them.which,ls,git rev-parse, andsecurity find-identitystay.ci-setup,Write EditbecameEdit(.github/workflows/**) Edit(bitrise.yml) Edit(.circleci/config.yml). Insdk-setup,EditbecameEdit(build.gradle),Edit(build.gradle.kts),Edit(settings.gradle), andEdit(settings.gradle.kts). Claude Code checks onlyEdit(path)rules for writes, and ignores path rules onWrite(permissions).Listing assets
plugin/README.md. The directory uses it as the listing description, and it must be in the plugin folder. It covers install, the skills, and what the plugin runs, sends (onlyhttps://deploygate.com), stores (the device-flow token), and reads on request (the keystore and passwords given toupdate_keystore). It also explains howscripts/bundle.jsis built and checked.plugin/.claude-plugin/icon.png(512×512 PNG). The directory takes the listing icon from the first save or submission, so it has to be onmainbefore the new submission.Tests and docs
skills.test.tschecks theallowed-toolsconstraints for every skill. Pre-approved MCP tools must be in an explicit allowlist (PRE_APPROVABLE_MCP_TOOLS), so wildcards and destructive or access-granting tools fail the test.plugin.test.tschecks both MCP configs, the README word count, and the icon dimensions.CLAUDE.mddocuments the two MCP configs and theallowed-toolsrules.README.mdnow describes the token path accurately (XDG_CONFIG_HOMEis honored, and0600applies on macOS and Linux only).Findings left for the reviewer
scripts/bundle.js. The bundle is over the 256 KiB per-file limit, and the security scan flagged it as code it can't read. A Node server in a subfolder is also always held ("Scripts the validator couldn't follow"). The README now explains how the bundle is built.plugin.jsonis the plugin's own device-flow token. Thereferences/andtemplates/cases are CI secrets on the user's CI provider.Test plan
npm run build && npm test(489 tests pass)claude plugin validate ./pluginandclaude plugin validate .passscripts/smoke-bundle.mjspasses when the bundle is started by absolute path (Claude) and by./scripts/bundle.jsfromplugin/(Codex)plugin, and run Validate🤖 Generated with Claude Code