# Secretos

Cómo Beeuni almacena las credenciales del proyecto y controla si el código del agente puede leer cada valor.

Canonical page: https://beeuni.ai/docs/es/project/secrets

Un secreto es una credencial por proyecto — una clave de API, un token o una cadena de conexión — que una sesión necesita, pero que no debe estar en el repositorio.
Beeuni almacena los secretos en el proyecto, nunca en la cuenta, y cifra cada valor con AES-256-GCM mediante una clave derivada por proyecto.

<a id="identifier-and-name"></a>

## Identificador y nombre

Cada secreto tiene dos nombres. El `identifier` es el identificador que usas en la CLI y en la concesión `secrets` de un agente. El `name` es la clave de variable de entorno en mayúsculas dentro del sandbox, por ejemplo `STRIPE_API_KEY`. En la mayoría de los proyectos, el identificador y el nombre coinciden. Solo difieren cuando un proyecto contiene varios valores candidatos para un mismo nombre; por ejemplo, una clave principal y una de respaldo de Google Maps pueden resolver ambas a `GOOGLE_MAPS_API_KEY`.

Cada regla de acceso usa el identificador. Ninguna usa el nombre.

<a id="exposure-and-usage"></a>

## Exposición y uso

Un secreto tiene dos configuraciones independientes. Léelas por separado; responden a preguntas diferentes.

| Configuración | Pregunta que responde | Valores |
|---|---|---|
| **Exposición** | ¿Puede el código del agente leer el valor real? | `environment`, `egress-enforced`, `none` |
| **Uso** | ¿Quién lo consume? | Código del agente, gateway de LLM, Connector, Git |

La documentación antigua de Beeuni presentaba una sola lista que mezclaba ambas. Ya no existe. No hay que elegir entre un «límite de red» y un «intermediario HTTPS»: un único mecanismo sirve para todos los secretos con salida de red controlada en todos los proveedores de sandbox.

<a id="the-three-exposures"></a>

### Las tres exposiciones

| Exposición | Qué contiene el sandbox | Úsala para |
|---|---|---|
| **Environment** | El valor real, como una variable de entorno sin cifrar | La opción predeterminada. Valores con los que el agente debe hacer cálculos y protocolos que no usan HTTPS |
| **Egress-enforced** | Un **identificador** — un marcador autoexplicativo que no tiene valor por sí solo | Experimental. Llamadas HTTPS, una vez activado el indicador `secrets_egress` |
| **None** | Nada | Una credencial que solo consume un servicio de Beeuni, o un valor guardado y deshabilitado |

> **La regla práctica**
>
> **Environment** es la exposición predeterminada. El valor real se carga en el sandbox, donde el agente puede leerlo, imprimirlo y reenviarlo. **Egress-enforced** mantiene el valor fuera del sandbox, pero es experimental: activa el indicador de funcionalidad `secrets_egress` (Settings → Feature flags) para usarlo. Hasta entonces, el secreto se carga en el entorno del sandbox.

<a id="usages"></a>

### Usos

Beeuni asigna la mayoría de los usos, no tú:

- **Código del agente** — implícito siempre que la exposición no sea `none`.
- **Gateway de LLM** — se asigna cuando el valor es una clave reconocida de un proveedor de modelos. El gateway autentica las solicitudes al proveedor en el servidor.
- **Connector:&lt;slug&gt;** — se asigna mediante el flujo de vinculación del conector.
- **Git** — Beeuni lo asigna para su propio acceso a Git. Es de solo lectura; no puedes establecerlo ni eliminarlo.

Un secreto con exposición `none` y sin uso se muestra como **Disabled**: está almacenado y cifrado, pero nada lo consume.

<a id="sent-secrets-and-computed-secrets"></a>

## Secretos enviados y secretos calculados

La exposición que puede usar un secreto depende del **sistema ascendente**, no de Beeuni.

- **Secretos enviados** — el valor viaja por la red. Claves de API, tokens de portador y contraseñas. Son la gran mayoría. Hay un momento en el que el valor está presente como bytes en una solicitud saliente, por lo que Beeuni puede colocarlo directamente, fuera del sandbox. Un secreto enviado puede pasar a **egress-enforced** cuando el indicador `secrets_egress` está activado; de forma predeterminada, se carga en el entorno del sandbox.
- **Secretos calculados** — el valor es un ingrediente de un cálculo y nunca viaja. Claves de firma AWS SigV4, secretos de firma de webhooks HMAC, aserciones de cliente JWT y claves privadas SSH. Quien calcula debe tener el valor. Ningún límite de red sirve de ayuda, porque nada en la red contiene la credencial. Los secretos calculados deben permanecer en **environment**.

