Skip to content

Commit 658763a

Browse files
committed
fix: ci test
1 parent da2ddb7 commit 658763a

5 files changed

Lines changed: 53 additions & 2 deletions

File tree

packages/commands/src/commands/update.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
ansi,
1515
fetchLatestVersion,
1616
fetchBinaryChannelVersion,
17+
isValidUpdateTargetVersion,
1718
normalizeBinaryVersion,
1819
performBinaryUpdate,
1920
type AnsiStyles,
@@ -73,8 +74,10 @@ export default defineCommand({
7374
},
7475
exampleArgs: ["", "--to 0.1.14"],
7576
validate(flags) {
76-
if (flags.to !== undefined && !flags.to.trim()) {
77-
return "--to requires a non-empty version";
77+
if (flags.to === undefined) return undefined;
78+
if (!flags.to.trim()) return "--to requires a non-empty version";
79+
if (!isValidUpdateTargetVersion(flags.to)) {
80+
return `--to must be a semver version (e.g. 1.13.0, v1.13.0, 0.0.0-beta-<sha>-<YYYYMMDDHHMM>), got: ${flags.to.trim()}`;
7881
}
7982
return undefined;
8083
},

packages/commands/tests/e2e/update.e2e.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,14 @@ describe("e2e: update", () => {
2020
const { stderr, exitCode } = await runCommandE2e(UPDATE_ROUTES, ["update", "--to"]);
2121
expect(exitCode, stderr).toBe(2);
2222
});
23+
24+
test("update --to 非法版本时退出为用法错误 (2)", async () => {
25+
const { stderr, exitCode } = await runCommandE2e(UPDATE_ROUTES, [
26+
"update",
27+
"--to",
28+
"not-a-version",
29+
]);
30+
expect(exitCode, stderr).toBe(2);
31+
expect(stderr).toMatch(/semver|--to/i);
32+
});
2333
});

packages/runtime/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export {
7575
getBinaryCurrentPath,
7676
getBinaryShareRoot,
7777
getBinaryVersionsDir,
78+
isValidUpdateTargetVersion,
7879
normalizeBinaryVersion,
7980
performBinaryUpdate,
8081
pruneBinaryVersions,

packages/runtime/src/utils/binary-update.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,21 @@ export function normalizeBinaryVersion(raw: string): string {
9494
return trimmed;
9595
}
9696

97+
/**
98+
* Semver core + optional pre-release / build metadata.
99+
* Accepts this repo's channel betas (`0.0.0-beta-<sha7>-<YYYYMMDDHHMM>`) and
100+
* ordinary releases (`1.13.0`, `1.4.2-beta.1`). Optional leading `v` is allowed.
101+
*/
102+
const UPDATE_TARGET_VERSION_RE =
103+
/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
104+
105+
/** True if `raw` is a usable `--to` target after trim (optional `v` prefix). */
106+
export function isValidUpdateTargetVersion(raw: string): boolean {
107+
const trimmed = raw.trim();
108+
if (!trimmed) return false;
109+
return UPDATE_TARGET_VERSION_RE.test(trimmed);
110+
}
111+
97112
async function fetchSha256FromVersionSums(
98113
version: string,
99114
fileName: string,

packages/runtime/tests/binary-update-layout.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
getBinaryCurrentPath,
1010
getBinaryShareRoot,
1111
getBinaryVersionsDir,
12+
isValidUpdateTargetVersion,
1213
normalizeBinaryVersion,
1314
pruneBinaryVersions,
1415
readCurrentVersionDir,
@@ -83,6 +84,27 @@ test("normalizeBinaryVersion strips release-style v prefix", () => {
8384
expect(normalizeBinaryVersion(" 0.1.14-channel.1 ")).toBe("0.1.14-channel.1");
8485
});
8586

87+
test("isValidUpdateTargetVersion accepts semver and channel betas", () => {
88+
expect(isValidUpdateTargetVersion("1.13.0")).toBe(true);
89+
expect(isValidUpdateTargetVersion("v1.13.0")).toBe(true);
90+
expect(isValidUpdateTargetVersion("1.4.2-beta.1")).toBe(true);
91+
expect(isValidUpdateTargetVersion("0.0.0-beta-be3033b-202607311142")).toBe(true);
92+
expect(isValidUpdateTargetVersion("v0.0.0-beta-be3033b-202607311142")).toBe(true);
93+
expect(isValidUpdateTargetVersion("latest")).toBe(false);
94+
expect(isValidUpdateTargetVersion("1.2")).toBe(false);
95+
expect(isValidUpdateTargetVersion("foo")).toBe(false);
96+
expect(isValidUpdateTargetVersion("")).toBe(false);
97+
// Path-traversal / path-separator inputs must never reach versions/<ver>/
98+
expect(isValidUpdateTargetVersion("../../../..")).toBe(false);
99+
expect(isValidUpdateTargetVersion("..\\..\\..")).toBe(false);
100+
expect(isValidUpdateTargetVersion("1.2.3/../x")).toBe(false);
101+
expect(isValidUpdateTargetVersion("1.2.3\\..\\x")).toBe(false);
102+
expect(isValidUpdateTargetVersion("/etc/passwd")).toBe(false);
103+
expect(isValidUpdateTargetVersion("versions/../../tmp")).toBe(false);
104+
expect(isValidUpdateTargetVersion("1.2.3/")).toBe(false);
105+
expect(isValidUpdateTargetVersion("..")).toBe(false);
106+
});
107+
86108
test("resolveBinaryDownloadSpec targets version assets, not latest manifest url", async () => {
87109
const version = "0.1.14-channel.1";
88110
const { detectBinaryPlatform } = await import("bailian-cli-core");

0 commit comments

Comments
 (0)