Skip to content

fix: resolve package root by directory depth in clone command#309

Open
cs-raj wants to merge 1 commit into
v2-devfrom
fix/DX-8736
Open

fix: resolve package root by directory depth in clone command#309
cs-raj wants to merge 1 commit into
v2-devfrom
fix/DX-8736

Conversation

@cs-raj

@cs-raj cs-raj commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

The cm:stacks:clone command computed its content directory path by substring-splitting __dirname on /src/ or /lib/:

const packageRoot = __dirname.includes('/src/') ? __dirname.split('/src/')[0] : __dirname.split('/lib/')[0];

In a real installed environment this is unreliable, because the install path itself can contain /lib/ more than once (for example, Node's own lib/node_modules directory, in addition to this package's own compiled lib/ output). .split('/lib/')[0] matches the first occurrence, so it resolved to an unrelated ancestor directory instead of the package's actual root.

Every cleanup path in the command — the pre-clone check that clears leftover data, the post-import cleanup on success, and the interrupt-handler cleanup — used this incorrectly-resolved path. All three were faithfully deleting a directory that was essentially always empty, while the real export/import data (resolved correctly and independently in clone-handler.ts via path.resolve) was never targeted by any cleanup call.

Net effect: content from a completed clone run stayed on disk indefinitely and bled into the next clone of a different stack, causing content-type/entry resolution failures during export.

Fix

Resolve packageRoot by fixed relative directory depth instead of string matching, mirroring the approach clone-handler.ts already uses:

const packageRoot = path.resolve(__dirname, '../../../..');

commands/cm/stacks is always exactly 3 directories below the package's src/lib root, so this reliably lands on the package root regardless of how the surrounding path is structured — it doesn't depend on any substring content of the install path at all.

Verification

  • Confirmed the mismatch directly from a real debug-logged run: the Content directory path line (cleanup target) and the Export directory line (actual data path) diverged before the fix, and a subsequent clone into a different stack printed "The export directory is not empty. Existing files in this folder may be overwritten."
  • Patched the fix into a real production install and re-ran the same two-stack clone repro: the two paths now match, and the warning no longer appears.
  • Verified packageRoot resolution against nested (.../node_modules/@scope/cli/node_modules/@scope/pkg/...), flat/hoisted, and pnpm .pnpm virtual-store install layouts — all resolve correctly.
  • Confirmed the delete operation's blast radius: only two rimraf calls exist in the package, both scoped to a single fixed contents subfolder under packageRoot, and pathDir cannot be overridden by a user-supplied external config (it's set after the config merge, unconditionally).
  • tsc --noEmit and tsc -b both pass cleanly.

Test plan

  • Clone a stack successfully, confirm the package's contents/ directory is removed afterward
  • Clone a second, different stack immediately after, confirm no "export directory is not empty" warning and no cross-contamination between the two stacks' content types/entries
  • Interrupt a clone mid-run (Ctrl+C), confirm the interrupt-handler cleanup still clears the correct directory

The clone command computed its content directory path by substring-
splitting __dirname on '/src/' or '/lib/'. In a published/installed
layout this breaks because the install path itself can contain
'/lib/' (e.g. Node's own lib/node_modules), so the split matched the
wrong occurrence and resolved to an ancestor directory instead of the
package root.

As a result, the pre-clone check, the post-import cleanup, and the
interrupt-handler cleanup were all deleting an unrelated, effectively
empty directory, while the actual export/import data (written to the
correct path via clone-handler.ts's own resolution) was never cleaned
up. Content from a previous clone run persisted on disk and bled into
subsequent clones of a different stack.

Resolve packageRoot by fixed relative directory depth instead,
matching the approach already used in clone-handler.ts. This is
independent of the surrounding install path and has been verified
against nested, flat/hoisted, and pnpm virtual-store install layouts.
@cs-raj
cs-raj requested a review from a team as a code owner July 24, 2026 08:22
@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 1 500 ✅ Passed
🔵 Low Severity 0 0 1000 ✅ Passed

⏱️ SLA Breach Summary

⚠️ Warning: The following vulnerabilities have exceeded their SLA thresholds (days since publication).

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 1 90 / 365 days ⚠️ Warning
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ Vulnerabilities Without Available Fixes (Informational Only)

The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:

  • Critical without fixes: 0
  • High without fixes: 0
  • Medium without fixes: 1
  • Low without fixes: 0

⚠️ BUILD PASSED WITH WARNINGS - SLA breaches detected for issues without available fixes

Consider reviewing these vulnerabilities when fixes become available.

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