Environment es la exposición predeterminada y la única que puede servir una credencial con la que el sandbox debe hacer cálculos. Los protocolos que no usan HTTPS — una cadena de conexión de Postgres o credenciales SMTP — están en la misma situación: deben permanecer en environment.

Cuando guardas un valor que parece material de firma, como un par de claves de acceso `AKIA…` o material PEM/SSH, Beeuni lo establece de forma predeterminada en **environment** y explica el motivo: esta clave firma las solicitudes localmente, por lo que la aplicación de salida de red no puede utilizarse.

<a id="egress-enforced-exposure"></a>

## Exposición Egress-enforced

> **Experimental — necesita el indicador secrets_egress**
>
> La aplicación de reglas en la red es experimental. Activa el indicador de funcionalidad `secrets_egress` (Settings → Feature flags) para usarla. Hasta entonces, el secreto se carga en el entorno del sandbox. Con el indicador desactivado, crear un secreto egress-enforced devuelve `403` `feature_disabled`.

El sandbox recibe una variable de entorno cuyo valor es un **identificador**, no la credencial. El agente usa esa variable exactamente como usaría la clave real: en un encabezado, una cadena de consulta o un cuerpo. `Authorization: Bearer $VAR`, `Cookie: …=$VAR`, un encabezado `X-Api-Key`, un parámetro de consulta y un campo de cuerpo JSON o de formulario funcionan: Beeuni encuentra el identificador dondequiera que aparezca (sin procesar, codificado en URL, como base64 independiente o con escape JSON) y lo sustituye por el valor real. Al salir, Beeuni reemplaza el identificador por el valor real, pero solo en solicitudes a hosts que hayas aprobado.

> **Envía el identificador tal cual; no lo codifiques tú mismo en base64**
>
> Hay algo que no funciona: ocultar el identificador dentro de un bloque base64 que construyas tú mismo, como hace la **autenticación HTTP Basic** (`curl -u $VAR:` → `Authorization: Basic <base64>`). Beeuni no puede encontrar un identificador incrustado y desalineado dentro de un base64 que hayas codificado, por lo que el reemplazo nunca ocurre y el sistema ascendente responde `401`. Coloca el identificador en un encabezado Bearer/token, un parámetro de consulta o un campo del cuerpo. Si la API solo admite autenticación Basic, usa la exposición **environment** para ese secreto.

Hechos que se derivan de esta estructura:

- El valor real **nunca** está en el sandbox: ni como variable de entorno, ni en un archivo ni como alias.
- Un identificador enviado a un host que no hayas aprobado llega como la cadena literal del identificador. El sistema ascendente lo rechaza. No tiene ningún valor.
- Un identificador con una firma incorrecta nunca se acepta, y Beeuni lo registra como un identificador falsificado. Un identificador válido para un secreto que esta sesión no puede consumir se registra como robado.
- Cada solicitud retransmitida genera un registro de auditoría por solicitud.
- Los hosts que no están en la lista se tunelizan sin ser leídos. Los clientes con TLS fijado y mTLS hacia esos hosts no se ven afectados.

<a id="hosts-match-exactly"></a>

### Coincidencia exacta de hosts

Enumera todos los hosts a los que llamas, un nombre de host exacto por línea.

| Rechazado | Motivo |
|---|---|
| Un host comodín, `*.example.com` | El agente nunca debe elegir el destino |
| Un esquema de URL distinto de HTTPS | Beeuni termina TLS para realizar la sustitución |

`api.example.com` no cubre `uploads.api.example.com`. Añade el segundo host al mismo secreto. Beeuni rechaza una política que no se puede aplicar con `400` al guardarla; nunca almacena una regla que no pueda aplicar.

Dos secretos con control de salida pueden compartir un host. Cada identificador se asocia a su propio
valor, por lo que ambos se sustituyen correctamente en la misma solicitud.

<a id="verify-it-with-two-probes"></a>

### Verifícalo con dos pruebas

Ejecuta ambas pruebas desde dentro del entorno aislado, contra un host que esté en la lista.
El ejemplo usa `postman-echo.com`, que ofrece un endpoint de cada tipo.
Añádelo como host permitido mientras dure la prueba.

```bash
# 1. Reachability — an endpoint that does NOT echo request headers.
curl -s -o /dev/null -w '%{http_code}\n' https://postman-echo.com/status/200
# expected: 200

# 2. Substitution — an endpoint that DOES echo request headers.
curl -sS -H "authorization: Bearer $STRIPE_API_KEY" https://postman-echo.com/get
# expected: 200, with "Bearer [REDACTED]" in the echoed headers
```

