Skip to content

Release v1.58.0 official plugin compatibility - #26

Merged
Esquetta merged 25 commits into
mainfrom
feature/v1.58-official-plugin-compatibility
Aug 11, 2026
Merged

Release v1.58.0 official plugin compatibility#26
Esquetta merged 25 commits into
mainfrom
feature/v1.58-official-plugin-compatibility

Conversation

@Esquetta

Copy link
Copy Markdown
Owner

Summary\n\n- add official MCP layout normalization for direct maps, mcp_servers, and legacy mcpServers\n- validate official plugin metadata, apps, component paths, and lifecycle hooks without executing package content\n- enforce canonical package containment and fail-closed runtime planning across previews, Inspector, audit, and runtime flows\n- redact portable runtime credentials while preserving exact approval-digest binding\n- prepare synchronized v1.58.0 docs, changelog, package metadata, and release pins\n\n## Security\n\n- reject lexical and canonical link escapes before MCP config reads\n- reject malformed or ambiguous MCP declarations with structured failure and exit code 1\n- harden lifecycle-hook remote-pipe detection and finding precision\n- remove Windows shell execution from doctor size npm-pack measurement\n\n## Verification\n\n- npm run release-check\n- npm test: 1,090 passed; 6 expected skips\n- npx tsc -p tsconfig.json --noEmit\n- npm run build\n- npm pack --dry-run: 201 intended files\n- doctor corpus: 4/4 expectations passed\n- independent spec, quality/security, and final branch reviews: approved\n

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Release v1.58.0: official plugin compatibility & hardened MCP safety

✨ Enhancement 🐞 Bug fix 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Normalize official MCP layouts (direct, mcp_servers, legacy mcpServers) across all workflows.
• Add static validation for official plugin metadata, apps, component paths, and lifecycle hooks.
• Enforce canonical package containment and fail closed on malformed/ambiguous manifests.
• Redact runtime-plan secrets while preserving exact approval digest binding.
Diagram

graph TD
  A["Plugin package"] --> B["MCP normalizer"] --> C["Plugin validation"] --> D["Security audit"] --> E["Runtime plan"]
  B --> F["Install previews"]
  B --> G["Inspector"]
  C --> E
  D --> E
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Schema-driven validation (Ajv/Zod) for manifest/hooks/MCP shape
  • ➕ More declarative validation with consistent error reporting
  • ➕ Easier evolution if official schemas expand
  • ➕ Less bespoke shape-checking code
  • ➖ Adds dependency/supply-chain surface area
  • ➖ Containment/canonical-path checks still need custom code
  • ➖ Risk of changing failure semantics/output shape across workflows
2. Fully centralize containment + config loading into one shared service/module
  • ➕ Single source of truth for path handling across previews/inspector/runtime/audit
  • ➕ Reduces risk of drift between workflows
  • ➖ Bigger refactor; more churn for a release-focused PR
  • ➖ Requires aligning error models and messages across multiple call sites

Recommendation: The PR’s approach (small, explicit MCP normalizer + explicit containment and fail-closed guards in each consumer) is well-suited for security-critical behavior and preserves existing report schemas. If the validation surface continues to grow, consider moving purely structural checks to a schema library while keeping containment/redaction as explicit code paths.

Files changed (54) +2984 / -226

Enhancement (17) +1207 / -175
claude-desktop-install-preview.tsParse MCP configs via shared normalizer in Claude Desktop preview +4/-6

Parse MCP configs via shared normalizer in Claude Desktop preview

• Switches install preview parsing to use 'normalizeMcpConfig' so direct maps and wrappers work consistently.

src/compatibility/claude-desktop-install-preview.ts

cline-install-preview.tsParse MCP configs via shared normalizer in Cline preview +4/-6

Parse MCP configs via shared normalizer in Cline preview

• Uses the MCP config normalizer instead of assuming a legacy 'mcpServers' wrapper.

src/compatibility/cline-install-preview.ts

compatibility-matrix.tsNormalize MCP parsing and enforce containment for compatibility checks +17/-29

Normalize MCP parsing and enforce containment for compatibility checks

