@saulwade/swl-ses 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +238 -0
- package/README.md +560 -0
- package/_userland/agentes/.gitkeep +0 -0
- package/_userland/habilidades/.gitkeep +0 -0
- package/agentes/.evolved.json +9 -0
- package/agentes/accesibilidad-wcag-swl.md +692 -0
- package/agentes/arquitecto-swl.md +238 -0
- package/agentes/auto-evolucion-swl.md +854 -0
- package/agentes/backend-api-swl.md +470 -0
- package/agentes/backend-csharp-swl.md +418 -0
- package/agentes/backend-go-swl.md +388 -0
- package/agentes/backend-java-swl.md +279 -0
- package/agentes/backend-node-swl.md +477 -0
- package/agentes/backend-python-swl.md +608 -0
- package/agentes/backend-rust-swl.md +362 -0
- package/agentes/backend-workers-swl.md +480 -0
- package/agentes/cloud-infra-swl.md +485 -0
- package/agentes/consolidador-swl.md +539 -0
- package/agentes/datos-swl.md +584 -0
- package/agentes/depurador-swl.md +349 -0
- package/agentes/devops-ci-swl.md +374 -0
- package/agentes/disenador-ui-swl.md +558 -0
- package/agentes/documentador-swl.md +343 -0
- package/agentes/evals/arquitecto-swl.evals.json +56 -0
- package/agentes/evals/auto-evolucion-swl.evals.json +68 -0
- package/agentes/evals/implementador-swl.evals.json +56 -0
- package/agentes/evals/orquestador-swl.evals.json +60 -0
- package/agentes/evals/perfilador-usuario-swl.evals.json +60 -0
- package/agentes/evals/red-team-swl.evals.json +59 -0
- package/agentes/evals/revisor-codigo-swl.evals.json +59 -0
- package/agentes/frontend-angular-swl.md +627 -0
- package/agentes/frontend-css-swl.md +720 -0
- package/agentes/frontend-react-swl.md +696 -0
- package/agentes/frontend-swl.md +500 -0
- package/agentes/frontend-tailwind-swl.md +830 -0
- package/agentes/implementador-swl.md +328 -0
- package/agentes/investigador-swl.md +430 -0
- package/agentes/investigador-ux-swl.md +500 -0
- package/agentes/llm-apps-swl.md +276 -0
- package/agentes/migrador-swl.md +417 -0
- package/agentes/mobile-android-swl.md +509 -0
- package/agentes/mobile-cross-swl.md +539 -0
- package/agentes/mobile-ios-swl.md +500 -0
- package/agentes/mobile-testing-swl.md +300 -0
- package/agentes/notificador-swl.md +916 -0
- package/agentes/observabilidad-swl.md +436 -0
- package/agentes/orquestador-swl.md +884 -0
- package/agentes/pagos-swl.md +283 -0
- package/agentes/perfilador-usuario-swl.md +306 -0
- package/agentes/planificador-swl.md +402 -0
- package/agentes/producto-prd-swl.md +587 -0
- package/agentes/red-team-swl.md +216 -0
- package/agentes/release-manager-swl.md +568 -0
- package/agentes/rendimiento-swl.md +714 -0
- package/agentes/resolutor-build-swl.md +243 -0
- package/agentes/revisor-angular-swl.md +276 -0
- package/agentes/revisor-codigo-swl.md +348 -0
- package/agentes/revisor-csharp-swl.md +262 -0
- package/agentes/revisor-go-swl.md +257 -0
- package/agentes/revisor-java-swl.md +255 -0
- package/agentes/revisor-kotlin-swl.md +271 -0
- package/agentes/revisor-nextjs-swl.md +279 -0
- package/agentes/revisor-php-swl.md +269 -0
- package/agentes/revisor-react-swl.md +276 -0
- package/agentes/revisor-rust-swl.md +344 -0
- package/agentes/revisor-seguridad-swl.md +390 -0
- package/agentes/revisor-swift-swl.md +266 -0
- package/agentes/revisor-typescript-swl.md +344 -0
- package/agentes/sre-swl.md +265 -0
- package/agentes/tdd-qa-swl.md +354 -0
- package/agentes/ux-disenador-swl.md +501 -0
- package/bin/lib/bot-comandos.js +1030 -0
- package/bin/lib/bot-discovery.js +182 -0
- package/bin/lib/bot-git.js +142 -0
- package/bin/swl-ses.js +325 -0
- package/bin/swl-telegram-bot.js +442 -0
- package/bin/swl-telegram-bot.plist +21 -0
- package/bin/swl-telegram-bot.service +14 -0
- package/comandos/swl/.evolved.json +23 -0
- package/comandos/swl/actualizar.md +174 -0
- package/comandos/swl/adoptar-proyecto.md +207 -0
- package/comandos/swl/aprender.md +701 -0
- package/comandos/swl/auditar-deps.md +134 -0
- package/comandos/swl/autoresearch.md +170 -0
- package/comandos/swl/ayuda.md +224 -0
- package/comandos/swl/brainstorm.md +50 -0
- package/comandos/swl/checkpoint.md +330 -0
- package/comandos/swl/compactar.md +283 -0
- package/comandos/swl/configurar-ci.md +227 -0
- package/comandos/swl/contexto.md +112 -0
- package/comandos/swl/contribuir.md +233 -0
- package/comandos/swl/crear-skill.md +292 -0
- package/comandos/swl/cron.md +196 -0
- package/comandos/swl/dashboard.md +146 -0
- package/comandos/swl/discutir-fase.md +230 -0
- package/comandos/swl/ejecutar-fase.md +135 -0
- package/comandos/swl/evaluar-skill.md +487 -0
- package/comandos/swl/evolucion-estado.md +142 -0
- package/comandos/swl/evolucionar.md +259 -0
- package/comandos/swl/exportar-vault.md +189 -0
- package/comandos/swl/gateway.md +158 -0
- package/comandos/swl/inbox.md +116 -0
- package/comandos/swl/instalar.md +220 -0
- package/comandos/swl/instintos.md +86 -0
- package/comandos/swl/mapear-codebase.md +312 -0
- package/comandos/swl/mcp-status.md +175 -0
- package/comandos/swl/metricas.md +270 -0
- package/comandos/swl/modelo.md +102 -0
- package/comandos/swl/notificaciones.md +396 -0
- package/comandos/swl/nuevo-proyecto.md +154 -0
- package/comandos/swl/planear-fase.md +221 -0
- package/comandos/swl/plugins.md +256 -0
- package/comandos/swl/reflect-skills.md +125 -0
- package/comandos/swl/release.md +217 -0
- package/comandos/swl/revisar-impacto.md +206 -0
- package/comandos/swl/revisar.md +330 -0
- package/comandos/swl/salud.md +363 -0
- package/comandos/swl/sesiones.md +200 -0
- package/comandos/swl/skill-search.md +113 -0
- package/comandos/swl/verificar.md +585 -0
- package/comandos/swl/wiki.md +620 -0
- package/contextos/dev.md +32 -0
- package/contextos/research.md +30 -0
- package/contextos/review.md +31 -0
- package/habilidades/accesibilidad-a11y/SKILL.md +201 -0
- package/habilidades/accesibilidad-a11y/evals/evals.json +56 -0
- package/habilidades/accesibilidad-a11y/recursos/ejemplos-y-checklist-completo.md +441 -0
- package/habilidades/agent-browser/SKILL.md +218 -0
- package/habilidades/agentes-como-servicio/SKILL.md +218 -0
- package/habilidades/ai-runtime-security/SKILL.md +273 -0
- package/habilidades/angular-avanzado/SKILL.md +164 -0
- package/habilidades/angular-avanzado/recursos/ejemplos-avanzados.md +219 -0
- package/habilidades/angular-moderno/SKILL.md +186 -0
- package/habilidades/angular-moderno/evals/evals.json +45 -0
- package/habilidades/angular-moderno/recursos/ejemplos-avanzados.md +106 -0
- package/habilidades/api-rest-diseno/SKILL.md +191 -0
- package/habilidades/api-rest-diseno/recursos/openapi-template.yaml +506 -0
- package/habilidades/api-rest-diseno/recursos/referencia-api.md +140 -0
- package/habilidades/aprendizaje-continuo/SKILL.md +151 -0
- package/habilidades/aprendizaje-continuo/evals/evals.json +53 -0
- package/habilidades/aprendizaje-continuo/recursos/referencia-instintos.md +290 -0
- package/habilidades/async-python/SKILL.md +149 -0
- package/habilidades/async-python/evals/evals.json +47 -0
- package/habilidades/async-python/recursos/patrones-y-ejemplos-completos.md +292 -0
- package/habilidades/auth-patrones/.evolved.json +9 -0
- package/habilidades/auth-patrones/SKILL.md +413 -0
- package/habilidades/auth-patrones/recursos/implementaciones-completas.md +229 -0
- package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -0
- package/habilidades/auto-evolucion-protocolo/evals/evals.json +55 -0
- package/habilidades/auto-evolucion-protocolo/recursos/referencia-completa.md +145 -0
- package/habilidades/autoresearch/SKILL.md +268 -0
- package/habilidades/autoresearch/evals/evals.json +41 -0
- package/habilidades/autoresearch/recursos/checklist-template.md +191 -0
- package/habilidades/autoresearch/scripts/calcular-score.js +88 -0
- package/habilidades/azure-cloud/SKILL.md +308 -0
- package/habilidades/azure-cloud/recursos/aks.md +327 -0
- package/habilidades/backend-mcp-servidor/SKILL.md +270 -0
- package/habilidades/backend-production-resilience/SKILL.md +288 -0
- package/habilidades/brainstorming/SKILL.md +295 -0
- package/habilidades/brainstorming/recursos/componentes-html.md +247 -0
- package/habilidades/build-errors-cpp/SKILL.md +270 -0
- package/habilidades/build-errors-csharp/SKILL.md +265 -0
- package/habilidades/build-errors-go/SKILL.md +306 -0
- package/habilidades/build-errors-java/SKILL.md +278 -0
- package/habilidades/build-errors-kotlin/SKILL.md +303 -0
- package/habilidades/build-errors-nextjs/SKILL.md +312 -0
- package/habilidades/build-errors-php/SKILL.md +270 -0
- package/habilidades/build-errors-python/SKILL.md +292 -0
- package/habilidades/build-errors-rust/SKILL.md +284 -0
- package/habilidades/build-errors-swift/SKILL.md +272 -0
- package/habilidades/build-errors-typescript/SKILL.md +369 -0
- package/habilidades/checklist-calidad/SKILL.md +271 -0
- package/habilidades/checklist-calidad/recursos/quality-report-template.md +148 -0
- package/habilidades/checklist-seguridad/SKILL.md +285 -0
- package/habilidades/checkpoints-verificacion/SKILL.md +298 -0
- package/habilidades/checkpoints-verificacion/recursos/checkpoint-templates.md +360 -0
- package/habilidades/ci-cd-pipelines/SKILL.md +157 -0
- package/habilidades/ci-cd-pipelines/recursos/github-actions-template.yaml +403 -0
- package/habilidades/ci-cd-pipelines/recursos/pipelines-completos.md +487 -0
- package/habilidades/cloud-aws/SKILL.md +142 -0
- package/habilidades/cloud-aws/recursos/servicios-aws-referencia.md +321 -0
- package/habilidades/compactacion-contexto/SKILL.md +247 -0
- package/habilidades/contenedores-docker/SKILL.md +137 -0
- package/habilidades/contenedores-docker/recursos/dockerfile-template.dockerfile +160 -0
- package/habilidades/contenedores-docker/recursos/ejemplos-y-configuraciones.md +327 -0
- package/habilidades/context-builder/SKILL.md +170 -0
- package/habilidades/control-profundidad/SKILL.md +128 -0
- package/habilidades/csharp-experto/SKILL.md +322 -0
- package/habilidades/csharp-patrones/SKILL.md +316 -0
- package/habilidades/csharp-testing/SKILL.md +286 -0
- package/habilidades/css-moderno/SKILL.md +166 -0
- package/habilidades/css-moderno/evals/evals.json +43 -0
- package/habilidades/css-moderno/recursos/ejemplos-y-patrones-completos.md +337 -0
- package/habilidades/datos-etl/SKILL.md +129 -0
- package/habilidades/datos-etl/recursos/implementaciones-completas.md +322 -0
- package/habilidades/dbml-experto/SKILL.md +339 -0
- package/habilidades/dbml-experto/evals/evals.json +56 -0
- package/habilidades/dependencias-auditoria/SKILL.md +320 -0
- package/habilidades/deprecacion-migracion/SKILL.md +169 -0
- package/habilidades/deprecacion-migracion/recursos/implementaciones-completas.md +220 -0
- package/habilidades/design-tokens/SKILL.md +158 -0
- package/habilidades/design-tokens/recursos/tokens-y-configuracion.md +363 -0
- package/habilidades/devsecops-pipeline-security/SKILL.md +309 -0
- package/habilidades/diagrama-arquitectura/SKILL.md +165 -0
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -0
- package/habilidades/discutir-fase/SKILL.md +188 -0
- package/habilidades/diseno-herramientas-agente/SKILL.md +199 -0
- package/habilidades/diseno-responsivo/SKILL.md +186 -0
- package/habilidades/diseno-responsivo/recursos/ejemplos-layouts.md +156 -0
- package/habilidades/django-experto/SKILL.md +205 -0
- package/habilidades/django-experto/recursos/async-django.md +390 -0
- package/habilidades/django-experto/recursos/drf-patrones.md +438 -0
- package/habilidades/django-experto/recursos/orm-avanzado.md +382 -0
- package/habilidades/django-experto/recursos/referencia-completa.md +188 -0
- package/habilidades/django-experto/recursos/testing-django.md +415 -0
- package/habilidades/doc-sync/SKILL.md +280 -0
- package/habilidades/drift-detection/SKILL.md +179 -0
- package/habilidades/ejecutar-fase/SKILL.md +468 -0
- package/habilidades/estilo-sin-ai-isms/SKILL.md +775 -0
- package/habilidades/estilo-sin-ai-isms/evals/evals.json +63 -0
- package/habilidades/estilo-sin-ai-isms/scripts/detectar_aiisms.py +500 -0
- package/habilidades/estructura-proyecto-claude/SKILL.md +215 -0
- package/habilidades/estructura-proyecto-claude/recursos/claude-md-template.md +261 -0
- package/habilidades/estructura-proyecto-claude/recursos/configuracion-y-extensiones.md +176 -0
- package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +289 -0
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +77 -0
- package/habilidades/estructura-proyecto-claude/recursos/variantes-por-stack.md +177 -0
- package/habilidades/evaluacion-agentes/SKILL.md +314 -0
- package/habilidades/event-driven/SKILL.md +153 -0
- package/habilidades/event-driven/recursos/implementaciones-completas.md +423 -0
- package/habilidades/extraccion-documentos/SKILL.md +221 -0
- package/habilidades/extractor-de-aprendizajes/.evolved.json +9 -0
- package/habilidades/extractor-de-aprendizajes/SKILL.md +311 -0
- package/habilidades/extractor-de-aprendizajes/evals/evals.json +55 -0
- package/habilidades/fastapi-experto/SKILL.md +221 -0
- package/habilidades/fastapi-experto/recursos/async-patterns.md +438 -0
- package/habilidades/fastapi-experto/recursos/dependency-injection.md +330 -0
- package/habilidades/fastapi-experto/recursos/referencia-completa.md +79 -0
- package/habilidades/fastapi-experto/recursos/testing-httpx.md +420 -0
- package/habilidades/filament-admin/SKILL.md +290 -0
- package/habilidades/frontend-avanzado/SKILL.md +257 -0
- package/habilidades/frontend-avanzado/recursos/apis-nativas-ejemplos.md +341 -0
- package/habilidades/gcp-cloud/SKILL.md +260 -0
- package/habilidades/gcp-cloud/recursos/gke.md +234 -0
- package/habilidades/gcp-cloud/recursos/terraform-gcp.md +307 -0
- package/habilidades/generacion-mermaid/SKILL.md +229 -0
- package/habilidades/git-worktrees-paralelo/SKILL.md +270 -0
- package/habilidades/go-experto/SKILL.md +305 -0
- package/habilidades/go-patrones/SKILL.md +299 -0
- package/habilidades/go-testing/SKILL.md +291 -0
- package/habilidades/graphql-experto/SKILL.md +323 -0
- package/habilidades/guardrail-semantico/SKILL.md +282 -0
- package/habilidades/harness-claude-code/SKILL.md +299 -0
- package/habilidades/iam-secretos/SKILL.md +265 -0
- package/habilidades/iam-secretos/recursos/implementaciones-completas.md +356 -0
- package/habilidades/infra-github-actions/SKILL.md +166 -0
- package/habilidades/instalar-sistema/.evolved.json +9 -0
- package/habilidades/instalar-sistema/SKILL.md +221 -0
- package/habilidades/java-experto/SKILL.md +290 -0
- package/habilidades/java-patrones/SKILL.md +275 -0
- package/habilidades/java-testing/SKILL.md +288 -0
- package/habilidades/kotlin-compose/SKILL.md +278 -0
- package/habilidades/kotlin-compose/recursos/animaciones-performance.md +93 -0
- package/habilidades/kotlin-experto/SKILL.md +318 -0
- package/habilidades/kotlin-testing/SKILL.md +267 -0
- package/habilidades/kotlin-testing/recursos/testing-avanzado.md +74 -0
- package/habilidades/kubernetes-orquestacion/SKILL.md +152 -0
- package/habilidades/kubernetes-orquestacion/recursos/manifiestos-completos.md +452 -0
- package/habilidades/langchain-langraph/SKILL.md +386 -0
- package/habilidades/langchain-langraph/recursos/evaluacion-rag.md +321 -0
- package/habilidades/langchain-langraph/recursos/rag-maturity-model.md +225 -0
- package/habilidades/langchain-langraph/recursos/vectorstores.md +306 -0
- package/habilidades/legacy-code-rescue/SKILL.md +267 -0
- package/habilidades/likec4-experto/SKILL.md +412 -0
- package/habilidades/likec4-experto/evals/evals.json +69 -0
- package/habilidades/manejo-errores/.evolved.json +9 -0
- package/habilidades/manejo-errores/SKILL.md +407 -0
- package/habilidades/manejo-errores/recursos/implementaciones-completas.md +248 -0
- package/habilidades/mapear-codebase/SKILL.md +275 -0
- package/habilidades/memoria-busqueda/SKILL.md +194 -0
- package/habilidades/memoria-busqueda/evals/evals.json +44 -0
- package/habilidades/meta-skills-estandar/SKILL.md +298 -0
- package/habilidades/meta-skills-estandar/recursos/anti-patrones-y-leyes.md +205 -0
- package/habilidades/meta-skills-estandar/recursos/frameworks-seguridad.md +107 -0
- package/habilidades/meta-skills-estandar/recursos/idiomas-framework.md +60 -0
- package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -0
- package/habilidades/microservicios/SKILL.md +155 -0
- package/habilidades/microservicios/recursos/patrones-y-ejemplos-completos.md +325 -0
- package/habilidades/mobile-flutter/SKILL.md +199 -0
- package/habilidades/mobile-flutter/recursos/ejemplos-completos.md +319 -0
- package/habilidades/mobile-react-native/SKILL.md +176 -0
- package/habilidades/mobile-react-native/recursos/ejemplos-completos.md +216 -0
- package/habilidades/mongodb-experto/SKILL.md +302 -0
- package/habilidades/monitoring-alertas/SKILL.md +201 -0
- package/habilidades/monitoring-alertas/recursos/instrumentacion-y-alertas.md +301 -0
- package/habilidades/nestjs-experto/SKILL.md +307 -0
- package/habilidades/nestjs-experto/recursos/guards-interceptors.md +339 -0
- package/habilidades/nestjs-experto/recursos/modulos-di.md +287 -0
- package/habilidades/nestjs-experto/recursos/testing-nestjs.md +354 -0
- package/habilidades/nextjs-experto/SKILL.md +335 -0
- package/habilidades/nextjs-patrones/SKILL.md +303 -0
- package/habilidades/nextjs-testing/SKILL.md +331 -0
- package/habilidades/node-experto/.evolved.json +9 -0
- package/habilidades/node-experto/SKILL.md +266 -0
- package/habilidades/node-experto/recursos/patrones-completos.md +283 -0
- package/habilidades/notificaciones-multicanal/SKILL.md +159 -0
- package/habilidades/notificaciones-multicanal/recursos/config-template.json +115 -0
- package/habilidades/notificaciones-multicanal/recursos/configuracion-y-templates.md +303 -0
- package/habilidades/nuevo-proyecto/SKILL.md +204 -0
- package/habilidades/orquestacion-async/SKILL.md +303 -0
- package/habilidades/paid-media-tracking/SKILL.md +269 -0
- package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +220 -0
- package/habilidades/paid-media-tracking/recursos/google-ads-api.md +215 -0
- package/habilidades/patrones-python/SKILL.md +228 -0
- package/habilidades/patrones-python/evals/evals.json +56 -0
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -0
- package/habilidades/patrones-python/recursos/referencia-completa.md +202 -0
- package/habilidades/perfil-usuario/SKILL.md +200 -0
- package/habilidades/perfil-usuario/evals/evals.json +55 -0
- package/habilidades/performance-baseline/SKILL.md +297 -0
- package/habilidades/php-experto/SKILL.md +291 -0
- package/habilidades/php-patrones/SKILL.md +306 -0
- package/habilidades/php-testing/SKILL.md +280 -0
- package/habilidades/planear-fase/SKILL.md +269 -0
- package/habilidades/postgresql-experto/SKILL.md +151 -0
- package/habilidades/postgresql-experto/evals/evals.json +53 -0
- package/habilidades/postgresql-experto/recursos/referencia-completa.md +215 -0
- package/habilidades/prevencion-racionalizacion/SKILL.md +175 -0
- package/habilidades/prevencion-sobreingenieria/SKILL.md +323 -0
- package/habilidades/privacy-memoria/SKILL.md +141 -0
- package/habilidades/privacy-memoria/evals/evals.json +43 -0
- package/habilidades/prompt-engineering/SKILL.md +518 -0
- package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +467 -0
- package/habilidades/rag-arquitectura/SKILL.md +338 -0
- package/habilidades/rails-experto/SKILL.md +237 -0
- package/habilidades/rails-experto/recursos/active-record.md +260 -0
- package/habilidades/rails-experto/recursos/hotwire-turbo.md +293 -0
- package/habilidades/rails-experto/recursos/testing-rspec.md +362 -0
- package/habilidades/react-experto/SKILL.md +209 -0
- package/habilidades/react-experto/evals/evals.json +55 -0
- package/habilidades/react-experto/recursos/patrones-y-ejemplos-completos.md +240 -0
- package/habilidades/react-optimizacion/SKILL.md +174 -0
- package/habilidades/react-optimizacion/recursos/patrones-avanzados.md +138 -0
- package/habilidades/redis-experto/SKILL.md +305 -0
- package/habilidades/release-semver/.evolved.json +9 -0
- package/habilidades/release-semver/SKILL.md +248 -0
- package/habilidades/release-semver/scripts/generar-changelog.sh +238 -0
- package/habilidades/rust-experto/SKILL.md +400 -0
- package/habilidades/rust-patrones/SKILL.md +296 -0
- package/habilidades/rust-testing/SKILL.md +311 -0
- package/habilidades/seguridad-skills-ia/SKILL.md +262 -0
- package/habilidades/sql-optimizacion/SKILL.md +200 -0
- package/habilidades/sql-optimizacion/evals/evals.json +54 -0
- package/habilidades/sql-optimizacion/recursos/patrones-sql-avanzados.md +131 -0
- package/habilidades/sre-patrones/SKILL.md +333 -0
- package/habilidades/sre-patrones/recursos/chaos-engineering.md +241 -0
- package/habilidades/sre-patrones/recursos/oncall-design.md +236 -0
- package/habilidades/stripe-pagos/SKILL.md +550 -0
- package/habilidades/stripe-pagos/recursos/errores-reintentos.md +390 -0
- package/habilidades/stripe-pagos/recursos/stripe-connect.md +290 -0
- package/habilidades/structured-outputs/SKILL.md +343 -0
- package/habilidades/swift-experto/SKILL.md +320 -0
- package/habilidades/swift-experto/recursos/keychain-y-wrappers.md +110 -0
- package/habilidades/swift-patrones/SKILL.md +313 -0
- package/habilidades/swift-patrones/recursos/tca-ejemplo-completo.md +113 -0
- package/habilidades/swift-testing/SKILL.md +254 -0
- package/habilidades/swift-testing/recursos/xcuitest-planes.md +143 -0
- package/habilidades/swl-dashboard/SKILL.md +370 -0
- package/habilidades/swl-markitdown/SKILL.md +285 -0
- package/habilidades/swl-markitdown/evals/evals.json +52 -0
- package/habilidades/swl-revisar-impacto/SKILL.md +233 -0
- package/habilidades/tailwind-experto/SKILL.md +240 -0
- package/habilidades/tailwind-experto/recursos/referencia-completa.md +184 -0
- package/habilidades/tdd-workflow/SKILL.md +293 -0
- package/habilidades/terraform-experto/SKILL.md +321 -0
- package/habilidades/testing-python/SKILL.md +340 -0
- package/habilidades/testing-python/recursos/ejemplos-completos.md +167 -0
- package/habilidades/threat-model-lite/SKILL.md +246 -0
- package/habilidades/tracing-processor/SKILL.md +212 -0
- package/habilidades/tracking-measurement/SKILL.md +239 -0
- package/habilidades/tracking-measurement/recursos/consent-mode.md +231 -0
- package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +216 -0
- package/habilidades/tracking-measurement/recursos/meta-capi.md +262 -0
- package/habilidades/typescript-avanzado/SKILL.md +144 -0
- package/habilidades/typescript-avanzado/evals/evals.json +55 -0
- package/habilidades/typescript-avanzado/recursos/patrones-y-ejemplos-completos.md +298 -0
- package/habilidades/typescript-diagnosticos/SKILL.md +513 -0
- package/habilidades/ux-diseno/SKILL.md +116 -0
- package/habilidades/ux-diseno/evals/evals.json +43 -0
- package/habilidades/ux-diseno/recursos/patrones-ux-referencia.md +214 -0
- package/habilidades/validacion-ci-sistema/SKILL.md +136 -0
- package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +369 -0
- package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +286 -0
- package/habilidades/verificacion-evidencia/SKILL.md +160 -0
- package/habilidades/verificar-trabajo/SKILL.md +303 -0
- package/habilidades/verificar-trabajo/recursos/plantilla-verificacion.md +60 -0
- package/habilidades/wiki-conocimiento/SKILL.md +276 -0
- package/habilidades/wireframes-flujos/SKILL.md +212 -0
- package/habilidades/wireframes-flujos/recursos/referencia-completa.md +192 -0
- package/habilidades/workflow-claude-code/SKILL.md +260 -0
- package/habilidades/workflow-claude-code/recursos/referencia-completa.md +109 -0
- package/hooks/_run-hook.sh +57 -0
- package/hooks/actualizar-perfil-usuario.js +364 -0
- package/hooks/agente-lifecycle.js +71 -0
- package/hooks/aiisms-detector.js +173 -0
- package/hooks/audit-trail.js +204 -0
- package/hooks/auto-background.js +97 -0
- package/hooks/auto-consolidacion.js +178 -0
- package/hooks/auto-evolucion.js +666 -0
- package/hooks/auto-restaurar-settings.js +360 -0
- package/hooks/calidad-pre-commit.js +929 -0
- package/hooks/calidad-typescript.js +511 -0
- package/hooks/captura-feedback-usuario.js +148 -0
- package/hooks/check-update.js +211 -0
- package/hooks/clasificador-mensajes.js +271 -0
- package/hooks/degradacion-instintos.js +272 -0
- package/hooks/escaneo-secretos.js +389 -0
- package/hooks/extraccion-aprendizajes.js +763 -0
- package/hooks/grafo-contexto.js +129 -0
- package/hooks/graph-update.js +67 -0
- package/hooks/guardrail-modelo.js +247 -0
- package/hooks/inbox-aviso.js +75 -0
- package/hooks/inyeccion-contexto.js +246 -0
- package/hooks/lib/abort-registry.js +214 -0
- package/hooks/lib/agent-backend.js +210 -0
- package/hooks/lib/agent-comms.js +263 -0
- package/hooks/lib/agent-issue-codes.js +284 -0
- package/hooks/lib/agent-matcher.js +189 -0
- package/hooks/lib/async-hook-registry.js +252 -0
- package/hooks/lib/atomic-write.js +130 -0
- package/hooks/lib/auto-consolidator.js +335 -0
- package/hooks/lib/canary-skills.js +187 -0
- package/hooks/lib/consolidation-lock.js +291 -0
- package/hooks/lib/context-builder.js +430 -0
- package/hooks/lib/context-compressor.js +657 -0
- package/hooks/lib/convergence-detector.js +105 -0
- package/hooks/lib/delegation-tracker.js +198 -0
- package/hooks/lib/detectar-package-manager.js +423 -0
- package/hooks/lib/edit-accumulator.js +171 -0
- package/hooks/lib/error-classifier.js +308 -0
- package/hooks/lib/event-bus.js +112 -0
- package/hooks/lib/evolution-tracker.js +442 -0
- package/hooks/lib/execution-state.js +316 -0
- package/hooks/lib/fingerprint-id.js +135 -0
- package/hooks/lib/gateway-notify.js +116 -0
- package/hooks/lib/graph-security.js +75 -0
- package/hooks/lib/guardrail-metrics.js +202 -0
- package/hooks/lib/hook-circuit-breaker.js +206 -0
- package/hooks/lib/loop-detector.js +267 -0
- package/hooks/lib/mcp-health.js +184 -0
- package/hooks/lib/mcp-pool.js +436 -0
- package/hooks/lib/memory-search.js +506 -0
- package/hooks/lib/merkle-audit.js +96 -0
- package/hooks/lib/model-router.js +222 -0
- package/hooks/lib/normalize-error.js +324 -0
- package/hooks/lib/normalize-input.js +65 -0
- package/hooks/lib/nudge-tracker.js +306 -0
- package/hooks/lib/otlp-exporter.js +365 -0
- package/hooks/lib/performance-marks.js +239 -0
- package/hooks/lib/privacy-filter.js +128 -0
- package/hooks/lib/prompt-injection-scanner.js +209 -0
- package/hooks/lib/provenance-tracker.js +183 -0
- package/hooks/lib/rate-limit-tracker.js +253 -0
- package/hooks/lib/reflect-classifier.js +164 -0
- package/hooks/lib/resource-quota.js +122 -0
- package/hooks/lib/retry-jitter.js +165 -0
- package/hooks/lib/risk-engine.js +368 -0
- package/hooks/lib/run-log.js +408 -0
- package/hooks/lib/session-fts.js +379 -0
- package/hooks/lib/session-store.js +293 -0
- package/hooks/lib/singleton-guard.js +159 -0
- package/hooks/lib/skill-auditor.js +588 -0
- package/hooks/lib/sync-status.js +228 -0
- package/hooks/lib/taint-tracker.js +107 -0
- package/hooks/lib/task-service.js +295 -0
- package/hooks/lib/tech-skills-map.js +146 -0
- package/hooks/lib/telegram-cliente.js +159 -0
- package/hooks/lib/telegram-config.js +170 -0
- package/hooks/lib/token-budget.js +156 -0
- package/hooks/lib/token-estimator.js +420 -0
- package/hooks/lib/toon-compressor.js +245 -0
- package/hooks/lib/usage-model.js +183 -0
- package/hooks/lib/variable-resolver.js +230 -0
- package/hooks/linea-estado.js +324 -0
- package/hooks/metricas-evolucion.js +209 -0
- package/hooks/monitor-contexto.js +325 -0
- package/hooks/notificacion-sesion-stop.js +198 -0
- package/hooks/notificacion-telegram-notification.js +4 -0
- package/hooks/notificacion-telegram-subagent.js +4 -0
- package/hooks/notificacion-telegram.js +267 -0
- package/hooks/preservar-estado-pre-compact.js +150 -0
- package/hooks/proteccion-rutas.js +366 -0
- package/hooks/registro-turnos.js +209 -0
- package/hooks/resumen-sesion.js +249 -0
- package/hooks/risk-scoring.js +323 -0
- package/hooks/rotar-audit-auto.js +122 -0
- package/hooks/sugerir-regenerar-inventario.js +170 -0
- package/hooks/telemetria-agentes.js +167 -0
- package/hooks/tracking-costos.js +688 -0
- package/instintos/global.yaml +8 -0
- package/instintos/perfil-usuario.yaml +53 -0
- package/instintos/prompt-appendices.yaml +57 -0
- package/instintos/proyecto.yaml +372 -0
- package/manifiestos/gateway-config.json +77 -0
- package/manifiestos/handoff-context.json +223 -0
- package/manifiestos/hook-profiles.json +44 -0
- package/manifiestos/hooks-config.json +360 -0
- package/manifiestos/modulos.json +1173 -0
- package/manifiestos/perfiles.json +404 -0
- package/package.json +86 -0
- package/plantillas/ESTADO.md +109 -0
- package/plantillas/HOJA-RUTA.md +143 -0
- package/plantillas/PROYECTO.md +122 -0
- package/plantillas/REQUISITOS.md +132 -0
- package/plantillas/auditor-veto-template.md +105 -0
- package/plantillas/github-workflows/README.md +47 -0
- package/plantillas/github-workflows/release-please.yml +44 -0
- package/plantillas/github-workflows/swl-ci.yml +107 -0
- package/plantillas/github-workflows/swl-security.yml +51 -0
- package/plantillas/mcp-mineru.json +13 -0
- package/plantillas/research/ARQUITECTURA.md +220 -0
- package/plantillas/research/FUNCIONALIDADES.md +175 -0
- package/plantillas/research/RESUMEN.md +165 -0
- package/plantillas/research/STACK.md +233 -0
- package/plantillas/research/TRAMPAS.md +299 -0
- package/plantillas/skill-evals-template.json +44 -0
- package/plugin.json +343 -0
- package/reglas/accesibilidad.md +269 -0
- package/reglas/api-diseno.md +400 -0
- package/reglas/arquitectura.md +352 -0
- package/reglas/brevedad-output.md +124 -0
- package/reglas/cloud-infra.md +247 -0
- package/reglas/docs.md +245 -0
- package/reglas/estilo-codigo.md +201 -0
- package/reglas/git-workflow.md +245 -0
- package/reglas/gobernanza.md +271 -0
- package/reglas/harness-claude-code.md +213 -0
- package/reglas/hooks.md +186 -0
- package/reglas/lenguajes/csharp/estilo-codigo.md +231 -0
- package/reglas/lenguajes/csharp/hooks.md +281 -0
- package/reglas/lenguajes/csharp/patrones.md +226 -0
- package/reglas/lenguajes/csharp/seguridad.md +258 -0
- package/reglas/lenguajes/csharp/testing.md +176 -0
- package/reglas/lenguajes/go/estilo-codigo.md +195 -0
- package/reglas/lenguajes/go/hooks.md +249 -0
- package/reglas/lenguajes/go/patrones.md +249 -0
- package/reglas/lenguajes/go/seguridad.md +225 -0
- package/reglas/lenguajes/go/testing.md +272 -0
- package/reglas/lenguajes/java/estilo-codigo.md +217 -0
- package/reglas/lenguajes/java/hooks.md +251 -0
- package/reglas/lenguajes/java/patrones.md +226 -0
- package/reglas/lenguajes/java/seguridad.md +233 -0
- package/reglas/lenguajes/java/testing.md +238 -0
- package/reglas/lenguajes/kotlin/estilo-codigo.md +208 -0
- package/reglas/lenguajes/kotlin/hooks.md +245 -0
- package/reglas/lenguajes/kotlin/patrones.md +201 -0
- package/reglas/lenguajes/kotlin/seguridad.md +202 -0
- package/reglas/lenguajes/kotlin/testing.md +236 -0
- package/reglas/lenguajes/nextjs/estilo-codigo.md +175 -0
- package/reglas/lenguajes/nextjs/hooks.md +186 -0
- package/reglas/lenguajes/nextjs/patrones.md +225 -0
- package/reglas/lenguajes/nextjs/seguridad.md +216 -0
- package/reglas/lenguajes/nextjs/testing.md +193 -0
- package/reglas/lenguajes/php/estilo-codigo.md +228 -0
- package/reglas/lenguajes/php/hooks.md +165 -0
- package/reglas/lenguajes/php/patrones.md +233 -0
- package/reglas/lenguajes/php/seguridad.md +186 -0
- package/reglas/lenguajes/php/testing.md +205 -0
- package/reglas/lenguajes/rust/estilo-codigo.md +207 -0
- package/reglas/lenguajes/rust/hooks.md +240 -0
- package/reglas/lenguajes/rust/patrones.md +250 -0
- package/reglas/lenguajes/rust/seguridad.md +221 -0
- package/reglas/lenguajes/rust/testing.md +194 -0
- package/reglas/lenguajes/swift/estilo-codigo.md +238 -0
- package/reglas/lenguajes/swift/hooks.md +257 -0
- package/reglas/lenguajes/swift/patrones.md +235 -0
- package/reglas/lenguajes/swift/seguridad.md +248 -0
- package/reglas/lenguajes/swift/testing.md +242 -0
- package/reglas/markitdown.md +60 -0
- package/reglas/memoria-consolidada.md +209 -0
- package/reglas/patrones.md +225 -0
- package/reglas/performance.md +195 -0
- package/reglas/pruebas.md +159 -0
- package/reglas/seguridad-agentes.md +351 -0
- package/reglas/seguridad.md +151 -0
- package/reglas/skills-estandar.md +373 -0
- package/reglas/testing.md +193 -0
- package/schemas/agent-contract.json +176 -0
- package/schemas/agent-frontmatter.schema.json +149 -0
- package/schemas/agent-message.schema.json +53 -0
- package/schemas/agent-output-implementacion.schema.json +85 -0
- package/schemas/agent-output-planificacion.schema.json +113 -0
- package/schemas/agent-output-review.schema.json +78 -0
- package/schemas/diary-entry.schema.json +80 -0
- package/schemas/hook-profiles.schema.json +39 -0
- package/schemas/hooks-config.schema.json +74 -0
- package/schemas/instinct.schema.json +115 -0
- package/schemas/modulos.schema.json +29 -0
- package/schemas/perfiles.schema.json +28 -0
- package/schemas/plugin.schema.json +64 -0
- package/schemas/skill-evals.schema.json +95 -0
- package/schemas/skill-frontmatter.schema.json +170 -0
- package/scripts/actualizar.js +145 -0
- package/scripts/audit-skills.sh +78 -0
- package/scripts/auditar-agentes-gaps.js +149 -0
- package/scripts/auditar-cobertura-frameworks.js +241 -0
- package/scripts/auditar-skills-gaps.js +206 -0
- package/scripts/bootstrap-instintos.js +259 -0
- package/scripts/check-update.js +109 -0
- package/scripts/comandos/agents.js +105 -0
- package/scripts/comandos/info.js +108 -0
- package/scripts/comandos/install-asistido.js +186 -0
- package/scripts/comandos/skills.js +211 -0
- package/scripts/configurar-branch-protection.js +418 -0
- package/scripts/daemon-swl.py +388 -0
- package/scripts/desinstalar.js +130 -0
- package/scripts/doctor.js +559 -0
- package/scripts/field-report.js +199 -0
- package/scripts/generar-inventario.js +317 -0
- package/scripts/inbox-tmux-inject.js +161 -0
- package/scripts/inferir-herramientas-permitidas.js +586 -0
- package/scripts/inicializar.js +133 -0
- package/scripts/instalador.js +1031 -0
- package/scripts/instalar-git-hook.js +122 -0
- package/scripts/lib/agp-frontmatter.js +222 -0
- package/scripts/lib/append-con-marcadores.js +199 -0
- package/scripts/lib/artefactos-python.js +43 -0
- package/scripts/lib/audit-query.js +221 -0
- package/scripts/lib/autostart-linux.js +347 -0
- package/scripts/lib/autostart-macos.js +360 -0
- package/scripts/lib/autostart-windows.js +307 -0
- package/scripts/lib/budget-enforcer.js +252 -0
- package/scripts/lib/claude-sessions.js +285 -0
- package/scripts/lib/configurar-ci.js +380 -0
- package/scripts/lib/console-span-exporter.js +92 -0
- package/scripts/lib/contadores-inventario.js +217 -0
- package/scripts/lib/dashboard-widgets.js +290 -0
- package/scripts/lib/detectar-runtime.js +279 -0
- package/scripts/lib/detectar-stack.js +187 -0
- package/scripts/lib/diary-entry.js +234 -0
- package/scripts/lib/drift-detector.js +545 -0
- package/scripts/lib/estado.js +124 -0
- package/scripts/lib/gestor-componentes.js +243 -0
- package/scripts/lib/gitignore-manifest.js +305 -0
- package/scripts/lib/graph-analyze.py +556 -0
- package/scripts/lib/graph-builder.py +485 -0
- package/scripts/lib/graph-cluster.py +259 -0
- package/scripts/lib/health-row.js +168 -0
- package/scripts/lib/hooks-settings.js +789 -0
- package/scripts/lib/manifiestos.js +138 -0
- package/scripts/lib/mc-client.js +137 -0
- package/scripts/lib/notificaciones-telegram.js +1107 -0
- package/scripts/lib/npm-version.js +261 -0
- package/scripts/lib/paquetes-conocidos.js +50 -0
- package/scripts/lib/preservar-usuario.js +586 -0
- package/scripts/lib/prompt-builder.js +264 -0
- package/scripts/lib/resolver-externo.js +332 -0
- package/scripts/lib/schedule-parser.js +305 -0
- package/scripts/lib/scoring-instintos.js +240 -0
- package/scripts/lib/seguridad.js +160 -0
- package/scripts/lib/selector-interactivo.js +152 -0
- package/scripts/lib/semantic-search.js +242 -0
- package/scripts/lib/skill-discovery.js +234 -0
- package/scripts/lib/skill-metrics.js +246 -0
- package/scripts/lib/skill-normalizer.js +112 -0
- package/scripts/lib/skills-hub.js +340 -0
- package/scripts/lib/span-schema.js +134 -0
- package/scripts/lib/tool-cost-analyzer.js +255 -0
- package/scripts/lib/tracing-processor-interface.js +286 -0
- package/scripts/lib/transformadores/base.js +80 -0
- package/scripts/lib/transformadores/claude.js +124 -0
- package/scripts/lib/transformadores/codex.js +115 -0
- package/scripts/lib/transformadores/copilot.js +106 -0
- package/scripts/lib/transformadores/gemini.js +74 -0
- package/scripts/lib/transformadores/index.js +35 -0
- package/scripts/lib/transformadores/opencode.js +75 -0
- package/scripts/lib/ui.js +259 -0
- package/scripts/limpiar-artefactos-python.js +131 -0
- package/scripts/mcp-orchestrator.py +386 -0
- package/scripts/mcp-pool-manager.py +352 -0
- package/scripts/mcp-telemetry.py +378 -0
- package/scripts/poblar-evolvable.js +226 -0
- package/scripts/publicar.js +287 -0
- package/scripts/reflect-skills.js +403 -0
- package/scripts/rotar-audit-logs.js +185 -0
- package/scripts/run-skill-evals.js +242 -0
- package/scripts/smoke-test.js +374 -0
- package/scripts/token-analysis.py +471 -0
- package/scripts/validar-manifest.js +195 -0
- package/scripts/validar-memoria.js +321 -0
- package/scripts/validar-tests-aislamiento.js +184 -0
- package/scripts/validar-tokens-test.js +208 -0
- package/scripts/validar.js +147 -0
- package/scripts/validate-markdown.py +339 -0
- package/scripts/validate-skills.py +385 -0
- package/scripts/vendor/claude-usage/README.md +116 -0
- package/scripts/vendor/claude-usage/cli.py +334 -0
- package/scripts/vendor/claude-usage/dashboard.py +795 -0
- package/scripts/vendor/claude-usage/scanner.py +467 -0
- package/scripts/vendor/markitdown/cli.py +194 -0
- package/scripts/verificar-evolucion.js +289 -0
- package/scripts/verificar-release.js +494 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: iam-secretos
|
|
3
|
+
description: >
|
|
4
|
+
Identity and Access Management y gestión de secretos: RBAC, ABAC, HashiCorp Vault,
|
|
5
|
+
AWS Secrets Manager, Azure Key Vault, rotación de secretos, principio de mínimo
|
|
6
|
+
privilegio, cuentas de servicio, gestión de API keys, zero trust.
|
|
7
|
+
version: "1.1.0"
|
|
8
|
+
evolved: true
|
|
9
|
+
evolved-from: "1.0.0"
|
|
10
|
+
evolved-at: "2026-04-24"
|
|
11
|
+
evolved-by: "aprender"
|
|
12
|
+
evolved-note: "Sección nueva: logs con PII → gitignore + hard-block env flag en producción (defense in depth)"
|
|
13
|
+
herramientasPermitidas: [Read, Grep]
|
|
14
|
+
evolvable: true # default para skill estandar
|
|
15
|
+
nist_csf: [PR.AA-01, PR.AA-02, PR.AA-05, PR.DS-02]
|
|
16
|
+
attack_techniques: [T1552, T1078]
|
|
17
|
+
d3fend_techniques: [D3-MFA]
|
|
18
|
+
exclusiones:
|
|
19
|
+
- "No cargar para autenticación y autorización de usuarios en el frontend (login, JWT en browser, OAuth PKCE) — para auth de usuario final cargar `auth-patrones`."
|
|
20
|
+
- "No cargar para configuración de IAM en nubes específicas (AWS IAM roles, GCP Service Accounts, Azure Managed Identity) sin relación con la aplicación — para cloud IAM cargar el skill de la nube correspondiente (`cloud-aws`, `gcp-cloud`, `azure-cloud`)."
|
|
21
|
+
- "No cargar para auditoría de dependencias con CVEs (vulnerabilidades en paquetes npm/pip) — para auditoría de dependencias cargar `dependencias-auditoria`."
|
|
22
|
+
- "No cargar para cifrado de datos en reposo o en tránsito sin relación con secretos o identidades (TLS, AES en columnas de BD) — para cifrado de datos cargar el skill de seguridad del stack correspondiente."
|
|
23
|
+
---
|
|
24
|
+
# IAM y Gestión de Secretos — Guía de Producción
|
|
25
|
+
|
|
26
|
+
## Cuándo NO cargar
|
|
27
|
+
|
|
28
|
+
- La tarea es autenticación de usuario en el frontend (login, JWT en browser, OAuth PKCE): cargar `auth-patrones`.
|
|
29
|
+
- La tarea es configuración de IAM en la nube (AWS IAM, GCP Service Accounts, Azure Managed Identity) sin relación con la aplicación: cargar el skill de la nube correspondiente.
|
|
30
|
+
- La tarea es auditoría de CVEs en paquetes de dependencias: cargar `dependencias-auditoria`.
|
|
31
|
+
- La tarea es cifrado de datos en reposo o en tránsito sin relación con identidades o secretos: cargar el skill de seguridad del stack.
|
|
32
|
+
|
|
33
|
+
## Principios Base
|
|
34
|
+
|
|
35
|
+
### Zero Trust — "Nunca confíes, siempre verifica"
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
Modelo perimetral tradicional: Modelo Zero Trust:
|
|
39
|
+
[Firewall externo] Toda petición se autentica
|
|
40
|
+
└── Interior "seguro" Toda petición se autoriza
|
|
41
|
+
└── Sin verificación Acceso mínimo siempre
|
|
42
|
+
Red, identidad y datos cifrados
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Reglas de oro:**
|
|
46
|
+
1. Ningún secreto en código fuente, variables de entorno de CI/CD, ni logs.
|
|
47
|
+
2. Todo acceso privilegiado tiene duración máxima y se rota periódicamente.
|
|
48
|
+
3. Las cuentas de servicio tienen permisos mínimos necesarios (least privilege).
|
|
49
|
+
4. Toda acción privilegiada deja registro de auditoría.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## RBAC — Control de Acceso Basado en Roles
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from enum import Enum
|
|
57
|
+
from typing import FrozenSet
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class Permiso(str, Enum):
|
|
61
|
+
USUARIO_LEER = "usuario:leer"
|
|
62
|
+
USUARIO_CREAR = "usuario:crear"
|
|
63
|
+
USUARIO_EDITAR = "usuario:editar"
|
|
64
|
+
USUARIO_ELIMINAR = "usuario:eliminar"
|
|
65
|
+
REPORTE_LEER = "reporte:leer"
|
|
66
|
+
REPORTE_EXPORTAR = "reporte:exportar"
|
|
67
|
+
ADMIN_CONFIGURAR = "admin:configurar"
|
|
68
|
+
ADMIN_AUDITAR = "admin:auditar"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class Rol(str, Enum):
|
|
72
|
+
LECTURA = "LECTURA"
|
|
73
|
+
OPERADOR = "OPERADOR"
|
|
74
|
+
ADMIN = "ADMIN"
|
|
75
|
+
AUDITOR = "AUDITOR"
|
|
76
|
+
SUPER = "SUPER"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
PERMISOS_POR_ROL: dict[Rol, FrozenSet[Permiso]] = {
|
|
80
|
+
Rol.LECTURA: frozenset({Permiso.USUARIO_LEER, Permiso.REPORTE_LEER}),
|
|
81
|
+
Rol.OPERADOR: frozenset({
|
|
82
|
+
Permiso.USUARIO_LEER, Permiso.USUARIO_CREAR, Permiso.USUARIO_EDITAR,
|
|
83
|
+
Permiso.REPORTE_LEER, Permiso.REPORTE_EXPORTAR,
|
|
84
|
+
}),
|
|
85
|
+
Rol.ADMIN: frozenset({
|
|
86
|
+
Permiso.USUARIO_LEER, Permiso.USUARIO_CREAR, Permiso.USUARIO_EDITAR,
|
|
87
|
+
Permiso.USUARIO_ELIMINAR, Permiso.REPORTE_LEER,
|
|
88
|
+
Permiso.REPORTE_EXPORTAR, Permiso.ADMIN_CONFIGURAR,
|
|
89
|
+
}),
|
|
90
|
+
Rol.AUDITOR: frozenset({Permiso.USUARIO_LEER, Permiso.REPORTE_LEER, Permiso.ADMIN_AUDITAR}),
|
|
91
|
+
Rol.SUPER: frozenset(Permiso),
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def requiere_permiso(permiso: Permiso):
|
|
96
|
+
"""Decorador FastAPI para verificación de permisos granulares."""
|
|
97
|
+
from fastapi import Depends, HTTPException, status
|
|
98
|
+
|
|
99
|
+
def verificar(usuario=Depends(get_current_user)):
|
|
100
|
+
if permiso not in PERMISOS_POR_ROL.get(usuario.rol, frozenset()):
|
|
101
|
+
raise HTTPException(
|
|
102
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
103
|
+
detail={"permiso_requerido": permiso.value, "rol_actual": usuario.rol.value},
|
|
104
|
+
)
|
|
105
|
+
return usuario
|
|
106
|
+
|
|
107
|
+
return Depends(verificar)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Anti-Patrones de IAM y Secretos
|
|
113
|
+
|
|
114
|
+
| Anti-patrón | Riesgo | Solución |
|
|
115
|
+
|-------------|--------|----------|
|
|
116
|
+
| Secretos en variables de entorno del proceso | Visibles en `/proc/environ` | Usar Vault/AWS SM con acceso programático |
|
|
117
|
+
| Secretos en código fuente o Git | Exposición permanente | Detección con `git-secrets`, `truffleHog` en CI |
|
|
118
|
+
| Credenciales de larga duración sin rotación | Ventana de ataque infinita | Credenciales dinámicas o rotación automática |
|
|
119
|
+
| Rol de servicio con permisos de admin | Un compromiso = acceso total | Least privilege: solo los permisos necesarios |
|
|
120
|
+
| API keys sin expiración ni scopes | Key comprometida da acceso total | Expiración obligatoria + scopes granulares |
|
|
121
|
+
| Logs que contienen secretos | Secretos filtrados en logs | Nunca loguear headers de Authorization ni tokens |
|
|
122
|
+
| Sin auditoría de acceso a secretos | Sin visibilidad | Habilitar audit logs en Vault/AWS SM |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Implementaciones Completas
|
|
127
|
+
|
|
128
|
+
Para implementaciones de ABAC, HashiCorp Vault, AWS Secrets Manager con caché,
|
|
129
|
+
gestión de API Keys, estrategias de rotación de secretos y configuración de
|
|
130
|
+
cuentas de servicio en Kubernetes, ver
|
|
131
|
+
[recursos/implementaciones-completas.md](recursos/implementaciones-completas.md).
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Checklist de Revisión — IAM y Secretos
|
|
136
|
+
|
|
137
|
+
- [ ] Cero secretos en código fuente, `.env` de producción, o CI/CD variables sin cifrar.
|
|
138
|
+
- [ ] Toda cuenta de servicio tiene permisos mínimos (least privilege).
|
|
139
|
+
- [ ] Los secretos se leen de Vault/AWS SM en tiempo de ejecución, no en tiempo de build.
|
|
140
|
+
- [ ] Las API keys se almacenan sólo como hash (SHA-256), nunca en texto plano.
|
|
141
|
+
- [ ] Hay un plan de rotación documentado con frecuencia para cada tipo de secreto.
|
|
142
|
+
- [ ] El acceso a recursos sensibles pasa por verificación ABAC (no sólo RBAC) donde aplica.
|
|
143
|
+
- [ ] Los audit logs de acceso a secretos están habilitados y retenidos por 1 año mínimo.
|
|
144
|
+
- [ ] Los Kubernetes ServiceAccounts tienen RBAC restringido a sus propios recursos.
|
|
145
|
+
- [ ] Los certificados TLS tienen alerta de expiración 30 días antes.
|
|
146
|
+
- [ ] El código tiene pruebas que verifican que usuarios sin rol no pueden acceder a recursos protegidos.
|
|
147
|
+
|
|
148
|
+
## Gotchas / Errores comunes no obvios
|
|
149
|
+
|
|
150
|
+
**Las variables de entorno de proceso no son más seguras que los archivos `.env` en contenedores Docker porque `docker inspect` expone todas las variables de entorno en texto plano**: configurar secretos con `-e DATABASE_PASSWORD=secreto` en `docker run` o en `docker-compose.yml` los hace visibles para cualquiera con acceso al daemon Docker (`docker inspect <container>`). Causa: las variables de entorno de proceso en Linux son visibles en `/proc/<pid>/environ` y en la API de Docker sin autenticación adicional. Fix: usar Docker Secrets (`docker secret create`) o montar el secreto como archivo en un volumen `tmpfs` y leerlo desde el código, nunca como variable de entorno de proceso.
|
|
151
|
+
|
|
152
|
+
**HashiCorp Vault con `AppRole` en CI/CD usa el mismo `role_id` + `secret_id` para todos los pipelines, eliminando la trazabilidad de auditoría**: si el `secret_id` es estático y compartido entre todos los jobs de CI, el audit log de Vault solo muestra "appRole autenticó" sin identificar cuál pipeline específico accedió al secreto. Causa: el propósito de `AppRole` es autenticación por instancia, pero se usa como credencial global. Fix: usar `secret_id` de un solo uso (`use_limit=1`) generado por cada job de CI al inicio del pipeline con un `wrapped token`. Esto garantiza trazabilidad y elimina la ventana de reutilización.
|
|
153
|
+
|
|
154
|
+
**La rotación automática de secretos en AWS Secrets Manager puede romper conexiones de larga duración a la BD que no leen el secreto en cada conexión**: las aplicaciones que leen `DATABASE_URL` una sola vez al arrancar y la cachean en memoria durante la vida del proceso siguen usando la credencial antigua después de la rotación. Causa: AWS SM rota el secreto pero no reinicia la aplicación ni invalida el caché del proceso. Fix: implementar un mecanismo de reconexión que re-lee el secreto desde SM cuando la BD devuelve un error de autenticación (código `PGCONN_ERROR` en PostgreSQL o `ER_ACCESS_DENIED_ERROR` en MySQL). No cachear la URL de conexión más allá de la frecuencia de rotación.
|
|
155
|
+
|
|
156
|
+
**RBAC implementado solo en el frontend produce IDOR (Insecure Direct Object Reference) cuando los endpoints no validan permisos server-side**: si el botón "Eliminar" se oculta en la UI para usuarios sin el rol `ADMIN` pero el endpoint `DELETE /api/usuarios/:id` no verifica el rol del JWT, cualquier usuario autenticado puede enviar el request directamente con curl y eliminará el registro. Causa: la verificación de RBAC en el frontend es UX, no seguridad. Fix: el decorador `requiere_permiso(Permiso.USUARIO_ELIMINAR)` o equivalente DEBE estar en CADA endpoint mutante, sin excepción. Verificar en code review que no hay endpoint de escritura sin `Depends(require_role([...]))` en FastAPI o equivalente en el framework del stack.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Logs con PII: gitignore + hard-block env flag en producción (defense in depth)
|
|
161
|
+
|
|
162
|
+
### Regla
|
|
163
|
+
|
|
164
|
+
Cuando la aplicación tiene capacidad de loggear contenido que puede incluir
|
|
165
|
+
PII (prompts de usuario, payloads de request, body de webhooks de terceros,
|
|
166
|
+
stack traces con datos concretos), aplicar **defensa en profundidad** con dos
|
|
167
|
+
capas independientes:
|
|
168
|
+
|
|
169
|
+
1. **Capa 1 — Infraestructura**: `logs/*.jsonl` (o el path equivalente) fuera
|
|
170
|
+
del tracking de git via `.gitignore`. Previene fuga accidental al publicar
|
|
171
|
+
el repo.
|
|
172
|
+
2. **Capa 2 — Runtime**: flag de feature (`llm_prompt_audit_log_text=True` o
|
|
173
|
+
similar) que **rechaza duro** en producción, sin importar si la capa 1
|
|
174
|
+
funcionó o no.
|
|
175
|
+
|
|
176
|
+
Una sola capa no basta: `.gitignore` no protege contra un bucket mal configurado
|
|
177
|
+
ni contra un desarrollador que copia logs a otro destino. El env flag por sí
|
|
178
|
+
solo no protege contra un commit accidental del log mismo.
|
|
179
|
+
|
|
180
|
+
### Implementación canónica
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
# .gitignore (capa 1)
|
|
184
|
+
logs/
|
|
185
|
+
*.jsonl
|
|
186
|
+
*.log
|
|
187
|
+
data/local/
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
# config.py (capa 2: runtime guard)
|
|
192
|
+
from pydantic import field_validator, Field
|
|
193
|
+
from pydantic_settings import BaseSettings
|
|
194
|
+
|
|
195
|
+
class Settings(BaseSettings):
|
|
196
|
+
environment: str = Field("development")
|
|
197
|
+
llm_prompt_audit_log_text: bool = Field(False)
|
|
198
|
+
|
|
199
|
+
@field_validator("llm_prompt_audit_log_text")
|
|
200
|
+
@classmethod
|
|
201
|
+
def _bloquear_en_produccion(cls, v: bool, info) -> bool:
|
|
202
|
+
ambiente = info.data.get("environment", "development")
|
|
203
|
+
if v and ambiente == "production":
|
|
204
|
+
raise ValueError(
|
|
205
|
+
"llm_prompt_audit_log_text=True está prohibido con "
|
|
206
|
+
"environment=production. Los logs contienen PII y no "
|
|
207
|
+
"pueden persistir fuera de dev/staging. "
|
|
208
|
+
"Para auditoría en prod, usar Presidio + redaction."
|
|
209
|
+
)
|
|
210
|
+
return v
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
# En el servicio que loggea
|
|
215
|
+
from config import settings
|
|
216
|
+
|
|
217
|
+
def log_llm_prompt(prompt: str, user_id: str) -> None:
|
|
218
|
+
if not settings.llm_prompt_audit_log_text:
|
|
219
|
+
# Log sin el cuerpo del prompt: solo metadata
|
|
220
|
+
logger.info("llm_prompt_sent", extra={
|
|
221
|
+
"user_id_hash": _hash_estable(user_id),
|
|
222
|
+
"prompt_len": len(prompt),
|
|
223
|
+
"tokens_estimados": estimar_tokens(prompt),
|
|
224
|
+
})
|
|
225
|
+
return
|
|
226
|
+
|
|
227
|
+
# Este path es inalcanzable en production (validator lanza al cargar settings).
|
|
228
|
+
# Solo se alcanza en dev/staging con flag explícito.
|
|
229
|
+
logger.debug("llm_prompt_content", extra={
|
|
230
|
+
"user_id_hash": _hash_estable(user_id),
|
|
231
|
+
"prompt": prompt,
|
|
232
|
+
})
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Reglas
|
|
236
|
+
|
|
237
|
+
- **`.gitignore` es capa 1**: cubre el filesystem del repo. Verificar con `git check-ignore -v logs/foo.jsonl` que el path está cubierto.
|
|
238
|
+
- **El env flag es capa 2**: validar con test de integración que `environment=production + flag=True` lanza al cargar settings, **no** en runtime cuando se intenta loggear.
|
|
239
|
+
- **Nombres del flag explícitos**: `llm_prompt_audit_log_text`, `http_body_log_full`, `stacktrace_log_full_data` — el nombre debe dejar claro que habilita log de contenido sensible. Nombres genéricos como `debug_mode` no comunican el riesgo.
|
|
240
|
+
- **Tercera capa opcional pero recomendada**: en el logger central, aplicar filtro Presidio o regex para redactar patrones PII (email, RFC, teléfono, CURP) antes de escribir a disco. Esto convierte "si los 2 gates fallan, el daño es total" en "si los 2 gates fallan, el daño es parcial".
|
|
241
|
+
- **Test de capa 2 en CI**: test que crea `Settings(environment="production", llm_prompt_audit_log_text=True)` y verifica `ValidationError`. Sin este test, la capa 2 puede desactivarse silenciosamente en un refactor futuro.
|
|
242
|
+
|
|
243
|
+
### Anti-patrón
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
# MAL — solo capa 1 (gitignore), sin hard-block en runtime
|
|
247
|
+
# Si un dev sube los logs a un bucket S3 o a Slack para debugging,
|
|
248
|
+
# la PII sale del perímetro sin alarma.
|
|
249
|
+
|
|
250
|
+
# MAL — solo capa 2, sin gitignore
|
|
251
|
+
# Si el flag se activó una vez y los logs quedaron en disco,
|
|
252
|
+
# un `git add .` en un pull request los filtra al repo público.
|
|
253
|
+
|
|
254
|
+
# MAL — log fuente de verdad para auditoría regulatoria
|
|
255
|
+
# Los logs JSONL no son un sistema de auditoría conforme. Para compliance
|
|
256
|
+
# (GDPR Art. 30, SOC 2 CC6.2), usar un audit trail dedicado con retención,
|
|
257
|
+
# integridad (merkle, firmas) y control de acceso separado del log operacional.
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Frameworks de seguridad
|
|
261
|
+
|
|
262
|
+
- OWASP Top 10 A02:2021 — Cryptographic Failures (incluye log exposure de PII).
|
|
263
|
+
- NIST CSF PR.DS-01 (data-at-rest protection), PR.DS-02 (data-in-transit).
|
|
264
|
+
- NIST AI RMF MANAGE-3.1 — AI system information, including sensitive data, is protected.
|
|
265
|
+
- GDPR Art. 5 principle of data minimization.
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
# IAM y Gestión de Secretos — Implementaciones Completas
|
|
2
|
+
|
|
3
|
+
## ABAC — Control de Acceso Basado en Atributos
|
|
4
|
+
|
|
5
|
+
ABAC se usa cuando RBAC no es suficientemente granular.
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
# Ejemplo: un usuario OPERADOR sólo puede editar usuarios de su departamento
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class ContextoAutorizacion:
|
|
15
|
+
sujeto: dict # Atributos del usuario que hace la acción
|
|
16
|
+
recurso: dict # Atributos del recurso al que accede
|
|
17
|
+
accion: str # Acción que intenta realizar
|
|
18
|
+
entorno: dict # Hora, IP, etc.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def puede_editar_usuario(
|
|
22
|
+
usuario_solicitante: dict,
|
|
23
|
+
usuario_objetivo: dict,
|
|
24
|
+
) -> bool:
|
|
25
|
+
"""
|
|
26
|
+
Política ABAC: un OPERADOR sólo puede editar usuarios de su departamento.
|
|
27
|
+
Un ADMIN puede editar cualquier usuario en su organización.
|
|
28
|
+
Un SUPER puede editar cualquier usuario.
|
|
29
|
+
"""
|
|
30
|
+
rol = usuario_solicitante.get("rol")
|
|
31
|
+
|
|
32
|
+
if rol == "SUPER":
|
|
33
|
+
return True
|
|
34
|
+
|
|
35
|
+
if rol == "ADMIN":
|
|
36
|
+
return (
|
|
37
|
+
usuario_solicitante.get("organizacion_id")
|
|
38
|
+
== usuario_objetivo.get("organizacion_id")
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if rol == "OPERADOR":
|
|
42
|
+
return (
|
|
43
|
+
usuario_solicitante.get("departamento_id")
|
|
44
|
+
== usuario_objetivo.get("departamento_id")
|
|
45
|
+
and usuario_solicitante.get("organizacion_id")
|
|
46
|
+
== usuario_objetivo.get("organizacion_id")
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return False
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# En el endpoint — prevención de IDOR
|
|
53
|
+
@router.put("/usuarios/{usuario_id}")
|
|
54
|
+
async def actualizar_usuario(
|
|
55
|
+
usuario_id: str,
|
|
56
|
+
datos: ActualizarUsuarioSchema,
|
|
57
|
+
usuario_actual: Usuario = Depends(get_current_user),
|
|
58
|
+
db: AsyncSession = Depends(get_db),
|
|
59
|
+
):
|
|
60
|
+
usuario_objetivo = await db.get(Usuario, usuario_id)
|
|
61
|
+
if not usuario_objetivo:
|
|
62
|
+
raise HTTPException(404, "Usuario no encontrado")
|
|
63
|
+
|
|
64
|
+
# ABAC — verificar autorización con atributos de ambos
|
|
65
|
+
if not puede_editar_usuario(
|
|
66
|
+
usuario_solicitante=usuario_actual.__dict__,
|
|
67
|
+
usuario_objetivo=usuario_objetivo.__dict__,
|
|
68
|
+
):
|
|
69
|
+
raise HTTPException(403, "Sin permisos para editar este usuario")
|
|
70
|
+
|
|
71
|
+
# Continuar con la actualización...
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## HashiCorp Vault — Integración en Python
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
# vault_client.py
|
|
80
|
+
import hvac
|
|
81
|
+
import os
|
|
82
|
+
from functools import lru_cache
|
|
83
|
+
from typing import Any
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@lru_cache(maxsize=1)
|
|
87
|
+
def obtener_cliente_vault() -> hvac.Client:
|
|
88
|
+
"""Cliente Vault singleton — se autentica una vez por proceso."""
|
|
89
|
+
cliente = hvac.Client(url=os.environ["VAULT_ADDR"])
|
|
90
|
+
|
|
91
|
+
# Autenticación con rol de Kubernetes (en producción)
|
|
92
|
+
if os.environ.get("KUBERNETES_SERVICE_HOST"):
|
|
93
|
+
with open("/var/run/secrets/kubernetes.io/serviceaccount/token") as f:
|
|
94
|
+
jwt_token = f.read()
|
|
95
|
+
|
|
96
|
+
cliente.auth.kubernetes.login(
|
|
97
|
+
role=os.environ["VAULT_ROLE"],
|
|
98
|
+
jwt=jwt_token,
|
|
99
|
+
)
|
|
100
|
+
else:
|
|
101
|
+
# Autenticación con token (desarrollo local)
|
|
102
|
+
cliente.token = os.environ["VAULT_TOKEN"]
|
|
103
|
+
|
|
104
|
+
if not cliente.is_authenticated():
|
|
105
|
+
raise RuntimeError("No se pudo autenticar con Vault")
|
|
106
|
+
|
|
107
|
+
return cliente
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def obtener_secreto(ruta: str, clave: str) -> str:
|
|
111
|
+
"""
|
|
112
|
+
Lee un secreto de Vault KV v2.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
ruta: Ruta en Vault, ej: "secret/data/produccion/base-de-datos"
|
|
116
|
+
clave: Clave específica dentro del secreto
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
El valor del secreto como string.
|
|
120
|
+
"""
|
|
121
|
+
cliente = obtener_cliente_vault()
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
respuesta = cliente.secrets.kv.v2.read_secret_version(
|
|
125
|
+
path=ruta.replace("secret/data/", ""),
|
|
126
|
+
mount_point="secret",
|
|
127
|
+
)
|
|
128
|
+
valor = respuesta["data"]["data"].get(clave)
|
|
129
|
+
|
|
130
|
+
if valor is None:
|
|
131
|
+
raise KeyError(f"Clave {clave!r} no encontrada en {ruta!r}")
|
|
132
|
+
|
|
133
|
+
return valor
|
|
134
|
+
|
|
135
|
+
except hvac.exceptions.InvalidPath:
|
|
136
|
+
raise KeyError(f"Ruta de Vault no encontrada: {ruta!r}")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def obtener_credenciales_bd() -> dict[str, str]:
|
|
140
|
+
"""Obtiene credenciales de base de datos con rotación automática vía Vault Dynamic Secrets."""
|
|
141
|
+
cliente = obtener_cliente_vault()
|
|
142
|
+
|
|
143
|
+
# Vault genera credenciales temporales que expiran automáticamente
|
|
144
|
+
creds = cliente.secrets.database.generate_credentials(
|
|
145
|
+
name="mi-aplicacion-rol",
|
|
146
|
+
mount_point="database",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
"usuario": creds["data"]["username"],
|
|
151
|
+
"contrasena": creds["data"]["password"],
|
|
152
|
+
"ttl": creds["lease_duration"],
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## AWS Secrets Manager — Integración con Caché
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
# aws_secrets.py
|
|
162
|
+
import boto3
|
|
163
|
+
import json
|
|
164
|
+
import time
|
|
165
|
+
from typing import Any
|
|
166
|
+
from dataclasses import dataclass, field
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
@dataclass
|
|
170
|
+
class SecretoEnCache:
|
|
171
|
+
valor: Any
|
|
172
|
+
expira_en: float # Unix timestamp
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class ClienteSecretos:
|
|
176
|
+
"""Cliente con caché local para reducir llamadas a AWS Secrets Manager."""
|
|
177
|
+
|
|
178
|
+
def __init__(self, region: str = "us-east-1", ttl_segundos: int = 300):
|
|
179
|
+
self._cliente = boto3.client("secretsmanager", region_name=region)
|
|
180
|
+
self._cache: dict[str, SecretoEnCache] = {}
|
|
181
|
+
self._ttl = ttl_segundos
|
|
182
|
+
|
|
183
|
+
def obtener(self, nombre_secreto: str) -> dict[str, Any]:
|
|
184
|
+
ahora = time.time()
|
|
185
|
+
entrada = self._cache.get(nombre_secreto)
|
|
186
|
+
|
|
187
|
+
if entrada and entrada.expira_en > ahora:
|
|
188
|
+
return entrada.valor
|
|
189
|
+
|
|
190
|
+
respuesta = self._cliente.get_secret_value(SecretId=nombre_secreto)
|
|
191
|
+
|
|
192
|
+
if "SecretString" in respuesta:
|
|
193
|
+
valor = json.loads(respuesta["SecretString"])
|
|
194
|
+
else:
|
|
195
|
+
valor = json.loads(respuesta["SecretBinary"].decode("utf-8"))
|
|
196
|
+
|
|
197
|
+
self._cache[nombre_secreto] = SecretoEnCache(
|
|
198
|
+
valor=valor,
|
|
199
|
+
expira_en=ahora + self._ttl,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
return valor
|
|
203
|
+
|
|
204
|
+
def rotar(self, nombre_secreto: str) -> None:
|
|
205
|
+
"""Fuerza rotación inmediata y limpia el caché."""
|
|
206
|
+
self._cliente.rotate_secret(SecretId=nombre_secreto)
|
|
207
|
+
self._cache.pop(nombre_secreto, None)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
# Uso en la aplicación
|
|
211
|
+
_secretos = ClienteSecretos(region="us-east-1")
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def get_db_url() -> str:
|
|
215
|
+
creds = _secretos.obtener("produccion/bd-principal")
|
|
216
|
+
return (
|
|
217
|
+
f"postgresql+asyncpg://{creds['usuario']}:{creds['contrasena']}"
|
|
218
|
+
f"@{creds['host']}:{creds['puerto']}/{creds['nombre_bd']}"
|
|
219
|
+
)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Gestión de API Keys
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
# api_keys.py
|
|
228
|
+
import secrets
|
|
229
|
+
import hashlib
|
|
230
|
+
from datetime import datetime, timedelta, timezone
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def generar_api_key() -> tuple[str, str]:
|
|
234
|
+
"""
|
|
235
|
+
Genera una API key y su hash para almacenamiento.
|
|
236
|
+
La clave en texto plano se muestra UNA SOLA VEZ al usuario.
|
|
237
|
+
Solo el hash se almacena en la base de datos.
|
|
238
|
+
"""
|
|
239
|
+
clave = f"sk_{secrets.token_urlsafe(32)}"
|
|
240
|
+
hash_clave = hashlib.sha256(clave.encode()).hexdigest()
|
|
241
|
+
return clave, hash_clave
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def verificar_api_key(clave_recibida: str, hash_almacenado: str) -> bool:
|
|
245
|
+
"""Verifica una API key en tiempo constante para prevenir timing attacks."""
|
|
246
|
+
hash_recibido = hashlib.sha256(clave_recibida.encode()).hexdigest()
|
|
247
|
+
return secrets.compare_digest(hash_recibido, hash_almacenado)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# Modelo de API Key con scopes y expiración
|
|
251
|
+
from sqlalchemy import String, DateTime, ARRAY
|
|
252
|
+
from sqlalchemy.orm import Mapped, mapped_column
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class APIKey(Base):
|
|
256
|
+
__tablename__ = "api_keys"
|
|
257
|
+
|
|
258
|
+
id: Mapped[str] = mapped_column(String, primary_key=True)
|
|
259
|
+
nombre: Mapped[str] = mapped_column(String(100))
|
|
260
|
+
hash_clave: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
|
261
|
+
scopes: Mapped[list[str]] = mapped_column(ARRAY(String))
|
|
262
|
+
propietario_id: Mapped[str] = mapped_column(String(255))
|
|
263
|
+
expira_en: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
264
|
+
ultimo_uso: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
265
|
+
activa: Mapped[bool] = mapped_column(default=True)
|
|
266
|
+
|
|
267
|
+
def esta_vigente(self) -> bool:
|
|
268
|
+
if not self.activa:
|
|
269
|
+
return False
|
|
270
|
+
if self.expira_en and self.expira_en < datetime.now(timezone.utc):
|
|
271
|
+
return False
|
|
272
|
+
return True
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Rotación de Secretos — Estrategia
|
|
278
|
+
|
|
279
|
+
```yaml
|
|
280
|
+
# Política de rotación por tipo de secreto
|
|
281
|
+
rotacion:
|
|
282
|
+
credenciales_bd:
|
|
283
|
+
frecuencia: "cada 7 días"
|
|
284
|
+
estrategia: "doble escritura"
|
|
285
|
+
pasos:
|
|
286
|
+
1: "Crear nuevo usuario de BD"
|
|
287
|
+
2: "Actualizar secreto en Vault/AWS SM"
|
|
288
|
+
3: "Desplegar nueva versión de la app"
|
|
289
|
+
4: "Verificar que la nueva versión funciona"
|
|
290
|
+
5: "Revocar credenciales antiguas"
|
|
291
|
+
|
|
292
|
+
jwt_secret:
|
|
293
|
+
frecuencia: "cada 30 días"
|
|
294
|
+
estrategia: "período de gracia de 24h"
|
|
295
|
+
pasos:
|
|
296
|
+
1: "Generar nuevo secret"
|
|
297
|
+
2: "Configurar validación de AMBOS secrets (nuevo y viejo) durante 24h"
|
|
298
|
+
3: "Después de 24h, eliminar el viejo"
|
|
299
|
+
|
|
300
|
+
api_keys_externas:
|
|
301
|
+
frecuencia: "cada 90 días"
|
|
302
|
+
estrategia: "reemplazo directo con downtime cero"
|
|
303
|
+
notas: "Las APIs externas dan período de transición de 24-72h"
|
|
304
|
+
|
|
305
|
+
certificados_tls:
|
|
306
|
+
frecuencia: "cada 90 días (automático con cert-manager/Let's Encrypt)"
|
|
307
|
+
alerta_anticipacion: "30 días antes de expiración"
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Configuración de Cuentas de Servicio — Kubernetes
|
|
313
|
+
|
|
314
|
+
```yaml
|
|
315
|
+
# k8s/service-account.yaml
|
|
316
|
+
apiVersion: v1
|
|
317
|
+
kind: ServiceAccount
|
|
318
|
+
metadata:
|
|
319
|
+
name: api-backend
|
|
320
|
+
namespace: produccion
|
|
321
|
+
annotations:
|
|
322
|
+
eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/api-backend-role
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
apiVersion: rbac.authorization.k8s.io/v1
|
|
326
|
+
kind: Role
|
|
327
|
+
metadata:
|
|
328
|
+
name: api-backend-role
|
|
329
|
+
namespace: produccion
|
|
330
|
+
rules:
|
|
331
|
+
# Solo leer secrets propios — NO acceso a todos los secrets
|
|
332
|
+
- apiGroups: [""]
|
|
333
|
+
resources: ["secrets"]
|
|
334
|
+
resourceNames: ["api-backend-secrets"]
|
|
335
|
+
verbs: ["get"]
|
|
336
|
+
# Solo leer configmaps propios
|
|
337
|
+
- apiGroups: [""]
|
|
338
|
+
resources: ["configmaps"]
|
|
339
|
+
resourceNames: ["api-backend-config"]
|
|
340
|
+
verbs: ["get", "watch"]
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
apiVersion: rbac.authorization.k8s.io/v1
|
|
344
|
+
kind: RoleBinding
|
|
345
|
+
metadata:
|
|
346
|
+
name: api-backend-binding
|
|
347
|
+
namespace: produccion
|
|
348
|
+
subjects:
|
|
349
|
+
- kind: ServiceAccount
|
|
350
|
+
name: api-backend
|
|
351
|
+
namespace: produccion
|
|
352
|
+
roleRef:
|
|
353
|
+
kind: Role
|
|
354
|
+
name: api-backend-role
|
|
355
|
+
apiGroup: rbac.authorization.k8s.io
|
|
356
|
+
```
|