pub struct Client { /* private fields */ }Expand description
XJP Secret Store client
The main client for interacting with the XJP Secret Store API. Provides methods for managing secrets, including get, put, delete, and batch operations. Supports caching, retries, and conditional requests.
Implementations§
Source§impl Client
impl Client
Sourcepub fn cache_stats(&self) -> &CacheStats
pub fn cache_stats(&self) -> &CacheStats
Get cache statistics
Returns statistics about the cache including hit rate, number of hits/misses, and evictions. Useful for monitoring cache performance.
§Example
let stats = client.cache_stats();
println!("Cache hit rate: {:.2}%", stats.hit_rate());
println!("Total hits: {}, misses: {}", stats.hits(), stats.misses());Sourcepub fn clear_cache(&self)
pub fn clear_cache(&self)
Clear the cache
Removes all entries from the cache and resets cache statistics. This is useful when you need to force fresh data retrieval.
§Example
// Clear all cached secrets
client.clear_cache();Sourcepub async fn invalidate_cache(&self, namespace: &str, key: &str)
pub async fn invalidate_cache(&self, namespace: &str, key: &str)
Invalidate a specific cache entry
Removes a single secret from the cache, forcing the next retrieval to fetch fresh data from the server.
§Arguments
namespace- The namespace of the secretkey- The key of the secret
§Example
// Invalidate a specific secret from cache
client.invalidate_cache("production", "api-key").await;Sourcepub async fn get_secret(
&self,
namespace: &str,
key: &str,
opts: GetOpts,
) -> Result<Secret>
pub async fn get_secret( &self, namespace: &str, key: &str, opts: GetOpts, ) -> Result<Secret>
Get a secret from the store
Retrieves a secret value from the specified namespace and key. Supports caching and conditional requests via ETags.
§Arguments
namespace- The namespace containing the secretkey- The key identifying the secretopts- Options controlling cache usage and conditional requests
§Returns
The secret value with metadata on success, or an error if the secret doesn’t exist or access is denied.
§Errors
Error::Httpwith status 404 if the secret doesn’t existError::Httpwith status 403 if access is deniedError::Httpwith status 401 if authentication failsError::Networkfor connection issuesError::Timeoutif the request times out
§Example
// Simple get with default options (cache enabled)
let secret = client.get_secret("production", "database-url", GetOpts::default()).await?;
println!("Secret version: {}", secret.version);
// Get without cache
let opts = GetOpts { use_cache: false, ..Default::default() };
let fresh_secret = client.get_secret("production", "api-key", opts).await?;
// Conditional get with ETag
let opts = GetOpts {
if_none_match: Some(secret.etag.unwrap()),
..Default::default()
};
match client.get_secret("production", "database-url", opts).await {
Ok(updated) => println!("Secret was updated"),
Err(e) if e.status_code() == Some(304) => println!("Not modified"),
Err(e) => return Err(e.into()),
}Sourcepub async fn put_secret(
&self,
namespace: &str,
key: &str,
value: impl Into<String>,
opts: PutOpts,
) -> Result<PutResult>
pub async fn put_secret( &self, namespace: &str, key: &str, value: impl Into<String>, opts: PutOpts, ) -> Result<PutResult>
Put a secret into the store
Creates or updates a secret in the specified namespace. Automatically invalidates any cached value for this key.
§Arguments
namespace- The namespace to store the secret inkey- The key for the secretvalue- The secret value (will be securely stored)opts- Options including TTL, metadata, and idempotency key
§Returns
A PutResult containing the operation details and timestamp.
§Security
The secret value is transmitted over HTTPS and stored encrypted.
The SDK uses the secrecy crate to prevent accidental exposure
of secret values in logs or debug output.
§Example
// Simple put
client.put_secret("production", "new-key", "secret-value", PutOpts::default()).await?;
// Put with TTL and metadata
let opts = PutOpts {
ttl_seconds: Some(3600), // Expires in 1 hour
metadata: Some(json!({
"owner": "backend-team",
"rotation_date": "2024-12-01"
})),
idempotency_key: Some("deploy-12345".to_string()),
};
client.put_secret("production", "api-key", "new-api-key", opts).await?;Sourcepub async fn delete_secret(
&self,
namespace: &str,
key: &str,
) -> Result<DeleteResult>
pub async fn delete_secret( &self, namespace: &str, key: &str, ) -> Result<DeleteResult>
Delete a secret from the store
Sourcepub async fn list_secrets(
&self,
namespace: &str,
opts: ListOpts,
) -> Result<ListSecretsResult>
pub async fn list_secrets( &self, namespace: &str, opts: ListOpts, ) -> Result<ListSecretsResult>
List secrets in a namespace
Sourcepub async fn batch_get(
&self,
namespace: &str,
keys: BatchKeys,
format: ExportFormat,
) -> Result<BatchGetResult>
pub async fn batch_get( &self, namespace: &str, keys: BatchKeys, format: ExportFormat, ) -> Result<BatchGetResult>
Batch get secrets
Sourcepub async fn batch_operate(
&self,
namespace: &str,
operations: Vec<BatchOp>,
transactional: bool,
idempotency_key: Option<String>,
) -> Result<BatchOperateResult>
pub async fn batch_operate( &self, namespace: &str, operations: Vec<BatchOp>, transactional: bool, idempotency_key: Option<String>, ) -> Result<BatchOperateResult>
Batch operate on secrets
Sourcepub async fn export_env(
&self,
namespace: &str,
opts: ExportEnvOpts,
) -> Result<EnvExport>
pub async fn export_env( &self, namespace: &str, opts: ExportEnvOpts, ) -> Result<EnvExport>
Export secrets as environment variables
Exports all secrets from a namespace in the specified format. Supports conditional requests using ETag for efficient caching.
§Arguments
namespace- The namespace to exportopts- Export options including format and conditional request headers
§Returns
Returns EnvExport::Json for JSON format or EnvExport::Text for other formats.
§Errors
- Returns
Error::Httpwith status 304 if content hasn’t changed (when using if_none_match) - Returns other errors for authentication, network, or server issues
§Example
// Simple export
let opts = ExportEnvOpts {
format: ExportFormat::Dotenv,
..Default::default()
};
let export = client.export_env("production", opts).await?;
// Conditional export with ETag
let opts = ExportEnvOpts {
format: ExportFormat::Json,
use_cache: true,
if_none_match: Some("previous-etag".to_string()),
};
match client.export_env("production", opts).await {
Ok(export) => println!("Content updated"),
Err(e) if e.status_code() == Some(304) => println!("Not modified"),
Err(e) => return Err(e.into()),
}Sourcepub async fn list_namespaces(&self) -> Result<ListNamespacesResult>
pub async fn list_namespaces(&self) -> Result<ListNamespacesResult>
List all namespaces
Sourcepub async fn create_namespace(
&self,
name: &str,
description: Option<String>,
idempotency_key: Option<String>,
) -> Result<CreateNamespaceResult>
pub async fn create_namespace( &self, name: &str, description: Option<String>, idempotency_key: Option<String>, ) -> Result<CreateNamespaceResult>
Create a new namespace
Creates a new namespace in the secret store. Requires global admin permissions.
§Arguments
name- The name of the namespace to createdescription- Optional description for the namespaceidempotency_key- Optional idempotency key to prevent duplicate creation
§Returns
A CreateNamespaceResult containing the creation details.
§Errors
Error::Httpwith status 403 if not authorized to create namespacesError::Httpwith status 409 if the namespace already existsError::Httpwith status 400 for invalid namespace names
§Example
let result = client.create_namespace(
"production",
Some("Production environment secrets".to_string()),
None
).await?;
println!("Created namespace: {}", result.namespace);Sourcepub async fn get_namespace(&self, namespace: &str) -> Result<NamespaceInfo>
pub async fn get_namespace(&self, namespace: &str) -> Result<NamespaceInfo>
Get namespace information
Sourcepub async fn init_namespace(
&self,
namespace: &str,
template: NamespaceTemplate,
idempotency_key: Option<String>,
) -> Result<InitNamespaceResult>
pub async fn init_namespace( &self, namespace: &str, template: NamespaceTemplate, idempotency_key: Option<String>, ) -> Result<InitNamespaceResult>
Initialize a namespace with a template
Initializes a new namespace using a predefined template to create a set of initial secrets.
§Arguments
namespace- The namespace to initializetemplate- The template configurationidempotency_key- Optional idempotency key to prevent duplicate initialization
§Example
let template = NamespaceTemplate {
template: "web-app".to_string(),
params: json!({
"environment": "staging",
"region": "us-west-2"
}),
};
let result = client.init_namespace(
"staging-app",
template,
Some("init-staging-12345".to_string())
).await?;
println!("Created {} secrets", result.secrets_created);Sourcepub async fn delete_namespace(
&self,
namespace: &str,
) -> Result<DeleteNamespaceResult>
pub async fn delete_namespace( &self, namespace: &str, ) -> Result<DeleteNamespaceResult>
Delete a namespace and all its secrets
Warning: This operation is irreversible and will delete all secrets in the namespace. Use with extreme caution.
This operation may take some time for namespaces with many secrets. The response includes the number of secrets that were deleted.
§Arguments
namespace- The namespace to delete
§Returns
A DeleteNamespaceResult containing deletion details.
§Errors
Error::Httpwith status 404 if the namespace doesn’t existError::Httpwith status 403 if deletion is forbiddenError::Httpwith status 409 if namespace has protection enabled
§Example
let result = client.delete_namespace("test-namespace").await?;
println!("Deleted {} secrets from namespace {}",
result.secrets_deleted,
result.namespace
);Sourcepub async fn delete_namespace_idempotent(
&self,
namespace: &str,
idempotency_key: Option<String>,
) -> Result<DeleteNamespaceResult>
pub async fn delete_namespace_idempotent( &self, namespace: &str, idempotency_key: Option<String>, ) -> Result<DeleteNamespaceResult>
Delete a namespace and all its secrets with idempotency support
Same as delete_namespace but with idempotency key support for safe retries.
§Arguments
namespace- The namespace to deleteidempotency_key- Optional idempotency key to prevent duplicate deletion
§Example
let result = client.delete_namespace_idempotent(
"test-namespace",
Some("delete-ns-12345".to_string())
).await?;
println!("Deleted {} secrets", result.secrets_deleted);Sourcepub async fn list_versions(
&self,
namespace: &str,
key: &str,
) -> Result<VersionList>
pub async fn list_versions( &self, namespace: &str, key: &str, ) -> Result<VersionList>
List versions of a secret
Sourcepub async fn get_version(
&self,
namespace: &str,
key: &str,
version: i32,
) -> Result<Secret>
pub async fn get_version( &self, namespace: &str, key: &str, version: i32, ) -> Result<Secret>
Get a specific version of a secret
Sourcepub async fn rollback(
&self,
namespace: &str,
key: &str,
version: i32,
) -> Result<RollbackResult>
pub async fn rollback( &self, namespace: &str, key: &str, version: i32, ) -> Result<RollbackResult>
Rollback a secret to a previous version
Sourcepub async fn audit(&self, query: AuditQuery) -> Result<AuditResult>
pub async fn audit(&self, query: AuditQuery) -> Result<AuditResult>
Query audit logs
Sourcepub async fn list_api_keys(&self) -> Result<ListApiKeysResult>
pub async fn list_api_keys(&self) -> Result<ListApiKeysResult>
List all API keys
Retrieves a list of all API keys associated with the current account. The response includes metadata about each key but not the key values themselves.
§Returns
A ListApiKeysResult containing the list of API keys and total count.
§Errors
Error::Httpwith status 403 if not authorized to list keys
§Example
let keys = client.list_api_keys().await?;
for key in &keys.keys {
println!("Key {}: {} (active: {})", key.id, key.name, key.active);
}Sourcepub async fn create_api_key(
&self,
request: CreateApiKeyRequest,
idempotency_key: Option<String>,
) -> Result<ApiKeyInfo>
pub async fn create_api_key( &self, request: CreateApiKeyRequest, idempotency_key: Option<String>, ) -> Result<ApiKeyInfo>
Create a new API key
Creates a new API key with the specified permissions and restrictions. The key value is only returned in the creation response and cannot be retrieved later.
§Arguments
request- The API key creation request containing name, permissions, etc.idempotency_key- Optional idempotency key to prevent duplicate creation
§Returns
An ApiKeyInfo containing the newly created key details including the key value.
§Security
The returned API key value should be stored securely. It cannot be retrieved again after this call.
§Errors
Error::Httpwith status 403 if not authorized to create keysError::Httpwith status 400 for invalid permissions or parameters
§Example
let request = CreateApiKeyRequest {
name: "CI/CD Pipeline Key".to_string(),
expires_at: Some("2024-12-31T23:59:59Z".to_string()),
namespaces: vec!["production".to_string()],
permissions: vec!["read".to_string()],
metadata: None,
};
let key_info = client.create_api_key(request, Some("unique-key-123".to_string())).await?;
if let Some(key) = &key_info.key {
println!("New API key: {}", key.expose_secret());
// Store this securely - it won't be available again!
}Sourcepub async fn get_api_key(&self, key_id: &str) -> Result<ApiKeyInfo>
pub async fn get_api_key(&self, key_id: &str) -> Result<ApiKeyInfo>
Get API key details
Retrieves detailed information about a specific API key. Note that the key value itself is never returned for security reasons.
§Arguments
key_id- The ID of the API key to retrieve
§Returns
An ApiKeyInfo with the key’s metadata (without the key value).
§Errors
Error::Httpwith status 404 if the key doesn’t existError::Httpwith status 403 if not authorized to view the key
§Example
let key_info = client.get_api_key("key_123abc").await?;
println!("Key {} last used: {:?}", key_info.name, key_info.last_used_at);Sourcepub async fn revoke_api_key(&self, key_id: &str) -> Result<RevokeApiKeyResult>
pub async fn revoke_api_key(&self, key_id: &str) -> Result<RevokeApiKeyResult>
Revoke an API key
Revokes an API key, immediately invalidating it for future use. This operation is irreversible.
§Arguments
key_id- The ID of the API key to revoke
§Returns
A RevokeApiKeyResult confirming the revocation.
§Errors
Error::Httpwith status 404 if the key doesn’t existError::Httpwith status 403 if not authorized to revoke the key
§Example
let result = client.revoke_api_key("key_123abc").await?;
println!("Revoked key: {}", result.key_id);Sourcepub async fn search_secrets(
&self,
opts: SearchSecretsOpts,
) -> Result<SearchSecretsResult>
pub async fn search_secrets( &self, opts: SearchSecretsOpts, ) -> Result<SearchSecretsResult>
Search secrets across namespaces
Searches for secrets matching a pattern across multiple namespaces. Supports exact, prefix, and contains matching modes.
§Arguments
opts- Search options including pattern, mode, and namespace filters
§Returns
A SearchSecretsResult containing matching secrets.
§Errors
Error::Httpwith status 400 if the pattern is emptyError::Httpwith status 403 if no accessible namespaces
§Example
// Search for all secrets containing "api" in their key
let opts = SearchSecretsOpts {
pattern: "api".to_string(),
mode: SearchMode::Contains,
..Default::default()
};
let result = client.search_secrets(opts).await?;
for m in &result.matches {
println!("{}/{}: v{}", m.namespace, m.key, m.version);
}
// Search with prefix in specific namespaces
let opts = SearchSecretsOpts {
pattern: "db-".to_string(),
mode: SearchMode::Prefix,
namespaces: vec!["production".to_string(), "staging".to_string()],
include_values: false,
};
let result = client.search_secrets(opts).await?;
println!("Found {} secrets", result.total);Sourcepub async fn bulk_delete_secrets(
&self,
opts: BulkDeleteOpts,
) -> Result<BulkDeleteResult>
pub async fn bulk_delete_secrets( &self, opts: BulkDeleteOpts, ) -> Result<BulkDeleteResult>
Bulk delete a secret across namespaces
Deletes a secret with the given key from multiple namespaces in a single operation. Requires admin permission on each namespace.
§Arguments
opts- Bulk delete options including the key and target namespaces
§Returns
A BulkDeleteResult containing lists of successful and failed deletions.
§Errors
Error::Httpwith status 400 if the key is emptyError::Httpwith status 403 if no accessible namespaces
§Example
// Delete a secret from all accessible namespaces
let opts = BulkDeleteOpts {
key: "deprecated-api-key".to_string(),
namespaces: vec![], // empty = all accessible
};
let result = client.bulk_delete_secrets(opts).await?;
println!("Deleted from: {:?}", result.deleted);
if !result.failed.is_empty() {
println!("Failed in: {:?}", result.failed);
}
// Delete from specific namespaces only
let opts = BulkDeleteOpts {
key: "old-secret".to_string(),
namespaces: vec!["staging".to_string(), "dev".to_string()],
};
let result = client.bulk_delete_secrets(opts).await?;Sourcepub async fn livez(&self) -> Result<()>
pub async fn livez(&self) -> Result<()>
Check liveness
Performs a simple liveness check against the service.
Returns Ok(()) if the service is alive and responding.
This endpoint is typically used by Kubernetes liveness probes. It does not check dependencies and should respond quickly.
§Errors
Returns an error if the service is not responding or returns a non-2xx status code.
§Example
match client.livez().await {
Ok(()) => println!("Service is alive"),
Err(e) => eprintln!("Service is down: {}", e),
}Sourcepub async fn readyz(&self) -> Result<HealthStatus>
pub async fn readyz(&self) -> Result<HealthStatus>
Check readiness with detailed status
Performs a comprehensive readiness check that may include checking dependencies (database, cache, etc.).
This endpoint is typically used by Kubernetes readiness probes to determine if the service is ready to accept traffic.
§Returns
Returns a HealthStatus with details about the service health
including individual component checks.
§Errors
Returns an error if the service is not ready or if the request fails.
§Example
let health = client.readyz().await?;
println!("Service status: {}", health.status);
for (check, result) in &health.checks {
println!(" {}: {} ({}ms)",
check,
result.status,
result.duration_ms.unwrap_or(0)
);
}Sourcepub async fn metrics(&self, metrics_token: Option<&str>) -> Result<String>
pub async fn metrics(&self, metrics_token: Option<&str>) -> Result<String>
Get service metrics
Retrieves metrics from the service in Prometheus format. This endpoint may require special authentication using a metrics token.
§Arguments
metrics_token- Optional metrics-specific authentication token. If not provided, uses the client’s default authentication.
§Returns
Returns the metrics as a raw string in Prometheus exposition format.
§Errors
Error::Httpwith status 401 if authentication failsError::Httpwith status 403 if not authorized to view metrics
§Example
// Using default authentication
let metrics = client.metrics(None).await?;
println!("Metrics:\n{}", metrics);
// Using specific metrics token
let metrics = client.metrics(Some("metrics-token-xyz")).await?;
println!("Metrics with token:\n{}", metrics);