Lee los resultados en conjunto y ejecuta primero la prueba 1: es la única que te indica si se puede acceder al
host, y la prueba 2 no demuestra nada hasta que la primera pase.

| Resultado de la prueba 2 | Significado |
|---|---|
| `200`, el encabezado reflejado muestra `[REDACTED]` | Funciona. El valor real llegó al servidor de destino y se ocultó en la respuesta. |
| `200`, el encabezado reflejado muestra el identificador | No se realizó la sustitución. Comprueba la lista de hosts y el permiso del agente. |
| `401` de un host de API real | No se realizó la sustitución. Las mismas dos comprobaciones. |
| Respuesta vacía o error de conexión | Un fallo real. No es un síntoma de éxito. |

Confirma que el valor real no aparece en ninguna parte del entorno invitado:

```bash
env | grep '^STRIPE_API_KEY='
# expected: the handle, not the credential
```

El identificador también aparece en `BEEUNI_SECRET_CAPABILITIES`, el catálogo sin valores
que indica al agente qué secretos existen, qué variable contiene cada identificador y qué hosts cubre cada uno.
Nunca contiene un valor.

Un host de la lista presenta un certificado que Beeuni emitió para este entorno aislado, en el que
el entorno aislado ya confía, en lugar del certificado propio del origen:

```bash
curl -sv https://postman-echo.com/status/200 2>&1 | grep 'issuer:'
# issuer: CN=Beeuni Egress CA (<project prefix>); O=Beeuni
```

<a id="what-the-relay-changes"></a>

### Qué cambia con el relay

Se accede a un host aprobado a través de Beeuni, por lo que se comporta de forma algo diferente
a una llamada directa:

- Las respuestas no se transmiten en streaming. Los eventos enviados por el servidor y los websockets no funcionan
a través de un host aprobado.
- El cuerpo de una solicitud tiene un límite de 1 MiB, el de una respuesta, de 5 MiB, y la llamada completa,
de 30 segundos. Beeuni sigue un máximo de 3 redirecciones.
- Solo se devuelven un conjunto fijo de encabezados de respuesta: tipo y lenguaje del contenido,
validadores de caché, la familia de límites de velocidad, `retry-after`, `x-request-id`.
- Solo se interceptan los clientes que respetan `https_proxy`. Beeuni establece esa
variable y la confianza de CA correspondiente en el entorno del agente. Un proceso iniciado con un entorno
limpio llama directamente al host y su solicitud sale con el identificador.

Para una solicitud que Beeuni no puede interceptar, el agente dispone de una vía explícita a los
mismos hosts con la misma política:

```bash
beeuni secrets call STRIPE_API_KEY https://api.stripe.com/v1/customers
```

<a id="environment-exposure"></a>

## Exposición en el entorno

El entorno aislado recibe el valor real como una variable de entorno de texto sin formato. El código del agente
puede leerlo, imprimirlo y enviarlo a cualquier parte. Beeuni no puede ocultarlo,
ni auditar su uso ni impedir que salga.

La exposición en el entorno es la opción predeterminada. Todos los secretos nuevos usan esta opción, a menos que
cambies el secreto a control de salida, que es experimental y requiere la marca
`secrets_egress`. Una credencial calculada y cualquier protocolo que no sea HTTPS deben
permanecer en el entorno.

<a id="who-can-use-a-secret"></a>

## Quién puede usar un secreto

Cada valor secreto tiene un público: la misma opción **Quién puede usarlo** que para una cuenta de conector:

| Opción | Quién puede usar el valor |
| --- | --- |
| **Todos en el proyecto** (opción predeterminada) | Todas las sesiones del proyecto, incluidos los desencadenadores, las programaciones y las sesiones compartidas. |
| **Solo tú** | Tú, directamente, y tus propias sesiones privadas. |
| **Personas, grupos o agentes específicos** | Las personas y los grupos que elijas (directamente y en sus propias sesiones privadas), y los agentes que elijas (en todas sus sesiones). |

Una sesión actúa como dos cosas a la vez: siempre como su **agente** y como su
**persona** solo mientras la sesión sea privada.

- **Una persona** obtiene acceso a un valor en una sesión **privada** que esa persona
ha iniciado. Un mensaje de cualquier otra persona elimina a la persona de la sesión, por lo que el valor deja de estar disponible. Las sesiones compartidas, los desencadenadores,
las programaciones, los webhooks y las sesiones de correo electrónico y Telegram no tienen persona.
- **Un agente** obtiene acceso a un valor en todas las sesiones de ese agente, incluidos los desencadenadores,
las programaciones y las sesiones compartidas. Comparte un valor con el agente si lo necesita para una ejecución desatendida. Cualquier persona que pueda ejecutar ese agente podrá usar el
valor a través de él, así que ejecutar el agente es el control de acceso (quién puede ejecutar un agente
se configura en el agente).
- Los consumidores del lado del servidor siguen la misma regla. Un conector vinculado al secreto
solo lo usa si quien lo llama pertenece al público. Cualquier otra persona recibe
`credential_not_shared` y ninguna solicitud sale de Beeuni.
- Los servicios de Beeuni que no actúan en nombre de nadie —el proxy de Git, las comprobaciones de firma de webhooks,
las instalaciones de canales y las aplicaciones de Beeuni— solo usan valores compartidos con todos.

