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>
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
# 0024b — Security loader: security/ YAML files + shell/security/ loader
|
||||
|
||||
> Parte b del issue [0024-centralized-security-groups.md](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.go` — **impuro**: lee filesystem, parsea YAML, construye `security.SecurityPolicy`
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1: YAML files
|
||||
|
||||
- [ ] **1.1** Crear `security/user-groups.yaml`:
|
||||
```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`:
|
||||
```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`:
|
||||
```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
|
||||
|
||||
```go
|
||||
// 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.
|
||||
Reference in New Issue
Block a user