1. 專案定位與核心價值
問題背景
傳統開發流程中,.env 檔案是管理環境變數的主流方式,但在 AI 編碼代理(如 Claude Code、OpenAI Codex)日益普及的今天,.env 檔案已成為嚴重的安全隱患:
- 代理洩漏風險:AI 代理天生傾向執行
cat .env、grep -r KEY等指令來理解專案,敏感值可能進入模型 context - 意外提交:
.env若未妥善.gitignore,機密值會直接進入版控歷史 - Shell 繼承:
direnv等工具將值注入持久 shell,從該 shell 啟動的任何子程序(含 AI 代理)都會繼承所有機密
hush 的解答
hush 是一款專為 macOS 設計的本地端機密管理 CLI (Command Line Interface; 命令列介面) 工具,其核心設計理念為:
- Value-free declaration(無值宣告):repo 中僅有
.hush.toml記錄 key 名稱,永遠不含值 - Encrypted at rest(靜態加密):所有機密值以
age encryption (age 加密)儲存於~/.config/hush/store.age,master key 存放在 macOS Keychain - Child-only injection(僅子程序注入):值僅注入
hush run -- <cmd>啟動的子程序環境,永遠不進入 shell - Dual-mode(雙模式):人類獲得 shim + 提示;agent 被自動限制為「use, don’t see(只用、不看)」
與既有工具的對比
| 面向 | .env + dotenv | direnv | sops | hush |
|---|---|---|---|---|
| 值在 repo 中 | ✅ 是 | ❌ 否 | ✅ 加密 | ❌ 完全不在 |
| 值進入 shell | ✅ 是 | ✅ 是 | N/A | ❌ 僅子程序 |
| Agent 安全 | ❌ | ❌ | ❌ | ✅ 雙模式 |
| macOS Keychain | ❌ | ❌ | ❌ | ✅ |
| RAM disk 編輯 | ❌ | ❌ | ❌ | ✅ |
| 零服務依賴 | ✅ | ✅ | ✅ | ✅ |
2. 安裝指南
2.1 系統需求
- macOS(必要:依賴 Keychain + hdiutil RAM disk)
- Go 1.24+(若選擇從原始碼安裝)
- Homebrew(若選擇 brew 安裝)
2.2 安裝方式
方式 A:Go install(推薦 — 本地建置,無 Gatekeeper 隔離問題)
1go install github.com/allen-hsu/hush@latest
方式 B:Homebrew
1brew install allen-hsu/tap/hush
方式 C:從 GitHub Release 下載
至 https://github.com/allen-hsu/hush/releases 下載對應架構的 tarball(支援 darwin_amd64 與 darwin_arm64)。
2.3 Shell 整合
1hush install # 在 ~/.zshrc 自動加入 eval "$(hush hook)"
此指令是冪等的(idempotent),重複執行不會重複加入。安裝後重啟 shell 或執行 source ~/.zshrc。
2.4 版本確認
1hush version
2# 輸出: hush v0.1.5
3. 核心架構解析
3.1 架構總覽
graph TB
subgraph "Repository(版控內)"
TOML[".hush.toml
無值宣告
keys + profile 規則"]
end
subgraph "macOS Keychain"
KEY["age X25519 Identity
master key"]
end
subgraph "~/.config/hush/"
STORE["store.age
age 加密的 JSON
project → profile → key → value"]
end
subgraph "hush CLI"
RESOLVE["resolve
讀 .hush.toml + git branch
→ project/profile"]
DECRYPT["store
Keychain 取 key
→ age decrypt"]
INJECT["cli/run
env 注入子程序
exec(cmd)"]
end
subgraph "子程序(唯一能見值的地方)"
CHILD["npm run dev
process.env.DATABASE_URL"]
end
TOML --> RESOLVE
KEY --> DECRYPT
STORE --> DECRYPT
RESOLVE --> INJECT
DECRYPT --> INJECT
INJECT --> CHILD
3.2 檔案格式
.hush.toml(在 repo 中,已提交,永不含值)
1project = "my-app" # store 命名空間
2profile = "branch" # branch | cwd | fixed:<name>
3extends = "base" # fallback profile
4keys = ["DATABASE_URL", "STRIPE_KEY"]
5shims = ["npm", "pnpm"] # 自動包裝的指令
store.age(加密 JSON,解密後結構)
1{
2 "my-app": {
3 "base": { "DATABASE_URL": "...", "STRIPE_KEY": "..." },
4 "feature-x": { "DATABASE_URL": "..." }
5 }
6}
3.3 Profile 解析流程
- 從
.hush.toml取project(若空則用 repo 目錄名) - 依
profile設定決定 active profile:branch→ 當前 git branch 名稱cwd→ 工作目錄名稱fixed:<name>→ 固定名稱
- 對每個宣告的 key,依 extends chain 查找值(active → base),首個命中者勝出
- 未找到的 key 回報為 missing error
3.4 Agent 偵測機制
hush 透過兩層偵測判斷是否在 agent 環境中:
- 環境變數標記:
CLAUDECODE(Claude Code)、CODEX_SANDBOX(Codex)、HUSH_AGENT(手動覆寫) - TTY 檢查:
stdin非終端機時視為非互動模式
偵測結果影響:
hush get→ 拒絕執行hush edit→ 拒絕執行hush run(若deny_agent_run = true)→ 拒絕執行agent_profile設定時 → 切換至 sandbox profile
4. 主要功能與 API 詳解
4.1 指令一覽
| 指令 | 用途 | Agent 可用 |
|---|---|---|
hush run -- <cmd> | 解析 profile、注入 env、exec | ✅(除非 deny_agent_run) |
hush edit [--profile p] | 在 $EDITOR 中編輯 profile(RAM disk) | ❌ TTY only |
hush set <KEY> | 設定單一值(互動提示或 pipe stdin) | ✅(via pipe) |
hush unset <KEY> | 從 active profile 移除值 | ✅ |
hush purge <KEY> [--yes] | 從所有 profile + .hush.toml 移除 | 需 --yes |
hush ls [--json] | 列出宣告的 key 與解析來源 | ✅ |
hush get [KEY] | 印出值(TTY only) | ❌ |
hush import [path] [--shred] | 匯入現有 .env | ✅ |
hush fork [--from p] | 從 source profile 複製至 active | ✅ |
hush cp <from> <to> | 複製 profile | ✅ |
hush init | 建立 .hush.toml 範本 | ✅ |
hush install | 寫入 shell hook 至 ~/.zshrc | ✅ |
hush hook | 輸出 shell 整合程式碼 | ✅ |
hush scrub | 清除 shell 中的 hush 變數/shim | ✅ |
hush context | 快速輸出 project/profile(無解密) | ✅ |
4.2 核心使用流程
初始化專案
1cd my-project
2hush init # 建立 .hush.toml
從現有 .env 遷移
1hush import .env # 讀取 .env、加密、寫入 store
2hush import .env --shred # 遷移後安全刪除原始 .env
設定與管理值
1hush set DATABASE_URL # 互動式輸入值(不回顯、不進歷史記錄)
2echo "sk_test_xxx" | hush set STRIPE_KEY # pipe 方式
3hush unset OLD_KEY # 從 active profile 移除
4hush purge DEPRECATED_KEY --yes # 從所有 profile 完全移除
使用機密
1hush run -- npm run dev # 值僅注入此子程序
2hush run -- python app.py
3hush run -- docker compose up
Profile 管理
1hush ls # 查看 key 清單與解析來源
2hush ls --json # 機器可讀輸出
3hush fork --from base # 從 base 複製至 active profile
4hush cp staging production # 跨 profile 複製
編輯機密(人類專用)
1hush edit # 開啟 $EDITOR,在 RAM disk 上操作
2hush edit --profile base # 編輯指定 profile
4.3 Exit Code 規範
| Code | 意義 |
|---|---|
0 | 成功 |
2 | 設定/用法錯誤 |
3 | 拒絕執行(如 agent 模式下的 get) |
4 | 解密/Keychain/執行時錯誤 |
4.4 JSON 輸出
所有讀寫指令支援 --json 旗標,方便機器解析:
1hush ls --json
2# {"project":"my-app","profile":"main","keys":[{"key":"DATABASE_URL","set":true,"from":"base"},...]}}
3
4hush set API_KEY --json
5# {"ok":true,"action":"set","key":"API_KEY","project":"my-app","profile":"main"}
5. 應用場景與實戰範例
5.1 場景一:全新專案設定
1cd ~/projects/my-saas
2hush init
3
4# 編輯 .hush.toml
5cat .hush.toml
6# project = "my-saas"
7# profile = "branch"
8# extends = "base"
9# keys = []
10
11hush set DATABASE_URL
12hush set STRIPE_SECRET_KEY
13hush set OPENAI_API_KEY
14
15# 從現在起
16hush run -- npm run dev
5.2 場景二:團隊成員遷移現有 .env
1# 一步遷移
2hush import .env --shred
3
4# 確認結果
5hush ls
6# project my-saas · profile main
7# DATABASE_URL set (main)
8# STRIPE_SECRET_KEY set (main)
9# OPENAI_API_KEY set (main)
10
11# 提交 .hush.toml(無值,安全)
12git add .hush.toml
13git commit -m "chore: migrate secrets to hush"
5.3 場景三:功能分支使用不同 DB
1git checkout -b feature/new-db
2hush fork --from base # 從 base 複製所有值
3hush set DATABASE_URL # 僅覆寫此 key
4hush run -- npm run test # 使用 feature/new-db profile
5.4 場景四:Claude Code 開發
1# Claude Code 環境下(CLAUDECODE 已設定)
2hush run -- npm run dev # ✅ 正常運行
3hush get DATABASE_URL # ❌ 拒絕:agent 模式
4hush edit # ❌ 拒絕:agent 模式
5
6# 加強版:deny_agent_run
7# .hush.toml: deny_agent_run = true
8hush run -- npm run dev # ❌ 也拒絕
9
10# 折衷版:agent_profile
11# .hush.toml: agent_profile = "sandbox"
12# 預先設定 sandbox profile 使用測試 credentials
13hush run -- npm run test # ✅ 但使用 sandbox 的測試值
5.5 場景五:啟動代理前清理 shell
1eval "$(hush scrub)" # 清除所有 hush 管理的 env 變數與 shim 函式
2# 然後安全啟動 AI 代理
6. 資安掃描報告
6.1 掃描摘要
針對 hush 原始碼進行靜態安全掃描,涵蓋所有 .go、.yaml、.sh 檔案。
6.2 發現項目
🟢 安全設計亮點(正面發現)
| # | 項目 | 說明 |
|---|---|---|
| 1 | Keychain 存取 | master key 存於 macOS Keychain,無明文 key 檔案落盤 |
| 2 | RAM disk 編輯 | hush edit 使用 hdiutil RAM disk,明文不觸碰持久儲存 |
| 3 | Secure remove | secureRemove() 先覆零再刪除(best effort on APFS) |
| 4 | Agent 偵測 | 多層偵測(env marker + TTY)自動鎖定敏感指令 |
| 5 | Atomic write | store 寫入使用 .tmp + rename,避免中斷損毀 |
| 6 | 值不入 shell | hush run 透過 exec.Command 注入子程序 env,不汙染 parent shell |
| 7 | 密碼不入 CLI 參數 | hush set 用互動提示或 stdin pipe,避免 ps 洩漏 |
| 8 | 權限控制 | store.age 目錄 0700、暫存檔 0600 |
🟡 中等風險(設計限制,非漏洞)
| # | 項目 | 風險說明 | 緩解 |
|---|---|---|---|
| 1 | 環境變數標記可被取消 | 同 uid 程序可 unset CLAUDECODE 繞過 agent 偵測 | 設計文件已明確聲明此為 threat boundary |
| 2 | APFS secure delete 不可靠 | 即使覆零,CoW 檔案系統可能保留舊資料 | RAM disk 為主路徑,fallback 時有警告 |
| 3 | exec.Command("sh", "-c", ...) in edit | 透過 shell 呼叫 editor,理論上可注入 | 值來自 $EDITOR 環境變數,需本地攻擊者 |
| 4 | CI tokens in YAML | GITHUB_TOKEN 和 HOMEBREW_TAP_GITHUB_TOKEN | 標準 GitHub Actions secrets 用法,無硬編碼 |
🔴 高風險發現
無。本專案的安全設計品質極高,在同類工具中屬於前段水準。
6.3 總結
hush 的安全模型定位清晰:防禦「accidental exposure and an agent’s reflex to read files(意外洩漏與代理的讀檔反射)」,而非防禦「同 uid 的惡意攻擊者」。在這個 threat boundary 內,實作品質優秀。
7. FAQ 常見問題
Q1: hush 支援 Linux 嗎?
不支援。hush 依賴 macOS 專屬功能:Keychain(security CLI)和 hdiutil RAM disk。在 Linux 上需要替換這兩個元件(例如使用 gnome-keyring 和 tmpfs),但目前作者明確將此列為 non-goal。
Q2: 我的 .env 已經在 git 歷史中了,hush 能幫忙嗎?
hush 能阻止未來的洩漏,但無法清除已在 git 歷史中的值。你需要:
- 先用
hush import .env --shred遷移 - 再用
git filter-branch或BFG Repo-Cleaner清除歷史 - 輪替所有已曝露的 credentials
Q3: hush 和 direnv 可以共存嗎?
可以。但 direnv 會將值注入 shell(hush 不會),所以混用時 direnv 管理的值仍有被代理讀取的風險。建議將 direnv 僅用於非機密的環境設定(如 PATH),機密一律走 hush。
Q4: 多人團隊怎麼分享 secrets?
hush 是單人工具(single-user),不提供團隊分享機制。這是有意的設計決策——team sharing 需要 multi-recipient encryption,會大幅增加複雜度。多人場景建議搭配 Vault、AWS Secrets Manager 等,hush 專注本地開發環境。
Q5: CI/CD 怎麼辦?
hush 僅用於本地開發。CI/CD 環境應使用 GitHub Actions secrets、GitLab CI variables 等平台原生機制。.hush.toml 中的 key 名稱可作為 CI 環境變數設定的參考清單。
Q6: fish shell 支援嗎?
目前 shell hook 僅支援 zsh。fish 使用者需手動在 config.fish 中設定等效整合,或直接使用 hush run -- 而不依賴 shim。
8. 進階技巧與最佳實踐
8.1 .hush.toml 最佳配置
1project = "my-app"
2profile = "branch"
3extends = "base"
4keys = ["DATABASE_URL", "STRIPE_KEY", "OPENAI_API_KEY"]
5
6# 推薦:對高敏感專案
7disable_get = true # 即使人類也不能 print 值
8deny_agent_run = true # agent 完全不能執行
9# 或折衷:
10agent_profile = "sandbox" # agent 使用測試 credentials
11
12# 推薦:常用指令加入 shim
13shims = ["npm", "node", "pnpm"]
8.2 Profile 策略
- base profile 放共用的預設值(開發 DB、test API keys)
- branch profile 僅覆寫需要不同值的 key(
extends = "base"自動 fallback) - sandbox profile 放純測試 credentials(搭配
agent_profile使用)
8.3 與 Docker 搭配
1hush run -- docker compose up
2# 或單一容器
3hush run -- docker run -e DATABASE_URL=$DATABASE_URL my-image
hush 注入值到 docker compose 的程序環境中,docker-compose.yml 中使用 ${DATABASE_URL} 即可接收。
8.4 搭配 Makefile
1dev:
2 hush run -- npm run dev
3
4test:
5 hush run -- npm test
6
7deploy:
8 hush run -- ./scripts/deploy.sh
8.5 Git Worktree 工作流
hush 的 per-worktree 設計天生適合 git worktree:
1git worktree add ../my-app-feature feature/x
2cd ../my-app-feature
3# .hush.toml 已在 repo 中,自動繼承
4# profile 自動解析為 feature/x(branch mode)
5hush run -- npm run dev # 使用 feature/x 的值
9. 整合進其他工作流
9.1 與 Claude Code 整合
在 .claude/settings.json 中加入以下權限規則,形成縱深防禦:
1{
2 "permissions": {
3 "deny": [
4 "Read(.env*)",
5 "Bash(cat .env*)",
6 "Bash(grep .env*)"
7 ]
8 }
9}
搭配 hush 的 agent 偵測,Claude Code 環境下:
.hush.toml可讀(僅 key 名稱)hush run -- <cmd>可用(若未設deny_agent_run)hush get/hush edit被拒絕
9.2 與 Codex 整合
Codex sandbox 環境中,CODEX_SANDBOX 環境變數自動觸發 hush 的 strict 模式。無需額外設定。
9.3 與 pre-commit hooks 搭配
1# .git/hooks/pre-commit
2#!/bin/sh
3# 確保 .env 不被意外提交
4if git diff --cached --name-only | grep -q '\.env'; then
5 echo "ERROR: .env files should not be committed. Use hush instead."
6 exit 1
7fi
9.4 啟動代理前的清理
1# 在 shell 腳本中啟動 AI 代理前
2eval "$(hush scrub)"
3# 然後啟動代理
4claude-code
10. 重點摘要 Checklist
- ✅ macOS 限定工具,依賴 Keychain + hdiutil
- ✅ 安裝方式:
go install/brew install allen-hsu/tap/hush - ✅ 一步遷移:
hush import .env --shred - ✅ 使用機密:
hush run -- <cmd>是唯一正途 - ✅ 值永不進入 shell,僅存在於子程序環境
- ✅ Agent 自動偵測:
CLAUDECODE/CODEX_SANDBOX/HUSH_AGENT/ non-TTY - ✅ 編輯機密用 RAM disk,明文不落盤
- ✅
.hush.toml可安全提交至 repo(僅 key 名稱) - ✅ Profile 按 git branch 自動切換,支援 extends 繼承
- ✅
--json旗標支援機器可讀輸出 - ✅ Per-project agent policy:
disable_get/deny_agent_run/agent_profile - ✅ Exit code 明確:0/2/3/4 分層
11. 進一步閱讀
官方文件
相關技術
- age encryption — hush 使用的加密函式庫
- direnv — 傳統 shell 層級環境變數管理工具(hush 的對比對象)
- sops — Mozilla 的加密機密管理工具(hush edit 靈感來源)
- macOS Keychain Services — hush 存放 master key 的系統服務
延伸思考
- OWASP Secrets Management Cheat Sheet
- 12-Factor App: Config — 環境變數管理的經典原則
- LLM Agent Security Considerations — AI 代理的安全考量
12. 與 AI-Knowledge Template (AIKT) 的關聯性
12.1 概述
hush 作為一款 macOS 專屬的 agent-safe 機密管理工具,與 AIKT 的 22 層架構有著天然的互補關係。AIKT 的各 Layer 大量依賴 API key、access token、service credential 等機密資訊,而 hush 正好提供了一種安全的方式來管理這些機密——特別是在 Claude Code 作為主要執行環境的情境下。
12.2 與各 Layer 的搭配場景
高度相關的 Layer
| Layer | 名稱 | 搭配方式 |
|---|---|---|
| Layer 5 | ai-notebooklm | NotebookLM API 的 credential 可由 hush 管理,hush run -- bash scripts/notebooklm-save.sh |
| Layer 9 | paper-search | PubMed/Semantic Scholar 等 API key 存入 hush store |
| Layer 10 | paper-qa-lite | OpenAI/Anthropic API key 用於 embedding 與 RAG,是最敏感的 credential |
| Layer 18 | research-pipeline-v2 | 多管線研究工作流涉及多個 API credential,hush 可統一管理 |
| Layer 19 | tu-plan-generator | ToolUniverse 的 API key(OpenRouter 等),搭配 agent_profile = "sandbox" 使用測試 key |
| Layer 22 | company-intel | 盡調資料涉及商業機密 API,搭配 hush 的 profile 隔離 |
中度相關的 Layer
| Layer | 名稱 | 搭配方式 |
|---|---|---|
| Layer 1 | ai-save | markitdown/playwright 等工具若需認證,可走 hush |
| Layer 2 | ai-gh-save | GitHub Personal Access Token 管理 |
| Layer 3 | ai-autofetch | cron job 執行的 API 呼叫,需在 shell 中先 hush run 包裝 |
| Layer 12 | gh-tutorial-qd | GitHub API 存取 token |
| Layer 16 | rtk | rtk 本身不需 credential,但它代理的指令可能需要 |
| Layer 21 | blog-publish | Netlify deploy token 管理 |
低度相關(本地處理為主)
| Layer | 名稱 | 說明 |
|---|---|---|
| Layer 4 | graphify | 純本地處理,通常不需 API key |
| Layer 6 | gitnexus | 純本地符號索引 |
| Layer 7 | quarkdown | 本地 markdown 編譯(--deny=network 為預設) |
| Layer 8 | docling | 本地文件解析 |
| Layer 11 | kami | 本地 HTML → PDF |
| Layer 17 | video-to-tutorial | 本地 whisper + ffmpeg |
| Layer 20 | sync-v1-to-clean | 本地 git 操作 |
12.3 實作建議
在 AIKT 環境中導入 hush 的推薦步驟:
1# 1. 安裝 hush
2go install github.com/allen-hsu/hush@latest
3hush install
4
5# 2. 在 AIKT v1 根目錄初始化
6cd "/config/workspace/1. 25-26 Finished Project/260414 Cli tools/260416 AI-knowledge_template v1"
7hush init
8
9# 3. 遷移現有 API keys
10hush set OPENROUTER_API_KEY # ToolUniverse / perplexity-search
11hush set ANTHROPIC_API_KEY # paper-qa-lite embedding
12hush set GITHUB_TOKEN # gh-save / gh-tutorial-qd
13hush set NETLIFY_AUTH_TOKEN # blog-publish
14
15# 4. 在 scripts 中包裝
16# 原始: bash scripts/paper-search.sh "query"
17# hush: hush run -- bash scripts/paper-search.sh "query"
18
19# 5. 設定 agent 政策
20# .hush.toml 中加入:
21# agent_profile = "sandbox" # Claude Code 使用測試 key
12.4 與 AIKT 機密邊界的協同
- company-intel:使用獨立的
projectnamespace(ci-<company>),避免與其他專案的 credential 交叉 - research-pipeline-v2 internal mode:
agent_profile = "internal"指向含 decoy 資訊的 profile
12.5 限制與注意事項
- macOS 限定:若 AIKT 執行環境為 Linux(Docker/遠端伺服器),hush 不適用,需改用其他方案(如
pass、age原生、sops) - Claude Code 的 CLAUDECODE 環境變數:hush 預設偵測此標記。若需讓 Claude Code 透過
hush run執行指令(不設deny_agent_run),需確保 scripts 內部也走hush run包裝 - cron job(ai-autofetch):需在 cron entry 中使用
hush run -- bash scripts/ai-autofetch.sh,而非直接呼叫 - 單人工具:AIKT 目前為單人使用,與 hush 的 single-user 定位完美契合;若未來需多人協作,credential 分享需另覓方案
Comments