Go to file
voson d0796e9c9a feat: delete 命令支持批量删除,--name 改为可选
省略 --name 时按 namespace(+ 可选 --kind)批量删除所有匹配记录;
支持 --dry-run 预览;删除前自动快照历史并写入审计日志。
移除独立的 delete-ns 子命令,合并为统一的 delete 入口。
更新 AGENTS.md 文档,版本 bump 至 0.9.3。

Made-with: Cursor
2026-03-19 16:31:18 +08:00

secrets

跨设备密钥与配置管理 CLI基于 Rust + PostgreSQL 18。

将服务器信息、服务凭据统一存入数据库,供本地工具和 AI 读取上下文。每个敏感字段单独行存储(secrets 子表),字段名、类型、长度以明文保存便于 AI 理解,仅值本身使用 AES-256-GCM 加密;主密钥由 Argon2id 从主密码派生并存入系统钥匙串。

安装

cargo build --release
# 或从 Release 页面下载预编译二进制

已有旧版本时,可执行 secrets upgrade 自动下载最新版并替换。该命令会校验 Release 附带的 .sha256 摘要后再安装。

首次使用(每台设备各执行一次)

# 1. 配置数据库连接(会先验证连接可用再写入)
secrets config set-db "postgres://postgres:<password>@<host>:<port>/secrets"

# 2. 初始化主密钥(提示输入至少 8 位的主密码,派生后存入 OS 钥匙串)
secrets init

主密码不会存储,仅用于派生主密钥,且至少需 8 位。同一主密码在所有设备上会得到相同主密钥salt 存于数据库,首台设备生成后共享)。

主密钥存储macOS → KeychainWindows → Credential ManagerLinux → keyutils会话级重启后需再次 secrets init)。

从旧版(明文存储)升级:升级后首次运行需执行 secrets init 即可(明文记录需手动重新 add 或通过 update 更新)。

AI Agent 快速指南

这个 CLI 以 AI 使用优先设计。核心路径只有一条:读取用 search,写入用 add / update

第一步:发现有哪些数据

# 列出所有记录摘要(默认最多 50 条,安全起步)
secrets search --summary --limit 20

# 按 namespace 过滤
secrets search -n refining --summary --limit 20

# 按最近更新排序
secrets search --sort updated --limit 10 --summary

--summary 只返回轻量字段namespace、kind、name、tags、desc、updated_at不含完整 metadata 和 secrets。

第二步:精确读取单条记录

# 精确定位namespace + kind + name 三元组)
secrets search -n refining --kind service --name gitea

# 获取完整记录(含 secrets 字段 schemafield_name、field_type、value_len无需 master_key
secrets search -n refining --kind service --name gitea -o json

# 直接提取单个 metadata 字段值(最短路径)
secrets search -n refining --kind service --name gitea -f metadata.url

# 同时提取多个 metadata 字段
secrets search -n refining --kind service --name gitea \
  -f metadata.url -f metadata.default_org

# 需要 secrets 时,改用 inject / run
secrets inject -n refining --kind service --name gitea
secrets run -n refining --kind service --name gitea -- printenv

search 展示 metadata 与 secrets 的字段 schema字段名、类型、长度不展示 secret 值本身;需要值时用 inject / run

输出格式

场景 推荐命令
AI 解析 / 管道处理 -o json-o json-compact
注入 secrets 到环境变量 inject / run
人类查看 默认 textTTY 下自动启用)
非 TTY管道/重定向) 自动 json-compact

说明:text 输出中的时间会按当前机器本地时区显示;json/json-compact 继续使用 UTCRFC3339 风格)以便脚本和 AI 稳定解析。

# 管道直接 jq 解析(非 TTY 自动 json-compact
secrets search -n refining --kind service | jq '.[].name'

# 需要 secrets 时,使用 inject / run
secrets inject -n refining --kind service --name gitea > ~/.config/gitea/secrets.env
secrets run -n refining --kind service --name gitea -- ./deploy.sh

完整命令参考

