Skip to content
Back to skills

Company Messaging

BSecurity

Usar cuando se envían mensajes internos cifrados entre miembros de la organización vía Company Savia.

  • 50 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 27, 2026
ai-agentsgobashvueawsgit

Security analysis

B88/100
  • criticalPipes output to a shell interpreter

Pro scans all 7 files and shows the line behind each finding

Scanned October 5, 2026

npx -y skills add gonzalezpazmonica/savia --skill company-messaging --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Company Messaging?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Company Messaging
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/gonzalezpazmonica-company-messaging/badge)](https://www.skillsdirectory.com/skills/gonzalezpazmonica-company-messaging)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
layer: peripheral
name: company-messaging
description: Usar cuando se envían mensajes internos cifrados entre miembros de la organización vía Company Savia.
allowed-tools: [Read, Bash, Glob, Grep]
metadata:
  # --- metadata.savia.* (SE-333) ---
  savia.category: communication
  savia.maturity: beta
  savia.disable-model-invocation: false
  savia.priority: medium
  savia.summary: "Mensajeria interna Company Savia sobre ramas git con cifrado hibrido RSA+AES (confidencialidad, sin autenticacion ni integridad). Soporta mensajes directos, broadcasts y threading. Datos en company repo compartido. Nivel N2 (empresa)."
  savia.tags: "messaging, company, encryption, privacy"
  savia.user-invocable: False
---

# Company Messaging — Skill (ramas git, v3)

Mensajería asíncrona entre miembros de una organización sobre un repo git
compartido (Company Savia). Cada mensaje es un fichero markdown con
frontmatter YAML. Comportamiento verificado por `tests/test-company-messaging.bats`
contra un remoto bare local.

## Ramas y rutas reales

```
main
  ├── directory.md              ← directorio: tabla "| @handle | Nombre | Rol | Estado |"
  ├── pubkeys/{handle}.pem      ← claves públicas
  └── company/inbox/{id}.md     ← anuncios
exchange (huérfana)
  └── pending/{id}.md           ← mensajes directos en tránsito
user/{handle} (huérfana)
  ├── inbox/unread/{id}.md
  ├── inbox/read/{id}.md
  └── outbox/{id}.md            ← copia de lo enviado
```

Un handle solo admite `[A-Za-z0-9_-]`: se convierte en nombre de rama y de
ruta. La resolución es exacta (`@bo` no resuelve a `@bob`) y acepta tanto
filas de tabla (`| @bob | ... |`, el formato que genera `company-repo`) como
líneas `@bob` sueltas.

## Ciclo de vida de un mensaje

El cuerpo NUNCA va en argv (`/proc/<pid>/cmdline` es legible por cualquier
usuario local durante todo el envío): llega por stdin o con
`--body-file <fichero>`, que debe tener modo 0600 (o 0400); `--body-file -`
es stdin. Un cuerpo como argumento posicional se rechaza con código 2 y un
cuerpo vacío con código 1. Internamente el mensaje llega a
`savia-branch.sh write ... -` y a `savia-crypto.sh encrypt` también por
stdin. Ejemplo:

```bash
printf '%s' "$cuerpo" | bash scripts/savia-messaging.sh send bob "Asunto" --encrypt
```

1. `send <handle> <asunto> [--body-file f] [--encrypt] [--priority p]`: trae `main`
   (directorio y claves frescos; sin red avisa y usa la última vista), resuelve el
   handle, cifra el cuerpo si se pide, pasa el mensaje entero por
   `privacy-check-company.sh --stdin` (bloquea si hay secretos) y lo escribe
   en `exchange:pending/{id}.md` más una copia en `user/{remitente}:outbox/`.
2. `inbox`: entrega los pendientes dirigidos al usuario
   (`exchange:pending` → `user/{handle}:inbox/unread/`) y lista no leídos y
   anuncios. Un mensaje ya presente en `unread/` o `read/` no se vuelve a
   entregar. Sin acceso al remoto avisa y muestra la última vista.
3. `read <id>`: muestra el mensaje y lo mueve de `unread/` a `read/` en un
   solo commit (sale de `unread/`).
4. `reply <id> [--body-file f]`: hereda `thread` del original (o usa su id) y fija
   `reply_to`.
5. `broadcast <asunto> [--body-file f]`: un `send` independiente por cada handle del
   directorio salvo el propio; devuelve error si falla alguno.
6. `announce <asunto> [--body-file f]`: escribe en `main:company/inbox/` (sin
   cifrar). Lectura de anuncios en `$HOME/.pm-workspace/company-inbox-read.log`.

Los ids son `AAAAMMDD-HHMMSS-PID-aleatorio`: los mensajes de un mismo
broadcast no colisionan.

No hay purga: los ficheros de `exchange:pending/` permanecen tras la
entrega (la deduplicación evita reentregas). No existe política de retención
implementada.

## Escrituras entre ramas (`savia-branch.sh`)

`write`, `move` y `ensure-orphan` operan con un worktree temporal desacoplado
(`mktemp -d`), sin cambiar la rama del clon:

- Con remoto `origin`: base en `origin/<rama>` recién traída (una rama local
  obsoleta perdería mensajes de otros), commit y `push HEAD:<rama>`. Si el
  push se rechaza por no ser fast-forward (otro miembro escribió a la vez),
  reintenta hasta 5 veces con espera aleatoria creciente; con muchos
  escritores simultáneos puede agotar los reintentos, siempre con error
  visible. Cualquier otro fallo de push devuelve código 1
  con el motivo en stderr: nunca se traga en silencio.
- La rama local se adelanta si no está extraída en ningún worktree; la rama
  extraída (normalmente `main`) no se toca para no desincronizar su árbol.
- Sin remoto `origin`: el commit va a la rama local.
- Reescribir el mismo contenido es un no-op con éxito.

## Cifrado (`savia-crypto.sh`)

Híbrido RSA-4096 + AES-256-CBC con openssl. Da confidencialidad, no
autenticación: no es "E2E" en sentido fuerte (ver límites).

- `keygen [--force]`: par en `~/.pm-workspace/savia-keys/` (privada en 600).
  Sin `--force` no sobrescribe un par existente.
- `encrypt <pubkey.pem> [texto]`: sin texto lee stdin; un texto vacío cifra
  vacío. Salida `base64(clave cifrada):::base64(cuerpo cifrado)`. Un secreto
  aleatorio de 256 bits por mensaje deriva clave e IV (PBKDF2 con sal) y llega
  a openssl por fichero (`-pass file:`), nunca por argv; `send` pasa el cuerpo
  por stdin. El secreto viaja cifrado con RSA como `p:<secreto>`.
- `decrypt` acepta también el formato anterior (`<clave>:<iv>` con `-K/-iv`),
  que sí expone la clave en argv al descifrar.
- `decrypt [paquete|-]`: con `-` o sin argumento lee stdin. Los paquetes de
  más de 128 KB solo caben por stdin (límite de un argumento en Linux).
- Descifrar con otra clave privada o un paquete sin `:::` falla con código
  distinto de 0.

El flujo de mensajería NO descifra al leer: `read` muestra el paquete y el
destinatario lo descifra con `savia-crypto.sh decrypt`. El asunto nunca se
cifra.

Límites conocidos (no resueltos aquí): relleno RSA PKCS#1 v1.5, AES-CBC sin
MAC (el cifrado no detecta manipulación) y sin firma del remitente, así que
`from:` no está autenticado.

## Privacidad (`privacy-check-company.sh`)

- `--stdin`: analiza un mensaje (claves AWS, PAT de GitHub, claves `sk-`,
  JWT, IP privadas, cadenas de conexión, claves privadas PEM) de cualquier
  tamaño. Lo invocan `send` y `announce` antes de cualquier push. Con
  `--encrypt` analiza el mensaje ya cifrado: el cuerpo en claro no se
  inspecciona (solo frontmatter y asunto).
- `<repo> <handle>`: analiza `user/{handle}:inbox/unread/` y `documents/` por
  rama, y los cambios staged solo si el clon está en `user/{handle}` o
  `exchange`.
- El asunto se revisa aparte con `check_subject_sensitivity`: solo avisa, no
  bloquea (ver `docs/rules/domain/messaging-subject-safety.md`).

## Scripts

| Script | Función |
|--------|---------|
| `scripts/savia-branch.sh` | read, list, write, move, exists, ensure-orphan, check-permission, fetch-messages |
| `scripts/savia-messaging.sh` (+ `-inbox`, `-actions`, `-privacy`) | send, inbox, read, reply, announce, broadcast, directory |
| `scripts/savia-crypto.sh` (+ `savia-crypto-ops.sh`) | keygen, encrypt, decrypt, export-pubkey |
| `scripts/privacy-check-company.sh` | Filtro de privacidad |
| `scripts/savia-compat.sh` | Utilidades portables (base64, YAML, config) |

Configuración: `~/.pm-workspace/company-repo` con `LOCAL_PATH=` y `USER_HANDLE=`.

Files in this skill

  • DOMAIN.md1.7 KB
  • SKILL.md4.7 KB
  • references/company-savia-config.md6.1 KB
  • references/confidentiality-config.md4.6 KB
  • references/confidentiality-strategies.md2.9 KB
  • references/flow-schemas.md2.5 KB
  • references/message-schema.md2.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…