Secrets Plugin
Resolve allowlisted logical secret references without putting secret values in the App Plan.
lenso.secrets@1 exposes one resolve request. Consumers ask for a logical
reference such as database/url; App Composition binds that requirement to one
provider. Secret values never belong in Plan configuration, diagnostics,
errors, or Debug output.
Configure the Env provider
The linked Rust Env provider is intended for local development and controlled host deployments:
{
"references": {
"database/url": "APP_DATABASE_URL",
"auth/signing-key": "APP_AUTH_SIGNING_KEY"
}
}
Register its factory in the native App and bind the consumer’s exactly-one
lenso.secrets@1 requirement to that Instance:
use lenso_native_adapter::NativePluginRegistry;
use lenso_secrets_env_module::EnvSecretsFactory;
let native = NativePluginRegistry::new()
.with_factory(EnvSecretsFactory::new());
The allowlist must be non-empty. Logical references are canonical paths up to
256 bytes: no leading or trailing slash, empty segment, . segment, or ..
segment. Duplicate references and non-portable environment variable names fail
Plan admission.
Resolve from a Plugin
use lenso_capability_secrets::{
ResolveRequest, SecretsClient, SecretsInvocationError,
};
use lenso_kernel::{PluginDependencies, RuntimeFailure};
fn client(dependencies: &PluginDependencies) -> Result<SecretsClient, RuntimeFailure> {
SecretsClient::from_dependencies(dependencies)
}
async fn database_url(secrets: &SecretsClient) -> Result<String, SecretsInvocationError> {
let response = secrets.resolve(ResolveRequest {
reference: "database/url".into(),
}).await?;
Ok(response.value)
}
invalid_reference means the request is malformed;
unknown_reference means it is valid but absent from this Instance’s
allowlist. An unavailable configured source is a Runtime Failure, not a Domain
Error and not a signal to try another provider.
During prepare, the Env provider verifies every configured source without
printing the environment variable name or value. It reads the current process
environment again for every resolve, so a host-side rotation is observed
without changing the Plan. If the source later disappears, resolution fails
truthfully.
Implement another provider
A production cloud provider belongs in its own Plugin. It implements the
generated SecretsProvider, returns only the requested value, and owns its
authentication, rotation, availability, and audit policy:
use futures::future::LocalBoxFuture;
use lenso_capability_secrets::{
ResolveRequest, ResolveResponse, SecretsInvocationError, SecretsProvider,
};
use lenso_kernel::InvocationContext;
#[derive(Debug)]
struct CloudSecrets;
impl SecretsProvider for CloudSecrets {
fn resolve(
&self,
context: InvocationContext,
request: ResolveRequest,
) -> LocalBoxFuture<'static, Result<ResolveResponse, SecretsInvocationError>> {
Box::pin(async move {
// Authenticate to the selected backend, authorize `request.reference`,
// fetch the value, and map expected failures explicitly.
todo!()
})
}
}
Do not add implicit provider fallback or put a cloud SDK in the Kernel.
The owner repository currently marks registry publication as parked. Check the
package registry before relying on cargo add; source implementation and
registry availability are separate facts.