# 查看帮助(包含各子命令 EXAMPLES
secrets --help
secrets init --help           # 主密钥初始化
secrets search --help
secrets add --help
secrets update --help
secrets delete --help
secrets config --help
secrets upgrade --help     # 检查并更新 CLI 版本
secrets export --help      # 批量导出JSON/TOML/YAML
secrets import --help      # 批量导入JSON/TOML/YAML

# ── search ──────────────────────────────────────────────────────────────────
secrets search --summary --limit 20                        # 发现概览
secrets search -n refining --kind service                  # 按 namespace + kind
secrets search -n refining --kind service --name gitea     # 精确查找
secrets search -q mqtt                                     # 关键词模糊搜索
secrets search --tag hongkong                              # 按 tag 过滤
secrets search -n refining --kind service --name gitea -f metadata.url   # 提取 metadata 字段
secrets search -n refining --kind service --name gitea -o json            # 完整记录(含 secrets schema
secrets search --sort updated --limit 10 --summary         # 最近改动
secrets search -n refining --summary --limit 10 --offset 10  # 翻页

# ── add ──────────────────────────────────────────────────────────────────────
secrets add -n refining --kind server --name my-server \
  --tag aliyun --tag shanghai \
  -m ip=10.0.0.1 -m desc="Example ECS" \
  -s username=root -s ssh_key=@./keys/server.pem

# 多行文件直接写入嵌套 secret 字段
secrets add -n refining --kind server --name my-server \
  -s credentials:content@./keys/server.pem

# 使用 typed JSON 写入 secret布尔、数字、数组、对象
secrets add -n refining --kind service --name deploy-bot \
  -s enabled:=true \
  -s retry_count:=3 \
  -s scopes:='["repo","workflow"]' \
  -s extra:='{"region":"ap-east-1","verify_tls":true}'

secrets add -n refining --kind service --name gitea \
  --tag gitea \
  -m url=https://code.example.com -m default_org=myorg \
  -s token=<token>

# ── update ───────────────────────────────────────────────────────────────────
secrets update -n refining --kind server --name my-server -m ip=10.0.0.1
secrets update -n refining --kind service --name gitea --add-tag production -s token=<new>
secrets update -n refining --kind service --name mqtt --remove-meta old_port --remove-secret old_key
secrets update -n refining --kind server --name my-server --remove-secret credentials:content

# ── delete ───────────────────────────────────────────────────────────────────
secrets delete -n refining --kind service --name legacy-mqtt

# ── init ─────────────────────────────────────────────────────────────────────
secrets init              # 主密钥初始化(每台设备一次,主密码至少 8 位,派生后存钥匙串)

# ── config ───────────────────────────────────────────────────────────────────
secrets config set-db "postgres://postgres:<password>@<host>:<port>/secrets"   # 先验证再写入
secrets config show    # 密码脱敏展示
secrets config path    # 打印配置文件路径

# ── upgrade ──────────────────────────────────────────────────────────────────
secrets upgrade --check   # 仅检查是否有新版本
secrets upgrade           # 下载、校验 SHA-256 并安装最新版(可通过 SECRETS_UPGRADE_URL 自托管)

# ── export ────────────────────────────────────────────────────────────────────
secrets export --file backup.json                        # 全量导出到 JSON
secrets export -n refining --file refining.toml          # 按 namespace 导出为 TOML
secrets export -n refining --kind service --file svc.yaml   # 按 kind 导出为 YAML
secrets export --tag production --file prod.json         # 按 tag 过滤
secrets export -q mqtt --file mqtt.json                   # 模糊搜索导出
secrets export --no-secrets --file schema.json           # 仅导出 schema无需主密钥
secrets export -n refining --format yaml                  # 输出到 stdout指定格式

# ── import ────────────────────────────────────────────────────────────────────
secrets import backup.json                               # 导入(冲突时报错)
secrets import --force refining.toml                     # 冲突时覆盖已有记录
secrets import --dry-run backup.yaml                     # 预览将要执行的操作(不写入)

# ── 调试 ──────────────────────────────────────────────────────────────────────
secrets --verbose search -q mqtt
RUST_LOG=secrets=trace secrets search

数据模型

主表 entriesnamespace、kind、name、tags、metadata+ 子表 secrets(每个加密字段一行,含 field_name、field_type、value_len、encrypted。首次连接自动建表同时创建 audit_logentries_historysecrets_history 等表。

位置 字段 说明
entries namespace 一级隔离,如 refiningricnsmart
entries kind 记录类型,如 serverservicekey(可自由扩展)
entries name 人类可读唯一标识
entries tags 多维标签,如 ["aliyun","hongkong"]
entries metadata 明文描述ip、desc、domains、key_ref 等)
secrets field_name / field_type / value_len 明文search 可见AI 可推断 inject 会生成什么变量
secrets encrypted 仅加密值本身AES-256-GCM

-m / --meta 写入 metadata-s / --secret 写入 secrets 表的独立行。支持 key=valuekey=@filekey:=<json>,也支持 credentials:content@./key.pem 这类嵌套字段文件写入;删除时支持 --remove-secret credentials:content。加解密使用主密钥(由 secrets init 设置)。

PEM 共享:同一 PEM 被多台服务器共享时,可存为 kind=key 记录,服务器通过 metadata.key_ref 引用;轮换只需 update 一条 key 记录,所有引用自动生效。详见 AGENTS.md

-m / --meta JSON 语法速查

-m-s 走的是同一套解析规则,只是写入位置不同:-m 写到明文 metadata,适合端口、开关、标签、描述性配置等非敏感信息。

目标值 写法示例 实际存入
普通字符串 -m url=https://code.example.com "https://code.example.com"
文件内容字符串 -m notes=@./service-notes.txt "..."
布尔值 -m enabled:=true true
数字 -m port:=3000 3000
null -m deprecated_at:=null null
数组 -m domains:='["code.example.com","git.example.com"]' ["code.example.com","git.example.com"]
对象 -m tls:='{"enabled":true,"redirect_http":true}' {"enabled":true,"redirect_http":true}
嵌套路径 + JSON -m deploy:strategy:='{"type":"rolling","batch":2}' {"deploy":{"strategy":{"type":"rolling","batch":2}}}

常见规则:

  • = 表示按字符串存储。
  • := 表示按 JSON 解析。
  • shell 中数组和对象建议整体用单引号包住。
  • 嵌套字段继续用冒号分隔:-m runtime:max_open_conns:=20

示例:新增一条带 typed metadata 的记录

secrets add -n refining --kind service --name gitea \
  -m url=https://code.example.com \
  -m port:=3000 \
  -m enabled:=true \
  -m domains:='["code.example.com","git.example.com"]' \
  -m tls:='{"enabled":true,"redirect_http":true}'

示例:更新已有记录中的嵌套 metadata

secrets update -n refining --kind service --name gitea \
  -m deploy:strategy:='{"type":"rolling","batch":2}' \
  -m runtime:max_open_conns:=20

-s / --secret JSON 语法速查

当你希望写入的不是普通字符串,而是 true123null、数组或对象时,用 :=,右侧按 JSON 解析。

目标值 写法示例 实际存入
普通字符串 -s token=abc123 "abc123"
文件内容字符串 -s ssh_key=@./id_ed25519 "-----BEGIN ..."
布尔值 -s enabled:=true true
数字 -s retry_count:=3 3
null -s deprecated_at:=null null
数组 -s scopes:='["repo","workflow"]' ["repo","workflow"]
对象 -s extra:='{"region":"ap-east-1","verify_tls":true}' {"region":"ap-east-1","verify_tls":true}
嵌套路径 + JSON -s auth:policy:='{"mfa":true,"ttl":3600}' {"auth":{"policy":{"mfa":true,"ttl":3600}}}

