📂 fix: Preserve Nested Skill Paths in Code-Env Uploads#12877
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes Code Environment uploads so multipart filenames preserve nested paths (e.g. pptx/pptx.py) by using form-data’s filepath option, allowing the existing CodeAPI preservePath handling to place files into the expected subdirectories.
Changes:
- Introduce a small
FormDatahelper for CodeEnv uploads that uses{ filename, filepath }when a filename contains path separators (and normalizes Windows\to/). - Switch both single-file and batch CodeEnv upload flows to use the helper.
- Add regression tests proving the
form.append(..., 'dir/file')string overload strips directories while the helper preserves them.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| api/server/services/Files/Code/formData.js | Adds helper to build form-data options for path-preserving CodeEnv uploads. |
| api/server/services/Files/Code/crud.js | Uses the helper for single and batch CodeEnv uploads. |
| api/server/services/Files/Code/formData.spec.js | Adds tests asserting the multipart filename header preserves nested paths with filepath. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function getCodeEnvFileOptions(filename) { | ||
| const normalized = filename.replace(/\\/g, '/'); | ||
| const basename = path.posix.basename(normalized); | ||
|
|
||
| if (normalized !== basename) { | ||
| return { filename: basename, filepath: normalized }; | ||
| } | ||
|
|
||
| return { filename }; |
There was a problem hiding this comment.
getCodeEnvFileOptions forwards any path-bearing filename verbatim via filepath (after only replacing \\ with /). Since uploadCodeEnvFile can receive filename from multer's file.originalname (user-controlled), this enables sending ../ segments, absolute paths (/etc/passwd), or Windows drive paths (C:/...) to CodeAPI once path preservation is enabled. Please sanitize/validate the path before returning it (e.g., reuse sanitizeArtifactPath from @librechat/api, strip leading slashes / drive prefixes, and reject .. segments), and add a small regression test for traversal/absolute-path inputs so this doesn't become a sandbox path traversal vector if CodeAPI-side protections regress.
GitNexus: 🚀 deployedThe |
|
@codex review |
|
Codex Review: Didn't find any major issues. Swish! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
53c4276 to
65fd57a
Compare
GitNexus: 🚀 deployedThe |
GitNexus: 🚀 deployedThe |
…2877) * fix(code): preserve code env upload filepaths * chore: Reorder import statements in crud.js
…2877) * fix(code): preserve code env upload filepaths * chore: Reorder import statements in crud.js
Summary
Fixes the LibreChat half of nested code-environment file uploads. Skill priming builds filenames like
pptx/pptx.py, but the Nodeform-datastring overload silently converts that tofilename="pptx.py"before CodeAPI receives the multipart request.The new backend logic lives in
packages/api:appendCodeEnvFileuses theform-datafilepathoption for path-bearing names so the multipart filename remainspptx/pptx.py. The legacy/apiupload service only imports that package helper and applies it to single-file and batch CodeEnv uploads.CodeAPI already has
busboy({ preservePath: true }), header encoding, RFC 5987 download parsing, and recursive sandbox placement, so this lets the existing server-side path preservation finally see the path LibreChat intended to send.Root Cause
form.append("file", stream, "pptx/pptx.py")does not send that string verbatim. Inform-data, the bare string overload is treated asoptions.filenameand passed throughpath.basename, producing:Content-Disposition: form-data; name="file"; filename="pptx.py"Using
filepathproduces the path-bearing multipart header CodeAPI expects:Content-Disposition: form-data; name="file"; filename="pptx/pptx.py"Without this, skill helper modules still land flat at
/mnt/data/pptx.pyand can shadow installed packages likepython-pptx.Changes
packages/api/src/files/code/form.tsthat uses{ filename, filepath }for nested filenames and normalizes Windows separators.@librechat/apiand keep/api/server/services/Files/Code/crud.jsas the thin legacy caller.Test Plan
cd packages/api && npx jest src/files/code/form.spec.ts --runInBandcd api && npx jest server/services/Files/Code/crud.spec.js --runInBandcd packages/api && npm run buildnpx eslint packages/api/src/files/code/form.ts packages/api/src/files/code/form.spec.ts api/server/services/Files/Code/crud.js api/server/services/Files/Code/crud.spec.js/mnt/data/pptx/pptx.pyexists while/mnt/data/pptx.pydoes not.Related
Pairs with ClickHouse/ai#1358 for CodeAPI-side internal header hardening.