• Adds containment checks when resolving MCP config paths and reads server names/entries via 'normalizeMcpConfig'. Improves consistency for generic MCP checks.

src/compatibility/compatibility-matrix.ts

cursor-install-preview.tsParse MCP configs via shared normalizer in Cursor preview +4/-6

Parse MCP configs via shared normalizer in Cursor preview

• Uses the MCP config normalizer and fails when no valid server map is present.

src/compatibility/cursor-install-preview.ts

windsurf-install-preview.tsParse MCP configs via shared normalizer in Windsurf preview +4/-6

Parse MCP configs via shared normalizer in Windsurf preview

• Updates preview generation to rely on normalized server definitions rather than a single wrapper shape.

src/compatibility/windsurf-install-preview.ts

inspector-bridge.tsInspector enforces containment and uses normalized MCP layouts +12/-18

Inspector enforces containment and uses normalized MCP layouts

• Adds canonical containment checks for the configured MCP path and uses 'normalizeMcpConfig' to derive server names.

src/core/inspector-bridge.ts

mcp-config-normalizer.tsIntroduce MCP layout normalizer (direct, snake_case, legacy camelCase) +74/-0

Introduce MCP layout normalizer (direct, snake_case, legacy camelCase)

• Adds a shared normalizer that accepts direct server maps, 'mcp_servers', or 'mcpServers', rejects ambiguous combinations, and reports invalid server entries while preserving prototype-sensitive names.

src/core/mcp-config-normalizer.ts

package-path.tsAdd canonical containment resolver for package-relative paths +33/-0

Add canonical containment resolver for package-relative paths

• Introduces 'resolveContainedPackagePath' to reject lexical and realpath (symlink) escapes while still permitting missing-path resolution for later validation.

src/core/package-path.ts

plugin-components.tsAdd static validation for official manifest components and apps +224/-0

Add static validation for official manifest components and apps

• Implements optional metadata validation (URLs, strings, arrays), safe './' path resolution with canonical containment, and validates referenced '.app.json' presence and JSON parseability without executing app content.

src/core/plugin-components.ts

plugin-hooks.tsAdd static lifecycle hook validation and hook command auditing +260/-0

Add static lifecycle hook validation and hook command auditing

• Validates hook config sources (default file discovery, explicit paths, inline configs), supported events/shape constraints, and audits command handler strings via security checks without executing hooks.

src/core/plugin-hooks.ts

runtime-plan.tsFail-closed runtime planning, containment enforcement, and secret redaction +136/-16

Fail-closed runtime planning, containment enforcement, and secret redaction

• Enforces manifest 'mcpServers' validity and in-package containment, fails closed on malformed/ambiguous MCP configs or failing security status, and redacts credential-bearing args in portable outputs while computing digests over unredacted args.

src/core/runtime-plan.ts

runtime-probe.tsLoad MCP servers via normalized layouts for runtime probing +3/-10

Load MCP servers via normalized layouts for runtime probing

• Switches MCP server loading to 'normalizeMcpConfig' and returns null when no valid server map is present.

src/core/runtime-probe.ts

validate-plugin.tsIntegrate component/hook validation and normalize MCP shape checks +63/-28

Integrate component/hook validation and normalize MCP shape checks

• Uses the MCP normalizer for '.mcp.json' validation (including ambiguous/server invalid reporting), adds component and hook validators, and gates skills/MCP validation when component paths are already invalid to avoid duplicate findings.

src/core/validate-plugin.ts

types.tsExtend manifest types for official fields and hook config types +54/-0

Extend manifest types for official fields and hook config types

• Adds optional manifest fields (author/homepage/repository/license/keywords/apps/interface) and defines lifecycle hook event/config types used by validators.

src/domain/types.ts

generic-mcp-doctor.tsUse normalized MCP layouts in generic MCP doctor findings +23/-38

Use normalized MCP layouts in generic MCP doctor findings

• Replaces ad-hoc object checks with 'normalizeMcpConfig' to support all accepted layouts and improve invalid server reporting.

src/mcp/generic-mcp-doctor.ts

rule-catalog.tsRegister new component/hook rules and MCP ambiguity rule +130/-4

Register new component/hook rules and MCP ambiguity rule

