mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-01 16:59:21 +00:00
feat(credentials): support managed credential synchronization (#2490)
* feat(credentials): support managed credential synchronization Allow managed callers to upsert credentials with an exact ID, secret, permissions, reuse policy, and expiry. Return non-secret attributes plus a public-key fingerprint so callers can verify relay credential consistency. Persist imported credentials atomically and preserve identity and expiry across restarts. * fix(credentials): make managed upserts durable Write the candidate credential snapshot before committing it to memory. Propagate storage failures so controllers can retry instead of observing false convergence. Cover a transient storage failure to verify that memory stays unchanged and the retry persists the credential. * fix(credentials): atomically replace stored snapshots Define CredentialStorage::store as an atomic replacement boundary and use atomic-write-file in the management adapter. This keeps the last committed credential JSON readable when a replacement fails. Cover replacement of an existing credential snapshot and keep the dependency scoped to the management feature.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
use std::{io::Write, path::PathBuf, sync::Arc};
|
||||
|
||||
use atomic_write_file::AtomicWriteFile;
|
||||
use easytier_core::peers::credential_manager::CredentialStorage;
|
||||
|
||||
struct FileCredentialStorage {
|
||||
@@ -16,7 +17,9 @@ impl CredentialStorage for FileCredentialStorage {
|
||||
}
|
||||
|
||||
fn store(&self, serialized_credentials: &str) -> anyhow::Result<()> {
|
||||
std::fs::write(&self.path, serialized_credentials)?;
|
||||
let mut file = AtomicWriteFile::open(&self.path)?;
|
||||
file.write_all(serialized_credentials.as_bytes())?;
|
||||
file.commit()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -40,9 +43,10 @@ mod tests {
|
||||
|
||||
assert_eq!(storage.load().unwrap(), None);
|
||||
storage.store("{\"credential\":true}").unwrap();
|
||||
storage.store("{\"credential\":false}").unwrap();
|
||||
assert_eq!(
|
||||
storage.load().unwrap().as_deref(),
|
||||
Some("{\"credential\":true}")
|
||||
Some("{\"credential\":false}")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user