Skip to content

Commit e5e3e9e

Browse files
authored
fix(cli): reject empty-name target in wheels packages install (#2290)
`$parseTarget` called `Left(target, Find("@", target) - 1)` without guarding against targets starting with `@` (e.g., `wheels packages install @1.0.0`). That evaluates to `Left(str, 0)`, which crashes on Lucee 7 per the documented gotcha in CLAUDE.md and produces a cryptic empty-name install attempt on other engines. Throw `Wheels.Packages.BadInput` explicitly when the name segment is empty, with a message that points at the correct syntax. Preserves the existing valid-input paths (no `@`, or `name@version`). Adds a regression spec in PackagesMainCliSpec.
1 parent 54849c8 commit e5e3e9e

2 files changed

Lines changed: 28 additions & 2 deletions

File tree

‎cli/lucli/services/packages/PackagesMainCli.cfc‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,16 @@ component {
252252
}
253253

254254
private struct function $parseTarget(required string target) {
255-
if (Find("@", arguments.target)) {
256-
local.at = Find("@", arguments.target);
255+
local.at = Find("@", arguments.target);
256+
if (local.at == 1) {
257+
// Target starts with "@" — no name before the pin. Reject cleanly
258+
// rather than crashing on Left(str, 0) (a documented Lucee 7 hazard).
259+
Throw(
260+
type = "Wheels.Packages.BadInput",
261+
message = "Package name is required before '@'. Use: wheels packages install <name>[@<version>]"
262+
);
263+
}
264+
if (local.at > 1) {
257265
return {
258266
name: Left(arguments.target, local.at - 1),
259267
pin: Mid(arguments.target, local.at + 1, Len(arguments.target))

‎cli/lucli/tests/specs/packages/PackagesMainCliSpec.cfc‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,24 @@ component extends="wheels.wheelstest.system.BaseSpec" {
190190
stack.cache.refresh();
191191
DirectoryDelete(proj, true);
192192
});
193+
194+
it("install throws BadInput when target starts with '@' (empty name)", () => {
195+
// Regression guard: `@1.0.0` used to hit Left(str, 0), which
196+
// crashes on Lucee 7 and produces a cryptic error on other
197+
// engines. Must reject cleanly with BadInput.
198+
var proj = $scratch();
199+
var stack = $buildStack(proj);
200+
var threw = false;
201+
try {
202+
stack.cli.install({target: "@1.0.0"});
203+
} catch (any e) {
204+
threw = true;
205+
expect(e.type).toBe("Wheels.Packages.BadInput");
206+
}
207+
expect(threw).toBeTrue();
208+
stack.cache.refresh();
209+
DirectoryDelete(proj, true);
210+
});
193211
});
194212

195213
describe("PackagesRegistryCli", () => {

0 commit comments

Comments
 (0)