import: contenido inicial de la skill bitwarden

This commit is contained in:
2026-04-26 14:22:15 -06:00
parent 976454dc79
commit 5534ab954c
9 changed files with 872 additions and 1 deletions

322
SKILL.md Normal file
View File

@@ -0,0 +1,322 @@
---
name: bitwarden
description: Da acceso a TU PROPIO vault de bot (cuenta claudecode0) en el Vaultwarden self-hosted del beneficio Rio Frio (vault.nucleoriofrio.com). NO es el vault del usuario humano — es el tuyo, paralelo a tu cuenta de Gitea. Úsala para guardar/recuperar tus propias credenciales de bot (PATs, API keys de servicios que necesitás como agente), leer credenciales compartidas del org NucleOS (con permiso "Can view"), generar passwords nuevos, o consultar TOTP/exposiciones HIBP. El usuario humano puede pedirte que guardes algo en tu vault o que recuperes algo que tenés guardado, pero las credenciales personales del usuario humano viven en SU vault separado, no acá. Ejemplos de cosas que el usuario te puede pedir: "guardá tu nuevo PAT de gitea en tu vault", "qué credenciales tenés guardadas vos", "buscá en tu vault si tenés el token de X", "generame una password de 24 chars" (utility), "tenés algo guardado para el servicio Y", "leé del org NucleOS el password compartido de Z".
allowed-tools: Bash, Read, Grep
---
# Bitwarden / Vaultwarden — TU vault de bot
## Qué es esto
Skill que te da acceso a **tu propia cuenta** (`claudecode0@nucleoriofrio.com`)
en el Vaultwarden del beneficio (`vault.nucleoriofrio.com`). Es paralela a tu
cuenta `claudecode0` de Gitea — NO es la cuenta del usuario humano.
**Punto importante para no confundirte:**
- Tu vault personal contiene **tus credenciales de bot**: PATs, API keys, tokens
de servicios que necesitás como agente para hacer tu trabajo.
- El usuario humano tiene su propio vault separado en el mismo Vaultwarden, con
sus credenciales personales — **no las tocás vos, no las leés vos**.
- El usuario humano sí tiene acceso administrativo a tu cuenta (puede ver,
modificar y borrar items en TU vault) porque el `.env` con tu master password
vive en su PC y él es admin del servidor. Eso es para auditoría — los items
funcionalmente son tuyos.
- Si el usuario te pide "guardá esto", lo guardás en TU vault. Si te pide
"buscá esto", buscás en TU vault. Si te pide algo personal de él que él no
guardó en TU vault, decile que no lo tenés.
Funciona vía `bw serve`: el CLI oficial de Bitwarden levanta un servidor REST local
en `127.0.0.1:8087` y la skill llama a esos endpoints. La encriptación/desencriptación
del vault pasa local con master password. El server de Vaultwarden solo recibe blobs
encriptados.
- **Server**: `https://vault.nucleoriofrio.com`
- **Tu cuenta**: `claudecode0@nucleoriofrio.com`
- **Auth**: master password (en `.env`) → email+password login → session cacheada
- **Modelo de permisos**: read + create. **PUT/DELETE/PATCH bloqueados** por script guard
- **Bind**: solo `127.0.0.1` (no exposed a la LAN)
## Cómo invocarla correctamente
Antes de cualquier query:
1. **Verificá `~/.claude/skills/bitwarden/.env`**. Si no existe, avisá al usuario:
`cp ~/.claude/skills/bitwarden/.env.example ~/.claude/skills/bitwarden/.env`
y pedí que complete los valores (master password + credenciales).
2. **Primer uso de la sesión**: el primer `query.sh` arranca `bw serve` automáticamente
(vía `serve-up.sh`). Tarda ~3s. Las llamadas siguientes son instantáneas.
3. **Si `query.sh` devuelve 401**: la session expiró o el vault está locked. Corré
`bash ~/.claude/skills/bitwarden/scripts/setup.sh` para re-unlock.
El helper canónico es `query.sh`:
```bash
~/.claude/skills/bitwarden/scripts/query.sh /status
~/.claude/skills/bitwarden/scripts/query.sh /list/object/items
~/.claude/skills/bitwarden/scripts/query.sh "/object/item/<uuid>"
```
Ver `endpoints.md` para la cheat sheet completa.
## Modelo de seguridad (read + create)
Tres capas:
1. **Server-side (la que importa para org NucleOS)**: la cuenta `claudecode0` está
en el org "NucleOS" con role User + collections con permiso "Can view" → server
rechaza cualquier POST/PUT/DELETE en collections del org. Esto te garantiza no
romper nada compartido.
2. **Script guard (la que importa para vault personal)**: `query.sh` rechaza
`-X PUT/DELETE/PATCH` y los POST a `/move/*`, `/restore/*`, `/confirm/*`,
`/object/attachment` antes de salir a la red. Defensa contra modify/delete en
el vault personal del bot, donde server-side no podés limitarte a vos mismo.
3. **bw serve bind a 127.0.0.1**: nadie en la LAN puede pegarle. Solo procesos
locales del usuario.
> ⚠️ El bw CLI tiene una vulnerabilidad histórica conocida
> ([clients#3932](https://github.com/bitwarden/clients/issues/3932)): cualquier
> proceso del usuario en este equipo puede pegar a `127.0.0.1:8087` mientras esté
> unlocked. En la PC personal del usuario es aceptable. Si esta skill se mueve a
> un equipo compartido, hay que repensar.
> ⚠️ El script guard NO es perfecto: se bypass-ea llamando `bw` directo. Si la
> auto-mode runtime te bloquea un `bw delete` o similar, **respetá el bloqueo** —
> incluso para limpieza de pruebas, pedile al usuario que lo borre desde web.
## Cuándo usar qué endpoint
Recordá: cuando el usuario diga "buscá", "guardá", "tenés", se refiere a
**TU vault** (claudecode0). Si te pide algo que no está y suena a personal
del usuario humano, decile que probablemente está en SU vault — no en el tuyo.
### Usuario te pide "buscá en tu vault si tenés X"
```bash
# Buscar por nombre o URL en TU vault
~/.claude/skills/bitwarden/scripts/query.sh "/list/object/items?search=gitea"
# → tomá el id del match. Si necesitás el password en plaintext:
~/.claude/skills/bitwarden/scripts/query.sh "/object/password/<id>"
```
### Usuario te pide "qué tenés guardado vos / inventario de tu vault"
```bash
~/.claude/skills/bitwarden/scripts/query.sh /list/object/items \
| python -c "import json,sys; [print(i['name'], '|', i.get('login',{}).get('username','-')) for i in json.load(sys.stdin)['data']['data']]"
```
### Usuario te pide "generame un password" (utility, no toca vault)
```bash
~/.claude/skills/bitwarden/scripts/query.sh "/generate?length=24&uppercase&lowercase&numbers&special"
# Para passphrase:
~/.claude/skills/bitwarden/scripts/query.sh "/generate?passphrase=true&words=4&separator=-&capitalize"
```
### Usuario te pide "guardá esto en tu vault"
Esto agrega un item a TU vault. Antes de hacerlo:
1. **Listá primero con `?search=<name>`** para ver si ya tenés algo con ese nombre.
Vaultwarden permite duplicados (no overwrite), y crear sin chequear te deja
con dos items idénticos que vos no podés mergear (DELETE bloqueado).
2. Pedí el template para no equivocarte con el schema:
```bash
~/.claude/skills/bitwarden/scripts/query.sh /object/template/item.login
```
3. Construí el JSON con `name`, `login.username`, `login.password`, `login.uris`.
4. POST:
```bash
~/.claude/skills/bitwarden/scripts/query.sh -X POST \
-H 'Content-Type: application/json' \
-d '{"organizationId":null,"folderId":null,"type":1,"name":"...","login":{"username":"...","password":"...","uris":[{"uri":"https://..."}]}}' \
/object/item
```
5. Si la credencial venía del usuario en el chat, **confirmale al usuario**
"guardé `<name>` en mi vault con username `<username>`" sin re-mostrar el
password. Si la generaste vos, podés mostrarla **una vez** al confirmar.
### Usuario te pide TOTP de algo que tenés guardado
```bash
# Buscá el item primero, después:
~/.claude/skills/bitwarden/scripts/query.sh "/object/totp/<item-id>"
# → devuelve el código actual (rota cada 30s)
```
### Usuario te pide "chequeá si esa password fue expuesta"
```bash
~/.claude/skills/bitwarden/scripts/query.sh "/object/exposed/<item-id>"
# → { exposed: <count en HIBP> }
```
### Usuario te pide "leé el password compartido X del org NucleOS"
Si estás invitado al org "NucleOS" con permiso "Can view" en alguna collection:
```bash
# Listar tus orgs
~/.claude/skills/bitwarden/scripts/query.sh /list/object/organizations
# Listar collections del org a las que tenés acceso
~/.claude/skills/bitwarden/scripts/query.sh "/list/object/org-collections?organizationid=<id>"
# Listar items del org
~/.claude/skills/bitwarden/scripts/query.sh "/list/object/items?organizationid=<id>"
# Leer password de un item específico
~/.claude/skills/bitwarden/scripts/query.sh "/object/password/<item-id>"
```
Estos items son **del org**, no tuyos personales. El usuario humano y otros
miembros del org también los ven. NO podés modificarlos ni borrarlos
(server-side rechaza por permiso "Can view").
## Reglas de comportamiento
### Cuando devolvés passwords/secrets al usuario
- El usuario humano tiene acceso administrativo a TU vault, así que técnicamente
puede ver todo igual desde web. Mostrar un password tuyo en el chat cuando él
te lo pide explícitamente está bien — no estás filtrando nada.
- Pero **no muestres passwords espontáneamente**. Si te piden "qué tenés
guardado", listá `name` + `username`, NO password. Si quieren el password,
te lo van a pedir aparte.
- **Nunca cites un password en un summary, commit message, PR description, ni
en cualquier output que pueda quedar en git history, tickets, o canales
externos** — incluso siendo "tu" password de bot, igual es un secret.
- Si te piden "verificá que tengo guardado X", alcanza con devolver "✓ tengo
un item llamado X con username Y" — no hace falta el password para verificar
existencia.
### Cuando creás items nuevos en TU vault
- Listá primero con `?search=<name>` para chequear duplicados. Vaultwarden
permite crear varios items con el mismo nombre (no overwrite), y como vos no
podés borrar (DELETE bloqueado), si te equivocás vas a tener basura
permanente que solo el usuario humano puede limpiar desde web.
- Si la password te la pasa el usuario, no la repitas en el chat — confirmá con
"guardé el item con username X" sin re-mostrar la password.
- Si la password la generás vos (con `/generate`), podés mostrarla **una vez**
al confirmar el guardado para que el usuario sepa qué se guardó. No la
repitas en respuestas posteriores.
- Etiquetá bien el `name` para no confundirte vos en el futuro: usá nombres
descriptivos como `gitea-pat-claudecode0` o `openai-api-key-bot`, no
`gitea` a secas (que se confunde con el password de Gitea del usuario humano,
que NO es tuyo).
### Cuando el usuario te pide modificar/eliminar algo de TU vault
- El guard te lo bloquea por diseño. Opciones:
1. Decile al usuario que él lo haga desde el web vault (él tiene acceso).
2. Pedile autorización explícita para bypass-ear vía `bw` CLI directo. En ese
caso, la línea exacta:
```bash
BITWARDENCLI_APPDATA_DIR=~/.claude/skills/bitwarden/.cache/bw \
BW_SESSION=$(cat ~/.claude/skills/bitwarden/.cache/session) \
bw delete item <id>
```
- **No bypass-ees por iniciativa propia ni para "limpieza" de pruebas**. La
auto-mode runtime te va a frenar y va a tener razón. Si vos creaste basura
por error, asumí el costo y dejala.
### Cuando el usuario te pide algo que NO es tuyo
- Si suena a credencial personal del usuario humano (ej. "buscame mi password
de Netflix"), avisá: "eso debería estar en TU vault personal, no en el mío.
Yo solo tengo acceso a la cuenta `claudecode0`". No intentés "buscar igual
por las dudas".
- Si el usuario te pide algo que crees que está en una collection del org
NucleOS pero no lo encontrás, podría ser que no estés invitado a esa
collection o que el item no exista. Decile.
### Errores típicos
- `401 unauthorized` o output de bw "vault is locked" → corré `setup.sh`
- `Connection refused` a localhost:8087 → `bw serve` murió, corré `serve-up.sh`
- `403 forbidden` en endpoints del org → permiso "Can view" rechaza writes,
esperado y correcto
- `400 bad request` en POST → schema del item está mal, pedí
`GET /object/template/item.login` (o `.card`, etc.)
## Lifecycle: cuándo correr cada script
| Script | Cuándo |
|---|---|
| `setup.sh` | (a) Primera vez. (b) Cuando session expira (401). (c) Cuando se cambió la master password en el .env |
| `serve-up.sh` | Idempotente. Lo llama `query.sh` automáticamente. Solo lo corrés a mano si querés calentar el daemon antes de un batch de queries |
| `serve-down.sh` | Cuando querés liberar el puerto/proceso (raro: el daemon es liviano y no consume mientras no recibe queries) |
| `query.sh` | Para todo lo demás |
`bw serve` queda corriendo en background entre invocaciones de Claude Code (es
un proceso del sistema, no de la sesión). Si reiniciás la PC, la primera query
después del reboot relanzará el daemon.
## Setup inicial (lo hace el usuario UNA vez)
### 1. Crear cuenta `claudecode0` en Vaultwarden web
1. Login admin a `https://vault.nucleoriofrio.com/admin` con `ADMIN_TOKEN`
2. Users → Invite User → email `claudecode0@nucleoriofrio.com`
3. (Como no hay SMTP, no llega mail — alcanza con que quede el invite verificado)
4. Ir a `https://vault.nucleoriofrio.com/#/register` (logueado anónimo)
5. Email: `claudecode0@nucleoriofrio.com`, master password: la que vayas a poner en `.env`
6. Submit → cuenta queda activa
7. **No usar SSO** — actualmente está roto en producción (discovery falla desde dentro
del container, ver task spawn-eada). Email+password directo funciona porque
`SSO_ONLY=false`.
### 2. Crear `.env` local
```bash
cp ~/.claude/skills/bitwarden/.env.example ~/.claude/skills/bitwarden/.env
# Editar y completar BW_PASSWORD, BW_CLIENTID, BW_CLIENTSECRET
chmod 600 ~/.claude/skills/bitwarden/.env # best-effort en Windows
```
> Aunque el .env tiene campos para `BW_CLIENTID` y `BW_CLIENTSECRET`, **la skill
> no los usa actualmente**. Login va por email+password (`bw login --apikey` tiene
> un bug en bw CLI 2026.4.x: deja el cryptographic state null y rompe el unlock
> posterior). Los campos están por si se arregla el bug y queremos volver a API key.
### 3. Correr setup
```bash
~/.claude/skills/bitwarden/scripts/setup.sh
```
Esperado: `→ Listo: unlocked | claudecode0@nucleoriofrio.com | https://vault.nucleoriofrio.com`
### 4. Probar
```bash
~/.claude/skills/bitwarden/scripts/query.sh /status
# → JSON con status: unlocked
```
### 5. (Opcional) Org NucleOS
Si existe organization "NucleOS" en Vaultwarden, el usuario humano debe invitar
a `claudecode0@nucleoriofrio.com` con role **User** + collections con permiso
**Can view** desde el web vault. Después la skill puede leer (no escribir) lo
del org.
## Qué NO hace esta skill
- **No modifica ni elimina** (PUT/DELETE bloqueados, POST en endpoints destructivos
bloqueado).
- **No usa SSO** (el flow está roto en producción — task spawn-eada para fix).
- **No expone MCP** — Bash + curl, igual que unifi y whatsapp.
- **No mantiene cache de items** — cada query golpea localhost:8087 que a su vez
consulta vault local desencriptado.
- **No comparte items con otros users/orgs** (`/move`, `/share` bloqueados).
- **No accede al vault personal del usuario humano** — son cuentas separadas en
Vaultwarden, distintas master passwords, distintos vaults encriptados.
## Archivos de la skill
| Archivo | Qué tiene |
|---|---|
| `SKILL.md` | Este archivo |
| `endpoints.md` | Cheat sheet de endpoints `bw serve` |
| `.env.example` | Plantilla de config |
| `.env` | Config local (no versionado, contiene master password) |
| `scripts/setup.sh` | One-time/recovery setup (config server + login + unlock + sync) |
| `scripts/serve-up.sh` | Asegura `bw serve` arriba (idempotente) |
| `scripts/serve-down.sh` | Mata `bw serve` |
| `scripts/query.sh` | Helper REST con auth + read+create guard |
| `.cache/session` | Session token cacheada (chmod 600) |
| `.cache/serve.pid` | PID de `bw serve` |
| `.cache/serve.log` | stdout/stderr de `bw serve` (debug) |
| `.cache/bw/` | Data dir aislado de `bw` CLI (vault encriptado local, server config) |
## Referencias
- `endpoints.md` — cheat sheet de endpoints
- Doc oficial CLI: https://bitwarden.com/help/cli/
- Vault Management API spec: https://bitwarden.com/help/vault-management-api/
- Vaultwarden self-hosted (compatible 100% con bw CLI): https://github.com/dani-garcia/vaultwarden
- Stack en producción: `nucleo-infra/infrastructure/vaultwarden/stack.yml`