codex-plugin-doctor 1.46.1 → 1.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -79,6 +79,7 @@ Runtime MCP validation with `--runtime`:
79
79
  - runtime capability scorecard
80
80
  - redacted verbose transcript with `--verbose-runtime`
81
81
  - optional runtime approval gating with a precomputed `doctor runtime-plan` digest
82
+ - optional Docker isolation for local Node.js stdio servers with `--sandbox docker`
82
83
 
83
84
  Output formats:
84
85
 
@@ -195,6 +196,9 @@ codex-plugin-doctor doctor contract
195
196
  codex-plugin-doctor doctor contract --json --output output-contract.json
196
197
  codex-plugin-doctor doctor corpus
197
198
  codex-plugin-doctor doctor corpus --json --output validation-corpus.json
199
+ codex-plugin-doctor doctor corpus --manifest ../private-corpus/corpus.json --json
200
+ codex-plugin-doctor doctor corpus metrics --manifest ../private-corpus/metrics.json --markdown
201
+ codex-plugin-doctor doctor corpus metrics --manifest ../private-corpus/metrics.json --json --min-precision 0.90 --min-recall 0.85 --max-false-positive-rate 0.10
198
202
  codex-plugin-doctor doctor npm <published-plugin-package>
199
203
  codex-plugin-doctor doctor npm <published-plugin-package> --json --output npm-preinstall.json
200
204
  codex-plugin-doctor doctor attest .
@@ -216,8 +220,10 @@ codex-plugin-doctor doctor perf . --max-total-ms 2500 --max-stage-ms validation=
216
220
  codex-plugin-doctor doctor runtime-plan .
217
221
  codex-plugin-doctor doctor runtime-plan . --json --output runtime-plan.json
218
222
  codex-plugin-doctor doctor runtime-plan . --markdown --output runtime-plan.md
223
+ codex-plugin-doctor doctor runtime-plan . --sandbox docker --json
219
224
  codex-plugin-doctor doctor runtime-policy .
220
225
  codex-plugin-doctor doctor runtime-policy . --json --output runtime-policy.json
226
+ codex-plugin-doctor doctor runtime-policy . --sandbox docker --json
221
227
  codex-plugin-doctor doctor review-bundle . --output review-bundle --sign-key-env CODEX_PLUGIN_DOCTOR_SIGNING_KEY
222
228
  codex-plugin-doctor doctor review-bundle verify review-bundle --target . --sign-key-env CODEX_PLUGIN_DOCTOR_SIGNING_KEY
223
229
  codex-plugin-doctor doctor review-bundle diff --before old-review-bundle --after review-bundle
@@ -285,13 +291,16 @@ codex-plugin-doctor check . --badge-markdown
285
291
  codex-plugin-doctor check . --sarif --output results.sarif
286
292
  codex-plugin-doctor check . --ascii
287
293
  codex-plugin-doctor check . --no-animations
288
- codex-plugin-doctor check . --runtime
289
- codex-plugin-doctor check . --runtime --require-runtime-approval --runtime-approval-digest sha256:<approved-plan-digest>
290
- codex-plugin-doctor release check .
291
- codex-plugin-doctor release check . --json
292
- codex-plugin-doctor release check . --runtime
293
- codex-plugin-doctor release check . --runtime --require-runtime-approval --runtime-approval-digest sha256:<approved-plan-digest>
294
- codex-plugin-doctor check . --config .codex-doctor.json
294
+ codex-plugin-doctor check . --runtime
295
+ codex-plugin-doctor check . --runtime --require-runtime-approval --runtime-approval-digest sha256:<approved-plan-digest>
296
+ codex-plugin-doctor check . --runtime --sandbox docker
297
+ codex-plugin-doctor check . --runtime --sandbox docker --require-runtime-approval --runtime-approval-digest sha256:<approved-docker-plan-digest>
298
+ codex-plugin-doctor release check .
299
+ codex-plugin-doctor release check . --json
300
+ codex-plugin-doctor release check . --runtime
301
+ codex-plugin-doctor release check . --runtime --require-runtime-approval --runtime-approval-digest sha256:<approved-plan-digest>
302
+ codex-plugin-doctor release check . --runtime --sandbox docker --require-runtime-approval --runtime-approval-digest sha256:<approved-docker-plan-digest>
303
+ codex-plugin-doctor check . --config .codex-doctor.json
295
304
  codex-plugin-doctor baseline create . --output .codex-doctor-baseline.json
