lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

commit 0b180bd81b69d5f6e39418808eed39f8937aa524
parent a8487b1d3f5ee1d1086ebd03a91b14e99e303ef2
Author: triesap <tyson@radroots.org>
Date:   Mon, 27 Jul 2026 19:14:15 +0000

identity: remove filesystem and runtime-path behavior

- Delete identity-owned JSON files, default paths, and legacy storage errors.
- Remove runtime, protected-store, path, vault, tracing, and tempfile edges.
- Prove the package manifest and public API exclude host persistence behavior.
- Preserve portable std, serde, no-default, wasm, and documentation coverage.

Diffstat:
MCargo.lock | 6------
Mcrates/identity/Cargo.toml | 23++---------------------
Mcrates/identity/README.md | 3+--
Mcrates/identity/src/error.rs | 32--------------------------------
Mcrates/identity/src/lib.rs | 13+++++++------
Dcrates/identity/src/storage.rs | 87-------------------------------------------------------------------------------
Acrates/identity/tests/package_boundary.rs | 22++++++++++++++++++++++
Mcrates/nostr_accounts/Cargo.toml | 5+----
Mdocs/migration/identity.md | 7++++---
9 files changed, 37 insertions(+), 161 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -4614,15 +4614,9 @@ name = "radroots_identity" version = "0.1.0" dependencies = [ "k256", - "radroots_protected_store", - "radroots_runtime", - "radroots_runtime_paths", - "radroots_secret_vault", "serde", "serde_json", - "tempfile", "thiserror 2.0.18", - "tracing", ] [[package]] diff --git a/crates/identity/Cargo.toml b/crates/identity/Cargo.toml @@ -16,36 +16,17 @@ readme = "README.md" name = "radroots_identity" [features] -default = ["std", "serde", "json-file"] -std = [ - "dep:radroots_protected_store", - "dep:radroots_runtime_paths", - "dep:radroots_secret_vault", - "dep:serde_json", - "dep:tracing", - "thiserror/std", -] +default = ["std", "serde"] +std = ["thiserror/std"] serde = ["dep:serde"] -json-file = ["std", "serde", "dep:radroots_runtime"] [dependencies] k256 = { version = "0.13", default-features = false, features = ["arithmetic"] } -radroots_runtime = { workspace = true, optional = true } -radroots_protected_store = { workspace = true, optional = true, features = [ - "std", -] } -radroots_runtime_paths = { workspace = true, optional = true } -radroots_secret_vault = { workspace = true, optional = true, features = [ - "std", -] } serde = { workspace = true, optional = true } -serde_json = { workspace = true, optional = true } thiserror = { version = "2", default-features = false } -tracing = { workspace = true, optional = true } [dev-dependencies] serde_json = { workspace = true, features = ["std"] } -tempfile = { workspace = true } [lints] workspace = true diff --git a/crates/identity/README.md b/crates/identity/README.md @@ -8,8 +8,7 @@ account, and profile value types for the Radroots package family. * validated canonical public keys, identity IDs, and account IDs; * public identity profiles and normalized usernames; * no raw secret keys, key generation, nsec/NIP-49 helpers, or secret export; - * transitional public-profile JSON file helpers pending their extraction to - the host storage layer. + * no filesystem, runtime-path, protected-store, or secret-vault behavior. See `docs/migration/identity.md` in the repository for the approved signing, Nostr-key, secrets, and storage ownership boundaries. diff --git a/crates/identity/src/error.rs b/crates/identity/src/error.rs @@ -1,10 +1,5 @@ use thiserror::Error; -#[cfg(all(feature = "std", feature = "json-file"))] -use radroots_runtime::RuntimeJsonError; -#[cfg(feature = "std")] -use std::{io, path::PathBuf}; - /// Errors produced while validating public identity values. #[non_exhaustive] #[derive(Debug, Error)] @@ -39,30 +34,3 @@ pub enum Error { #[error("username dots cannot be leading, trailing, or consecutive")] InvalidUsernameDotPlacement, } - -/// Transitional errors from the legacy filesystem identity API. -#[cfg(feature = "std")] -#[derive(Debug, Error)] -pub enum IdentityError { - #[error("identity file missing at {0}")] - NotFound(PathBuf), - - #[error("failed to read identity file at {0}: {1}")] - Read(PathBuf, #[source] io::Error), - - #[error("failed to create identity directory {0}: {1}")] - CreateDir(PathBuf, #[source] io::Error), - - #[error("failed to write identity file at {0}: {1}")] - Write(PathBuf, #[source] io::Error), - - #[error("invalid identity JSON: {0}")] - InvalidJson(#[from] serde_json::Error), - - #[cfg(feature = "json-file")] - #[error(transparent)] - Store(#[from] RuntimeJsonError), - - #[error(transparent)] - Paths(#[from] radroots_runtime_paths::RadrootsRuntimePathsError), -} diff --git a/crates/identity/src/lib.rs b/crates/identity/src/lib.rs @@ -1,6 +1,13 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(coverage_nightly, feature(coverage_attribute))] #![forbid(unsafe_code)] +//! Portable public identity and account values. +//! +//! Host filesystem and runtime-path APIs are intentionally absent: +//! +//! ```compile_fail +//! use radroots_identity::{storage, IdentityError}; +//! ``` extern crate alloc; @@ -8,16 +15,10 @@ pub mod account; pub mod error; pub mod key; pub mod profile; -#[cfg(feature = "json-file")] -pub mod storage; pub mod username; pub use account::AccountId; pub use error::Error; -#[cfg(feature = "std")] -pub use error::IdentityError; pub use key::{IdentityId, PublicKey}; pub use profile::{Profile, PublicIdentity}; -#[cfg(feature = "json-file")] -pub use storage::{load_identity_profile, store_identity_profile}; pub use username::Username; diff --git a/crates/identity/src/storage.rs b/crates/identity/src/storage.rs @@ -1,87 +0,0 @@ -//! Transitional filesystem helpers for public profile snapshots. -//! -//! Filesystem ownership is removed from this package in the next ordered -//! migration checkpoint. - -use std::{fs, path::Path}; - -use crate::{IdentityError, PublicIdentity}; - -/// Stores a validated public identity profile as JSON. -pub fn store_identity_profile( - path: impl AsRef<Path>, - identity: &PublicIdentity, -) -> Result<(), IdentityError> { - store_identity_profile_path(path.as_ref(), identity) -} - -fn store_identity_profile_path( - path: &Path, - identity: &PublicIdentity, -) -> Result<(), IdentityError> { - if let Some(parent) = path.parent().filter(|value| !value.as_os_str().is_empty()) { - fs::create_dir_all(parent) - .map_err(|source| IdentityError::CreateDir(parent.to_path_buf(), source))?; - } - let encoded = serde_json::to_vec_pretty(identity)?; - fs::write(path, encoded).map_err(|source| IdentityError::Write(path.to_path_buf(), source)) -} - -/// Loads and revalidates a public identity profile from JSON. -pub fn load_identity_profile(path: impl AsRef<Path>) -> Result<PublicIdentity, IdentityError> { - load_identity_profile_path(path.as_ref()) -} - -fn load_identity_profile_path(path: &Path) -> Result<PublicIdentity, IdentityError> { - let encoded = fs::read(path).map_err(|source| { - if source.kind() == std::io::ErrorKind::NotFound { - IdentityError::NotFound(path.to_path_buf()) - } else { - IdentityError::Read(path.to_path_buf(), source) - } - })?; - serde_json::from_slice(&encoded).map_err(IdentityError::from) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{Profile, PublicKey, Username}; - - const ALICE: &str = "585591529da0bab31b3b1b1f986611cf5f435dca84f978c89ee8a40cca7103df"; - - fn fixture_identity() -> PublicIdentity { - PublicIdentity::new(PublicKey::from_hex(ALICE).unwrap()) - .with_profile(Profile::new().with_username(Username::parse("alice.farm").unwrap())) - } - - #[test] - fn public_profile_file_round_trip_revalidates_identity() { - let directory = tempfile::tempdir().unwrap(); - let path = directory.path().join("profiles/alice.json"); - let identity = fixture_identity(); - - store_identity_profile(&path, &identity).unwrap(); - assert_eq!(load_identity_profile(&path).unwrap(), identity); - } - - #[test] - fn public_profile_file_rejects_mismatched_or_missing_data() { - let directory = tempfile::tempdir().unwrap(); - let path = directory.path().join("alice.json"); - let mut value = serde_json::to_value(fixture_identity()).unwrap(); - value["id"] = serde_json::Value::String( - "e0266e3cfb0d2886f91c73f5f868f3b98273713e5fcd97c081663f5518a4b3af".into(), - ); - fs::write(&path, serde_json::to_vec(&value).unwrap()).unwrap(); - - assert!(matches!( - load_identity_profile(&path), - Err(IdentityError::InvalidJson(_)) - )); - assert!(matches!( - load_identity_profile(directory.path().join("missing.json")), - Err(IdentityError::NotFound(_)) - )); - } -} diff --git a/crates/identity/tests/package_boundary.rs b/crates/identity/tests/package_boundary.rs @@ -0,0 +1,22 @@ +const MANIFEST: &str = include_str!("../Cargo.toml"); + +#[test] +fn manifest_has_no_host_persistence_feature_or_dependency() { + for forbidden in [ + "json-file", + "radroots_protected_store", + "radroots_runtime", + "radroots_runtime_paths", + "radroots_secret_vault", + "tracing", + "tempfile", + ] { + assert!( + !MANIFEST.contains(forbidden), + "identity manifest must not contain host persistence edge {forbidden}" + ); + } + + assert!(MANIFEST.contains("default = [\"std\", \"serde\"]")); + assert!(MANIFEST.contains("std = [\"thiserror/std\"]")); +} diff --git a/crates/nostr_accounts/Cargo.toml b/crates/nostr_accounts/Cargo.toml @@ -29,10 +29,7 @@ os-keyring = ["std", "radroots_secret_vault/os-keyring"] nostrdb-bridge = ["std", "dep:radroots_nostrdb"] [dependencies] -radroots_identity = { workspace = true, optional = true, default-features = false, features = [ - "std", - "json-file", -] } +radroots_identity = { workspace = true, optional = true, default-features = false, features = ["std"] } radroots_nostr_signer = { workspace = true, optional = true } radroots_nostrdb = { workspace = true, optional = true, default-features = false, features = [ "nostrdb", diff --git a/docs/migration/identity.md b/docs/migration/identity.md @@ -19,6 +19,7 @@ The approved destination boundaries are: `radroots_storage_sqlite` for durable secret persistence. Those destination APIs are introduced by their ordered release checkpoints. -Until then, callers must not recreate secret ownership in `radroots_identity` -or add a compatibility shim. Public identity profile file helpers remain only -for the immediately following filesystem-extraction checkpoint. +Until then, callers must not recreate secret ownership or persistence in +`radroots_identity` or add a compatibility shim. The former identity/profile +file helpers, default paths, runtime-path resolution, and encrypted storage +APIs have been removed from this package.