|
| 1 | +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; |
| 2 | +import { tmpdir } from "node:os"; |
| 3 | +import { join } from "node:path"; |
| 4 | +import { afterEach, describe, expect, test } from "vite-plus/test"; |
| 5 | +import { e2eFixturesDir, runCommandE2e } from "./helpers.ts"; |
| 6 | +import { MANAGED_AGENT_ROUTES } from "./topic-routes.ts"; |
| 7 | + |
| 8 | +/** |
| 9 | + * managed-agent 凭证链 e2e:验证 bl 自有配置体系(config 写入 / 命名 Profile / |
| 10 | + * logout)与错误映射如何流入 SDK 引擎。全部离线:`managed-agent validate` 会走 |
| 11 | + * authStage 凭证解析 + 引擎注入 + agents.yaml 校验,但不发任何网络请求。 |
| 12 | + * 配置一律通过 BAILIAN_CONFIG_DIR 指向临时目录,绝不触碰真实用户配置。 |
| 13 | + */ |
| 14 | + |
| 15 | +const ROUTES = { |
| 16 | + ...MANAGED_AGENT_ROUTES, |
| 17 | + "auth logout": "authLogout", |
| 18 | +}; |
| 19 | + |
| 20 | +const AGENTS_YAML = join(e2eFixturesDir, "managed-agent", "agents.yaml"); |
| 21 | +const AGENTS_YAML_INVALID = join(e2eFixturesDir, "managed-agent", "agents-invalid.yaml"); |
| 22 | + |
| 23 | +const tempDirs: string[] = []; |
| 24 | + |
| 25 | +afterEach(() => { |
| 26 | + for (const dir of tempDirs.splice(0)) rmSync(dir, { recursive: true, force: true }); |
| 27 | +}); |
| 28 | + |
| 29 | +/** 新建隔离配置目录并写入 config.json;返回子进程 env 覆盖(清空外部凭证 env)。 */ |
| 30 | +function makeConfigEnv(config: Record<string, unknown>): NodeJS.ProcessEnv { |
| 31 | + const configDir = mkdtempSync(join(tmpdir(), "bl-managed-agent-auth-")); |
| 32 | + tempDirs.push(configDir); |
| 33 | + writeFileSync(join(configDir, "config.json"), `${JSON.stringify(config, null, 2)}\n`); |
| 34 | + return { |
| 35 | + BAILIAN_CONFIG_DIR: configDir, |
| 36 | + DASHSCOPE_API_KEY: "", |
| 37 | + DASHSCOPE_BASE_URL: "", |
| 38 | + BAILIAN_BASE_URL: "", |
| 39 | + BAILIAN_WORKSPACE_ID: "", |
| 40 | + }; |
| 41 | +} |
| 42 | + |
| 43 | +function validateArgs(file: string): string[] { |
| 44 | + return ["managed-agent", "validate", "--file", file, "--quiet"]; |
| 45 | +} |
| 46 | + |
| 47 | +describe("e2e: managed-agent 凭证链(config 写入 / Profile / logout / 错误映射)", () => { |
| 48 | + test("config.json 写入的 api_key 流入引擎,validate 离线通过", async () => { |
| 49 | + const env = makeConfigEnv({ api_key: "sk-e2e-config-write" }); |
| 50 | + const { stderr, exitCode } = await runCommandE2e(ROUTES, validateArgs(AGENTS_YAML), env); |
| 51 | + expect(exitCode, stderr).toBe(0); |
| 52 | + }); |
| 53 | + |
| 54 | + test("active_config 指向的命名 Profile 提供凭证时通过", async () => { |
| 55 | + const env = makeConfigEnv({ |
| 56 | + work: { api_key: "sk-e2e-profile-work" }, |
| 57 | + active_config: "work", |
| 58 | + }); |
| 59 | + const { stderr, exitCode } = await runCommandE2e(ROUTES, validateArgs(AGENTS_YAML), env); |
| 60 | + expect(exitCode, stderr).toBe(0); |
| 61 | + }); |
| 62 | + |
| 63 | + test("active_config 切到无凭证 Profile 时报统一 AUTH 错误 (3)", async () => { |
| 64 | + const env = makeConfigEnv({ |
| 65 | + work: { api_key: "sk-e2e-profile-work" }, |
| 66 | + empty: {}, |
| 67 | + active_config: "empty", |
| 68 | + }); |
| 69 | + const { stderr, exitCode } = await runCommandE2e(ROUTES, validateArgs(AGENTS_YAML), env); |
| 70 | + expect(exitCode).toBe(3); |
| 71 | + expect(stderr).toMatch(/auth login|API key/i); |
| 72 | + }); |
| 73 | + |
| 74 | + test("auth logout 清除凭证后 validate 报 AUTH,而非用残留凭证", async () => { |
| 75 | + const env = makeConfigEnv({ api_key: "sk-e2e-before-logout" }); |
| 76 | + |
| 77 | + const before = await runCommandE2e(ROUTES, validateArgs(AGENTS_YAML), env); |
| 78 | + expect(before.exitCode, before.stderr).toBe(0); |
| 79 | + |
| 80 | + const logout = await runCommandE2e(ROUTES, ["auth", "logout"], env); |
| 81 | + expect(logout.exitCode, logout.stderr).toBe(0); |
| 82 | + |
| 83 | + const after = await runCommandE2e(ROUTES, validateArgs(AGENTS_YAML), env); |
| 84 | + expect(after.exitCode).toBe(3); |
| 85 | + expect(after.stderr).toMatch(/auth login|API key/i); |
| 86 | + }); |
| 87 | + |
| 88 | + test("agents.yaml schema 错误映射为 USAGE (2),不透传原始 zod dump", async () => { |
| 89 | + const env = makeConfigEnv({ api_key: "sk-e2e-config-write" }); |
| 90 | + const { stderr, exitCode } = await runCommandE2e( |
| 91 | + ROUTES, |
| 92 | + validateArgs(AGENTS_YAML_INVALID), |
| 93 | + env, |
| 94 | + ); |
| 95 | + expect(exitCode).toBe(2); |
| 96 | + expect(stderr).toMatch(/agents/i); |
| 97 | + expect(stderr).not.toMatch(/"code":\s*"invalid_type"/); |
| 98 | + }); |
| 99 | +}); |
0 commit comments