296
305
  codex-plugin-doctor check . --baseline .codex-doctor-baseline.json
297
306
  codex-plugin-doctor check . --history validation-history.jsonl
@@ -304,6 +313,12 @@ codex-plugin-doctor fix . --apply --backup
304
313
  codex-plugin-doctor check . --json --runtime --verbose-runtime
305
314
  ```
306
315
 
316
+ Docker runtime mode supports local Node.js stdio MCP servers. It uses a digest-pinned image, no network, read-only container and package filesystems, an unprivileged user, dropped capabilities, bounded resources, and a limited writable `/tmp`. It fails closed without native fallback and rejects package roots containing commas. The Docker daemon, base image, and host kernel remain trusted boundaries. Generate approval digests with the same `--sandbox docker` backend used for execution. See [Runtime Approval And Sandboxing](./docs/security/runtime-approval-and-sandboxing.md).
317
+
318
+ External corpus evaluation is static and offline. `doctor corpus --manifest <corpus.json>` validates anonymized local snapshots using stable content digests and exact finding fingerprints without downloading dependencies or starting target servers. Reports omit manifest and package paths and fail on digest drift, missing expected findings, present disputed findings, or unreviewed findings. See [Real-World Validation](./docs/guides/real-world-validation.md).
319
+
320
+ `doctor corpus metrics --manifest <corpus.json>` measures reviewed true positives, false positives, and false negatives as precision, recall, and emitted-finding false-positive share. Optional thresholds make the measurement release-gating; incomplete reviews and digest drift return exit `2` instead of producing a favorable score. The dedicated metrics manifest stays offline, requires contained snapshot paths, and may record immutable HTTPS Git provenance without fetching it.
321
+
307
322
  `self-test` runs the bundled runtime-complete sample through static validation, runtime MCP probes, and the compatibility scorecard. It is the fastest post-install check after `npm install -g codex-plugin-doctor`.
308
323
 
309
324
  `doctor` checks the local environment, including package version, platform, Node version, npm global prefix, Codex home, and Codex plugin cache visibility. The text output also includes recommended next commands for self-test, installed plugin discovery, runtime checks, compatibility scoring, and CI setup. `doctor contract` publishes the machine-readable output contract, including public JSON schema surfaces, stable-through-1.0 compatibility metadata, and a frozen rule catalog digest. Add `--json` for automation or `--output output-contract.json` to write the contract to disk. `doctor corpus` runs the bundled validation corpus against healthy runtime, risky security, starter skill, and generic MCP packages, then reports whether each case matched its expected outcome. Add `--json` for automation or `--output validation-corpus.json` to write the corpus report to disk. `doctor npm <package>` runs a preinstall scan by packing the npm package with scripts disabled, extracting the publish tarball, and running validation, security, trust, and recommendation checks against the shipped contents. The JSON report includes tarball metadata such as filename, path, integrity, shasum, sizes, file count, and extracted package root so automation can prove which archive was scanned. Use a published Codex plugin package as the target; scanning `codex-plugin-doctor` itself intentionally reports a missing plugin manifest because this CLI package is not a plugin package. Add `--json` for automation or `--output npm-preinstall.json` to write the report to disk. `doctor attest <path>` creates a local attestation with stable package/report digests, validation/security/compatibility/trust summary, and verification metadata. Add `--sign-key-env NAME` to attach a local HMAC-SHA256 signature without printing the secret, or `--json --output attestation.json` to write the artifact to disk. `doctor attest verify <attestation.json> --target <path> --sign-key-env NAME` recomputes the package fingerprint, report digest, and HMAC signature offline; verification intentionally treats `generatedAt`, `targetPath`, `verification`, and `signature.keyHint` as unsigned display metadata. `doctor runtime-plan <path>` creates a non-executing runtime plan that lists MCP server commands, safe probe methods, risk reasons, and a stable approval digest before any local server is started. Add `--markdown --output runtime-plan.md` to preserve a review-ready approval artifact with the execution boundary, checklist, servers, probes, and risk reasons. `doctor runtime-policy <path>` evaluates the same runtime plan and security signals, then recommends `allow`, `review`, `sandbox_recommended`, or `deny` before local MCP execution starts. `doctor review-bundle <path> --output <dir> --sign-key-env NAME` writes a signed review directory with runtime plan, runtime policy, attestation, release evidence, manifest, Markdown summary files, and SHA-256 file integrity digests. `doctor review-bundle verify <bundle-dir> --target <path> --sign-key-env NAME` verifies the bundle manifest, expected files, manifest integrity digests, runtime artifacts, signed attestation, and signed release evidence offline before a reviewer trusts the handoff. `doctor review-bundle diff --before <dir> --after <dir>` compares two review bundles and flags risk-increasing changes in status, runtime policy, release readiness, signatures, release evidence, and runtime plan digest. `check --runtime --require-runtime-approval --runtime-approval-digest <digest>` refuses to run runtime probes unless the current plan digest matches the approved digest. `doctor release-evidence <path> --sign-key-env NAME` creates one redacted release bundle with signed attestation, offline verification, corpus, performance, security, trust, package metadata, git release gates, and runtime approval status. Strict release evidence requires a clean tagged worktree; use `--allow-dirty` or `--allow-untagged` only for local rehearsal. `doctor release-evidence verify <evidence.json> --target <path> --sign-key-env NAME` verifies a shared release evidence artifact offline against an explicit package path; the artifact target path is treated as display metadata, not trusted input. `doctor release-evidence asset <path> --tag <tag> --output <evidence.json> --sign-key-env NAME` writes a signed release evidence file and prints the `gh release upload` command; add `--upload` to run the upload through GitHub CLI with `--clobber`. `doctor inspector <path>` builds a safe MCP Inspector launch command from a packaged `.mcp.json` file without starting the Inspector proxy automatically. Use `--server <name>` when the package contains multiple MCP server entries. `doctor diff --before <path> --after <path>` compares two package roots and reports new findings, resolved findings, trust score delta, and whether risk increased. `doctor recommend <path>` turns validation, security, and compatibility signals into a prioritized action plan with blocker, high, medium, and info actions. Add `--json` for automation or `--output recommendations.json` to write the report to disk. `doctor trust <path>` creates a local trust score from package lifecycle scripts, dependency specs, and MCP security findings. Use it before release when you want supply-chain risks summarized as one score. `doctor perf <path>` profiles the shared package analysis pipeline and reports per-stage durations for validation, config, security, compatibility, trust, recommendations, and total runtime. Add `--max-total-ms <ms>` or repeatable `--max-stage-ms stage=ms` to fail CI when a budget is exceeded. `doctor mcp <path>` exposes the generic MCP static health report under the doctor command family without starting local MCP servers. `doctor export --bundle <path>` creates a redacted operator handoff bundle that includes validation JSON, security scorecard data, compatibility matrix, recommendations, and trust score in one file. `doctor snapshot` creates a redacted diagnostics bundle with environment health, client config readiness, installed plugin metadata, and next commands. Add `--json` for machine-readable output or `--output doctor-snapshot.json` to write the bundle to disk. `doctor clients` reports local Codex, Claude Desktop, Cursor, Cline, and Windsurf config readiness. `doctor --update-check` compares the installed CLI version with the latest npm version and prints the upgrade command when a newer release is available.
@@ -410,9 +425,9 @@ jobs:
410
425
  runs-on: ubuntu-latest
411
426
  steps:
412
427
  - uses: actions/checkout@v5
413
- - uses: Esquetta/CodexPluginDoctor@v1.46.1
428
+ - uses: Esquetta/CodexPluginDoctor@v1.48.0
414
429
  with:
415
- version: "1.46.1"
430
+ version: "1.48.0"
416
431
  path: .
417
432
  runtime: "true"
418
433
  policy: codex-publish
@@ -439,7 +454,6 @@ docs/ Public architecture, guides, rules, security, and contribu
439
454
  examples/ Manual plugin packs for local CLI testing
440
455
  src/ CLI, validation logic, runtime probing, reports
441
456
  tests/ Fixture-based regression tests
442
- validation-sessions/ Real-world validation waves and tuning notes
443
457
  ```