Varios valores pueden compartir un nombre. Un valor compartido con la persona de la sesión
prevalece sobre uno compartido con su agente, y este, sobre el valor compartido con todos. Por ejemplo: `DEEL_API_TOKEN` contiene un valor para el equipo, y un segundo valor
con el identificador `DEEL_API_TOKEN-finance` se comparte solo con el grupo de Finanzas.
Los miembros de Finanzas obtienen el valor de Finanzas en sus sesiones privadas;
todos los demás y todos los desencadenadores obtienen el valor del equipo.

Una persona configura el público. Una sesión de agente no puede cambiarlo (`403`), así que un
agente no puede ampliar el acceso a un valor que se le haya restringido ni añadirse a sí mismo. Las personas que
administran los secretos del proyecto siguen viendo un valor que no se comparte con ellas, marcado como **No compartido contigo**, para que puedan ampliar el acceso de nuevo.

<a id="sharing-a-session-that-holds-a-personal-value"></a>

### Compartir una sesión que contiene un valor personal

Un valor compartido solo contigo que llegó a tu sesión privada como **variable de entorno** está en texto sin formato dentro de ese entorno aislado. Compartir la sesión
permitiría que cualquier nueva persona con acceso lo leyera, y no se puede retirar una variable de entorno de un entorno aislado en ejecución. Por eso Beeuni se niega a compartir esa sesión
o a crear un enlace público a ella si contiene `409 PERSONAL_SECRET_REQUIRES_PRIVATE_SESSION`
y los nombres que contiene. Inicia una sesión nueva para compartirla o comparte primero el valor con todos. Los valores a los que se accede a través del agente y los valores con control de salida
o del lado del servidor (que se comprueban en cada solicitud) no impiden compartir la sesión.

Cuando restringes un público, Beeuni vuelve a enviar todos los entornos aislados en ejecución. Un valor
que ya se haya entregado como variable de entorno permanece en un entorno aislado hasta que se reinicie. Si existe la posibilidad de que se haya leído, cámbialo.

<a id="when-you-enter-a-value-through-a-link"></a>

### Cuando introduces un valor mediante un enlace

Un agente que necesita un valor que no le has proporcionado te envía un enlace. La página del enlace
ofrece la opción **Quién puede usarlo**: todos en el proyecto (opción predeterminada) o solo la persona que lo solicitó. Elige la segunda opción para cualquier dato personal, como un token de nómina o
un inicio de sesión personal. La página muestra el nombre visible de la persona que lo solicitó, nunca su correo electrónico,
porque cualquiera que tenga el enlace puede abrirlo.

<a id="personal-override"></a>

### Anulación personal

Una anulación personal es tu propio valor para un nombre, que se usa en lugar del valor compartido en las sesiones que inicias. Actualmente, Beeuni solo la usa para una credencial de inicio de sesión OAuth.
Beeuni nunca permite que una clave de proveedor de LLM, por ejemplo
`ANTHROPIC_API_KEY`, se convierta en una anulación personal.

<a id="add-a-secret"></a>

## Añadir un secreto

### Establece el valor desde la CLI
```bash
beeuni secrets set STRIPE_API_KEY=sk_live_...
```

Beeuni lo guarda para todos en el proyecto. Añade `--only-me` para que
solo tú puedas usarlo. Para guardar más de un valor con el mismo nombre, añade
`--identifier <id>`. Los nombres no pueden empezar por `BEEUNI_`: Beeuni reserva ese
prefijo para los valores de la plataforma.

Cambia quién puede usarlo más adelante:

```bash
beeuni secrets share DEEL_API_TOKEN --user me
beeuni secrets share DEEL_API_TOKEN --user finance@example.com --group <group-id>
beeuni secrets share NIGHTLY_REPORT_TOKEN --agent reporter
beeuni secrets share DEEL_API_TOKEN --everyone
```

### O usa el panel
Abre la página Secrets del proyecto, introduce la clave y el valor, elige **Quién puede usarlo** y guarda. Beeuni cifra el valor de inmediato y, de forma predeterminada, configura cada secreto nuevo para **Todos en el proyecto** y con exposición **environment**: el valor real se carga en el sandbox. La columna **Quién puede usarlo** muestra a quién va dirigido cada valor.