• Adds rule definitions for new findings (invalid fields/paths, apps, hooks) and updates MCP invalid/ambiguous layout rule text/examples.

src/rules/rule-catalog.ts

security-audit.tsAudit hook commands; normalize MCP parsing; improve finding dedupe keys +162/-8

Audit hook commands; normalize MCP parsing; improve finding dedupe keys

• Adds 'auditHookCommand' to detect encoded commands, remote pipe installers, and shell wrappers with precise relative evidence; switches MCP audit to normalized layouts; and dedupes findings with hook-location specificity.

src/security/security-audit.ts

Bug fix (2) +25 / -5
doctor-size.tsAvoid Windows shell execution for npm pack dry-run sizing +23/-3

Avoid Windows shell execution for npm pack dry-run sizing

• Replaces 'shell: true' execution on Windows with a direct node + npm-cli invocation for 'npm pack --dry-run', reducing shell execution risk.

src/core/doctor-size.ts

init-plugin.tsScaffold canonical ./ paths in generated plugin manifests +2/-2

Scaffold canonical ./ paths in generated plugin manifests

• Changes scaffolding to emit './skills' and './.mcp.json' so manifests match containment/path validation expectations.

src/core/init-plugin.ts

Tests (27) +1639 / -16
check-command.test.tsExtend check-command coverage for new validations +26/-1

Extend check-command coverage for new validations

• Adds/updates assertions to reflect new rule surfaces and behavior introduced by official component and MCP layout validation.

tests/check-command.test.ts

cli-command.test.tsUpdate CLI tests for canonical ./ paths and new fixtures +161/-8

Update CLI tests for canonical ./ paths and new fixtures

• Adjusts init and fix-plan expectations for './skills' and './.mcp.json', and adds tests covering invalid optional metadata and MCP source layout behavior.

tests/cli-command.test.ts

contract-command.test.tsAdd contract coverage for official plugin compatibility +10/-0

Add contract coverage for official plugin compatibility

• Adds tests to ensure contract surfaces behave consistently with official layout normalization and validations.

tests/contract-command.test.ts

doctor-size.test.tsCover doctor size npm-pack invocation changes +51/-1

Cover doctor size npm-pack invocation changes

• Updates tests to reflect the new non-shell Windows execution path for 'npm pack --dry-run'.

tests/doctor-size.test.ts

plugin.jsonAdd ambiguous MCP layout fixture manifest +6/-0

Add ambiguous MCP layout fixture manifest

• Introduces a fixture plugin manifest used to validate fail-closed handling of ambiguous MCP layouts.

tests/fixtures/mcp-config-ambiguous/.codex-plugin/plugin.json

.mcp.jsonAdd ambiguous MCP layout fixture config +14/-0

Add ambiguous MCP layout fixture config

• Adds a fixture '.mcp.json' combining supported layout wrappers to ensure ambiguity is rejected.

tests/fixtures/mcp-config-ambiguous/.mcp.json

plugin.jsonAdjust fixture manifest path conventions +1/-1

Adjust fixture manifest path conventions

• Aligns fixture manifest path values to the canonical './'-prefixed conventions enforced by validators.

tests/fixtures/skill-missing-asset-reference/.codex-plugin/plugin.json

plugin.jsonAdjust fixture manifest path conventions +1/-1

Adjust fixture manifest path conventions

• Aligns fixture manifest path values to the canonical './'-prefixed conventions enforced by validators.

tests/fixtures/skill-valid-asset-reference/.codex-plugin/plugin.json

plugin.jsonAdd direct-map MCP fixture manifest +6/-0

Add direct-map MCP fixture manifest

• Adds a fixture plugin manifest for a package whose '.mcp.json' is a direct server map.

tests/fixtures/valid-plugin-with-mcp-direct/.codex-plugin/plugin.json

.mcp.jsonAdd direct-map MCP fixture config +6/-0

Add direct-map MCP fixture config

• Adds a direct-map '.mcp.json' fixture used to validate official MCP layout support.

tests/fixtures/valid-plugin-with-mcp-direct/.mcp.json

plugin.jsonAdd snake_case wrapper MCP fixture manifest +6/-0

Add snake_case wrapper MCP fixture manifest

