Security audit workflow - vulnerability scan → verification
npx skills add TrenzaCR/trenzaos-config --skill "trenza-security"
Install specific skill from multi-skill repository
# Description
>
# SKILL.md
name: trenza-security
description: >
Estándares de seguridad y políticas RLS para TrenzaOS.
Trigger: Al escribir código que accede a la base de datos, autenticación, o políticas de seguridad.
license: MIT
metadata:
author: trenza
version: "1.0"
TrenzaOS Security Skills
Purpose
Este skill enforce las reglas de seguridad obligatorias de TrenzaOS para todo desarrollo.
Core Rules
1. PROHIBICIÓN DE service_role
- ❌ NUNCA uses
service_role_keyen Server Components, Server Actions, API Routes, o cualquier código expuesto al cliente - ✅ Solo usa el JWT del usuario autenticado
- ✅ Si necesitas acceso privilegiado, crea una Edge Function con validación explícita
2. AISLAMIENTOS OBLIGATORIOS
Todo acceso a datos DEBE incluir:
// SIEMPRE: Filtrar por tenant_id
const products = await db.query.products.findMany({
where: eq(products.tenantId, currentTenantId) // ✅ Obligatorio
})
// NUNCA: Confiar en tenant_id del cliente
const products = await db.query.products.findMany({
where: eq(products.tenantId, formData.get('tenantId')) // ❌ PROHIBIDO
})
3. Row Level Security (RLS)
Toda tabla de negocio DEBE tener:
-- Política de aislamiento obligatoria
CREATE POLICY "table_tenant_isolation" ON table_name
FOR ALL
USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid)
WITH CHECK (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
Checklist para nuevas tablas:
- [ ] tenant_id como columna obligatoria
- [ ] Columnas auditoras: created_by, created_at, updated_at
- [ ] RLS habilitado: ALTER TABLE enable ROW LEVEL SECURITY
- [ ] Política de aislamiento creada
- [ ] Índice en tenant_id
4. Protección Contra IDOR
- ✅ Usa UUIDs, NUNCA IDs secuenciales
- ✅ Valida ownership server-side antes de mutaciones
- ✅ Usa Signed URLs para recursos compartidos
// Validar ownership
async function validateOwnership(resourceId: string, userId: string) {
const resource = await db.query.resources.findFirst({
where: and(
eq(resources.id, resourceId),
eq(resources.ownerId, userId)
)
})
if (!resource) throw new ForbiddenError('RESOURCE_NOT_OWNED')
}
5. Error Handling
- ❌ NUNCA expongas errores crudos al cliente
- ✅ Mapea a
error_codey mensaje genérico
catch (error) {
console.error('Operation failed:', error)
return {
status: 'error',
error_code: 'INTERNAL_ERROR',
message: 'Ha ocurrido un error interno'
}
}
Security Checklist
Antes de escribir código, verifica:
- [ ] ¿Estoy usando
service_role? → ELIMINAR - [ ] ¿Tengo
tenant_iden el WHERE? → AGREGAR - [ ] ¿La tabla tiene RLS? → CREAR política
- [ ] ¿Estoy exponiendo errores crudos? → MAPEAR a error_code
- [ ] ¿Uso UUIDs? → SÍ, nunca IDs secuenciales
References
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.