Para cambiar un secreto a exposición con aplicación de egreso, primero activa la `secrets_egress` feature flag (Settings → Feature flags); es experimental. Con la marca activada, la página Secrets muestra el control **«¿Tu código puede leer este valor?»**: si respondes *no*, el secreto pasa a la aplicación de egreso y se muestra la lista de hosts; si respondes *sí*, conserva la exposición environment. Con la marca desactivada, el secreto permanece en environment.

### Concédeselo a un agente
Elige un agente en la página Secrets o añade tú mismo el identificador a la lista `secrets` de ese agente en `beeuni.yaml`. Una sesión solo recibe los secretos que se le conceden a su agente. Consulta [Conceder un secreto a un agente](#grant-a-secret-to-an-agent).

<a id="grant-a-secret-to-an-agent"></a>

## Conceder un secreto a un agente

Una sesión recibe un secreto solo cuando el agente que la ejecuta incluye el identificador en su lista `secrets`. La coincidencia se basa en el identificador, no en el nombre, y no distingue entre mayúsculas y minúsculas.

> **Los usos con aplicación de egreso y los de servicios necesitan una concesión explícita**
>
> `secrets: all` solo concede exposición environment. Un secreto con aplicación de egreso y cualquier secreto que use un servicio de Beeuni necesitan que su identificador figure en la lista de un agente. Un proyecto sin un bloque `agents:` en `beeuni.yaml` nunca recibe uno. Los secretos no concedidos se descartan sin aviso: la sesión se inicia con normalidad y la primera llamada al host falla como si la credencial fuera incorrecta.

<a id="from-the-dashboard"></a>

### Desde el panel

La página Secrets marca los secretos que ningún agente puede recibir: **Ningún agente puede recibir este secreto**. Elige allí un agente y confirma. Beeuni edita `beeuni.yaml` y lo confirma como `chore(agents): grant <IDENTIFIER> to <agent>`.

La concesión funciona tanto si el manifiesto ya declara ese agente como si no. Si el agente no está declarado en el manifiesto, se añade una nueva entrada con esta única lista `secrets`. Si ya está declarado, conserva todos los demás campos —model, tools, connectors— y el identificador se agrega a su lista actual. Si el agente ya tiene acceso al identificador, no hace falta confirmar ningún cambio y Beeuni no lo hace.

Un agente en `secrets: all` es un caso especial. `all` no puede incluir un secreto con aplicación de egreso, así que Beeuni escribe una lista explícita con todos los identificadores que el proyecto tiene actualmente, más este. No cambia nada de lo que recibe el agente en este momento. Cualquier secreto que añadas más adelante necesitará su propia concesión.

Hay dos casos en los que se rechaza la concesión:

- Un proyecto en `beeuni_version: 1` (`beeuni.toml`) no tiene un mapa de agentes que editar. La solicitud falla con `400` y `manifest_v1_unsupported`. Edita el manifiesto manualmente o cambia el proyecto a `beeuni_version: 2`.
- Un secreto **Disabled** no tiene ningún valor que entregar. La solicitud falla con `409` y `secret_not_grantable`. Asígnale primero una exposición.

Si el proyecto aún no tiene un bloque `agents:`, lee [El primer bloque `agents:` cambia todo el proyecto](#the-first-agents-block-changes-the-whole-project) antes de confirmar.
Ese único cambio modifica el acceso a los secretos de todos los demás agentes.

<a id="by-hand"></a>

### Manualmente

La misma concesión, escrita directamente:

```yaml
beeuni_version: 2
agents:
  my-agent:
    secrets: [STRIPE_API_KEY]
```

<a id="when-a-session-asks-for-a-secret-its-agent-is-not-granted"></a>

### Cuando una sesión solicita un secreto que no se ha concedido a su agente

Un agente que necesita una credencial genera un enlace de secreto (`beeuni secrets request`).
El valor que introduzcas se guarda aunque no se haya concedido al agente de la sesión. Esa sesión nunca lo recibe, así que Beeuni lo indica en todas las interfaces:

- El formulario del enlace muestra **Guardado, pero `<agent>` aún no puede leerlo** e indica el secreto.
- La respuesta de generación y el mensaje posterior a la sesión indican los nombres de `withheld` y cómo solucionarlo.
- Dentro de la sesión, `beeuni secrets ls` muestra una clave declarada fuera de la concesión como `not granted`, no como `missing`.

El agente no puede ampliar su propia concesión. Abre **Customize → Agents → `<agent>` → Secrets** y activa el secreto. Al guardarlo, Beeuni aplica el cambio a las sesiones activas del agente. El agente también puede obtenerlo de inmediato con `beeuni secrets sync`, y cada prompt vuelve a sincronizar los secretos de la sesión. No es necesario reiniciarla.

<a id="the-first-agents-block-changes-the-whole-project"></a>

### El primer bloque `agents:` cambia todo el proyecto

> **Declarar un agente deniega el acceso al resto**
>
> Un proyecto sin un bloque `agents:` —o sin ningún `beeuni.yaml`— no tiene restricciones: todos los agentes reciben todos los secretos con exposición environment y ninguno recibe secretos con aplicación de egreso.
>
> En cuanto el proyecto declara su primer agente, ningún agente que **no** aparezca en la lista recibe secretos del proyecto, ni siquiera los secretos environment que funcionaban un minuto antes. Incluir un agente revoca el acceso de los demás.

Por eso, incluye a todos los agentes que necesiten secretos, no solo al que estás configurando. Por eso el panel te pide confirmación la primera vez: después de ese cambio, `agents:` será la lista de permitidos del proyecto y cualquier agente que no figure en ella se ejecutará sin secretos del proyecto.

<a id="exposing-capabilities-to-third-party-users"></a>

## Exponer capacidades a usuarios de terceros

> **Las políticas de secretos de Beeuni no son un sistema de autorización para varios usuarios**
>
> Una política de secretos protege al **agente de tu propio proyecto** para que no filtre tus propias credenciales. No determina cuáles de tus usuarios finales pueden utilizarlas.

Si estás creando algo donde **usuarios de terceros no confiables** acceden a una capacidad —un chat público, una aplicación compartida o un agente al que cualquier persona en internet puede enviar prompts—, no les des acceso a las políticas de secretos. Todos los usuarios de esa interfaz comparten un agente de proyecto, una concesión y una lista de hosts. Beeuni no puede distinguir a un cliente tuyo de otro, así que cualquier secreto con aplicación de egreso al que pueda acceder el prompt de un usuario es una credencial que todos pueden usar, hasta el alcance total que tenga la clave del servicio externo.

Implementa por tu cuenta el límite que realmente necesitas:

1. Crea tu propio servicio de autorización y proxy. Este servicio guarda la credencial del servicio externo.
2. Dirige el agente a tu servicio, no al servicio externo. Dale al agente solo una credencial para tu servicio; esta puede configurarse con aplicación de egreso para tu propio host.
3. Tu servicio identifica al usuario final, aplica tus propias reglas de autorización y cuotas por usuario, y solo entonces llama al servicio externo con la credencial que guarda.

Ese servicio es donde corresponden las reglas por usuario: quién puede llamar a qué, con qué frecuencia y para qué registros. La exposición de secretos de Beeuni es una capa inferior y no la sustituye.

<a id="list-your-secrets"></a>

## Listar tus secretos

Ejecuta `beeuni secrets ls` para ver qué secretos declara un proyecto y cuáles tienen un valor configurado.

La lista contiene metadatos de configuración. Nunca devuelve valores de secretos. Un token de agente con alcance solo ve los identificadores incluidos en la concesión de ese agente. Un `secrets_allowlist` específico de la sesión controla la entrega a esa sesión, pero no oculta los metadatos de configuración permitidos por la concesión del agente.

<a id="rotate-a-secret"></a>

## Rotar un secreto

### Configurar un valor nuevo
Ejecuta el mismo comando con el valor nuevo o vuelve a configurarlo en la página Secrets del proyecto:

```bash
beeuni secrets set STRIPE_API_KEY=sk_live_new...
```

### Beeuni la envía a las sesiones en ejecución
Beeuni envía el cambio a cada sandbox con una sesión activa del
proyecto, haciendo todo lo posible. Para las credenciales de modelos o de la puerta de enlace, Beeuni
reinicia el proceso de compatibilidad de harness estándar.

Rotar un secreto con aplicación de salida no requiere enviar el valor: el
sandbox conserva un identificador y Beeuni lee el valor actual cuando llega la
siguiente solicitud.

<a id="remove-a-secret"></a>

## Eliminar un secreto

Ejecuta `beeuni secrets unset STRIPE_API_KEY` (o `unset <identifier>`), o
elimínalo desde la página Secrets del proyecto.

> **La eliminación es inmediata, la propagación no**
>
> Beeuni elimina de inmediato un secreto compartido. El envío a los
> sandboxes que ya están en ejecución se hace todo lo posible, igual que con la rotación.

<a id="share-a-value-without-seeing-it"></a>

## Compartir un valor sin verlo

Ejecuta `beeuni secrets request STRIPE_API_KEY` para crear un enlace. Cualquiera que tenga el
enlace puede introducir el valor. Tú nunca lo ves. Los enlaces son válidos durante 7 días de
forma predeterminada; ajusta este plazo con `--expires <minutes>` (máximo 30 días). Un enlace caducado muestra
una página clara con el mensaje «caducado»: crea uno nuevo con el mismo comando.

<a id="give-an-agent-a-value-directly"></a>

## Darle un valor directamente a un agente

Si pegas una clave en una sesión, el agente la guarda de inmediato con
`beeuni secrets set`. No te envía un enlace. El
agente necesita permiso para escribir secretos en el proyecto. Si no lo tiene, recibe
`403` y crea un enlace para el secreto. Un agente puede guardar un secreto de entorno
o un secreto de conector (`--scope connector`). La entrega con aplicación de políticas y las listas de hosts
siguen siendo funciones exclusivas para las personas.

<a id="end-to-end-example"></a>

## Ejemplo completo

`beeuni.yaml`:

```yaml
beeuni_version: 2
default_agent: my-agent
agents:
  my-agent:
    secrets: [STRIPE_API_KEY]
```

Configuración de secretos. El primer comando guarda el valor con la exposición de entorno predeterminada.
El segundo lo cambia a exposición con aplicación de salida, que es
experimental y requiere la marca `secrets_egress` (Settings → Feature flags); devuelve `403` `feature_disabled` mientras la marca esté desactivada.

```bash
beeuni secrets set STRIPE_API_KEY=sk_live_...
beeuni secrets delivery STRIPE_API_KEY egress --allow-host api.stripe.com
```

A continuación, el agente llama a Stripe con la variable que recibió:

```bash
curl -s -o /dev/null -w '%{http_code}\n' \
  -H "authorization: Bearer $STRIPE_API_KEY" \
  https://api.stripe.com/v1/customers
# expected: 200
```

`$STRIPE_API_KEY` contiene un identificador. Stripe recibe la clave real porque
`api.stripe.com` está en la lista. La misma solicitud a un host que no está en la
lista envía el identificador, que el servicio ascendente rechaza.

La misma solicitud de un agente cuya lista `secrets` omite `STRIPE_API_KEY`
devuelve `401`. Esa sesión se inicia con normalidad: un secreto sin autorización no es un
error, simplemente nunca se entrega.

<a id="cli-commands"></a>

## Comandos de CLI

| Comando | Qué hace |
|---|---|
| `beeuni secrets ls` | Muestra los secretos declarados y configurados para el proyecto |
| `beeuni secrets set KEY=VALUE [--identifier <id>] [--scope runtime\|connector]` | Crea o actualiza un secreto. `KEY=-` lee el valor desde stdin. `--scope connector` lo mantiene en el servidor |
| `beeuni secrets unset IDENTIFIER` | Elimina un secreto |
| `beeuni secrets delivery IDENTIFIER egress --allow-host <host>` | Aplica la exposición de salida a los hosts indicados. Es experimental; requiere la marca `secrets_egress` |
| `beeuni secrets delivery IDENTIFIER runtime` | Exposición de entorno (la predeterminada) |
| `beeuni secrets delivery IDENTIFIER denied` | Desactivado |
| `beeuni secrets call IDENTIFIER URL` | Envía una solicitud HTTPS sujeta a una política a través de Beeuni. Es experimental; requiere la marca `secrets_egress` |
| `beeuni secrets sync` | En una sesión de agente: obtiene los secretos de esta sesión y concede acceso ahora. Como persona: vuelve a enviar los secretos a todos los sandboxes activos del proyecto |
| `beeuni secrets request NAME [--scope runtime\|connector] [--expires <min>]` | Crea un enlace para que otra persona introduzca un valor |
| `beeuni env push --from <path>` | Sube un archivo `.env` como secretos |
| `beeuni env pull [--out <path>] [--force]` | Exporta los nombres de los secretos, no sus valores, a un archivo `.env` |

La CLI conserva la terminología almacenada: `runtime` es la exposición de entorno,
`egress` es la exposición con aplicación de salida y `denied` está desactivado. Ejecuta
`beeuni secrets --help` para consultar todas las marcas.

De forma predeterminada, los enlaces de configuración usan `connector`. Usa `--scope runtime` solo si el shell del agente necesita
recibir el valor. Un secreto vinculado a un conector permanece en el servidor.

<a id="names-and-permissions"></a>

## Nombres y permisos

Reglas de formato para los dos nombres:

| Nombre | Formato |
|---|---|
| `identifier` | `^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$` |
| `name` | `^[A-Z_][A-Z0-9_]{0,63}$` |

Para leer o escribir un secreto se necesita el permiso `project.secret.read` o
`project.secret.write`. Un administrador del proyecto tiene ambos. Un rol personalizado
solo añade permisos —Beeuni no tiene reglas de denegación—, así que ningún rol puede quitarle ninguno
de los dos a un administrador. Para restringir a un administrador, quítale el rol de administrador.

La entrega a una sesión depende de los permisos de la persona que la inició,
intersectados con la concesión del manifiesto del agente que se inició. Ambos deben permitir el
secreto. Consulta
[Un vocabulario, dos vinculaciones](/docs/es/accounts#one-vocabulary-two-bindings).

<a id="rest-routes"></a>

## Rutas REST

Todas las rutas están bajo `/v1/projects/{projectId}`.

| Método | Ruta | Descripción |
|---|---|---|
| GET | `/secrets` | Muestra los secretos. Si quien llama es un token de agente con alcance restringido, se limita a los permisos concedidos. |
| POST | `/secrets` | Crea o actualiza el valor compartido. Cuerpo: `{name, identifier?, value}`, más una política de entrega opcional. |
| PUT | `/secrets/{identifier}/strategy` | Cambia la exposición y su lista de hosts. |
| POST | `/secrets/{identifier}/grant` | Añade el identificador a la lista `secrets` de un agente en `beeuni.yaml`. Cuerpo: `{agent}`. |
| DELETE | `/secrets/{name}` | Elimina el valor compartido. Las anulaciones personales se mantienen. |
| PUT | `/secrets/{name}/personal` | Configura o activa la anulación personal de quien llama. |
| DELETE | `/secrets/{name}/personal` | Elimina la anulación personal de quien llama. |

`POST /secrets` rechaza los nombres que empiezan por `BEEUNI_`. Devuelve `409`
si `identifier` ya existe con un `name` diferente. Rechaza el
nombre exacto `CODEX_AUTH_JSON` con `400`: Beeuni administra ese secreto
mediante la incorporación de suscripciones a ChatGPT.

Ambas rutas de escritura devuelven un objeto `delivery_sync` cuando el cambio debe llegar a
los sandboxes en ejecución. `ok: false` significa que el valor se guardó, pero al menos una sesión activa
sigue usando el anterior; las sesiones indicadas lo recibirán al reiniciarse.

Un secreto de la lista incluye `delivery_blocked_reason`. El valor
`no_agent_grant` significa que ningún agente puede recibir este secreto. `null` significa que
está concedido, que la exposición no requiere una concesión o que Beeuni no pudo leer el manifiesto.

`POST /secrets/{identifier}/grant` elimina ese motivo. Devuelve
`already_granted: true` si la lista del agente ya incluye el identificador;
en ese caso, Beeuni no realiza ningún cambio. Devuelve `adopted_governance: true` cuando
la edición añade el primer bloque `agents:` del proyecto, el cambio [descrito
arriba](#grant-a-secret-to-an-agent). Responde `400` `manifest_v1_unsupported`
si el proyecto es `beeuni.toml` y `409` `secret_not_grantable` si el secreto está desactivado.

<a id="rotation-and-propagation"></a>

## Rotación y propagación

La escritura de un secreto no espera a que se reinicie una sesión. Beeuni envía el
cambio a todos los sandboxes activos del proyecto:

1. Beeuni crea una nueva instantánea del entorno usando la concesión `secrets` del agente en ejecución.
2. El sandbox escribe la instantánea en el entorno activo del agente. Las nuevas llamadas a herramientas
   reciben el cambio de inmediato.
3. Si el secreto modificado es una credencial de proveedor de LLM, Beeuni reinicia
   harness estándar.

Este envío se hace todo lo posible. La llamada a la API que cambia el secreto se devuelve
antes de que termine el envío. Los fallos de envío solo se registran; no se vuelven a intentar. Un
sandbox cuyo envío falla conserva el valor anterior hasta el siguiente envío correcto
o hasta que se reinicie la sesión.

<a id="model-credentials"></a>

## Credenciales de modelo

Un proyecto que usa el acceso administrado a modelos de Beeuni no necesita su propia clave. Para
usar la tuya, configura las variables del proveedor a las que hace referencia la configuración de proveedor de harness estándar.
A una clave de modelo reconocida se le asigna el uso de **puerta de enlace de LLM**, que la usa
en el servidor; no es necesario que esté en el sandbox.

No uses un resultado genérico de verificación del proveedor como prueba del funcionamiento en tiempo de ejecución. No puede
verificar el modelo, la región, los derechos de acceso ni el dialecto de API seleccionados. Envía una solicitud real
al modelo exacto.