• Adds a fixture plugin manifest for the 'mcp_servers' wrapper layout.

tests/fixtures/valid-plugin-with-mcp-snake-case/.codex-plugin/plugin.json

.mcp.jsonAdd snake_case wrapper MCP fixture config +8/-0

Add snake_case wrapper MCP fixture config

• Adds an '.mcp.json' fixture using 'mcp_servers' to validate normalization behavior.

tests/fixtures/valid-plugin-with-mcp-snake-case/.mcp.json

inspector-command.test.tsAdd inspector command tests for normalization and containment +74/-0

Add inspector command tests for normalization and containment

• Adds coverage ensuring inspector behavior supports normalized layouts and rejects unsafe MCP config paths.

tests/inspector-command.test.ts

install-preview-security.test.tsEnsure install previews reject symlink-based MCP config escapes +45/-0

Ensure install previews reject symlink-based MCP config escapes

• Adds a regression suite verifying all install preview builders fail when MCP config resolves outside the package root via symlinks.

tests/install-preview-security.test.ts

mcp-command.test.tsAdd MCP command coverage for official layouts +22/-0

Add MCP command coverage for official layouts

• Expands MCP command tests to cover direct and wrapped official layouts and associated failure behavior.

tests/mcp-command.test.ts

mcp-config-normalizer.test.tsUnit test MCP layout normalization and ambiguity detection +111/-0

Unit test MCP layout normalization and ambiguity detection

• Covers direct maps, 'mcp_servers', legacy 'mcpServers', ambiguity rejection, invalid server maps, and prototype-sensitive server names.

tests/mcp-config-normalizer.test.ts

plugin-components.test.tsTest optional metadata, safe paths, and apps validation behavior +178/-0

Test optional metadata, safe paths, and apps validation behavior

• Verifies acceptance of valid official metadata, correct failures for invalid field types and unsafe paths, and that evidence does not leak provided secret-like content.

tests/plugin-components.test.ts

plugin-hooks.test.tsTest lifecycle hook validation, defaults, containment, and auditing +313/-0

Test lifecycle hook validation, defaults, containment, and auditing

• Adds comprehensive coverage for hook source selection (including default hooks), invalid shapes/events, ignored matchers/warned handlers, containment escapes, and command auditing without leaking command content.

tests/plugin-hooks.test.ts

public-readiness.test.tsUpdate public readiness suite for v1.58 surfaces +42/-0

Update public readiness suite for v1.58 surfaces

• Adjusts readiness checks for new docs/rules and release expectations.

tests/public-readiness.test.ts

release-check.test.tsSync release-check tests for 1.58.0 +15/-0

Sync release-check tests for 1.58.0

• Updates tests ensuring release metadata and checks align with the 1.58.0 version bump.

tests/release-check.test.ts

release-notes.test.tsAdd/adjust release notes tests for 1.58.0 +16/-0

Add/adjust release notes tests for 1.58.0

• Adds/updates assertions covering the new 1.58.0 changelog/release notes behavior.

tests/release-notes.test.ts

release-sync.test.tsValidate version pin synchronization for 1.58.0 +10/-0

Validate version pin synchronization for 1.58.0

• Adds/updates tests ensuring docs and metadata pins match the release version.

tests/release-sync.test.ts

rule-catalog.test.tsEnsure rule catalog includes new component/hook/MCP rules +41/-0

Ensure rule catalog includes new component/hook/MCP rules

• Adds coverage that newly introduced rule IDs are present and documented in the catalog.

tests/rule-catalog.test.ts

runtime-plan-command.test.tsHarden runtime-plan tests for containment, fail-closed, and redaction/digest +316/-3

Harden runtime-plan tests for containment, fail-closed, and redaction/digest

• Adds tests for official MCP layouts, lexical/canonical escape rejection, security fail-closed planning, and secret redaction while preserving digest changes for argument changes.

tests/runtime-plan-command.test.ts

runtime-policy-command.test.tsUpdate runtime-policy tests for new runtime-plan behavior +1/-1

Update runtime-policy tests for new runtime-plan behavior

• Adjusts a runtime-policy expectation to align with updated runtime plan semantics.

