Skip to content

fix: layer publish support code is http url#143

Open
mozhou52 wants to merge 1 commit intomasterfrom
support-http
Open

fix: layer publish support code is http url#143
mozhou52 wants to merge 1 commit intomasterfrom
support-http

Conversation

@mozhou52
Copy link
Collaborator

@mozhou52 mozhou52 commented Mar 4, 2026

Summary by CodeRabbit

  • Tests

    • Added mocks for the downloads module to resolve test initialization failures.
  • Bug Fixes

    • Improved cleanup of temporary download and zip files during deployment and layer publishing.
  • Refactor

    • Centralized URL download handling into a shared utility and updated layer publish flow to use it (including optional temp-dir propagation).
    • Adjusted a public helper signature/parameter naming to align with the refactor.

@mozhou52 mozhou52 requested a review from rsonghuster March 4, 2026 05:19
@coderabbitai
Copy link

coderabbitai bot commented Mar 4, 2026

📝 Walkthrough

Walkthrough

Extracted URL-download logic into a new exported utility _downloadFromUrl in src/utils; deploy and layer flows now call this shared utility, with added cleanup of temporary download artifacts. Tests add Jest mocks for @serverless-devs/downloads. checkFcDir param renamed to inputPath.

Changes

Cohort / File(s) Summary
Test Module Mocks
__tests__/ut/commands/invoke_test.ts, __tests__/ut/utils/utils_test.ts
Added Jest mocks for @serverless-devs/downloads to prevent import errors during tests.
Shared Utilities
src/utils/index.ts
Added exported async _downloadFromUrl(url: string): Promise<string> to download URL content into a temp dir and return local path; renamed checkFcDir(path...)checkFcDir(inputPath...).
Deploy Implementation
src/subCommands/deploy/impl/function.ts
Replaced local download method with imported _downloadFromUrl, removed @serverless-devs/downloads/os imports, and implemented fs cleanup of downloaded temp files in skip/post-upload paths.
Layer Subcommand
src/subCommands/layer/index.ts
Detects HTTP(S) codeUri, downloads via _downloadFromUrl, forwards downloadedTempFile into safe_publish_layer (signature updated), and removes temp zip/downloaded dir after use or when skipping upload.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as "CLI/Command"
  participant Layer as "Layer.publish()"
  participant Deploy as "Deploy/function flow"
  participant Utils as "utils._downloadFromUrl"
  participant FS as "Filesystem (temp dirs)"

  CLI->>Layer: publish(codeUri)
  alt codeUri is http(s)
    Layer->>Utils: _downloadFromUrl(codeUri)
    Utils->>FS: create temp dir & download file
    Utils-->>Layer: local downloadedTempFile
    Layer->>Layer: safe_publish_layer(..., downloadedTempFile)
    Layer->>FS: remove temp zip & downloadedTempFile
  else non-URL
    Layer->>Layer: proceed with local path
  end

  CLI->>Deploy: deploy/function(codeUri)
  alt codeUri is http(s)
    Deploy->>Utils: _downloadFromUrl(codeUri)
    Utils->>FS: create temp dir & download file
    Utils-->>Deploy: local downloadedTempFile
    Deploy->>FS: remove downloadedTempFile on skip/after upload
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • fix: code support http url #142: Implements HTTP(S) code-URL download in deploy flow; closely related to this PR which centralizes download logic into src/utils.

Poem

🐰
I hopped to fetch a distant file,
I cached it in a cozy pile.
Then swept my burrow neat and fast,
No stray crumbs of temp files last.
A shared hole now saves us time and style!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding HTTP/HTTPS URL support for layer code publishing, which is the primary feature across multiple modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch support-http

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/subCommands/layer/index.ts (1)

34-100: ⚠️ Potential issue | 🟠 Major

Use try/finally in safe_publish_layer for guaranteed temp cleanup.

downloadedTempDir and generated zip cleanup run only on success/skip branches. If an exception is thrown during checksum, OSS upload, or create-layer call, temp artifacts are left behind.

