diff --git a/gadget-drone/src/gadget-drone.ts b/gadget-drone/src/gadget-drone.ts index 911a035..941bbf7 100644 --- a/gadget-drone/src/gadget-drone.ts +++ b/gadget-drone/src/gadget-drone.ts @@ -724,22 +724,43 @@ class GadgetDrone extends GadgetProcess { return cb(false, { error: "No session lock active" }); } - const projectRoot = WorkspaceService.getProjectDirectory(this.sessionLock.project.slug); + // Get the project directory for this session + const projectSlug = this.sessionLock.project.slug; + const projectRoot = WorkspaceService.getProjectDirectory(projectSlug); + + this.log.debug("fileTreeRequest received", { + projectSlug, + projectRoot, + requestedPath: args.path, + }); + if (!projectRoot) { - return cb(false, { error: "Project directory not found" }); + return cb(false, { error: `Project directory not found for slug: ${projectSlug}` }); } + // If no path specified, list from project root + // If path specified, resolve it relative to project root const targetPath = args.path ? path.resolve(projectRoot, args.path) : projectRoot; - // Security: Ensure path is within project root + // Security: Ensure resolved path is within project root const normalizedTarget = path.normalize(targetPath); const normalizedRoot = path.normalize(projectRoot); - if (!normalizedTarget.startsWith(normalizedRoot)) { + if (!normalizedTarget.startsWith(normalizedRoot + path.sep) && normalizedTarget !== normalizedRoot) { + this.log.warn("fileTreeRequest path traversal attempt", { + targetPath: normalizedTarget, + projectRoot: normalizedRoot, + }); return cb(false, { error: "Access denied: path outside project root" }); } + this.log.debug("fileTreeRequest resolved paths", { + projectRoot, + targetPath, + isRoot: targetPath === projectRoot, + }); + try { const stat = await fs.stat(targetPath); if (!stat.isDirectory()) { @@ -754,11 +775,17 @@ class GadgetDrone extends GadgetProcess { projectRoot, ); + this.log.debug("fileTreeRequest completed", { + entryCount: entries.length, + entries: entries.slice(0, 10).map(e => e.name), // Log first 10 entries + }); + cb(true, { entries }); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); this.log.error("failed to list directory for file tree", { path: args.path, + targetPath, error: errorMessage, }); cb(false, { error: `Failed to list directory: ${errorMessage}` });