Add local KV store commands

This commit is contained in:
Eric Wendland 2026-05-16 21:52:35 +02:00
commit 1a0f1e7671
14 changed files with 395 additions and 13 deletions

View file

@ -18,6 +18,7 @@ geth-crypto = { path = "../geth-crypto" }
geth-db = { path = "../geth-db" }
geth-iroh = { path = "../geth-iroh" }
geth-keychain = { path = "../geth-keychain" }
geth-kv = { path = "../geth-kv" }
geth-resource = { path = "../geth-resource" }
geth-ssh-identity = { path = "../geth-ssh-identity" }
geth-store = { path = "../geth-store" }

View file

@ -11,6 +11,7 @@ use geth_crypto::AgentKey;
use geth_db::DbResource;
use geth_iroh::{EndpointStatus, GethIrohConfig, GethIrohEndpoint, GethRelayMode};
use geth_keychain::{KeychainOp, KeychainOpKind};
use geth_kv::{KvEntry, KvResource};
use geth_resource::ResourceDescriptor;
use geth_ssh_identity::{
SshCertApproval, SshCertKind, SshCertRequest, SshCertRequestStatus, SshCertificateRecord,
@ -18,8 +19,8 @@ use geth_ssh_identity::{
certificate_id, revocation_id, ssh_public_key_fingerprint,
};
use geth_store::{
Store, StoredAuthOp, StoredDbResource, StoredKeychainOp, StoredResource, StoredSshCertRequest,
StoredSshCertificate, StoredSshRevocation,
Store, StoredAuthOp, StoredDbResource, StoredKeychainOp, StoredKvEntry, StoredKvStore,
StoredResource, StoredSshCertRequest, StoredSshCertificate, StoredSshRevocation,
};
use geth_types::{
AuthOpId, Capability, KeyId, NodeId, PrincipalId, ResourceId, ResourceKind, ResourceName,
@ -53,6 +54,12 @@ pub enum NodeError {
InvalidDbPath(String),
#[error("db resource not found: {0}")]
DbNotFound(String),
#[error("invalid kv store name: {0}")]
InvalidKvName(String),
#[error("invalid kv key: {0}")]
InvalidKvKey(String),
#[error("kv store not found: {0}")]
KvNotFound(String),
#[error("invalid ssh certificate kind: {0}")]
InvalidSshCertKind(String),
#[error("invalid ssh certificate request status: {0}")]
@ -592,6 +599,55 @@ pub fn handle_request(
db: db_resource_from_stored(&stored)?,
})
}
ControlRequest::KvCreate { name } => {
geth_kv::validate_kv_name(&name).map_err(|_| NodeError::InvalidKvName(name.clone()))?;
let resource_id = format!("resource:kv:{name}");
let kv_id = format!("kv:{name}");
let resource = StoredResource {
resource_id: resource_id.clone(),
kind: ResourceKind::Kv.to_string(),
name: name.clone(),
status: "active".to_owned(),
};
store.insert_resource(&resource)?;
let stored = StoredKvStore {
kv_id,
resource_id,
name,
};
store.insert_kv_store(&stored)?;
Ok(ControlResponse::KvCreated {
kv: kv_resource_from_stored(&stored),
})
}
ControlRequest::KvSet { name, key, value } => {
geth_kv::validate_kv_name(&name).map_err(|_| NodeError::InvalidKvName(name.clone()))?;
geth_kv::validate_kv_key(&key).map_err(|_| NodeError::InvalidKvKey(key.clone()))?;
let kv = store
.get_kv_store_by_name(&name)?
.ok_or_else(|| NodeError::KvNotFound(name.clone()))?;
let stored = StoredKvEntry {
kv_id: kv.kv_id,
key,
value,
updated_at_ms: geth_store::now_ms(),
};
store.set_kv_entry(&stored)?;
Ok(ControlResponse::KvSet {
entry: kv_entry_from_stored(stored),
})
}
ControlRequest::KvGet { name, key } => {
geth_kv::validate_kv_name(&name).map_err(|_| NodeError::InvalidKvName(name.clone()))?;
geth_kv::validate_kv_key(&key).map_err(|_| NodeError::InvalidKvKey(key.clone()))?;
let kv = store
.get_kv_store_by_name(&name)?
.ok_or_else(|| NodeError::KvNotFound(name.clone()))?;
let entry = store
.get_kv_entry(&kv.kv_id, &key)?
.map(kv_entry_from_stored);
Ok(ControlResponse::KvGet { entry })
}
ControlRequest::ModuleStub { module, command } => {
Ok(ControlResponse::NotImplemented { module, command })
}
@ -625,6 +681,23 @@ fn db_resource_from_stored(stored: &StoredDbResource) -> Result<DbResource, Node
})
}
fn kv_resource_from_stored(stored: &StoredKvStore) -> KvResource {
KvResource {
id: stored.kv_id.clone().into(),
resource: stored.resource_id.clone().into(),
name: stored.name.clone(),
sync_status: "local-only".to_owned(),
}
}
fn kv_entry_from_stored(stored: StoredKvEntry) -> KvEntry {
KvEntry {
store: stored.kv_id.into(),
key: stored.key,
value: stored.value,
}
}
fn store_auth_op(store: &Store, op: &AuthOp) -> Result<(), NodeError> {
store.insert_auth_op(&StoredAuthOp {
op_id: op.id.to_string(),