Compare commits
1 Commits
secrets-0.
...
secrets-0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ddafbe4b6 |
@@ -466,7 +466,7 @@ secrets --db-url "postgres://..." search -n refining
|
||||
- 新增 `kind` 类型时:只需在 `add` 调用时传入,无需改代码
|
||||
- 字段命名:CLI 短标志 `-n`=namespace,`-m`=meta,`-s`=secret,`-q`=query,`-v`=verbose,`-f`=field,`-o`=output
|
||||
- 日志:用户可见输出用 `println!`;调试/运维信息用 `tracing::debug!`/`info!`/`warn!`/`error!`
|
||||
- 审计:`add`/`update`/`delete` 成功后调用 `audit::log()`,写入 `audit_log` 表;失败只 warn 不中断
|
||||
- 审计:`add`/`update`/`delete` 成功后调用 `audit::log_tx`,写入 `audit_log` 表;失败只 warn 不中断
|
||||
- 加密:`encrypted` 列存储 AES-256-GCM 密文;`add`/`update`/`search`/`delete` 需主密钥(`secrets init` 后从 OS 钥匙串加载)
|
||||
- 输出:读命令通过 `OutputMode` 支持 text/json/json-compact/env;写命令 `add` 同样支持 `-o json`
|
||||
|
||||
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1836,7 +1836,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "secrets"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "secrets"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
||||
34
src/audit.rs
34
src/audit.rs
@@ -1,5 +1,5 @@
|
||||
use serde_json::Value;
|
||||
use sqlx::{PgPool, Postgres, Transaction};
|
||||
use sqlx::{Postgres, Transaction};
|
||||
|
||||
/// Write an audit entry within an existing transaction.
|
||||
pub async fn log_tx(
|
||||
@@ -30,35 +30,3 @@ pub async fn log_tx(
|
||||
tracing::debug!(action, namespace, kind, name, actor, "audit logged");
|
||||
}
|
||||
}
|
||||
|
||||
/// Write an audit entry using the pool (fire-and-forget, non-fatal).
|
||||
/// Kept for future use or scenarios without an active transaction.
|
||||
#[allow(dead_code)]
|
||||
pub async fn log(
|
||||
pool: &PgPool,
|
||||
action: &str,
|
||||
namespace: &str,
|
||||
kind: &str,
|
||||
name: &str,
|
||||
detail: Value,
|
||||
) {
|
||||
let actor = std::env::var("USER").unwrap_or_default();
|
||||
let result: Result<_, sqlx::Error> = sqlx::query(
|
||||
"INSERT INTO audit_log (action, namespace, kind, name, detail, actor) \
|
||||
VALUES ($1, $2, $3, $4, $5, $6)",
|
||||
)
|
||||
.bind(action)
|
||||
.bind(namespace)
|
||||
.bind(kind)
|
||||
.bind(name)
|
||||
.bind(&detail)
|
||||
.bind(&actor)
|
||||
.execute(pool)
|
||||
.await;
|
||||
|
||||
if let Err(e) = result {
|
||||
tracing::warn!(error = %e, "failed to write audit log");
|
||||
} else {
|
||||
tracing::debug!(action, namespace, kind, name, actor, "audit logged");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,6 @@ use crate::output::OutputMode;
|
||||
#[derive(FromRow)]
|
||||
struct HistoryRow {
|
||||
secret_id: Uuid,
|
||||
#[allow(dead_code)]
|
||||
namespace: String,
|
||||
#[allow(dead_code)]
|
||||
kind: String,
|
||||
#[allow(dead_code)]
|
||||
name: String,
|
||||
version: i64,
|
||||
action: String,
|
||||
tags: Vec<String>,
|
||||
@@ -33,7 +27,7 @@ pub struct RollbackArgs<'a> {
|
||||
pub async fn run(pool: &PgPool, args: RollbackArgs<'_>, master_key: &[u8; 32]) -> Result<()> {
|
||||
let snap: Option<HistoryRow> = if let Some(ver) = args.to_version {
|
||||
sqlx::query_as(
|
||||
"SELECT secret_id, namespace, kind, name, version, action, tags, metadata, encrypted \
|
||||
"SELECT secret_id, version, action, tags, metadata, encrypted \
|
||||
FROM secrets_history \
|
||||
WHERE namespace = $1 AND kind = $2 AND name = $3 AND version = $4 \
|
||||
ORDER BY id DESC LIMIT 1",
|
||||
@@ -46,7 +40,7 @@ pub async fn run(pool: &PgPool, args: RollbackArgs<'_>, master_key: &[u8; 32]) -
|
||||
.await?
|
||||
} else {
|
||||
sqlx::query_as(
|
||||
"SELECT secret_id, namespace, kind, name, version, action, tags, metadata, encrypted \
|
||||
"SELECT secret_id, version, action, tags, metadata, encrypted \
|
||||
FROM secrets_history \
|
||||
WHERE namespace = $1 AND kind = $2 AND name = $3 \
|
||||
ORDER BY id DESC LIMIT 1",
|
||||
|
||||
@@ -105,15 +105,6 @@ pub fn store_master_key(key: &[u8; 32]) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Delete the Master Key from the OS Keychain (used by tests / reset).
|
||||
#[cfg(test)]
|
||||
pub fn delete_master_key() -> Result<()> {
|
||||
let entry =
|
||||
keyring::Entry::new(KEYRING_SERVICE, KEYRING_USER).context("create keychain entry")?;
|
||||
let _ = entry.delete_credential();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ─── Minimal hex helpers (avoid extra dep) ────────────────────────────────────
|
||||
|
||||
mod hex {
|
||||
|
||||
Reference in New Issue
Block a user