Files
penguin-harness/packages/core/test/validate-id.test.ts
T
Yaowei Zheng 45bfae6e94 Initialize repository with harness code and assets
Initial import of all source code, config, and README assets: the
packages workspace (cli, core, server, web, docs, landing, skills),
build scripts, tooling config, and CI workflows.

Includes the data-layout revision made on this branch: the local data
root defaults to ~/.penguin/data (PENGUIN_HOME still overrides; the
installer keeps its binaries in ~/.penguin), and every Agent lives
under <project>/agents/<agent>/ — path helpers, the three
agent-enumeration scans, the system prompt, built-in Skills, tests
and docs all follow the new layout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ihk8iQuo3kv2aPjAYEPuR
2026-07-19 14:06:53 +08:00

85 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { assertValidId, isValidId, loadOrInitAgentState } from "../src/state/index.js";
describe("isValidId / assertValidId", () => {
const valid = ["default_project", "default_agent", "my-agent", "agent-1", "ABC_123"];
// Only alphanumerics, `_`, and `-` are allowed; dots, spaces/tabs, path separators, and any
// other character are all rejected.
const invalid = [
"",
" ",
"a b",
"a\tb",
" lead",
"trail ",
"a/b",
"a\\b",
".",
"..",
"...",
"a.b",
"v1.0",
".hidden",
"中文ok",
"emoji😀",
];
it.each(valid)("接受合法单段目录名:%j", (id) => {
expect(isValidId(id)).toBe(true);
expect(() => assertValidId("project_id", id)).not.toThrow();
expect(() => assertValidId("agent_id", id)).not.toThrow();
});
it.each(invalid)("拒绝非法 id:%j", (id) => {
expect(isValidId(id)).toBe(false);
expect(() => assertValidId("agent_id", id)).toThrow();
});
it("错误信息点明 kind 与非法 id", () => {
expect(() => assertValidId("agent_id", "a/b")).toThrow(/agent_id/);
expect(() => assertValidId("agent_id", "a/b")).toThrow(/a\/b/);
expect(() => assertValidId("project_id", "..")).toThrow(/project_id/);
});
});
describe("loadOrInitAgentState id 校验", () => {
let tmpRoot: string;
let prevHome: string | undefined;
beforeEach(async () => {
prevHome = process.env.PENGUIN_HOME;
tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), "penguin-validate-id-"));
process.env.PENGUIN_HOME = tmpRoot;
});
afterEach(async () => {
if (prevHome === undefined) {
delete process.env.PENGUIN_HOME;
} else {
process.env.PENGUIN_HOME = prevHome;
}
await fs.rm(tmpRoot, { recursive: true, force: true });
});
it("agentId 含路径分隔符时抛错", async () => {
await expect(loadOrInitAgentState({ agentId: "a/b" })).rejects.toThrow(/agent_id/);
});
it("projectId 为 .. 时抛错", async () => {
await expect(loadOrInitAgentState({ projectId: ".." })).rejects.toThrow(/project_id/);
});
it("agentId 为 Windows 结尾空格变体 '.. ' 时抛错(防路径穿越绕过)", async () => {
await expect(loadOrInitAgentState({ agentId: ".. " })).rejects.toThrow(/agent_id/);
});
it("默认 id 合法,可正常初始化", async () => {
const state = await loadOrInitAgentState();
expect(state.projectId).toBe("default_project");
expect(state.agentId).toBe("default_agent");
});
});