Files
agents_and_robots/dev/issues/completed/0024b-security-loader.md
T
egutierrez 0102afa06e chore: cerrar issue 0024b-security-loader
Mueve el issue a completed/ y actualiza el índice.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 20:32:23 +00:00

4.8 KiB

0024b — Security loader: security/ YAML files + shell/security/ loader

Parte b del issue 0024-centralized-security-groups.md. Requiere 0024a (pkg/security/ tipos).

Objetivo

Crear la carpeta security/ en la raíz del proyecto con los YAML de grupos de usuarios, grupos de agentes y permisos. Crear el loader impuro shell/security/loader.go que los lee y devuelve un security.SecurityPolicy.

Contexto

  • pkg/security/ ya existe (0024a). Este sub-issue añade la capa de persistencia (YAML) y el loader.
  • Los YAML de security/ se commitean al repositorio — son configuración de acceso, no secrets.
  • El código se mergea con feature flag = false (loader creado pero no usado todavía).

Arquitectura

security/                   NEW — en raíz del proyecto
  user-groups.yaml          NEW
  agent-groups.yaml         NEW
  permissions.yaml          NEW

shell/security/             NEW
  loader.go                 NEW
  loader_test.go            NEW

Patron pure core / impure shell

  • security/*.yaml — datos de configuración (no código)
  • shell/security/loader.goimpuro: lee filesystem, parsea YAML, construye security.SecurityPolicy

Tareas

Fase 1: YAML files

  • 1.1 Crear security/user-groups.yaml:
    # Grupos de usuarios del sistema
    # Members: lista de Matrix user IDs, o "*" para todos los usuarios
    groups:
      admins:
        members: []  # rellenar con los administradores reales
      everyone:
        members: ["*"]
    
  • 1.2 Crear security/agent-groups.yaml:
    # Grupos de agentes del sistema
    # Agents: lista de agent IDs (del campo agent.id en config.yaml), o "*" para todos
    groups:
      assistants:
        agents:
          - assistant-bot
          - asistente-2
      all:
        agents: ["*"]
    
  • 1.3 Crear security/permissions.yaml:
    # Políticas de permisos: para cada grupo de agentes, qué acciones tiene cada grupo de usuarios
    # Actions: "*" = todo, "ask" = chat libre, "command:<name>" = comandos, "tool:<name>" = tools
    policies:
      - agent_group: all
        permissions:
          - user_group: admins
            actions: ["*"]
          - user_group: everyone
            actions: ["ask"]
    

Fase 2: Shell loader

  • 2.1 Crear shell/security/loader.go con función Load(dir string) (security.SecurityPolicy, error):
    • Lee <dir>/user-groups.yaml[]security.UserGroup
    • Lee <dir>/agent-groups.yaml[]security.AgentGroup
    • Lee <dir>/permissions.yaml[]security.AgentPolicy
    • Si el directorio no existe o está vacío: devuelve security.SecurityPolicy{} sin error (backward compat)
    • Si un archivo no existe individualmente: ese campo queda vacío (no es error)
    • Si el YAML es inválido: devuelve error con mensaje claro indicando qué archivo falló
  • 2.2 Definir structs YAML intermedios (solo para parseo) distintos de los tipos puros de pkg/security/. Convertir tras parsear. Esto mantiene pkg/security/ independiente de gopkg.in/yaml.v3.

Fase 3: Tests del loader

  • 3.1 Test: directorio inexistente → policy vacía, sin error
  • 3.2 Test: directorio vacío (sin YAML) → policy vacía, sin error
  • 3.3 Test: los 3 YAML válidos → policy con todos los campos
  • 3.4 Test: solo user-groups.yaml presente → user groups poblados, resto vacío
  • 3.5 Test: YAML malformado → error con nombre de archivo en el mensaje
  • 3.6 Test: user_group: "*" y agent: ["*"] parseados correctamente como strings literales

Fase 4: Cleanup

  • 4.1 go build -tags goolm ./... compila
  • 4.2 go test -tags goolm ./shell/security/... pasa
  • 4.3 go test -tags goolm ./... pasa completo

Ejemplo de uso

// En el launcher (todavía no wired — eso es 0024c)
policy, err := shellsecurity.Load("security/")
if err != nil {
    log.Fatal("error loading security policy", err)
}
// policy.UserGroups, policy.AgentGroups, policy.Policies disponibles
acl := security.ResolveACL("assistant-bot", policy)

Decisiones de diseño

  • Structs YAML separados de los tipos puros: pkg/security/ no importa gopkg.in/yaml.v3. El loader usa tipos intermedios locales y convierte. Mantiene el core verdaderamente puro.
  • Directorio no existente = policy vacía: no fuerza a crear los YAML si no se necesitan (ej: agentes puramente públicos). Backward compat con configuraciones existentes.
  • 3 archivos separados: cada uno puede editarse independientemente. Los grupos son más estables que los permisos.

Prerequisitos

  • 0024a completado (pkg/security/ con tipos y ResolveACL)

Riesgos

  • Typos en user IDs de YAML: si un Matrix ID tiene un typo, el usuario no tendrá acceso. No hay validación de formato de ID en este issue — es aceptable para MVP.