Files
secrets/AGENTS.md
voson 535683b15c
Some checks failed
Secrets CLI - Build & Release / 版本 & Release (push) Successful in 3s
Secrets CLI - Build & Release / 质量检查 (fmt / clippy / test) (push) Successful in 1m17s
Secrets CLI - Build & Release / 通知 (push) Successful in 6s
Secrets CLI - Build & Release / 发布草稿 Release (push) Has been cancelled
Secrets CLI - Build & Release / Build (aarch64-apple-darwin) (push) Has started running
Secrets CLI - Build & Release / Build (x86_64-pc-windows-msvc) (push) Has been cancelled
Secrets CLI - Build & Release / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
feat: 添加结构化日志与审计
- tracing + tracing-subscriber,全局 --verbose/-v 与 RUST_LOG 控制
- 新增 audit_log 表,add/update/delete 成功后自动写入审计记录
- 新增 src/audit.rs,审计失败仅 warn 不中断主流程
- 更新 README/AGENTS.md,补充 verbose、audit_log 说明
- .vscode/tasks.json 增加 verbose/update/audit 测试任务

Made-with: Cursor
2026-03-18 16:30:42 +08:00

9.1 KiB
Raw Blame History

Secrets CLI — AGENTS.md

跨设备密钥与配置管理 CLI 工具,将 refining / ricnsmart 两个项目的服务器信息、服务凭据存储到 PostgreSQL 18供 AI 工具读取上下文。

项目结构

secrets/
  src/
    main.rs              # CLI 入口clap 命令定义auto-migrate--verbose 全局参数
    config.rs            # 配置读写:~/.config/secrets/config.tomldatabase_url
    db.rs                # PgPool 创建 + 建表/索引(幂等,含 audit_log
    models.rs            # Secret 结构体sqlx::FromRow + serde
    audit.rs             # 审计写入:向 audit_log 表记录所有写操作
    commands/
      add.rs             # add 命令upsert支持 --meta key=value / --secret key=@file
      config.rs          # config 命令set-db / show / path持久化 database_url
      search.rs          # search 命令:多条件动态查询
      delete.rs          # delete 命令
      update.rs          # update 命令:增量更新(合并 tags/metadata/encrypted
  scripts/
    seed-data.sh         # 从 refining/ricnsmart config.toml 导入全量数据
  .gitea/workflows/
    secrets.yml          # CIfmt + clippy + musl 构建 + Release 上传 + 飞书通知
  .vscode/tasks.json     # 本地测试任务build / config / search / add+delete / update / audit 等)

数据库

  • Host: 47.117.131.22:5432(阿里云上海 ECSPostgreSQL 18 with io_uring
  • Database: secrets
  • 连接串: postgres://postgres:<password>@47.117.131.22:5432/secrets
  • : secrets(主表)+ audit_log审计表首次连接自动建表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)
)

audit_log 表结构

audit_log (
  id          BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  action      VARCHAR(32)   NOT NULL,              -- 'add' | 'update' | 'delete'
  namespace   VARCHAR(64)   NOT NULL,
  kind        VARCHAR(64)   NOT NULL,
  name        VARCHAR(256)  NOT NULL,
  detail      JSONB         NOT NULL DEFAULT '{}', -- 变更摘要tags/meta keys/secret keys不含 value
  actor       VARCHAR(128)  NOT NULL DEFAULT '',    -- 操作者($USER 环境变量)
  created_at  TIMESTAMPTZ   NOT NULL DEFAULT NOW()
)

字段职责划分

字段 存什么 示例
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":"..."}

数据库配置

首次使用需显式配置数据库连接,设置一次后在该设备上持久生效:

secrets config set-db "postgres://postgres:<password>@47.117.131.22:5432/secrets"
secrets config show    # 查看当前配置(密码脱敏)
secrets config path   # 打印配置文件路径

配置文件:~/.config/secrets/config.toml,权限 0600。--db-url 参数可一次性覆盖。

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

# 开启 debug 级别日志(全局参数,位于子命令之前)
secrets --verbose <subcommand>
secrets -v <subcommand>
# 或通过环境变量控制RUST_LOG=secrets=trace secrets search

# 增量更新已有记录(合并语义,记录不存在则报错)
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>

# 配置(持久化 database_url设置一次即可
secrets config set-db <url>
secrets config show
secrets config path

示例

# 添加服务器
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,数据库操作 sqlx async
  • SQL使用 sqlx::query / sqlx::query_as 绑定参数,禁止字符串拼接(搜索的动态 WHERE 子句除外,需使用参数绑定 $1/$2
  • 新增 kind 类型时:只需在 add 调用时传入,无需改代码
  • 字段命名CLI 短标志 -n=namespace-m=meta-s=secret-q=query-v=verbose
  • 日志:用户可见输出用 println!;调试/运维信息用 tracing::debug!/info!/warn!/error!
  • 审计:add/update/delete 成功后调用 audit::log(),写入 audit_log 表;失败只 warn 不中断

提交前检查(必须全部通过)

每次提交代码前,请在本地依次执行以下检查,全部通过后再 push

1. 版本号(按需)

若本次改动需要发版,请先确认 Cargo.toml 中的 version 已提升,避免 CI 打出的 Tag 与已有版本重复。可通过 git tag 判断:

# 查看当前 Cargo.toml 版本
grep '^version' Cargo.toml

# 查看是否已存在该版本对应的 tagCI 使用格式 secrets-<version>
git tag -l 'secrets-*'

若当前版本已被 tag例如已有 secrets-0.1.0Cargo.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 Actionsrunner: debian
  • 触发:src/**Cargo.tomlCargo.lock 变更推送到 main
  • 构建目标:x86_64-unknown-linux-musl(静态链接,无 glibc 依赖)
  • 新版本自动打 Tag格式 secrets-<version>)并上传二进制到 Gitea Release
  • 通知:飞书 Webhookvars.WEBHOOK_URL
  • 所需 secrets/varsRELEASE_TOKENRelease 上传Gitea PATvars.WEBHOOK_URL(通知,可选)

环境变量

变量 说明
RUST_LOG 日志级别,如 secrets=debugsecrets=trace(默认 warn
USER 审计日志 actor 字段来源Shell 自动设置,通常无需手动配置

数据库连接通过 secrets config set-db 持久化到 ~/.config/secrets/config.toml,不支持环境变量。