lib

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

commit 16ded0a690655fedd6da0e8a427785c6e76098d3
parent 2dd2a8dc1e18f6f1b112be63f8519f529229669f
Author: triesap <tyson@radroots.org>
Date:   Sat,  1 Aug 2026 11:57:44 +0000

secrets: migrate workspace consumers

- activate the final SQLite secrets dependency edge
- quarantine exact publish-frozen predecessor consumers
- enforce package and consumer source boundaries
- record ordered migration and removal gates

Diffstat:
MCargo.lock | 3+++
Acrates/secrets/tests/consumer_migration.rs | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/storage_sqlite/Cargo.toml | 3+++
Acrates/storage_sqlite/tests/package_boundary.rs | 33+++++++++++++++++++++++++++++++++
Mdocs/implementation/DEVIATIONS.md | 1+
Mdocs/implementation/deviations.toml | 26++++++++++++++++++++++++++
6 files changed, 144 insertions(+), 0 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -5126,6 +5126,9 @@ version = "0.1.0-alpha" [[package]] name = "radroots_storage_sqlite" version = "0.1.0-alpha" +dependencies = [ + "radroots_secrets", +] [[package]] name = "radroots_sync" diff --git a/crates/secrets/tests/consumer_migration.rs b/crates/secrets/tests/consumer_migration.rs @@ -0,0 +1,78 @@ +use std::collections::BTreeSet; +use std::fs; +use std::path::{Path, PathBuf}; + +const DEVIATIONS: &str = include_str!("../../../docs/implementation/deviations.toml"); + +#[test] +fn legacy_secret_dependencies_are_confined_to_publish_frozen_quarantines() { + let workspace = Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .and_then(Path::parent) + .expect("workspace root"); + let crates = workspace.join("crates"); + let mut manifests = Vec::new(); + collect_manifests(&crates, &mut manifests); + let mut legacy_consumers = BTreeSet::new(); + + for path in manifests { + let manifest = fs::read_to_string(&path).expect("read package manifest"); + if manifest.contains("radroots_secret_vault") + || manifest.contains("radroots_protected_store") + { + assert!( + manifest.contains("publish = false"), + "legacy secret consumer must remain publish-frozen: {}", + path.display() + ); + let package = package_name(&manifest).expect("package name"); + legacy_consumers.insert(package.to_owned()); + } + } + + assert_eq!( + legacy_consumers, + BTreeSet::from([ + "radroots_nostr_accounts".to_owned(), + "radroots_protected_store".to_owned(), + "radroots_runtime".to_owned(), + "radroots_secret_vault".to_owned(), + "radroots_simplex_agent_store".to_owned(), + ]) + ); +} + +#[test] +fn quarantine_has_exact_future_removal_gates() { + for required in [ + "id = \"RCRV1-DEV-008\"", + "affected_steps = [\"153\", \"155\", \"171\", \"179\", \"226\", \"288\", \"293\", \"313\"]", + "Step 179 transfers canonical private storage", + "Step 313 removes every remaining compatibility package and legacy name", + ] { + assert!( + DEVIATIONS.contains(required), + "secret consumer quarantine is missing `{required}`" + ); + } +} + +fn collect_manifests(root: &Path, manifests: &mut Vec<PathBuf>) { + for entry in fs::read_dir(root).expect("read crates directory") { + let path = entry.expect("crate entry").path(); + if path.is_dir() { + let manifest = path.join("Cargo.toml"); + if manifest.is_file() { + manifests.push(manifest); + } + } + } +} + +fn package_name(manifest: &str) -> Option<&str> { + let package = manifest.split_once("[package]")?.1; + package + .lines() + .skip(1) + .find_map(|line| line.trim().strip_prefix("name = \"")?.strip_suffix('"')) +} diff --git a/crates/storage_sqlite/Cargo.toml b/crates/storage_sqlite/Cargo.toml @@ -14,5 +14,8 @@ publish = false [lib] name = "radroots_storage_sqlite" +[dependencies] +radroots_secrets = { workspace = true, default-features = false } + [lints] workspace = true diff --git a/crates/storage_sqlite/tests/package_boundary.rs b/crates/storage_sqlite/tests/package_boundary.rs @@ -0,0 +1,33 @@ +use std::collections::BTreeSet; + +const MANIFEST: &str = include_str!("../Cargo.toml"); +const ROOT: &str = include_str!("../src/lib.rs"); + +#[test] +fn sqlite_storage_declares_the_final_secret_boundary() { + assert_eq!( + dependency_keys(MANIFEST), + BTreeSet::from(["radroots_secrets"]) + ); + for forbidden in [ + "radroots_protected_store", + "radroots_secret_vault", + "radroots_nostr_accounts", + ] { + assert!(!MANIFEST.contains(forbidden)); + assert!(!ROOT.contains(forbidden)); + } +} + +fn dependency_keys(manifest: &str) -> BTreeSet<&str> { + manifest + .split_once("[dependencies]") + .map(|(_, dependencies)| dependencies) + .unwrap_or_default() + .lines() + .skip(1) + .take_while(|line| !line.starts_with('[')) + .filter_map(|line| line.split_once('=').map(|(key, _)| key.trim())) + .filter(|key| !key.is_empty()) + .collect() +} diff --git a/docs/implementation/DEVIATIONS.md b/docs/implementation/DEVIATIONS.md @@ -14,6 +14,7 @@ silently change `radroots.crates.release.v1`. | `RCRV1-DEV-004` | 098, 155, 225, 260, 268, 294, 298-299, 301-304, 314 | Enforce a temporary 90% four-dimension coverage baseline during heavy development; restore 100% only through a future explicit contract update. | | `RCRV1-DEV-005` | 013, 019-026, 027-315 | Pin every Rust crate and internal Radroots dependency in `radrootslabs/lib` to exactly `0.1.0-alpha` until further explicit authority. | | `RCRV1-DEV-007` | 122, 170, 235, 305 | Remove the predecessor monolithic transport SPI now; quarantine publish-frozen runtime, SDK, CLI, and daemon consumer shims until their explicit removal gates. | +| `RCRV1-DEV-008` | 153, 155, 171, 179, 226, 288, 293, 313 | Activate final secrets dependency edges now; quarantine legacy vault/store consumers until their ordered storage, SDK, downstream, and final-removal gates. | ## Record template diff --git a/docs/implementation/deviations.toml b/docs/implementation/deviations.toml @@ -37,6 +37,32 @@ normative_architecture_change = false adr_required = false [[deviation]] +id = "RCRV1-DEV-008" +date = "2026-08-01" +status = "active" +approval = "All code-review recommendations and the full multi-RCLD implementation sequence were explicitly approved by the user." +affected_steps = ["153", "155", "171", "179", "226", "288", "293", "313"] +spec_anchors = [ + "docs/specs/radroots_crates_release_v1.md#12-radroots_secrets", + "docs/specs/radroots_crates_release_v1.md#20-current-to-target-migration-map", +] +source_evidence = [ + "The final radroots_storage_sqlite scaffold can consume radroots_secrets immediately and has no predecessor secret dependency.", + "Step 179, not Step 153, owns transfer of the current SDK private database and its encrypted records into canonical SQLite storage.", + "Mixed publish-frozen runtime, Nostr-account, SimpleX preview, SDK private-store, Myc, and other external hosts still require predecessor vault/store behavior until their ordered migration steps.", +] +replacement_action = "Activate the final radroots_storage_sqlite and SDK dependency edges in Step 153; confine predecessor vault/store imports to exact publish-frozen quarantine packages and the SDK private-store module; Step 179 transfers canonical private storage, Steps 226/288/293 migrate the remaining SDK and downstream consumers, and Step 313 removes every remaining compatibility package and legacy name." +verification = [ + "Consumer-migration tests enumerate every lib package manifest that still names radroots_secret_vault or radroots_protected_store and reject any unapproved or publishable consumer.", + "Storage SQLite package-boundary tests require radroots_secrets and reject all predecessor secret package names.", + "SDK source-boundary tests confine predecessor imports to private_store.rs and require the final optional radroots_secrets dependency edge.", + "Step 155 release-policy validation keeps every quarantine package non-publishable until its exact removal gate.", +] +unresolved_risk = "Publish-frozen compatibility code remains reachable inside legacy runtime/private-preview paths until Steps 179, 226, 288, 293, and 313; no package-realistic publication may proceed while it remains." +normative_architecture_change = false +adr_required = false + +[[deviation]] id = "RCRV1-DEV-007" date = "2026-07-30" status = "active"