Skip to content

halo CLI 在无 secret service 的 Linux 环境下无法读取凭据(PermissionDenied) #10

@manjieqi

Description

@manjieqi

版本信息
halo CLI: 1.3.0 (linux-x64, node v25.6.0)
@napi-rs/keyring: 1.3.0
OS: Debian 12 (Linux 6.8.0), 非桌面/headless 环境
问题描述
halo auth login 登录成功,halo auth current 也能显示 profile,但执行任何需要凭据的命令(如 halo post list)时报错:

Failed to read credentials for profile "blog": Couldn't access platform storage: PermissionDenied
Caused by:
PermissionDenied
复现步骤

1. 登录 — 成功

halo auth login --profile blog --url https://xxx.com --auth-type bearer --token pat_xxx

2. 验证 profile — 成功

halo auth current

输出正常的 profile 信息

3. 执行任何需要 auth 的命令 — 失败

halo post list

→ PermissionDenied

根因分析
halo CLI 通过 @napi-rs/keyring(底层 Rust keyring-rs)管理凭据
Linux 上 keyring-rs 优先通过 DBus secret service 读写凭据,这需要一个运行中的 secret service 守护进程(如 gnome-keyring-daemon)
在 headless / CI / 容器等非桌面环境中,没有 secret service,直接抛出 PermissionDenied,并没有降级到文件存储后端
矛盾的是:登录时 token 已经写入了 ~/.config/halo/keyring.json,文件存在且可读。但 keyring-rs 读取时绕过文件,坚持走 DBus secret service
为什么影响大
这不仅是极端情况。以下场景都会触发:

headless 服务器(最常见的使用场景 — 博客服务器通常没桌面)
Docker 容器
CI/CD 流水线
SSH 会话(DBUS_SESSION_BUS_ADDRESS 未正确继承)
WSL
本质上,用 CLI 管理博客的人大概率是连服务器操作,而这恰恰是 secret service 最不可能存在的环境。

建议修复方向
短期:加 --token 参数 / HALO_TOKEN 环境变量

允许用户直接传 token,完全绕过 keyring
最低侵入性,Headless 场景首选
中期:完善文件后端降级

keyring-rs 已经能写 keyring.json,读取时也应能直接读这个文件
或者 halo CLI 层做 fallback:DBus 失败 → 自己读 keyring.json
长期:换用纯文件存储(如 ~/.config/halo/credentials.json)

抛弃对系统 keyring 的依赖
加文件权限检查(chmod 600)保证基本安全
类似 kubectl、docker CLI 的做法
临时绕过方案
// 手动读 keyring.json 拿 token
const fs = require('fs');
const keyring = JSON.parse(fs.readFileSync('/root/.config/halo/keyring.json', 'utf8'));
const token = JSON.parse(keyring['@halo-dev/cli/profile:blog']).token;
// 然后用 token 直接调 REST API

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions