Some checks failed
Secrets CLI - Build & Release / 探测 Runner (push) Successful in 1s
Secrets CLI - Build & Release / 版本 & Release (push) Successful in 3s
Secrets CLI - Build & Release / 质量检查 (fmt / clippy / test) (push) Failing after 21s
Secrets CLI - Build & Release / Build (x86_64-unknown-linux-musl) (push) Has been skipped
Secrets CLI - Build & Release / Build (aarch64-apple-darwin) (push) Has been skipped
Secrets CLI - Build & Release / 发布草稿 Release (push) Has been cancelled
Secrets CLI - Build & Release / 通知 (push) Has been cancelled
Secrets CLI - Build & Release / Build (x86_64-pc-windows-msvc) (push) Has been cancelled
- add secrets update: incremental merge for tags/metadata/encrypted - AGENTS.md: 提交前检查增加版本号与 git tag 说明 - README/AGENTS: update 命令文档与示例 - Cargo.toml 0.1.0 -> 0.2.0 (secrets-0.1.0 已存在) Made-with: Cursor
7.0 KiB
7.0 KiB
Secrets CLI — AGENTS.md
跨设备密钥与配置管理 CLI 工具,将 refining / ricnsmart 两个项目的服务器信息、服务凭据存储到 PostgreSQL 18,供 AI 工具读取上下文。
项目结构
secrets/
src/
main.rs # CLI 入口,clap 命令定义,auto-migrate
db.rs # PgPool 创建 + 建表/索引(幂等)
models.rs # Secret 结构体(sqlx::FromRow + serde)
commands/
add.rs # add 命令:upsert,支持 --meta key=value / --secret key=@file
search.rs # search 命令:多条件动态查询
delete.rs # delete 命令
scripts/
seed-data.sh # 从 refining/ricnsmart config.toml 导入全量数据
.gitea/workflows/
secrets.yml # CI:fmt + clippy + musl 构建 + Release 上传 + 飞书通知
.vscode/tasks.json # 本地测试任务(build / search / add+delete roundtrip 等)
.env # DATABASE_URL(gitignore,不提交)
数据库
- Host:
47.117.131.22:5432(阿里云上海 ECS,PostgreSQL 18 with io_uring) - Database:
secrets - 连接串:
postgres://postgres:<password>@47.117.131.22:5432/secrets - 表: 单张
secrets表,首次连接自动建表(auto-migrate)
表结构
secrets (
id UUID PRIMARY KEY DEFAULT uuidv7(), -- PG18 时间有序 UUID
namespace VARCHAR(64) NOT NULL, -- 一级隔离: "refining" | "ricnsmart"
kind VARCHAR(64) NOT NULL, -- 类型: "server" | "service"(可扩展)
name VARCHAR(256) NOT NULL, -- 人类可读标识
tags TEXT[] NOT NULL DEFAULT '{}', -- 灵活标签: ["aliyun","hongkong"]
metadata JSONB NOT NULL DEFAULT '{}', -- 明文描述: ip, desc, domains, location...
encrypted JSONB NOT NULL DEFAULT '{}', -- 敏感数据: ssh_key, password, token...
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(namespace, kind, name)
)
字段职责划分
| 字段 | 存什么 | 示例 |
|---|---|---|
namespace |
项目/团队隔离 | refining, ricnsmart |
kind |
记录类型 | server, service |
name |
唯一标识名 | i-uf63f2uookgs5uxmrdyc, gitea |
tags |
多维分类标签 | ["aliyun","hongkong","ricn"] |
metadata |
明文非敏感信息 | {"ip":"47.243.154.187","desc":"Grafana","domains":["..."]} |
encrypted |
敏感凭据(MVP 阶段明文存储,后续对 value 加密) | {"ssh_key":"-----BEGIN...","password":"..."} |
CLI 命令
# 查看版本
secrets -V / --version
# 查看帮助
secrets -h / --help
secrets help <subcommand> # 子命令详细帮助,如 secrets help add
# 添加或更新记录(upsert)
secrets add -n <namespace> --kind <kind> --name <name> \
[--tag <tag>]... # 可重复
[-m key=value]... # --meta 明文字段,-m 是短标志
[-s key=value]... # --secret 敏感字段,value 以 @ 开头表示从文件读取
# 搜索(默认隐藏 encrypted 内容)
secrets search [-n <namespace>] [--kind <kind>] [--tag <tag>] [-q <keyword>] [--show-secrets]
# -q 匹配范围:name、namespace、kind、metadata 全文内容、tags
# 增量更新已有记录(合并语义,记录不存在则报错)
secrets update -n <namespace> --kind <kind> --name <name> \
[--add-tag <tag>]... # 添加标签(不影响已有标签)
[--remove-tag <tag>]... # 移除标签
[-m key=value]... # 新增或覆盖 metadata 字段(不影响其他字段)
[--remove-meta <key>]... # 删除 metadata 字段
[-s key=value]... # 新增或覆盖 encrypted 字段(不影响其他字段)
[--remove-secret <key>]... # 删除 encrypted 字段
# 删除
secrets delete -n <namespace> --kind <kind> --name <name>
示例
# 添加服务器
secrets add -n refining --kind server --name i-uf63f2uookgs5uxmrdyc \
--tag aliyun --tag shanghai \
-m ip=47.117.131.22 -m desc="Aliyun Shanghai ECS" \
-s username=root -s ssh_key=@./keys/voson_shanghai_e.pem
# 添加服务凭据
secrets add -n refining --kind service --name gitea \
--tag gitea \
-m url=https://gitea.refining.dev \
-s token=<token>
# 搜索含 mqtt 的所有记录
secrets search -q mqtt
# 查看 refining 的全部服务配置(显示 secrets)
secrets search -n refining --kind service --show-secrets
# 按 tag 筛选
secrets search --tag hongkong
# 只更新一个 IP(不影响其他 metadata/secrets/tags)
secrets update -n refining --kind server --name i-uf63f2uookgs5uxmrdyc \
-m ip=10.0.0.1
# 给一条记录新增 tag 并轮换密码
secrets update -n refining --kind service --name gitea \
--add-tag production \
-s token=<new-token>
# 移除一个废弃的 metadata 字段
secrets update -n refining --kind service --name mqtt \
--remove-meta old_port
代码规范
- 错误处理:统一使用
anyhow::Result,不用unwrap() - 异步:全程
tokio,数据库操作sqlxasync - SQL:使用
sqlx::query/sqlx::query_as绑定参数,禁止字符串拼接(搜索的动态 WHERE 子句除外,需使用参数绑定$1/$2) - 新增
kind类型时:只需在add调用时传入,无需改代码 - 字段命名:CLI 短标志
-n=namespace,-m=meta,-s=secret,-q=query
提交前检查(必须全部通过)
每次提交代码前,请在本地依次执行以下检查,全部通过后再 push:
1. 版本号(按需)
若本次改动需要发版,请先确认 Cargo.toml 中的 version 已提升,避免 CI 打出的 Tag 与已有版本重复。可通过 git tag 判断:
# 查看当前 Cargo.toml 版本
grep '^version' Cargo.toml
# 查看是否已存在该版本对应的 tag(CI 使用格式 secrets-<version>)
git tag -l 'secrets-*'
若当前版本已被 tag(例如已有 secrets-0.1.0 且 Cargo.toml 仍为 0.1.0),则应在 Cargo.toml 中 bump 版本号后再提交,以便 CI 自动打新 Tag 并发布 Release。
2. 格式、Lint、测试
cargo fmt -- --check # 格式检查(不通过则运行 cargo fmt 修复)
cargo clippy -- -D warnings # Lint 检查(消除所有 warning)
cargo test # 单元/集成测试
或一次性执行:
cargo fmt -- --check && cargo clippy -- -D warnings && cargo test
CI/CD
- Gitea Actions(runner: debian)
- 触发:
src/**、Cargo.toml、Cargo.lock变更推送到 main - 构建目标:
x86_64-unknown-linux-musl(静态链接,无 glibc 依赖) - 新版本自动打 Tag(格式
secrets-<version>)并上传二进制到 Gitea Release - 通知:飞书 Webhook(
vars.WEBHOOK_URL) - 所需 secrets/vars:
RELEASE_TOKEN(Release 上传,Gitea PAT)、vars.WEBHOOK_URL(通知,可选)
环境变量
| 变量 | 说明 |
|---|---|
DATABASE_URL |
PostgreSQL 连接串,优先级高于 --db-url 参数 |