Skip to main content

RegistryService

Struct RegistryService 

Source
pub struct RegistryService<M, S, A, C, I>{ /* private fields */ }
Expand description

Composed registry orchestration.

Generic over the five infrastructure traits so tests can substitute fast, deterministic backends; production binaries wire the SQLCipher / OsKeyring / SystemClock / UuidV4IdGenerator quartet.

See evault-store-memory/tests/registry_service.rs for a full example exercising the public API with the in-memory backends.

Implementations§

Source§

impl<M, S, A> RegistryService<M, S, A, SystemClock, UuidV4IdGenerator>

Source

pub const fn with_defaults(metadata: M, secrets: S, audit: A) -> Self

Construct a registry with the default real-time clock and v4 UUID generator.

Convenience wrapper around Self::new for production wiring.

Source§

impl<M, S, A, C, I> RegistryService<M, S, A, C, I>

Source

pub const fn new(metadata: M, secrets: S, audit: A, clock: C, id_gen: I) -> Self

Construct a registry from its trait dependencies.

Source

pub fn create_var( &self, name: &str, group: Group, kind: VarKind, value: SecretString, ) -> Result<VarId, CoreError>

Create a new variable, route its value to the correct storage tier, and emit an audit entry.

The name is validated, then uniqueness is checked. If both succeed, the variable’s id is generated through the injected IdGenerator and its timestamps through the injected Clock.

§Atomicity (v1)

The implementation performs a best-effort compensation on value-tier failure: if the metadata row was written and the value write then fails, the metadata row is rolled back so the name is not permanently reserved. A failure of the audit append after a successful create is not compensated — the variable exists, only the audit row is missing — and surfaces as CoreError::Metadata. Full cross-tier atomic commit is on the roadmap for the SQLCipher backend.

§Errors

Returns CoreError::Metadata for validation, uniqueness, or storage failures; CoreError::Secret if writing to the secret store fails. Empty value is rejected with MetadataError::Invalid.

Source

pub fn update_value( &self, id: VarId, value: SecretString, ) -> Result<(), CoreError>

Update the value of an existing variable.

Routes the new value to the same storage tier the variable was created with. The metadata record’s length is refreshed but the kind is preserved.

The value-tier write happens before the metadata length update so that a partial failure cannot leave metadata advertising a length that no value in storage actually has.

§Atomicity (v1)

The kind on the metadata record is trusted to route the write. If the metadata is corrupted with a kind that disagrees with the actual stored value, this method will route to the corrupted kind’s tier and may leak the prior value to the opposite tier. Subsequent get_value calls then surface CoreError::TierMismatch. Hardening this path (probe-and-clear the opposite tier defensively) is scheduled for the v1.1 SQLCipher landing.

A failure of the audit append after a successful value write is reported as an error but the value is persisted; same v1 limitation as documented on Self::create_var.

§Errors

Returns MetadataError::VarNotFound if the variable does not exist, MetadataError::Invalid if the value is empty, or any error from the underlying storage tier.

Source

pub fn get_value(&self, id: VarId) -> Result<Option<SecretString>, CoreError>

Retrieve the value of a variable regardless of storage tier.

If the metadata record claims one VarKind but the value is found in the opposite tier, this method returns CoreError::TierMismatch rather than silently treating the situation as “value missing”. This surfaces corruption that bypassed the service layer’s normal routing.

§Errors

Returns any propagated storage error. Returns CoreError::TierMismatch when the variable’s metadata kind disagrees with where the value actually lives (corruption detection). Returns Ok(None) if the variable does not exist or has no value in either tier.

Source

pub fn get_var(&self, id: VarId) -> Result<Option<Var>, CoreError>

Fetch a variable by id.

§Errors

Propagates storage failures.

Source

pub fn find_var_by_name(&self, name: &str) -> Result<Option<Var>, CoreError>

Fetch a variable by name.

§Errors

Propagates storage failures.

Source

pub fn list_vars(&self, filter: &VarFilter) -> Result<Vec<Var>, CoreError>

List every variable matching the supplied filter.

§Errors

Propagates storage failures.

Source

pub fn delete_var(&self, id: VarId) -> Result<(), CoreError>

Delete a variable and every value stored for it across all tiers. Idempotent: deleting an absent variable is a successful no-op.

Order of operations: metadata first (cascading plain values + links), then a defensive secrets.delete for both kinds. The metadata-first order guarantees that a transient secret-tier failure cannot leave a “zombie” variable that the user can see but never read; the defensive secret delete on Plain kind closes a corruption-recovery path. A secret-tier failure after metadata has been deleted is returned to the caller but the variable is, from any reader’s perspective, gone.

§Errors

Propagates storage failures.

Source

pub fn create_project( &self, name: impl Into<String>, path: PathBuf, ) -> Result<ProjectId, CoreError>

Create a new project.

§Errors

Propagates storage failures.

Source

pub fn get_project(&self, id: ProjectId) -> Result<Option<Project>, CoreError>

Fetch a project by id.

§Errors

Propagates storage failures.

Source

pub fn list_projects(&self) -> Result<Vec<Project>, CoreError>

List every project, sorted by the backend’s contract (usually by name for deterministic output).

§Errors

Propagates storage failures.

Source

pub fn delete_project(&self, id: ProjectId) -> Result<(), CoreError>

Delete a project and every linkage it owns.

§Errors

Propagates storage failures.

Link a variable to a project under the given profile, optionally renaming it for the project’s context.

§Errors

Returns MetadataError::ProjectNotFound or MetadataError::VarNotFound if either side is missing.

Remove a linkage. Idempotent: removing an absent link is Ok(()).

Emits an AuditAction::Unlinked entry only when a linkage was actually removed. A call on an absent triple is a successful no-op and is not audited (avoids audit-log pollution that would degrade forensic value).

§Atomicity (v1)

A failure of the audit append after a successful linkage removal is surfaced as an error but the linkage is gone. Callers should not retry, since a retry of unlink_var would return Ok(()) (the triple is now absent). Same v1 limitation as Self::create_var; a dedicated AuditWriteFailed variant is scheduled for v1.1.

§Errors

Propagates storage failures.

Every linkage owned by a project.

§Errors

Propagates storage failures.

Every linkage that references a given variable.

§Errors

Propagates storage failures.

Source

pub fn recent_audit(&self, limit: usize) -> Result<Vec<AuditEntry>, CoreError>

Return the newest limit audit entries.

§Errors

Propagates storage failures.

Auto Trait Implementations§

§

impl<M, S, A, C, I> Freeze for RegistryService<M, S, A, C, I>
where M: Freeze, S: Freeze, A: Freeze, C: Freeze, I: Freeze,

§

impl<M, S, A, C, I> RefUnwindSafe for RegistryService<M, S, A, C, I>

§

impl<M, S, A, C, I> Send for RegistryService<M, S, A, C, I>

§

impl<M, S, A, C, I> Sync for RegistryService<M, S, A, C, I>

§

impl<M, S, A, C, I> Unpin for RegistryService<M, S, A, C, I>
where M: Unpin, S: Unpin, A: Unpin, C: Unpin, I: Unpin,

§

impl<M, S, A, C, I> UnsafeUnpin for RegistryService<M, S, A, C, I>

§

impl<M, S, A, C, I> UnwindSafe for RegistryService<M, S, A, C, I>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.