mirror of https://github.com/openclaw/openclaw.git
fix: tighten skill slug validation to ASCII-only
This commit is contained in:
parent
2be3c996fb
commit
40071ea23e
|
|
@ -95,6 +95,64 @@ describe("skills-clawhub", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("normalizeSlug rejects non-ASCII homograph slugs", () => {
|
||||
it("rejects Cyrillic homograph 'а' (U+0430) in slug", async () => {
|
||||
const result = await installSkillFromClawHub({
|
||||
workspaceDir: "/tmp/workspace",
|
||||
slug: "re\u0430ct",
|
||||
});
|
||||
expect(result).toMatchObject({ ok: false, error: expect.stringContaining("Invalid skill slug") });
|
||||
});
|
||||
|
||||
it("rejects Cyrillic homograph 'е' (U+0435) in slug", async () => {
|
||||
const result = await installSkillFromClawHub({
|
||||
workspaceDir: "/tmp/workspace",
|
||||
slug: "r\u0435act",
|
||||
});
|
||||
expect(result).toMatchObject({ ok: false, error: expect.stringContaining("Invalid skill slug") });
|
||||
});
|
||||
|
||||
it("rejects Cyrillic homograph 'о' (U+043E) in slug", async () => {
|
||||
const result = await installSkillFromClawHub({
|
||||
workspaceDir: "/tmp/workspace",
|
||||
slug: "t\u043Edo",
|
||||
});
|
||||
expect(result).toMatchObject({ ok: false, error: expect.stringContaining("Invalid skill slug") });
|
||||
});
|
||||
|
||||
it("rejects slug with mixed Unicode and ASCII", async () => {
|
||||
const result = await installSkillFromClawHub({
|
||||
workspaceDir: "/tmp/workspace",
|
||||
slug: "cаlеndаr",
|
||||
});
|
||||
expect(result).toMatchObject({ ok: false, error: expect.stringContaining("Invalid skill slug") });
|
||||
});
|
||||
|
||||
it("rejects slug with non-Latin scripts", async () => {
|
||||
const result = await installSkillFromClawHub({
|
||||
workspaceDir: "/tmp/workspace",
|
||||
slug: "技能",
|
||||
});
|
||||
expect(result).toMatchObject({ ok: false, error: expect.stringContaining("Invalid skill slug") });
|
||||
});
|
||||
|
||||
it("rejects slug starting with a hyphen", async () => {
|
||||
const result = await installSkillFromClawHub({
|
||||
workspaceDir: "/tmp/workspace",
|
||||
slug: "-calendar",
|
||||
});
|
||||
expect(result).toMatchObject({ ok: false, error: expect.stringContaining("Invalid skill slug") });
|
||||
});
|
||||
|
||||
it("accepts valid ASCII slugs", async () => {
|
||||
const result = await installSkillFromClawHub({
|
||||
workspaceDir: "/tmp/workspace",
|
||||
slug: "calendar-2",
|
||||
});
|
||||
expect(result).toMatchObject({ ok: true });
|
||||
});
|
||||
});
|
||||
|
||||
it("uses search for browse-all skill discovery", async () => {
|
||||
searchClawHubSkillsMock.mockResolvedValueOnce([
|
||||
{
|
||||
|
|
|
|||
|
|
@ -62,12 +62,14 @@ type Logger = {
|
|||
info?: (message: string) => void;
|
||||
};
|
||||
|
||||
const VALID_SLUG_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
||||
|
||||
function normalizeSlug(raw: string): string {
|
||||
const trimmed = raw.trim();
|
||||
if (!trimmed || trimmed.includes("/") || trimmed.includes("\\") || trimmed.includes("..")) {
|
||||
const slug = raw.trim().toLowerCase();
|
||||
if (!slug || !VALID_SLUG_PATTERN.test(slug)) {
|
||||
throw new Error(`Invalid skill slug: ${raw}`);
|
||||
}
|
||||
return trimmed;
|
||||
return slug;
|
||||
}
|
||||
|
||||
function resolveSkillInstallDir(workspaceDir: string, slug: string): string {
|
||||
|
|
|
|||
Loading…
Reference in New Issue