#![cfg_attr(
not(test),
deny(clippy::panic, clippy::unwrap_used, clippy::expect_used)
)]
#![deny(missing_docs)]
pub mod secret_key_audit;
pub mod secret_key_lifecycle;
pub mod secret_store_crypto;
pub mod secure_files;
#[cfg(test)]
pub(crate) fn init_test_schema(db_path: &std::path::Path) -> anyhow::Result<()> {
let conn = open_conn(db_path)?;
conn.execute_batch(
r#"
CREATE TABLE IF NOT EXISTS schema_version (
version INTEGER NOT NULL
);
INSERT INTO schema_version (version) VALUES (99);
CREATE TABLE IF NOT EXISTS secret_keys (
key_id TEXT PRIMARY KEY,
state TEXT NOT NULL,
fingerprint TEXT NOT NULL,
file_path TEXT NOT NULL,
created_at TEXT NOT NULL,
activated_at TEXT,
rotated_out_at TEXT,
retired_at TEXT,
revoked_at TEXT
);
CREATE INDEX IF NOT EXISTS idx_secret_keys_state ON secret_keys(state);
CREATE TABLE IF NOT EXISTS secret_key_audit (
id INTEGER PRIMARY KEY AUTOINCREMENT,
event_kind TEXT NOT NULL,
key_id TEXT NOT NULL,
key_fingerprint TEXT NOT NULL,
actor TEXT NOT NULL,
detail_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_secret_key_audit_created ON secret_key_audit(created_at);
CREATE INDEX IF NOT EXISTS idx_secret_key_audit_key_id ON secret_key_audit(key_id, created_at);
CREATE TABLE IF NOT EXISTS resources (
kind TEXT NOT NULL,
project TEXT NOT NULL,
name TEXT NOT NULL,
api_version TEXT NOT NULL,
spec_json TEXT NOT NULL,
metadata_json TEXT NOT NULL,
generation INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
PRIMARY KEY (kind, project, name)
);
CREATE TABLE IF NOT EXISTS resource_versions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
kind TEXT NOT NULL,
project TEXT NOT NULL,
name TEXT NOT NULL,
spec_json TEXT NOT NULL,
metadata_json TEXT NOT NULL DEFAULT '{}',
version INTEGER NOT NULL,
author TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_resource_versions_lookup
ON resource_versions(kind, project, name, version DESC);
"#,
)?;
Ok(())
}
pub(crate) fn now_ts() -> String {
chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true)
}
pub(crate) fn open_conn(db_path: &std::path::Path) -> anyhow::Result<rusqlite::Connection> {
use anyhow::Context;
let conn = rusqlite::Connection::open(db_path).context("failed to open sqlite db")?;
conn.busy_timeout(std::time::Duration::from_millis(5000))
.context("failed to set sqlite busy timeout")?;
conn.execute_batch("PRAGMA foreign_keys = ON;")
.context("failed to configure sqlite pragmas")?;
Ok(conn)
}