# IMA COS 上传凭证处理(Hermes redact_secrets 兼容模式) ## 问题 Hermes 配置 `security.redact_secrets: true` 时,`create_media` API 返回的 `cos_credential.token` 字段在 `terminal()` 输出中被替换为 `***`。 直接通过 `terminal()` 调用 `cos-upload.cjs` 会因 token 截断而失败(HTTP 403 InvalidAccessKeyId)。 ## 安全的工作流(execute_code + subprocess.run) 不要用 `terminal()` 传递 COS 凭证。改用 `execute_code()` + `subprocess.run()` 模式: ```python # Phase A: terminal() 中保存原始响应到文件 result = terminal(""" bash -c ' set -a source /home/ubuntu/zhu/github/reader/.env set +a OPTS=$(printf "%s" "{\\"clientId\\":\\""$IMA_OPENAPI_CLIENTID"\\",\\\"apiKey\\":\\\""$IMA_OPENAPI_APIKEY"\\\"}") RESP=$(node /root/.hermes/skills/openclaw-imports/ima-skill/ima_api.cjs "openapi/wiki/v1/create_media" "{...}" "$OPTS" 2>/dev/null) echo "$RESP" > /tmp/create_media_raw.json echo "saved" ' """) # Phase B: execute_code 中从文件读取凭证 import json, subprocess with open("/tmp/create_media_raw.json") as f: data = json.load(f) cred = data["data"]["cos_credential"] # Phase C: subprocess.run 直接调用,不经过 terminal() args = ["node", f"{SKILL_DIR}/knowledge-base/scripts/cos-upload.cjs", "--file", FILE_PATH, "--secret-id", cred["secret_id"], "--secret-key", cred["secret_key"], "--token", cred["token"], "--bucket", cred["bucket_name"], "--region", cred["region"], "--cos-key", cred["cos_key"], "--content-type", "text/markdown", "--start-time", cred["start_time"], "--expired-time", cred["expired_time"], "--timeout", "300000"] r = subprocess.run(args, capture_output=True, text=True, timeout=310) ``` ## 对比:错误的做法(terminal 直接传递) ```bash # ⛔ 这样不行!token 会被 redact_secrets 替换为 *** TOKEN=$(echo "$RESP" | jq -r '.data.cos_credential.token') node ... --token "$TOKEN" ... # 会收到 HTTP 403 ``` ## 关键原则 - `terminal()` 输出中的敏感字段会被自动脱敏,但不影响底层 JSON 文件写入 - `execute_code` 中 `terminal()` 返回的 `output` 已经是脱敏后的文本 - **唯一可靠的凭证源**是直接写入磁盘的原始 JSON 文件 - `subprocess.run` 在 `execute_code` 中绕过脱敏,因为凭证在 Python 内存中直接被传递给子进程,不经过 Hermes 的 stdout 脱敏管道