常见规则:

  • = 表示按字符串存储,不做 JSON 解析。
  • := 表示按 JSON 解析,适合布尔、数字、数组、对象、null
  • shell 里对象和数组通常要整体加引号,推荐单引号:-s flags:='["a","b"]'
  • 嵌套字段继续用冒号分隔:-s credentials:enabled:=true
  • 如果你就是想存一个“JSON 字符串字面量”,可以写成 -s note:='"hello"',但大多数字符串场景直接用 = 更直观。

示例:新增一条同时包含字符串、文件、布尔、数组、对象的记录

secrets add -n refining --kind service --name deploy-bot \
  -s token=abc123 \
  -s ssh_key=@./keys/deploy-bot.pem \
  -s enabled:=true \
  -s scopes:='["repo","workflow"]' \
  -s policy:='{"ttl":3600,"mfa":true}'

示例:更新已有记录中的嵌套 JSON 字段

secrets update -n refining --kind service --name deploy-bot \
  -s auth:config:='{"issuer":"gitea","rotate":true}' \
  -s auth:retry:=5

审计日志

addupdatedelete 操作成功后自动向 audit_log 表写入一条记录,包含操作类型、操作对象和变更摘要(不含 secret 值)。操作者取自 $USER 环境变量。

-- 查看最近 20 条审计记录
SELECT action, namespace, kind, name, actor, detail, created_at
FROM audit_log
ORDER BY created_at DESC
LIMIT 20;

项目结构

src/
  main.rs          # CLI 入口clap含各子命令 after_help 示例
  output.rs        # OutputMode 枚举 + TTY 检测
  config.rs        # 配置读写(~/.config/secrets/config.toml
  db.rs            # 连接池 + auto-migrateentries + secrets + entries_history + secrets_history + audit_log + kv_config
  crypto.rs        # AES-256-GCM 加解密、Argon2id 派生、OS 钥匙串
  models.rs        # Entry + SecretField 结构体
  audit.rs         # 审计日志写入audit_log 表)
  commands/
    init.rs        # 主密钥初始化(首次/新设备)
    add.rs         # upsert entries + secrets 行,支持 -o json
    config.rs      # config set-db/show/path
    search.rs      # 多条件查询,展示 secrets schema-f/-o/--summary/--limit/--offset/--sort
    delete.rs      # 删除CASCADE 删除 secrets
    update.rs      # 增量更新tags/metadata + secrets 行级 UPSERT/DELETE
    rollback.rs    # rollback / history按 entry_version 恢复
    run.rs         # inject / run逐字段解密 + key_ref 引用解析
    upgrade.rs     # 从 Gitea Release 自更新
    export_cmd.rs  # export批量导出支持 JSON/TOML/YAML含解密明文
    import_cmd.rs  # import批量导入冲突检测dry-run重新加密写入
scripts/
  setup-gitea-actions.sh  # 配置 Gitea Actions 变量与 Secrets

CI/CDGitea Actions

推送 main 分支时自动fmt/clippy/test 检查 → Linux/macOS/Windows 构建 → 上传二进制与 .sha256 摘要 → 所有平台成功后发布 Release。

首次使用需配置 Actions 变量和 Secrets

# 需有 ~/.config/gitea/config.envGITEA_URL、GITEA_TOKEN、GITEA_WEBHOOK_URL
./scripts/setup-gitea-actions.sh
  • RELEASE_TOKENSecretGitea PAT用于创建 Release 上传二进制
  • WEBHOOK_URLVariable飞书通知可选
  • 注意Secret/Variable 的 data/value 字段需传入原始值,不要 base64 编码

当前 Release 预编译产物覆盖:

  • Linux x86_64-unknown-linux-musl
  • macOS Apple Silicon aarch64-apple-darwin
  • macOS Intel x86_64-apple-darwin(由 ARM mac runner 交叉编译)
  • Windows x86_64-pc-windows-msvc

详见 AGENTS.md

Description
Secrets management project
Readme 4 MiB
2026-04-10 17:14:37 +08:00
Languages
Rust 66%
HTML 29.5%
Shell 2.1%
Python 2%
JavaScript 0.4%