Suggested fix
   static async safe_publish_layer(
@@
-    let zipPath = toZipDir;
-    let generateZipFilePath = '';
-    if (!toZipDir.endsWith('.zip')) {
+    let zipPath = toZipDir;
+    let generateZipFilePath = '';
+    try {
+      if (!toZipDir.endsWith('.zip')) {
         const zipConfig = {
@@
-      generateZipFilePath = (await zip(zipConfig)).outputFile;
-      zipPath = generateZipFilePath;
-    }
-    const latestLayer = await fcSdk.getLayerLatestVersion(layerName);
-    if (latestLayer) {
+        generateZipFilePath = (await zip(zipConfig)).outputFile;
+        zipPath = generateZipFilePath;
+      }
+      const latestLayer = await fcSdk.getLayerLatestVersion(layerName);
+      if (latestLayer) {
@@
-        return latestLayer;
+          return latestLayer;
+        }
       }
-    }
-    logger.debug(`Zip file: ${zipPath}`);
-    getFileSize(zipPath);
-    const ossConfig = await fcSdk.uploadCodeToTmpOss(zipPath);
-    logger.debug('ossConfig: ', ossConfig);
+      logger.debug(`Zip file: ${zipPath}`);
+      getFileSize(zipPath);
+      const ossConfig = await fcSdk.uploadCodeToTmpOss(zipPath);
+      logger.debug('ossConfig: ', ossConfig);
@@
-    console.log(JSON.stringify(result));
-    return result;
+      console.log(JSON.stringify(result));
+      return result;
+    } finally {
+      if (generateZipFilePath) {
+        try {
+          fs.rmSync(generateZipFilePath);
+        } catch (ex) {
+          logger.debug(`Unable to remove zip file: ${zipPath}`);
+        }
+      }
+      if (downloadedTempDir) {
+        try {
+          logger.debug(`Removing temp download dir: ${downloadedTempDir}`);
+          fs.rmSync(downloadedTempDir, { recursive: true, force: true });
+        } catch (ex) {
+          logger.debug(`Unable to remove temp download dir: ${downloadedTempDir}`);
+        }
+      }
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/subCommands/layer/index.ts` around lines 34 - 100, The temp artifacts
(downloadedTempDir and generateZipFilePath) are only deleted on the normal/skip
paths, leaving leftovers on exceptions; update the function (safe_publish_layer
/ the block using zipPath, generateZipFilePath, downloadedTempDir,
calculateCRC64, uploadCodeToTmpOss, createLayerVersion) to wrap the main work in
a try block and move all cleanup logic into a finally block that always attempts
to fs.rmSync(generateZipFilePath) and fs.rmSync(downloadedTempDir, { recursive:
true, force: true }), logging any removal errors with logger.debug; keep
existing conditional checks so you only remove files that were actually created
and preserve existing debug messages in the finally.
src/utils/index.ts (1)

301-304: ⚠️ Potential issue | 🟠 Major

Prefix validation in checkFcDir is over-broad and rejects valid paths.

Using startsWith(prefix) blocks unrelated paths like /various/... when checking /var. Match exact prefix directory boundaries instead.

Suggested fix
   for (const prefix of forbiddenPrefixes) {
-    if (normalizedPath.startsWith(prefix)) {
+    if (normalizedPath === prefix || normalizedPath.startsWith(`${prefix}/`)) {
       throw new Error(`Invalid ${paramName}, ${prefix} and its subdirectories are not allowed`);
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/index.ts` around lines 301 - 304, The check in checkFcDir currently
uses normalizedPath.startsWith(prefix) which falsely rejects paths that only
share a leading segment (e.g., "/various" vs "/var"); update the logic to only
reject when the normalizedPath equals the forbidden prefix or lies inside it by
checking boundary-aware matches: i.e., treat a forbidden prefix as matched only
if normalizedPath === prefix or normalizedPath.startsWith(prefix + path.sep)
(use the appropriate path.sep/posix separator for your environment) for each
entry in forbiddenPrefixes; update any references to normalizedPath and
forbiddenPrefixes in checkFcDir accordingly.
src/subCommands/deploy/impl/function.ts (1)

286-360: ⚠️ Potential issue | 🟠 Major

Make temp file cleanup exception-safe with finally.

downloadedTempDir cleanup currently runs only on normal branches. If an exception occurs after download (for example at Line 341), the temp dir can leak.

Suggested fix
   private async _uploadCode(): Promise<boolean> {
@@
-    let generateZipFilePath = '';
-    if (needZip) {
+    let generateZipFilePath = '';
+    try {
+      if (needZip) {
         setNodeModulesBinPermissions(zipPath);
@@
-      zipPath = generateZipFilePath;
-    }
+        zipPath = generateZipFilePath;
+      }
@@
-    const ossConfig = await this.fcSdk.uploadCodeToTmpOss(zipPath);
-    logger.debug('ossConfig: ', ossConfig);
-    _.set(this.local, 'code', ossConfig);
-
-    if (generateZipFilePath) {
-      try {
-        fs.rmSync(generateZipFilePath);
-      } catch (ex) {
-        logger.debug(`Unable to remove zip file: ${zipPath}`);
-      }
-    }
-
-    if (downloadedTempDir) {
-      try {
-        logger.debug(`Removing temp download dir: ${downloadedTempDir}`);
-        fs.rmSync(downloadedTempDir, { recursive: true, force: true });
-      } catch (ex) {
-        logger.debug(`Unable to remove temp download dir: ${downloadedTempDir}`);
-      }
-    }
-
-    return true;
+      const ossConfig = await this.fcSdk.uploadCodeToTmpOss(zipPath);
+      logger.debug('ossConfig: ', ossConfig);
+      _.set(this.local, 'code', ossConfig);
+      return true;
+    } finally {
+      if (generateZipFilePath) {
+        try {
+          fs.rmSync(generateZipFilePath);
+        } catch (ex) {
+          logger.debug(`Unable to remove zip file: ${zipPath}`);
+        }
+      }
+      if (downloadedTempDir) {
+        try {
+          logger.debug(`Removing temp download dir: ${downloadedTempDir}`);
+          fs.rmSync(downloadedTempDir, { recursive: true, force: true });
+        } catch (ex) {
+          logger.debug(`Unable to remove temp download dir: ${downloadedTempDir}`);
+        }
+      }
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/subCommands/deploy/impl/function.ts` around lines 286 - 360, The temp
download and generated zip cleanup can leak if an exception occurs; move the
deletion of downloadedTempDir and generateZipFilePath into a finally block so
they always run after processing (wrap the code between obtaining zipPath and
the return/oss upload in try { ... } finally { try {
fs.rmSync(generateZipFilePath) } catch{}; try { fs.rmSync(downloadedTempDir, {
recursive: true, force: true }) } catch{} }). Update the block that calls
calculateCRC64, this.fcSdk.uploadCodeToTmpOss, and _.set(this.local, 'code',
ossConfig) to be inside the try, and ensure you only attempt to remove
generateZipFilePath when it was created and not remove zipPath if it pointed to
a local codeUri; reference variables downloadedTempDir, generateZipFilePath,
zipPath, calculateCRC64, and uploadCodeToTmpOss when making the changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/utils/index.ts`:
- Around line 322-323: The current fixed temp directory (const tempDir =
path.join(os.tmpdir(), 'fc_code_download')) in _downloadFromUrl risks
collisions; replace it with a unique per-invocation temp directory (e.g., create
via fs.mkdtemp or fs.promises.mkdtemp using os.tmpdir() + 'fc_code_download-')
and use that new directory as the working downloadPath so each call gets its own
folder; ensure cleanup only removes the specific per-call directory (not a
shared parent) and update any logic that assumes a single shared tempDir.

---

Outside diff comments:
In `@src/subCommands/deploy/impl/function.ts`:
- Around line 286-360: The temp download and generated zip cleanup can leak if
an exception occurs; move the deletion of downloadedTempDir and
generateZipFilePath into a finally block so they always run after processing
(wrap the code between obtaining zipPath and the return/oss upload in try { ...
} finally { try { fs.rmSync(generateZipFilePath) } catch{}; try {
fs.rmSync(downloadedTempDir, { recursive: true, force: true }) } catch{} }).
Update the block that calls calculateCRC64, this.fcSdk.uploadCodeToTmpOss, and
_.set(this.local, 'code', ossConfig) to be inside the try, and ensure you only
attempt to remove generateZipFilePath when it was created and not remove zipPath
if it pointed to a local codeUri; reference variables downloadedTempDir,
generateZipFilePath, zipPath, calculateCRC64, and uploadCodeToTmpOss when making
the changes.

In `@src/subCommands/layer/index.ts`:
- Around line 34-100: The temp artifacts (downloadedTempDir and
generateZipFilePath) are only deleted on the normal/skip paths, leaving
leftovers on exceptions; update the function (safe_publish_layer / the block
using zipPath, generateZipFilePath, downloadedTempDir, calculateCRC64,
uploadCodeToTmpOss, createLayerVersion) to wrap the main work in a try block and
move all cleanup logic into a finally block that always attempts to
fs.rmSync(generateZipFilePath) and fs.rmSync(downloadedTempDir, { recursive:
true, force: true }), logging any removal errors with logger.debug; keep
existing conditional checks so you only remove files that were actually created
and preserve existing debug messages in the finally.

In `@src/utils/index.ts`:
- Around line 301-304: The check in checkFcDir currently uses
normalizedPath.startsWith(prefix) which falsely rejects paths that only share a
leading segment (e.g., "/various" vs "/var"); update the logic to only reject
when the normalizedPath equals the forbidden prefix or lies inside it by
checking boundary-aware matches: i.e., treat a forbidden prefix as matched only
if normalizedPath === prefix or normalizedPath.startsWith(prefix + path.sep)
(use the appropriate path.sep/posix separator for your environment) for each
entry in forbiddenPrefixes; update any references to normalizedPath and
forbiddenPrefixes in checkFcDir accordingly.

ℹ️ Review info
Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 72143392-0abe-4488-9c7f-04c710e13482

📥 Commits

Reviewing files that changed from the base of the PR and between 35a061a and c0b858b.

📒 Files selected for processing (5)
  • __tests__/ut/commands/invoke_test.ts
  • __tests__/ut/utils/utils_test.ts
  • src/subCommands/deploy/impl/function.ts
  • src/subCommands/layer/index.ts
  • src/utils/index.ts

logger.debug(
yellow(`skip uploadCode because code is no changed, codeChecksum=${crc64Value}`),
);
if (downloadedTempDir) {
Copy link
Contributor

Choose a reason for hiding this comment

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

为什么是删除那个文件夹, 不是那个 zip 文件

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/subCommands/layer/index.ts (1)

52-97: ⚠️ Potential issue | 🟠 Major

Cleanup is not guaranteed on failures and some early returns.

downloadedTempDir/generated zip cleanup only runs in selected branches. If upload/create throws, temp artifacts are left behind. Also, checksum-skip return does not clean generateZipFilePath.

Suggested refactor (single cleanup point)
   static async safe_publish_layer(...) {
     let zipPath = toZipDir;
     let generateZipFilePath = '';
-    if (!toZipDir.endsWith('.zip')) {
+    try {
+      if (!toZipDir.endsWith('.zip')) {
         ...
-    }
-    const latestLayer = await fcSdk.getLayerLatestVersion(layerName);
-    if (latestLayer) {
+      }
+      const latestLayer = await fcSdk.getLayerLatestVersion(layerName);
+      if (latestLayer) {
         ...
-      if (latestLayer.codeChecksum === crc64Value) {
+        if (latestLayer.codeChecksum === crc64Value) {
           ...
-        if (downloadedTempDir) {
-          ...
-        }
-        return latestLayer;
+          return latestLayer;
+        }
       }
-    }
-    ...
-    const result = await fcSdk.createLayerVersion(...);
-    ...
-    if (generateZipFilePath) { ... }
-    if (downloadedTempDir) { ... }
-    console.log(JSON.stringify(result));
-    return result;
+      ...
+      const result = await fcSdk.createLayerVersion(...);
+      console.log(JSON.stringify(result));
+      return result;
+    } finally {
+      if (generateZipFilePath) {
+        try { fs.rmSync(generateZipFilePath); } catch (ex) { logger.debug(`Unable to remove zip file: ${zipPath}`); }
+      }
+      if (downloadedTempDir) {
+        try { fs.rmSync(downloadedTempDir, { recursive: true, force: true }); } catch (ex) { logger.debug(`Unable to remove temp download dir: ${downloadedTempDir}`); }
+      }
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/subCommands/layer/index.ts` around lines 52 - 97, The code leaves temp
artifacts when errors or early-returns occur (e.g., the checksum-skip branch and
failures in fcSdk.uploadCodeToTmpOss / fcSdk.createLayerVersion); refactor the
flow in src/subCommands/layer/index.ts so all temporary cleanup is done in one
place: wrap the main work (checksum check, getFileSize,
fcSdk.uploadCodeToTmpOss, fcSdk.createLayerVersion) in a try block and perform
removal of generateZipFilePath and downloadedTempDir in a single finally block
(or extract a cleanup function and call it from finally), ensuring the checksum
early-return does not bypass cleanup by returning after the finally (e.g., set
latestLayer/skip flag and return after finally), and keep the existing guarded
fs.rmSync(... { recursive:true, force:true }) calls with try/catch and
logger.debug for any removal errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/utils/index.ts`:
- Line 319: The current logger.info call logs the full download URL
(logger.info(`Downloading code from URL: ${url}`)), which can leak sensitive
query parameters; update the logging to redact query strings by parsing the url
variable with the URL class and logging only the origin + pathname (e.g., new
URL(url).origin + new URL(url).pathname) or otherwise strip/redact url.search
before passing to logger.info so only non-sensitive parts are emitted.

---

Outside diff comments:
In `@src/subCommands/layer/index.ts`:
- Around line 52-97: The code leaves temp artifacts when errors or early-returns
occur (e.g., the checksum-skip branch and failures in fcSdk.uploadCodeToTmpOss /
fcSdk.createLayerVersion); refactor the flow in src/subCommands/layer/index.ts
so all temporary cleanup is done in one place: wrap the main work (checksum
check, getFileSize, fcSdk.uploadCodeToTmpOss, fcSdk.createLayerVersion) in a try
block and perform removal of generateZipFilePath and downloadedTempDir in a
single finally block (or extract a cleanup function and call it from finally),
ensuring the checksum early-return does not bypass cleanup by returning after
the finally (e.g., set latestLayer/skip flag and return after finally), and keep
the existing guarded fs.rmSync(... { recursive:true, force:true }) calls with
try/catch and logger.debug for any removal errors.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f23cd7fb-32fc-47ab-bdae-69d0d1d0d303

📥 Commits

Reviewing files that changed from the base of the PR and between c0b858b and 9063c57.

📒 Files selected for processing (5)
  • __tests__/ut/commands/invoke_test.ts
  • __tests__/ut/utils/utils_test.ts
  • src/subCommands/deploy/impl/function.ts
  • src/subCommands/layer/index.ts
  • src/utils/index.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/ut/utils/utils_test.ts
  • tests/ut/commands/invoke_test.ts
  • src/subCommands/deploy/impl/function.ts

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/utils/index.ts (1)

320-321: ⚠️ Potential issue | 🟠 Major

Use a per-invocation temp directory to avoid collisions.

A fixed fc_code_download folder can race across parallel runs and cross-cleanup each other.

Suggested fix
-  const tempDir = path.join(os.tmpdir(), 'fc_code_download');
+  const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'fc_code_download-'));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/index.ts` around lines 320 - 321, The temp directory is currently a
fixed path (tempDir = path.join(os.tmpdir(), 'fc_code_download')) which can
collide across concurrent runs; change it to create a per-invocation temp dir
(e.g. use fs.mkdtemp or fs.mkdtempSync with a prefix like path.join(os.tmpdir(),
'fc_code_download-')) and assign that result to tempDir/downloadPath so each
invocation gets a unique folder; update any code that references tempDir or
downloadPath accordingly and keep existing cleanup logic to remove the created
temp dir when finished.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/utils/index.ts`:
- Around line 326-333: The download filename sent to downloads() is missing the
extension (parsedPathName uses path.parse(...).name) causing downloadPath to
mismatch the actual file; fix by using the full basename (use
path.parse(...).base or path.basename(urlPath)) when constructing the name
passed to downloads() and ensure downloadPath is built using that same full
filename variable (update parsedPathName/filename usage so downloads(url, {
filename: fullFilename }) and downloadPath = path.join(tempDir, fullFilename)
are consistent).

---

Duplicate comments:
In `@src/utils/index.ts`:
- Around line 320-321: The temp directory is currently a fixed path (tempDir =
path.join(os.tmpdir(), 'fc_code_download')) which can collide across concurrent
runs; change it to create a per-invocation temp dir (e.g. use fs.mkdtemp or
fs.mkdtempSync with a prefix like path.join(os.tmpdir(), 'fc_code_download-'))
and assign that result to tempDir/downloadPath so each invocation gets a unique
folder; update any code that references tempDir or downloadPath accordingly and
keep existing cleanup logic to remove the created temp dir when finished.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0a7d0287-b6d2-4a4f-a504-86adb154e7a8

📥 Commits

Reviewing files that changed from the base of the PR and between 9063c57 and 7bfc4a0.

📒 Files selected for processing (5)
  • __tests__/ut/commands/invoke_test.ts
  • __tests__/ut/utils/utils_test.ts
  • src/subCommands/deploy/impl/function.ts
  • src/subCommands/layer/index.ts
  • src/utils/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/ut/utils/utils_test.ts

Comment on lines +326 to +333
const parsedPathName = path.parse(urlPath).name;
const filename = path.basename(urlPath) || `downloaded_code_${Date.now()}`;
downloadPath = path.join(tempDir, filename);

await downloads(url, {
dest: tempDir,
filename: parsedPathName,
extract: false,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

git ls-files | head -20

Repository: devsapp/fc3

Length of output: 468


🏁 Script executed:

fd -t f "index.ts" | grep -E "(utils|layer|deploy)" | head -20

Repository: devsapp/fc3

Length of output: 211


🏁 Script executed:

cat -n src/utils/index.ts | sed -n '320,340p'

Repository: devsapp/fc3

Length of output: 786


🏁 Script executed:

cat -n src/utils/index.ts | sed -n '300,350p'

Repository: devsapp/fc3

Length of output: 1906


🏁 Script executed:

cat -n src/subCommands/layer/index.ts | sed -n '240,255p'

Repository: devsapp/fc3

Length of output: 653


🏁 Script executed:

cat -n src/subCommands/deploy/impl/function.ts | sed -n '283,297p'

Repository: devsapp/fc3

Length of output: 647


🏁 Script executed:

cat package.json | grep -A 5 -B 5 "downloads"

Repository: devsapp/fc3

Length of output: 562


🏁 Script executed:

rg "from.*downloads|require.*downloads" -A 2 -B 2

Repository: devsapp/fc3

Length of output: 2179


🏁 Script executed:

rg "downloadPath" src/utils/index.ts -B 3 -A 3

Repository: devsapp/fc3

Length of output: 724


🏁 Script executed:

#!/bin/bash

# Check the main file structure around the lines mentioned
echo "=== src/utils/index.ts lines 320-350 ==="
head -350 src/utils/index.ts | tail -35 | cat -n

echo ""
echo "=== Package.json to find downloads version ==="
grep -A 10 '"dependencies"' package.json | grep downloads

echo ""
echo "=== Check layer/index.ts around line 247 ==="
sed -n '240,255p' src/subCommands/layer/index.ts | cat -n

echo ""
echo "=== Check function.ts around line 290 ==="
sed -n '283,300p' src/subCommands/deploy/impl/function.ts | cat -n

Repository: devsapp/fc3

Length of output: 2878


🌐 Web query:

@serverless-devs/downloads v0.0.7 filename option behavior documentation

💡 Result:

In @serverless-devs/downloads v0.0.7, the options.filename parameter controls the name of the file written to disk (“文件保存的名称” / file save name). It’s optional, and defaults to demo.zip. If you don’t set it, the downloaded content will be saved using that default name (in the directory indicated by options.dest, if provided). [1]

Source(s):

  • [1] Socket.dev package README for @serverless-devs/downloads (v0.0.7): options table (filename, default demo.zip).

Use the filename option with the full filename including extension.

Line 326 strips the extension from the filename (path.parse(...).name), but Line 332 passes this stripped name to the downloads() function. This creates a mismatch: downloadPath (Line 328) is calculated with the full filename including extension, but the actual downloaded file is saved without the extension. The function then returns a path that doesn't match the actual file location. This causes downstream issues in src/subCommands/layer/index.ts (line 247) and src/subCommands/deploy/impl/function.ts (line 290) when processing the returned path.

Suggested fix
-    const parsedPathName = path.parse(urlPath).name;
-    const filename = path.basename(urlPath) || `downloaded_code_${Date.now()}`;
+    const filename = path.basename(urlPath) || `downloaded_code_${Date.now()}.zip`;
     downloadPath = path.join(tempDir, filename);

     await downloads(url, {
       dest: tempDir,
-      filename: parsedPathName,
+      filename,
       extract: false,
     });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const parsedPathName = path.parse(urlPath).name;
const filename = path.basename(urlPath) || `downloaded_code_${Date.now()}`;
downloadPath = path.join(tempDir, filename);
await downloads(url, {
dest: tempDir,
filename: parsedPathName,
extract: false,
const filename = path.basename(urlPath) || `downloaded_code_${Date.now()}.zip`;
downloadPath = path.join(tempDir, filename);
await downloads(url, {
dest: tempDir,
filename,
extract: false,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/index.ts` around lines 326 - 333, The download filename sent to
downloads() is missing the extension (parsedPathName uses path.parse(...).name)
causing downloadPath to mismatch the actual file; fix by using the full basename
(use path.parse(...).base or path.basename(urlPath)) when constructing the name
passed to downloads() and ensure downloadPath is built using that same full
filename variable (update parsedPathName/filename usage so downloads(url, {
filename: fullFilename }) and downloadPath = path.join(tempDir, fullFilename)
are consistent).

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.

2 participants