Skip to content
Lenso
English
Esc
navigateopen⌘Jpreview
On this page

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.

Last updated on September 6, 2026

Was this page helpful?