tests/runtime-policy-command.test.ts

runtime-protocol.test.tsAdd runtime protocol regression coverage for updated planning outputs +79/-0

Add runtime protocol regression coverage for updated planning outputs

• Adds tests to ensure runtime protocol behaviors remain compatible after normalization and redaction changes.

tests/runtime-protocol.test.ts

security-command.test.tsTest security audit across official layouts and ambiguous audit behavior +80/-0

Test security audit across official layouts and ambiguous audit behavior

• Adds security command tests covering direct/snake/legacy MCP layouts, ensures ambiguous configs produce an audit-unavailable failure, and validates findings remain consistent.

tests/security-command.test.ts

Documentation (6) +110 / -27
CHANGELOG.mdAdd 1.58.0 release notes block +34/-0

Add 1.58.0 release notes block

• Adds a v1.58.0 changelog entry describing official MCP layout support, new static component/hook validation, containment hardening, fail-closed runtime planning, and runtime secret redaction.

CHANGELOG.md

README.mdUpdate action version pin and link new architecture doc +3/-2

Update action version pin and link new architecture doc

• Bumps GitHub Action examples to v1.58.0 and links the new Official Plugin Components documentation page.

README.md

README.mdAdd Official Plugin Components to docs index +1/-0

Add Official Plugin Components to docs index

• Adds a navigation entry for the new architecture doc covering official plugin component validation.

docs/README.md

official-plugin-components.mdDocument official plugin component and hook validation rules +33/-0

Document official plugin component and hook validation rules

• Introduces a new architecture doc describing supported MCP layouts, optional metadata/apps validation, lifecycle hook validation semantics, and report redaction behavior.

docs/architecture/official-plugin-components.md

github-action.mdBump GitHub Action guide pins to v1.58.0 +24/-24

Bump GitHub Action guide pins to v1.58.0

• Updates all referenced action tags and version inputs from 1.57.0 to 1.58.0.

docs/guides/github-action.md

catalog.mdAdd new rule IDs and clarify MCP layout failures +15/-1

Add new rule IDs and clarify MCP layout failures

• Documents new component/hook rule IDs and updates MCP invalid/ambiguous layout descriptions.

docs/rules/catalog.md

Other (2) +3 / -3
package-lock.jsonSync lockfile version to 1.58.0 +2/-2

Sync lockfile version to 1.58.0

• Updates top-level lockfile version fields to 1.58.0.

package-lock.json

package.jsonBump package version to 1.58.0 +1/-1

Bump package version to 1.58.0

• Updates the published package version from 1.57.0 to 1.58.0.

package.json

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb5dcd02ef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/core/runtime-plan.ts
Comment on lines +183 to +184
const secretRuntimeArgumentFlag = /^--?(?:token|api[-_]?key|apikey|password|secret|credential|authorization|bearer)$/i;
const secretRuntimeArgumentInline = /^(--?(?:token|api[-_]?key|apikey|password|secret|credential|authorization|bearer))[=:].*$/i;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Redact compound credential flags in runtime plans

Credential flags containing qualifiers are not matched by these exact-name expressions, so common arguments such as --auth-token secret, --client-secret=secret, or --private-key secret remain unchanged in the runtime-plan JSON, Markdown, review bundle, and release evidence. Because these artifacts are intended to be portable and persisted, broaden the credential-key detection rather than limiting it to the listed single-word names.

Useful? React with 👍 / 👎.

Comment thread src/core/runtime-plan.ts
highRiskServerCount: 0,
findings: { fail: 1, warn: 0, total: 1 }
},
servers: [],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep failed zero-server plans denied by runtime policy

When mcpServers is malformed or escapes the package, this helper returns a failed plan with no servers. buildDoctorRuntimePolicyReport derives deny, but buildRecommendation handles the zero-server case first and replaces it with an allow recommendation saying runtime probing is unnecessary. Thus the policy output simultaneously has fail status and recommends allow for an unsafe manifest; preserve a deny recommendation for failed zero-server plans.

