---
title: Secrets Plugin
description: 使用白名单逻辑 secret reference 取值，不把 secret value 放入 App Plan。
---

`lenso.secrets@1` 提供一个 `resolve` request。consumer 请求 `database/url` 这样的
逻辑 reference；App Composition 把 requirement 绑定到一个 provider。secret value
绝不属于 Plan configuration、diagnostic、error 或 `Debug` output。

## 配置 Env provider

linked Rust Env provider 适用于本地开发和受控 host 部署：

```json title="Plugin configuration"
{
  "references": {
    "database/url": "APP_DATABASE_URL",
    "auth/signing-key": "APP_AUTH_SIGNING_KEY"
  }
}
```

在 native App 中注册 factory，并把 consumer 的 exactly-one `lenso.secrets@1`
requirement 绑定到这个 Instance：

```rust
use lenso_native_adapter::NativePluginRegistry;
use lenso_secrets_env_module::EnvSecretsFactory;

let native = NativePluginRegistry::new()
    .with_factory(EnvSecretsFactory::new());
```

白名单不能为空。逻辑 reference 是最长 256 bytes 的 canonical path：不能有开头或
结尾 slash、空 segment、`.` segment 或 `..` segment。重复 reference 与不可移植的
environment variable name 会让 Plan admission 失败。

## 在 Plugin 中解析

```rust
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` 表示 request 格式非法；`unknown_reference` 表示格式有效但不在
该 Instance 的白名单中。已配置 source 不可用属于 Runtime Failure，而不是 Domain
Error，也不是尝试另一个 provider 的信号。

Env provider 会在 `prepare` 中验证全部 source，同时不输出 environment variable
name 或 value。每次 `resolve` 都重新读取当前进程环境，因此 host 侧 rotation 无需
修改 Plan 即可生效。source 后续消失时，解析会如实失败。

## 实现其他 provider

生产 cloud provider 应属于自己的 Plugin。它实现生成的 `SecretsProvider`，只返回
请求的 value，并自行拥有 authentication、rotation、availability 与 audit policy：

```rust
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 {
            // 对选定 backend 认证、授权 request.reference、读取 value，
            // 并显式映射预期失败。
            todo!()
        })
    }
}
```

不要增加隐式 provider fallback，也不要把 cloud SDK 放进 Kernel。

:::warning
当前 Secrets Descriptor 仅限 native（`portable: false`），也不允许 cross-lane
transfer。维护中的 Env provider 是 linked Rust Plugin。仅仅能生成 TypeScript 类型，
并不意味着 Bun Plugin 可以跨进程 lane 消费它；这需要 adapter-local provider，或
未来明确 portability 与 threat model 的 contract。
:::

owner repository 当前将 registry publication 标为 parked。依赖 `cargo add` 前请检查
package registry；source implementation 与 registry availability 是两件事。