444
458
 
445
459
  ## Validation Evidence
@@ -447,7 +461,6 @@ validation-sessions/ Real-world validation waves and tuning notes
447
461
  The validator is tuned against local fixtures and real marketplace-style plugin packages. See:
448
462
 
449
463
  - [Real-World Validation Workflow](./docs/guides/real-world-validation.md)
450
- - [Validation Sessions](./validation-sessions/README.md)
451
464
  - [Examples](./examples/README.md)
452
465
  - [Rule Catalog](./docs/rules/catalog.md)
453
466
 
@@ -467,9 +480,9 @@ npm run prepare-release
467
480
  npm run release-check
468
481
  ```
469
482
 
470
- `prepare-release` runs tests, builds the TypeScript output, and performs `npm pack --dry-run`. `release-check` adds release preflight checks for a clean git tree, existing npm versions, existing version tags, package/lockfile/changelog version consistency, tests, build, pack dry-run, fresh temp install audit, and publish dry-run.
471
-
472
- For plugin packages, `codex-plugin-doctor release check .` performs static readiness checks by default. Runtime probing executes package-local MCP servers and therefore requires an explicit `--runtime`; protected workflows can also require the approved runtime-plan digest.
483
+ `prepare-release` runs tests, builds the TypeScript output, and performs `npm pack --dry-run`. `release-check` adds release preflight checks for a clean git tree, existing npm versions, existing version tags, package/lockfile/changelog version consistency, tests, build, pack dry-run, fresh temp install audit, and publish dry-run.
484
+
485
+ For plugin packages, `codex-plugin-doctor release check .` performs static readiness checks by default. Runtime probing executes package-local MCP servers and therefore requires an explicit `--runtime`; protected workflows can also require the approved runtime-plan digest.
473
486
 
474
487
  Related docs:
475
488
 
@@ -95,6 +95,7 @@ export interface VerifyDoctorAttestationOptions {
95
95
  signingKey: string;
96
96
  artifactPath?: string;
97
97
  }
98
+ export declare function buildPackageFingerprint(rootPath: string): Promise<PackageFingerprint>;
98
99
  export declare function buildDoctorAttestation(targetPath: string, options?: BuildDoctorAttestationOptions): Promise<DoctorAttestation>;
99
100
  export declare function verifyDoctorAttestation(artifactPath: string, targetPath: string, options: VerifyDoctorAttestationOptions): Promise<DoctorAttestationVerificationReport>;
100
101
  export declare function verifyDoctorAttestationObject(artifact: unknown, targetPath: string, options: VerifyDoctorAttestationOptions): Promise<DoctorAttestationVerificationReport>;
@@ -61,7 +61,7 @@ async function collectFileEntries(rootPath, currentPath = rootPath) {
61
61
  }));
62
62
  return fileEntries.flat().sort((left, right) => left.relativePath.localeCompare(right.relativePath));
63
63
  }
64
- async function buildPackageFingerprint(rootPath) {
64
+ export async function buildPackageFingerprint(rootPath) {
65
65
  const files = await collectFileEntries(rootPath);
66
66
  const bytes = files.reduce((total, file) => total + file.size, 0);
67
67
  const digest = sha256(stableStringify(files));
@@ -0,0 +1,125 @@
1
+ import type { ExternalCorpusMode, ExternalCorpusProfile, ExternalCorpusSourceType, FindingReviewClassification } from "./external-validation-corpus.js";
2
+ export interface CorpusMetricThresholds {
3
+ minPrecision?: number;
4
+ minRecall?: number;
5
+ maxFalsePositiveRate?: number;
6
+ }
7
+ export interface CorpusMetricFindingReview {
8
+ findingId: string;
9
+ fingerprint: string;
10
+ classification: FindingReviewClassification;
11
+ }
12
+ export interface CorpusMetricSource {
13
+ repository: string;
14
+ revision: string;
15
+ }
16
+ export interface CorpusMetricTarget {
17
+ id: string;
18
+ profile: ExternalCorpusProfile;
19
+ sourceType: ExternalCorpusSourceType;
20
+ disclosure: "anonymized";
21
+ path: string;
22
+ mode: ExternalCorpusMode;
23
+ contentDigest: string;
24
+ source?: CorpusMetricSource;
25
+ reviews: CorpusMetricFindingReview[];
26
+ }
27
+ export interface CorpusMetricsManifest {
28
+ schemaVersion: "1.0.0";
29
+ thresholds?: CorpusMetricThresholds;
30
+ targets: CorpusMetricTarget[];
31
+ }
32
+ interface LoadedCorpusMetricTarget extends CorpusMetricTarget {
33
+ resolvedPath: string;
34
+ }
35
+ interface LoadedCorpusMetricsManifest extends CorpusMetricsManifest {
36
+ targets: LoadedCorpusMetricTarget[];
37
+ }
38
+ export interface CorpusMetricFinding {
39
+ findingId: string;
40
+ fingerprint: string;
41
+ }
42
+ export interface CorpusMetricCounts {
43
+ truePositives: number;
44
+ falsePositives: number;
45
+ falseNegatives: number;
46
+ resolvedFalsePositives: number;
47
+ unreviewed: number;
48
+ unclear: number;
49
+ }
50
+ export interface CorpusMetricValues {
51
+ precision: number | null;
52
+ recall: number | null;
53
+ falsePositiveRate: number | null;
54
+ }
55
+ export interface CorpusMetricOutcome extends CorpusMetricFinding {
56
+ classification: FindingReviewClassification | "unreviewed";
57
+ emitted: boolean;
58
+ }
59
+ export interface CorpusMetricReconciliation {
60
+ counts: CorpusMetricCounts;
61
+ metrics: CorpusMetricValues;
62
+ complete: boolean;
63
+ outcomes: CorpusMetricOutcome[];
64
+ }
65
+ export interface CorpusMetricThresholdCheck {
66
+ metric: keyof CorpusMetricValues;
67
+ operator: ">=" | "<=";
68
+ threshold: number;
69
+ actual: number | null;
70
+ passed: boolean;
71
+ }
72
+ export interface CorpusQualityMetricsTargetResult {
73
+ id: string;
74
+ profile: ExternalCorpusProfile;
75
+ sourceType: ExternalCorpusSourceType;
76
+ disclosure: "anonymized";
77
+ mode: ExternalCorpusMode;
78
+ source?: CorpusMetricSource;
79
+ digestMatched: boolean;
80
+ counts: CorpusMetricCounts;
81
+ metrics: CorpusMetricValues;
82
+ complete: boolean;
83
+ outcomes: CorpusMetricOutcome[];
84
+ }
85
+ export interface CorpusQualityMetricsReport {
86
+ schemaVersion: "1.0.0";
87
+ kind: "doctor.validation.corpus.metrics";
88
+ generatedAt: string;
89
+ version: string;
90
+ status: "pass" | "fail" | "incomplete";
91
+ exitCode: 0 | 1 | 2;
92
+ summary: CorpusMetricCounts & CorpusMetricValues & {
93
+ targetCount: number;
94
+ completeTargets: number;
95
+ incompleteTargets: number;
96
+ };
97
+ thresholds: CorpusMetricThresholds;
98
+ thresholdChecks: CorpusMetricThresholdCheck[];
99
+ targets: CorpusQualityMetricsTargetResult[];
100
+ }
101
+ export interface BuildCorpusMetricsOptions {
102
+ thresholds?: CorpusMetricThresholds;
103
+ environment?: {
104
+ env?: NodeJS.ProcessEnv;
105
+ platform?: NodeJS.Platform;
106
+ };
107
+ analyzeTarget?: (targetPath: string, mode: ExternalCorpusMode) => Promise<{
108
+ findings: CorpusMetricFinding[];
109
+ }>;
110
+ buildFingerprint?: (targetPath: string) => Promise<{
111
+ digest: string;
112
+ }>;
113
+ }
114
+ export declare class CorpusMetricsManifestError extends Error {
115
+ constructor(message: string);
116
+ }
117
+ export declare function loadCorpusMetricsManifest(manifestPath: string): Promise<LoadedCorpusMetricsManifest>;
118
+ export declare function reconcileCorpusMetricFindings(reviews: CorpusMetricFindingReview[], actualFindings: CorpusMetricFinding[]): CorpusMetricReconciliation;
119
+ export declare function buildCorpusQualityMetricsReport(manifestPath: string, options?: BuildCorpusMetricsOptions): Promise<CorpusQualityMetricsReport>;
120
+ export declare function renderCorpusQualityMetricsJson(report: CorpusQualityMetricsReport): string;
121
+ export declare function renderCorpusQualityMetricsText(report: CorpusQualityMetricsReport, options?: {
122
+ outputPath?: string | null;
123
+ }): string;
124
+ export declare function renderCorpusQualityMetricsMarkdown(report: CorpusQualityMetricsReport): string;
125
+ export {};