Skip to content

Commit a03ba67

Browse files
committed
fix(auth): clear model base URL on full logout
1 parent 4b504a1 commit a03ba67

9 files changed

Lines changed: 64 additions & 19 deletions

File tree

docs/agents/auth-change.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ defineCommand({ auth }) → runtime/authStage → ctx.client → command.run(ctx
3838
- `bl auth login --open-api ...` 只更新 `access_key_id` / `access_key_secret`
3939
- `bl auth logout --console` 只清 `access_token`
4040
- `bl auth logout --open-api` 只清 `access_key_id` / `access_key_secret` / `security_token`
41-
- `bl auth logout``api_key` + `access_token` + `access_key_*`
41+
- `bl auth logout``api_key` + `base_url` + `access_token` + `access_key_*`
4242

4343
解析分工:
4444

docs/agents/cli-e2e-tests.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ describe.skipIf(<ready>)("e2e: <topic>(DashScope …)", () => {
8585

8686
## 安全与例外
8787

88-
- **禁止真实破坏性操作**`auth logout` 只用 `--dry-run``config set` 只用 `--dry-run`
88+
- **禁止破坏真实用户配置**`auth logout` 默认只用 `--dry-run`;需要验证实际落盘时,必须通过
89+
`BAILIAN_CONFIG_DIR` 指向隔离 fixture;`config set` 只用 `--dry-run`
8990
- **不加 dry-run**`dryRun``resolveFileUrl` / `resolveCredential` / 上传**之后**的命令(如 `image edit``speech recognize``--url`
9091
- **`--list-voices` 等旁路**:先于 `--text` 校验的 flag,缺参用例勿带该 flag
9192
- 新增 required option → 至少一条缺参用例;改 dry-run 输出 → 更新对应断言

packages/commands/src/commands/auth/logout.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { defineCommand } from "bailian-cli-core";
22
import { emitBare } from "bailian-cli-runtime";
33

44
export default defineCommand({
5-
description: "Clear stored credentials",
5+
description: "Clear stored credentials; full logout also clears the model Base URL",
66
auth: "none",
77
usageArgs: "[--console | --open-api] [--dry-run]",
88
flags: {
@@ -68,24 +68,24 @@ export default defineCommand({
6868
return;
6969
}
7070

71-
const hasKey = stored.apiKey || stored.console || stored.openapi;
71+
const hasStoredAuth = stored.apiKey || stored.console || stored.openapi || !!stored.baseUrl;
7272

7373
if (settings.dryRun) {
74-
if (hasKey)
74+
if (hasStoredAuth)
7575
emitBare(
76-
`Would clear api_key / access_token / access_key_id / access_key_secret / security_token from ${store.path}`,
76+
`Would clear api_key / base_url / access_token / access_key_id / access_key_secret / security_token from ${store.path}`,
7777
);
78-
else emitBare("No credentials to clear.");
78+
else emitBare("No credentials or model Base URL to clear.");
7979
emitBare("No changes made.");
8080
return;
8181
}
8282

8383
if (await store.logout("all")) {
8484
process.stderr.write(
85-
`Cleared api_key / access_token / access_key_id / access_key_secret / security_token from ${store.path}\n`,
85+
`Cleared api_key / base_url / access_token / access_key_id / access_key_secret / security_token from ${store.path}\n`,
8686
);
8787
} else {
88-
process.stderr.write("No credentials to clear.\n");
88+
process.stderr.write("No credentials or model Base URL to clear.\n");
8989
}
9090
},
9191
});

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,38 @@ describe("e2e: auth", () => {
478478
expect(stderr).not.toContain("Cleared api_key");
479479
});
480480

481+
test("auth logout 清除当前 Config 的全部凭证和 Base URL,保留普通配置", async () => {
482+
const configDir = makeE2eOutputDir("auth-logout-all");
483+
writeFileSync(
484+
join(configDir, "config.json"),
485+
JSON.stringify(
486+
{
487+
api_key: "sk-e2e-placeholder",
488+
base_url: "https://model.example.com",
489+
access_token: "console-token-placeholder",
490+
access_key_id: "LTAI-e2e-placeholder",
491+
access_key_secret: "secret-e2e-placeholder",
492+
security_token: "sts-e2e-placeholder",
493+
output: "json",
494+
},
495+
null,
496+
2,
497+
) + "\n",
498+
);
499+
500+
const { stderr, exitCode } = await runCommandE2e(AUTH_ROUTES, ["auth", "logout"], {
501+
BAILIAN_CONFIG_DIR: configDir,
502+
});
503+
expect(exitCode, stderr).toBe(0);
504+
expect(stderr).toContain("api_key / base_url / access_token");
505+
506+
const config = JSON.parse(readFileSync(join(configDir, "config.json"), "utf8")) as Record<
507+
string,
508+
unknown
509+
>;
510+
expect(config).toEqual({ output: "json" });
511+
});
512+
481513
test.skipIf(!isDashScopeE2EReady())("auth status 文本输出", async () => {
482514
const { stdout, stderr, exitCode } = await runCommandE2e(AUTH_ROUTES, [
483515
"auth",

packages/core/src/auth/store.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@ import { describeAuthState, resolveModelBaseUrl } from "./resolver.ts";
99
const LOGOUT_KEYS = {
1010
console: ["access_token"],
1111
openapi: ["access_key_id", "access_key_secret", "security_token"],
12-
all: ["api_key", "access_token", "access_key_id", "access_key_secret", "security_token"],
12+
all: [
13+
"api_key",
14+
"base_url",
15+
"access_token",
16+
"access_key_id",
17+
"access_key_secret",
18+
"security_token",
19+
],
1320
} as const;
1421

1522
/** 登录允许落盘的键:凭证本体 + 登录回调携带的连接/作用域字段。 */
@@ -42,7 +49,7 @@ export interface AuthStore {
4249
resolveBaseUrl(fallback?: string): string;
4350
/** 登录落盘:合并写入,undefined 键忽略;显式 --config 成功后同时激活目标 Profile。 */
4451
login(patch: AuthPersistPatch): Promise<void>;
45-
/** 清凭证:console/openapi 只删对应域;all 清全部登录凭证。返回是否有变更。 */
52+
/** 清凭证:console/openapi 只删对应域;all 清全部登录凭证和 model baseUrl。返回是否有变更。 */
4653
logout(scope: "console" | "openapi" | "all"): Promise<boolean>;
4754
/** 实际写入的 config.json 路径(不受命名配置影响,一直是同一个文件)。 */
4855
path: string;

packages/core/tests/config-store.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ test("AuthStore:login 合并落盘,logout 按域清理并报告变更", async ()
7373
const store = makeAuthStore({ flags: {}, file: {}, env: {} });
7474
await store.login({
7575
api_key: "sk-1",
76+
base_url: "https://model.example.com/compatible-mode/v1",
7677
access_token: "tok-1",
7778
access_key_id: "ak-1",
7879
access_key_secret: "secret-1",
@@ -82,6 +83,7 @@ test("AuthStore:login 合并落盘,logout 按域清理并报告变更", async ()
8283
});
8384
expect(makeConfigStore().read()).toMatchObject({
8485
api_key: "sk-1",
86+
base_url: "https://model.example.com",
8587
access_token: "tok-1",
8688
workspace_id: "ws-1",
8789
console_site: "international",
@@ -90,15 +92,18 @@ test("AuthStore:login 合并落盘,logout 按域清理并报告变更", async ()
9092
expect(await store.logout("console")).toBe(true);
9193
expect(makeConfigStore().read().access_token).toBeUndefined();
9294
expect(makeConfigStore().read().api_key).toBe("sk-1");
95+
expect(makeConfigStore().read().base_url).toBe("https://model.example.com");
9396

9497
expect(await store.logout("openapi")).toBe(true);
9598
expect(makeConfigStore().read()).toMatchObject({ api_key: "sk-1" });
99+
expect(makeConfigStore().read().base_url).toBe("https://model.example.com");
96100
expect(makeConfigStore().read().access_key_id).toBeUndefined();
97101
expect(makeConfigStore().read().access_key_secret).toBeUndefined();
98102
expect(makeConfigStore().read().security_token).toBeUndefined();
99103

100104
expect(await store.logout("all")).toBe(true);
101105
expect(makeConfigStore().read().api_key).toBeUndefined();
106+
expect(makeConfigStore().read().base_url).toBeUndefined();
102107
expect(await store.logout("all")).toBe(false);
103108

104109
// 非凭证键不受 logout 影响

skills/bailian-cli/assets/setup.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Verify: `bl --version` (prints `bl X.Y.Z`).
3030

3131
```bash
3232
bl auth status # check current auth
33-
bl auth logout # clear credentials
33+
bl auth logout # clear credentials and the model Base URL
3434
bl auth logout --console # clear console token only
3535
bl auth logout --open-api # clear OpenAPI AK/SK only
3636
```

skills/bailian-cli/reference/auth.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Index: [index.md](index.md)
1111
| ------------------------------- | -------------------------------------------------------------------------------------------- |
1212
| `bl auth generate-access-token` | Generate a CLI access token using OpenAPI AK/SK |
1313
| `bl auth login` | Authenticate with API key, console browser login, or OpenAPI AK/SK (credentials can coexist) |
14-
| `bl auth logout` | Clear stored credentials |
14+
| `bl auth logout` | Clear stored credentials; full logout also clears the model Base URL |
1515
| `bl auth status` | Show current authentication state |
1616

1717
## Command details
@@ -78,11 +78,11 @@ bl auth login --open-api --access-key-id LTAIxxxxx --access-key-secret xxxxx
7878

7979
### `bl auth logout`
8080

81-
| Field | Value |
82-
| --------------- | ------------------------------------------------------ |
83-
| **Name** | `auth logout` |
84-
| **Description** | Clear stored credentials |
85-
| **Usage** | `bl auth logout [--console \| --open-api] [--dry-run]` |
81+
| Field | Value |
82+
| --------------- | -------------------------------------------------------------------- |
83+
| **Name** | `auth logout` |
84+
| **Description** | Clear stored credentials; full logout also clears the model Base URL |
85+
| **Usage** | `bl auth logout [--console \| --open-api] [--dry-run]` |
8686

8787
#### Flags
8888

skills/bailian-cli/reference/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Use this index for the full quick index and global flags.
1515
| `bl app list` | List Bailian applications | [app.md](app.md) |
1616
| `bl auth generate-access-token` | Generate a CLI access token using OpenAPI AK/SK | [auth.md](auth.md) |
1717
| `bl auth login` | Authenticate with API key, console browser login, or OpenAPI AK/SK (credentials can coexist) | [auth.md](auth.md) |
18-
| `bl auth logout` | Clear stored credentials | [auth.md](auth.md) |
18+
| `bl auth logout` | Clear stored credentials; full logout also clears the model Base URL | [auth.md](auth.md) |
1919
| `bl auth status` | Show current authentication state | [auth.md](auth.md) |
2020
| `bl config list` | List config profiles and show the active profile | [config.md](config.md) |
2121
| `bl config set` | Set a config value | [config.md](config.md) |

0 commit comments

Comments
 (0)