Skip to content

fix(bootstrap): reject on non-2xx tarball response and handle zlib errors - #356

Open
cs-raj wants to merge 2 commits into
developmentfrom
fix/DX-10257
Open

fix(bootstrap): reject on non-2xx tarball response and handle zlib errors#356
cs-raj wants to merge 2 commits into
developmentfrom
fix/DX-10257

Conversation

@cs-raj

@cs-raj cs-raj commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Problem

csdx cm:bootstrap crashed with an unhandled Z_DATA_ERROR (incorrect header check) when cloning the Kickstart Next.js starter app. Two bugs combined to cause this:

  1. streamRelease() did not check the HTTP response status. When the cli-use branch was absent from contentstack/kickstart-next, codeload.github.com returned a 404: Not Found body. That body stream was silently passed downstream as if it were a valid tarball.

  2. extract() had no error handler on the zlib.createUnzip() stream. Node's pipe() does not forward stream errors between stages. When zlib tried to decompress the "404: Not Found" bytes (which have no gzip magic header), it emitted an error event on the Unzip instance with no listener — causing an unhandled exception that crashed the process instead of rejecting the Promise cleanly.

Relates to: DX-10257

Fix

  • streamRelease() — throws GithubError with the actual HTTP status code for any 4xx/5xx response. The existing Bootstrap.run() catch block already handles GithubError with status === 404 and prints a user-friendly "Unable to find a repo" message; no caller changes needed.

  • extract() — extracts the zlib.createUnzip() instance and attaches .on('error', reject) directly to it, so zlib errors reject the Promise rather than escaping as unhandled events.

Test plan

  • 6 new unit tests added to packages/contentstack-bootstrap/test/github.test.js
    • streamRelease throws GithubError(404) on a 404 response
    • streamRelease throws GithubError(500) on a 500 response
    • streamRelease returns the data stream on a 200 response
    • streamRelease sends Authorization header for private repos
    • streamRelease throws immediately for private repos with no token
    • extract rejects with Z_DATA_ERROR (not a process crash) on invalid gzip data
  • All 71 existing tests continue to pass
  • csdx cm:bootstrap → Kickstart Next.js ran end-to-end successfully after the missing cli-use branch was created on the repo

🤖 Generated with Claude Code

…rors

streamRelease now throws GithubError for HTTP 4xx/5xx responses instead
of silently piping the error body (e.g. "404: Not Found") into the zlib
decompressor. This was the root cause of the Z_DATA_ERROR crash when the
cli-use branch was absent from a repo.

extract now attaches an error handler directly on the zlib.createUnzip()
stream. Node's pipe() does not forward stream errors, so without this
listener a zlib failure emitted an unhandled error event and crashed the
process rather than rejecting the Promise cleanly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@cs-raj
cs-raj requested a review from a team as a code owner August 20, 2026 11:31
@snyk-io

snyk-io Bot commented Aug 20, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 0 0 25 ✅ Passed
🟡 Medium Severity 0 0 500 ✅ Passed
🔵 Low Severity 0 0 1000 ✅ Passed

⏱️ SLA Breach Summary

✅ No SLA breaches detected. All vulnerabilities are within acceptable time thresholds.

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 0 90 / 365 days ✅ Passed
🔵 Low 0 0 180 / 365 days ✅ Passed

✅ BUILD PASSED - All security checks passed

Moving cliux.loader() (spinner stop) out of finally and into catch before
cliux.error() prevents the spinner's carriage-return from wiping the error
line. Success path stops the spinner inline after getLatest resolves.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 0 0 25 ✅ Passed
🟡 Medium Severity 0 0 500 ✅ Passed
🔵 Low Severity 0 0 1000 ✅ Passed

⏱️ SLA Breach Summary

✅ No SLA breaches detected. All vulnerabilities are within acceptable time thresholds.

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 0 90 / 365 days ✅ Passed
🔵 Low 0 0 180 / 365 days ✅ Passed

✅ BUILD PASSED - All security checks passed

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.

1 participant