Useful? React with 👍 / 👎.

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Unhandled MCP path throw 🐞 Bug ☼ Reliability
Description
readMcpConfigPath now throws on unsafe .mcp.json containment, but readMcpServerNames awaits it
outside a try/catch; an unsafe path can escape and abort or misclassify downstream compatibility
checks that call readMcpServerNames.
Code

src/compatibility/compatibility-matrix.ts[R66-69]

+    const containedDirectMcpPath = await resolveContainedPackagePath(rootPath, directMcpPath);
+
+    if (!containedDirectMcpPath) {
+      throw new Error("MCP config path resolves outside the package root.");
Evidence
The PR added throws in readMcpConfigPath for escaped MCP config paths, but readMcpServerNames
still calls it without guarding, so exceptions can escape before any local catch runs.

src/compatibility/compatibility-matrix.ts[61-100]
src/compatibility/compatibility-matrix.ts[158-173]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`readMcpConfigPath()` now throws when the resolved MCP config escapes the package root. `readMcpServerNames()` calls `readMcpConfigPath()` without handling exceptions, so unsafe-path packages can throw out of `readMcpServerNames()` and disrupt compatibility checks.

### Issue Context
This behavior was introduced when `readMcpConfigPath()` started enforcing canonical containment by throwing on escapes.

### Fix Focus Areas
- src/compatibility/compatibility-matrix.ts[61-100]
- src/compatibility/compatibility-matrix.ts[158-173]

### Suggested fix
Wrap the `readMcpConfigPath()` call inside `readMcpServerNames()` in a try/catch and return `[]` (or a structured failure) when containment fails. This keeps “duplicate server name” checks deterministic even for unsafe packages, while preserving the thrown-error behavior for callers that explicitly want a failing result (e.g., `checkGenericMcp`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Default hooks errors ignored 🐞 Bug ≡ Correctness
Description
When manifest.hooks is absent, validatePluginHooks returns [] for any stat() error on
./hooks/hooks.json, treating unreadable/broken paths the same as a missing optional file and
skipping hook validation findings.
Code

src/core/plugin-hooks.ts[R234-241]

+  if (configuredHooks === undefined) {
+    const defaultPath = "./hooks/hooks.json";
+    const resolved = await resolveSafePackagePath(rootPath, defaultPath);
+    if (!resolved) return [invalidHookPath(manifestPath)];
+    try {
+      if (!(await stat(resolved.path)).isFile()) return [];
+    } catch {
+      return [];
Evidence
The default-hooks branch returns [] for all stat errors, while the explicit hook-file validator
turns stat errors into a failure finding, showing an inconsistency that can suppress validation for
unreadable default hooks.

src/core/plugin-hooks.ts[194-227]
src/core/plugin-hooks.ts[229-244]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
In the default hooks discovery path (`manifest.hooks === undefined`), any `stat()` error causes an early `return []`. This conflates “default hooks file does not exist” (intended to be optional) with other filesystem errors (permission denied, IO errors, broken symlinks, etc.), which should likely produce a failure finding because Doctor cannot validate the hooks file it attempted to discover.

### Issue Context
`validateHookFile()` already fail-closes on stat/read errors for explicitly configured hooks sources, but the default discovery path is currently more permissive.

### Fix Focus Areas
- src/core/plugin-hooks.ts[194-227]
- src/core/plugin-hooks.ts[229-244]

### Suggested fix
Handle `ENOENT` as “no default hooks” (return `[]`), but for other errors emit a failure finding (e.g., reuse `plugin.hook.missing_file` with evidence indicating unreadable/uninspectable), and consider failing when the path exists but is not a regular file instead of returning `[]`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can group findings by type and pick your Finding display, from Minimal to Full

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment on lines +66 to +69
const containedDirectMcpPath = await resolveContainedPackagePath(rootPath, directMcpPath);

if (!containedDirectMcpPath) {
throw new Error("MCP config path resolves outside the package root.");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Unhandled mcp path throw 🐞 Bug ☼ Reliability

readMcpConfigPath now throws on unsafe .mcp.json containment, but readMcpServerNames awaits it
outside a try/catch; an unsafe path can escape and abort or misclassify downstream compatibility
checks that call readMcpServerNames.
Agent Prompt
### Issue description
`readMcpConfigPath()` now throws when the resolved MCP config escapes the package root. `readMcpServerNames()` calls `readMcpConfigPath()` without handling exceptions, so unsafe-path packages can throw out of `readMcpServerNames()` and disrupt compatibility checks.

### Issue Context
This behavior was introduced when `readMcpConfigPath()` started enforcing canonical containment by throwing on escapes.

### Fix Focus Areas
- src/compatibility/compatibility-matrix.ts[61-100]
- src/compatibility/compatibility-matrix.ts[158-173]

### Suggested fix
Wrap the `readMcpConfigPath()` call inside `readMcpServerNames()` in a try/catch and return `[]` (or a structured failure) when containment fails. This keeps “duplicate server name” checks deterministic even for unsafe packages, while preserving the thrown-error behavior for callers that explicitly want a failing result (e.g., `checkGenericMcp`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/core/plugin-hooks.ts
Comment on lines +234 to +241
if (configuredHooks === undefined) {
const defaultPath = "./hooks/hooks.json";
const resolved = await resolveSafePackagePath(rootPath, defaultPath);
if (!resolved) return [invalidHookPath(manifestPath)];
try {
if (!(await stat(resolved.path)).isFile()) return [];
} catch {
return [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. Default hooks errors ignored 🐞 Bug ≡ Correctness

When manifest.hooks is absent, validatePluginHooks returns [] for any stat() error on
./hooks/hooks.json, treating unreadable/broken paths the same as a missing optional file and
skipping hook validation findings.
Agent Prompt
### Issue description
In the default hooks discovery path (`manifest.hooks === undefined`), any `stat()` error causes an early `return []`. This conflates “default hooks file does not exist” (intended to be optional) with other filesystem errors (permission denied, IO errors, broken symlinks, etc.), which should likely produce a failure finding because Doctor cannot validate the hooks file it attempted to discover.

### Issue Context
`validateHookFile()` already fail-closes on stat/read errors for explicitly configured hooks sources, but the default discovery path is currently more permissive.

### Fix Focus Areas
- src/core/plugin-hooks.ts[194-227]
- src/core/plugin-hooks.ts[229-244]

### Suggested fix
Handle `ENOENT` as “no default hooks” (return `[]`), but for other errors emit a failure finding (e.g., reuse `plugin.hook.missing_file` with evidence indicating unreadable/uninspectable), and consider failing when the path exists but is not a regular file instead of returning `[]`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@Esquetta
Esquetta merged commit e4f2ad3 into main Aug 11, 2026
2 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ee4f6783d2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/core/runtime-plan.ts
Comment on lines +185 to +186
const authorizationBearerHeader = /^authorization\s*:\s*bearer\s+\S+/i;
const inlineAuthorizationBearerHeader = /^(?:--header|-H)=authorization\s*:\s*bearer\s+\S+/i;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Redact every Authorization header credential

When an MCP command supplies a non-Bearer authorization scheme, such as --header "Authorization: Basic dXNlcjpwYXNz" or --header=Authorization: Basic ..., these Bearer-only expressions leave the complete credential in runtime-plan JSON, Markdown, review bundles, and release evidence. Match and redact credential-bearing Authorization headers regardless of authentication scheme while retaining the raw value only for digest calculation.

Useful? React with 👍 / 👎.

Comment thread src/core/runtime-plan.ts
Comment on lines +401 to +406
status: !normalizedConfig.ok || highRiskServerCount > 0 || security.status === "fail"
? "fail" as const
: security.status === "warn"
? "warn" as const
: "pass" as const,
exitCode: (highRiskServerCount > 0 ? 1 : 0) as 0 | 1,
exitCode: (!normalizedConfig.ok || highRiskServerCount > 0 || security.status === "fail" ? 1 : 0) as 0 | 1,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve package-level denies in runtime policy

This also downgrades failed plans that contain a valid nonzero server: for example, a package with a local server and plugin.security.prompt_injection_text is marked failed here, but buildRisk does not attach that package-wide finding to the server because its message lacks the server name, so buildDoctorRuntimePolicyReport derives review and a warning instead of deny. Propagate deny-level plan findings into the overall runtime-policy decision rather than deriving it solely from per-server risks.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant