codecartographer-pi 0.12.10 → 0.12.11

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.
@@ -15,7 +15,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
15
15
  import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js";
16
16
  import { cp, mkdir, readFile, rename, writeFile } from "node:fs/promises";
17
17
  import { basename, isAbsolute, join } from "node:path";
18
- import { buildPhasePrompt, buildSkillPrompt, buildValidationSummary, canonicalPath, completeValidatedPhase, computePerPhaseTotals, computeTotals, createEmptyStatus, DEFAULT_PIPELINE_PATH, deriveSlug, discoverLibrary, getNextEligiblePhase, getPipelineLabel, getWorkspaceState, isValidSlug, listEntries, listSkillNames, loadCodecartoConfig, loadUsage, loadYamlFile, normalizeForComparison, PACKAGE_VERSION, packagedWorkspaceDir, pathExists, PhasePreflightError, publishEntry, reindex as libraryReindex, resolvePhase, resolvePipelineChoice, stringifySimpleYaml, switchPipeline, validatePhaseOutput, writeLibraryConfig, } from "../core/index.js";
18
+ import { buildPhasePrompt, buildSkillPrompt, buildValidationSummary, canonicalPath, completeValidatedPhase, computePerPhaseTotals, computeTotals, createEmptyStatus, DEFAULT_PIPELINE_PATH, deriveSlug, discoverLibrary, getNextEligiblePhase, getPipelineLabel, getWorkspaceState, isValidSlug, isWithinPathResolved, listEntries, listSkillNames, loadCodecartoConfig, loadUsage, loadYamlFile, normalizeForComparison, PACKAGE_VERSION, packagedWorkspaceDir, pathExists, PhasePreflightError, publishEntry, reindex as libraryReindex, resolvePhase, resolvePipelineChoice, stringifySimpleYaml, switchPipeline, validatePhaseOutput, writeLibraryConfig, } from "../core/index.js";
19
19
  import { initLibrary } from "../core/library.js";
20
20
  import { loadUserConfig, resolveUserConfigPath } from "../core/orchestrator-config.js";
21
21
  import { writeDashboard } from "../extensions/codecarto/dashboard-writer.js";
@@ -325,7 +325,7 @@ function buildGenerationFromArg(model_metadata) {
325
325
  out.notes = m.notes;
326
326
  return out;
327
327
  }
328
- async function readSpecArg(args) {
328
+ async function readSpecArg(args, allowedRoots = []) {
329
329
  if (typeof args.spec === "string" && args.spec.length > 0)
330
330
  return args.spec;
331
331
  if (typeof args.spec_path === "string" && args.spec_path.length > 0) {
@@ -335,6 +335,16 @@ async function readSpecArg(args) {
335
335
  if (!(await pathExists(args.spec_path))) {
336
336
  throw new McpError(ErrorCode.InvalidParams, `spec_path does not exist: ${args.spec_path}`);
337
337
  }
338
+ // Enforce path containment: spec_path must be within an allowed root
339
+ // (cwd's .codecarto/ or the configured library path) to prevent
340
+ // arbitrary file reads.
341
+ if (allowedRoots.length > 0) {
342
+ const resolvedSpecPath = await canonicalPath(args.spec_path);
343
+ const withinAllowed = await Promise.all(allowedRoots.map((root) => isWithinPathResolved(resolvedSpecPath, root)));
344
+ if (!withinAllowed.some((result) => result)) {
345
+ throw new McpError(ErrorCode.InvalidParams, `spec_path must be within the workspace (.codecarto/) or the configured library path. Got: ${args.spec_path}`);
346
+ }
347
+ }
338
348
  return readFile(args.spec_path, "utf8");
339
349
  }
340
350
  throw new McpError(ErrorCode.InvalidParams, "Either spec (inline content) or spec_path (absolute file path) is required");
@@ -375,7 +385,12 @@ export async function handlePublish(args) {
375
385
  if (!marker) {
376
386
  throw new McpError(ErrorCode.InvalidParams, `No CodeCartographer library at ${libraryPath} (missing .codecarto-library marker). Create one before publishing.`);
377
387
  }
378
- const spec = await readSpecArg(args);
388
+ // Build allowed roots for spec_path containment: workspace .codecarto/ and library path
389
+ const allowedRoots = [libraryPath];
390
+ if (typeof args.cwd === "string" && args.cwd.trim() !== "") {
391
+ allowedRoots.push(join(args.cwd.trim(), ".codecarto"));
392
+ }
393
+ const spec = await readSpecArg(args, allowedRoots);
379
394
  if (typeof args.source_repo !== "string" || args.source_repo.trim() === "") {
380
395
  throw new McpError(ErrorCode.InvalidParams, "source_repo is required");
381
396
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codecartographer-pi",
3
- "version": "0.12.10",
3
+ "version": "0.12.11",
4
4
  "mcpName": "io.github.HuginnIndustries/codecartographer",
5
5
  "description": "Evidence-backed reverse engineering and human-gated software planning for Pi and MCP coding agents.",
6
6
  "type": "module",