@saulwade/swl-ses 2.6.0 → 2.8.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 +209 -197
- package/README.md +647 -600
- package/agentes/accesibilidad-wcag-swl.md +690 -690
- package/agentes/arquitecto-swl.md +267 -267
- package/agentes/auto-evolucion-swl.md +932 -932
- package/agentes/backend-csharp-swl.md +420 -420
- package/agentes/backend-go-swl.md +390 -390
- package/agentes/backend-java-swl.md +281 -281
- package/agentes/backend-rust-swl.md +364 -364
- package/agentes/backend-workers-swl.md +482 -482
- package/agentes/cloud-infra-swl.md +509 -509
- package/agentes/consolidador-swl.md +541 -541
- package/agentes/depurador-swl.md +352 -352
- package/agentes/devops-ci-swl.md +400 -400
- package/agentes/disenador-ui-swl.md +569 -569
- package/agentes/documentador-swl.md +345 -345
- package/agentes/frontend-angular-swl.md +621 -621
- package/agentes/frontend-css-swl.md +716 -716
- package/agentes/frontend-react-swl.md +692 -692
- package/agentes/frontend-swl.md +496 -496
- package/agentes/frontend-tailwind-swl.md +826 -826
- package/agentes/investigador-swl.md +432 -432
- package/agentes/investigador-ux-swl.md +505 -505
- package/agentes/migrador-swl.md +442 -442
- package/agentes/mobile-android-swl.md +511 -511
- package/agentes/mobile-cross-swl.md +541 -541
- package/agentes/mobile-ios-swl.md +502 -502
- package/agentes/mobile-testing-swl.md +302 -302
- package/agentes/nemesis-auditor-swl.md +285 -285
- package/agentes/observabilidad-swl.md +438 -438
- package/agentes/pagos-swl.md +310 -310
- package/agentes/perfilador-usuario-swl.md +321 -321
- package/agentes/planificador-swl.md +399 -399
- package/agentes/producto-prd-swl.md +589 -589
- package/agentes/red-team-swl.md +218 -218
- package/agentes/release-manager-swl.md +590 -590
- package/agentes/rendimiento-swl.md +713 -713
- package/agentes/revisor-angular-swl.md +278 -278
- package/agentes/revisor-csharp-swl.md +264 -264
- package/agentes/revisor-go-swl.md +259 -259
- package/agentes/revisor-java-swl.md +257 -257
- package/agentes/revisor-kotlin-swl.md +273 -273
- package/agentes/revisor-nextjs-swl.md +281 -281
- package/agentes/revisor-php-swl.md +271 -271
- package/agentes/revisor-react-swl.md +278 -278
- package/agentes/revisor-rust-swl.md +346 -346
- package/agentes/revisor-seguridad-swl.md +399 -399
- package/agentes/revisor-swift-swl.md +268 -268
- package/agentes/revisor-typescript-swl.md +346 -346
- package/agentes/tdd-qa-swl.md +393 -393
- package/bin/swl-ses.js +10 -0
- package/comandos/swl/actualizar.md +174 -174
- package/comandos/swl/adoptar-proyecto.md +265 -265
- package/comandos/swl/aprender.md +836 -836
- package/comandos/swl/aprobar-plan.md +146 -146
- package/comandos/swl/auditar-deps.md +134 -134
- package/comandos/swl/autoresearch.md +264 -264
- package/comandos/swl/ayuda.md +224 -224
- package/comandos/swl/brainstorm.md +52 -51
- package/comandos/swl/checkpoint.md +325 -325
- package/comandos/swl/claudemd.md +234 -234
- package/comandos/swl/compactar.md +310 -310
- package/comandos/swl/configurar-ci.md +235 -235
- package/comandos/swl/contexto.md +110 -110
- package/comandos/swl/crear-skill.md +292 -292
- package/comandos/swl/cron.md +194 -194
- package/comandos/swl/deuda-codigo.md +97 -97
- package/comandos/swl/discutir-fase.md +169 -169
- package/comandos/swl/ejecutar-fase.md +233 -233
- package/comandos/swl/evaluar-skill.md +520 -520
- package/comandos/swl/evolucion-continua.md +73 -73
- package/comandos/swl/evolucionar.md +267 -267
- package/comandos/swl/exportar-vault.md +583 -583
- package/comandos/swl/fix.md +118 -118
- package/comandos/swl/gateway.md +158 -158
- package/comandos/swl/inbox.md +116 -116
- package/comandos/swl/instalar.md +220 -220
- package/comandos/swl/instintos.md +86 -86
- package/comandos/swl/mapear-codebase.md +312 -312
- package/comandos/swl/mcp-status.md +176 -175
- package/comandos/swl/modelo.md +100 -100
- package/comandos/swl/nemesis.md +433 -433
- package/comandos/swl/notificaciones.md +299 -299
- package/comandos/swl/nuevo-proyecto.md +251 -251
- package/comandos/swl/planear-fase.md +263 -263
- package/comandos/swl/plugins.md +256 -256
- package/comandos/swl/predecir.md +169 -169
- package/comandos/swl/reflect-skills.md +125 -125
- package/comandos/swl/release.md +450 -450
- package/comandos/swl/revisar-impacto.md +201 -201
- package/comandos/swl/revisar.md +330 -330
- package/comandos/swl/seguridad.md +189 -189
- package/comandos/swl/sesiones.md +200 -200
- package/comandos/swl/skill-search.md +113 -113
- package/comandos/swl/status.md +345 -345
- package/comandos/swl/verificar.md +817 -817
- package/comandos/swl/wiki.md +620 -620
- package/gateway/cron/jobs.example.json +12 -12
- package/gateway/lib/event-channel.js +191 -191
- package/habilidades/agent-deep-links/SKILL.md +148 -148
- package/habilidades/auto-evolucion-protocolo/SKILL.md +294 -294
- package/habilidades/backend-async-postgres-testing/SKILL.md +216 -215
- package/habilidades/backend-error-design/SKILL.md +221 -221
- package/habilidades/backend-production-resilience/SKILL.md +288 -288
- package/habilidades/calidad-anti-patrones-universales/SKILL.md +105 -1
- package/habilidades/calidad-contract-testing/SKILL.md +165 -165
- package/habilidades/calidad-mutation-testing/SKILL.md +25 -1
- package/habilidades/changelog-generator/SKILL.md +174 -174
- package/habilidades/checklist-seguridad/recursos/stride-cobertura.md +60 -60
- package/habilidades/ci-cd-pipelines/SKILL.md +5 -1
- package/habilidades/compactacion-contexto/SKILL.md +2 -1
- package/habilidades/contenedores-docker/SKILL.md +4 -2
- package/habilidades/css-moderno/SKILL.md +7 -1
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
- package/habilidades/doubt-driven-review/SKILL.md +207 -207
- package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
- package/habilidades/drift-detection/SKILL.md +1 -1
- package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +57 -57
- package/habilidades/extractor-de-aprendizajes/SKILL.md +12 -2
- package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
- package/habilidades/git-worktrees-paralelo/SKILL.md +19 -1
- package/habilidades/harness-claude-code/SKILL.md +315 -314
- package/habilidades/instalar-sistema/SKILL.md +227 -227
- package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
- package/habilidades/perfil-usuario/SKILL.md +200 -200
- package/habilidades/planear-fase/SKILL.md +358 -358
- package/habilidades/prevencion-sobreingenieria/recursos/EXAMPLES.md +580 -580
- package/habilidades/proceso-ddia-streaming/SKILL.md +231 -231
- package/habilidades/proceso-discovery-machote/SKILL.md +157 -157
- package/habilidades/proceso-dynamic-workflows/SKILL.md +60 -0
- package/habilidades/proceso-dynamic-workflows/recursos/template-adversarial-verify.js +65 -65
- package/habilidades/proceso-dynamic-workflows/recursos/template-triage.js +65 -65
- package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -147
- package/habilidades/proceso-intent-engineering/SKILL.md +269 -269
- package/habilidades/proceso-modular-split/SKILL.md +256 -256
- package/habilidades/release-semver/SKILL.md +2 -2
- package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -147
- package/habilidades/swl-claudemd/recursos/contrato-aprender.md +83 -83
- package/habilidades/swl-claudemd/recursos/duplicacion-reglas-globales.md +85 -85
- package/habilidades/swl-claudemd/recursos/plantillas-init.md +94 -94
- package/habilidades/tdd-workflow/SKILL.md +749 -749
- package/habilidades/tdd-workflow/recursos/gherkin-bdd.md +111 -111
- package/hooks/agente-lifecycle.js +1 -1
- package/hooks/audit-trail.js +1 -1
- package/hooks/auto-consolidacion.js +1 -1
- package/hooks/calidad-pre-commit.js +159 -10
- package/hooks/captura-acciones-post.js +1 -1
- package/hooks/captura-acciones-session.js +1 -1
- package/hooks/captura-feedback-usuario.js +1 -1
- package/hooks/ciclo-evolucion-subagente.js +26 -26
- package/hooks/ciclo-evolucion.js +26 -26
- package/hooks/contexto-iteracion.js +1 -1
- package/hooks/degradacion-instintos.js +1 -1
- package/hooks/grafo-contexto.js +1 -1
- package/hooks/guardrail-modelo.js +1 -1
- package/hooks/inbox-aviso.js +1 -1
- package/hooks/inyeccion-contexto.js +1 -1
- package/hooks/lib/agent-matcher.js +1 -1
- package/hooks/lib/agent-routing.js +1 -1
- package/hooks/lib/auto-consolidator.js +335 -335
- package/hooks/lib/captura-acciones.js +1 -1
- package/hooks/lib/ciclo-evolucion.js +47 -47
- package/hooks/lib/deep-links.js +185 -185
- package/hooks/lib/error-classifier.js +308 -308
- package/hooks/lib/etapa-metricas.js +1 -1
- package/hooks/lib/evolution-tracker.js +1 -1
- package/hooks/lib/gateway-notify.js +193 -193
- package/hooks/lib/mcp-health.js +1 -1
- package/hooks/lib/notificacion-formato.js +92 -0
- package/hooks/lib/nudge-tracker.js +1 -1
- package/hooks/lib/otlp-exporter.js +1 -1
- package/hooks/lib/propose-step.js +1 -1
- package/hooks/lib/provenance-tracker.js +191 -191
- package/hooks/lib/raiz-proyecto.js +158 -102
- package/hooks/lib/resource-quota.js +122 -122
- package/hooks/lib/retry-jitter.js +165 -165
- package/hooks/lib/run-log.js +1 -1
- package/hooks/lib/security-net.js +201 -201
- package/hooks/lib/singleton-guard.js +20 -13
- package/hooks/lib/skill-auditor.js +588 -588
- package/hooks/lib/sync-status.js +228 -228
- package/hooks/lib/taint-tracker.js +107 -107
- package/hooks/lib/telegram-cliente.js +11 -3
- package/hooks/lib/text-similarity.js +241 -241
- package/hooks/lib/toon-compressor.js +245 -245
- package/hooks/notificacion-telegram.js +17 -13
- package/hooks/preservar-estado-pre-compact.js +1 -1
- package/hooks/registro-turnos.js +1 -1
- package/hooks/resumen-sesion.js +1 -1
- package/hooks/risk-scoring.js +1 -1
- package/hooks/session-briefing.js +13 -5
- package/hooks/spec-gate.js +1 -1
- package/hooks/sugerir-regenerar-inventario.js +1 -1
- package/hooks/tdd-gate.js +1 -1
- package/hooks/telemetria-agentes.js +1 -1
- package/hooks/telemetria-skill-routing.js +1 -1
- package/hooks/tracking-costos.js +1 -1
- package/hooks/validar-formato-post-subagente.js +1 -1
- package/hooks/validar-intent-spec.js +1 -1
- package/hooks/validar-planning-paths.js +1 -1
- package/instintos/autonomia.yaml +27 -27
- package/instintos/prompt-appendices.yaml +57 -57
- package/llms.txt +29 -29
- package/manifiestos/agent-output-schemas.json +57 -57
- package/manifiestos/canonical-hashes.json +6250 -5257
- package/manifiestos/harness-ir.json +47536 -0
- package/manifiestos/modulos.json +1429 -1428
- package/manifiestos/policy-bundle.json +2065 -0
- package/manifiestos/policy-corpus-w2.json +3926 -0
- package/manifiestos/runtime-adapters-core3.json +208 -0
- package/manifiestos/runtime-conformance.json +139 -0
- package/manifiestos/skills-lock.json +1275 -1275
- package/package.json +94 -94
- package/plantillas/auditor-veto-template.md +105 -105
- package/plantillas/github-workflows/release-please.yml +44 -44
- package/plantillas/github-workflows/swl-ci.yml +107 -107
- package/plantillas/github-workflows/swl-security.yml +51 -51
- package/plugin.json +369 -369
- package/reglas/accesibilidad.md +10 -10
- package/reglas/auditorias-documentales-estructurales.md +7 -7
- package/reglas/cloud-infra.md +8 -8
- package/reglas/consultar-vault-primero.md +195 -195
- package/reglas/git-workflow.md +1 -0
- package/reglas/hooks.md +6 -6
- package/reglas/intent-engineering.md +218 -218
- package/reglas/markitdown.md +8 -8
- package/reglas/monitor-ci.md +12 -0
- package/reglas/patrones.md +6 -6
- package/reglas/testing.md +7 -7
- package/reglas/tests-cleanup.md +224 -224
- package/schemas/agent-message.schema.json +73 -73
- package/schemas/agent-output-implementacion.schema.json +114 -114
- package/schemas/agent-output-planificacion.schema.json +150 -150
- package/schemas/agent-output-review.schema.json +98 -98
- package/schemas/diary-entry.schema.json +112 -112
- package/schemas/gate-state.schema.json +76 -0
- package/schemas/harness-ir.schema.json +369 -0
- package/schemas/hook-profiles.schema.json +54 -54
- package/schemas/hooks-config.schema.json +89 -89
- package/schemas/legacy-gates.schema.json +45 -0
- package/schemas/modulos.schema.json +38 -38
- package/schemas/perfiles.schema.json +36 -36
- package/schemas/plugin.schema.json +77 -77
- package/schemas/policy-bundle.schema.json +140 -0
- package/schemas/policy-enforcement.schema.json +117 -0
- package/schemas/policy-operation.schema.json +261 -0
- package/schemas/runtime-adapter.schema.json +176 -0
- package/schemas/runtime-build-attestation.schema.json +100 -0
- package/schemas/runtime-conformance.schema.json +239 -0
- package/schemas/runtime-diagnostic.schema.json +395 -0
- package/schemas/skill-evals.schema.json +119 -119
- package/schemas/skill-frontmatter.schema.json +245 -245
- package/schemas/w4-certification-request.schema.json +72 -0
- package/schemas/w4-certification-verdict.schema.json +224 -0
- package/schemas/w4-corpus.schema.json +172 -0
- package/schemas/w4-mutation-report.schema.json +116 -0
- package/schemas/w4-replay-result.schema.json +164 -0
- package/schemas/w4-scoring-report.schema.json +89 -0
- package/scripts/audit-tools/audit-history.js +330 -330
- package/scripts/audit-tools/bundle-tracker.js +290 -290
- package/scripts/audit-tools/canary-monitor.js +352 -352
- package/scripts/audit-tools/code-profiler.js +605 -605
- package/scripts/audit-tools/dep-doctor.js +320 -320
- package/scripts/audit-tools/env-validator.js +206 -206
- package/scripts/audit-tools/lib/fs-walk.js +48 -48
- package/scripts/audit-tools/lib/output.js +23 -23
- package/scripts/audit-tools/migration-checker.js +392 -392
- package/scripts/audit-tools/pentest-scanner.js +1436 -1436
- package/scripts/auditar-clases-conocidas.js +134 -134
- package/scripts/bootstrap-instintos.js +88 -14
- package/scripts/canario-hooks.js +166 -166
- package/scripts/cli/aprobar-plan.js +73 -73
- package/scripts/cli/autonomia.js +23 -23
- package/scripts/cli/benchmark-memoria.js +37 -37
- package/scripts/cli/briefing.js +23 -23
- package/scripts/cli/ciclo-autonomo.js +73 -73
- package/scripts/cli/ciclo-evolucion.js +26 -26
- package/scripts/cli/ciclo-fase-b.js +102 -102
- package/scripts/cli/derivar-feature-list.js +25 -25
- package/scripts/cli/detectar-host.js +27 -27
- package/scripts/cli/diary-entry.js +69 -69
- package/scripts/cli/execution-state.js +18 -18
- package/scripts/cli/gateway-notify.js +41 -41
- package/scripts/cli/guardrail-metrics.js +39 -39
- package/scripts/cli/liberar-fase.js +42 -42
- package/scripts/cli/mark-evolved.js +56 -56
- package/scripts/cli/memoria-search.js +69 -69
- package/scripts/cli/metricas-dora.js +26 -26
- package/scripts/cli/near-duplicate.js +55 -55
- package/scripts/cli/notificaciones.js +123 -123
- package/scripts/cli/nudge-accionar.js +39 -39
- package/scripts/cli/propose-step.js +29 -29
- package/scripts/cli/run-eval.js +38 -38
- package/scripts/cli/schedule-parse.js +19 -19
- package/scripts/cli/sugerir-modelo.js +20 -20
- package/scripts/cli/verificar-plan.js +36 -36
- package/scripts/cli/verificar-trazabilidad.js +35 -35
- package/scripts/comandos/install-asistido.js +8 -7
- package/scripts/configurar-branch-protection.js +418 -418
- package/scripts/detectar-aprendizajes-duplicados.js +151 -151
- package/scripts/doctor.js +61 -13
- package/scripts/evidencia-valor.js +101 -101
- package/scripts/field-report.js +16 -16
- package/scripts/generar-checklists-consolidados.js +273 -273
- package/scripts/generar-claims-runtime.js +1342 -0
- package/scripts/generar-harness-ir.js +257 -0
- package/scripts/generar-inventario.js +52 -54
- package/scripts/generar-policy-bundle.js +202 -0
- package/scripts/instalador.js +39 -7
- package/scripts/lib/activar-hooks-proyecto.js +116 -116
- package/scripts/lib/approval-receipts.js +190 -0
- package/scripts/lib/artefactos-python.js +43 -43
- package/scripts/lib/benchmark-metrics.js +160 -160
- package/scripts/lib/budget-enforcer.js +252 -252
- package/scripts/lib/certificacion-loop-state.js +421 -0
- package/scripts/lib/ci-reader.js +193 -193
- package/scripts/lib/ciclo-autonomo/candidatos.js +174 -174
- package/scripts/lib/ciclo-autonomo/config.js +165 -165
- package/scripts/lib/ciclo-autonomo/drenador-feedback.js +174 -174
- package/scripts/lib/ciclo-autonomo/fallback.js +77 -77
- package/scripts/lib/ciclo-autonomo/guard-convivencia.js +139 -139
- package/scripts/lib/ciclo-autonomo/higiene-nudges.js +112 -112
- package/scripts/lib/ciclo-autonomo/index.js +301 -301
- package/scripts/lib/ciclo-autonomo/lock.js +124 -124
- package/scripts/lib/ciclo-autonomo/presupuesto.js +122 -122
- package/scripts/lib/ciclo-autonomo/puente-degradacion.js +240 -240
- package/scripts/lib/ciclo-autonomo/runner-fase-b.js +248 -248
- package/scripts/lib/ciclo-autonomo/writer-instintos.js +190 -190
- package/scripts/lib/ciclo-autonomo/yaml-instintos.js +591 -535
- package/scripts/lib/clasificar-directorio.js +92 -0
- package/scripts/lib/contadores-inventario.js +217 -217
- package/scripts/lib/detectar-host-swl.js +175 -175
- package/scripts/lib/detectar-runtime.js +29 -20
- package/scripts/lib/detectar-stack-detallado.js +307 -307
- package/scripts/lib/detector-autoduplicacion-intra-archivo.js +234 -234
- package/scripts/lib/detector-reglas-duplicadas.js +220 -220
- package/scripts/lib/eval-metrics-store.js +218 -218
- package/scripts/lib/eval-quality.js +171 -171
- package/scripts/lib/eval-schemas.js +144 -144
- package/scripts/lib/eval-self-correct.js +106 -106
- package/scripts/lib/eval-validator.js +185 -185
- package/scripts/lib/evidence-verifier.js +192 -0
- package/scripts/lib/evidencia-release.js +322 -322
- package/scripts/lib/evidencia-valor.js +228 -228
- package/scripts/lib/expandir-targets.js +71 -71
- package/scripts/lib/frontmatter-canonico.js +509 -0
- package/scripts/lib/gate-engine.js +871 -0
- package/scripts/lib/gate-hooks-requires.js +249 -249
- package/scripts/lib/gate-licencias.js +212 -212
- package/scripts/lib/git-config-preflight.js +48 -0
- package/scripts/lib/git-metricas.js +257 -257
- package/scripts/lib/harness-ir.js +778 -0
- package/scripts/lib/harness-source-snapshot.js +309 -0
- package/scripts/lib/integrity-ledger.js +1147 -0
- package/scripts/lib/jaccard-similarity.js +98 -98
- package/scripts/lib/legacy-gate-migration.js +324 -0
- package/scripts/lib/limpiar-basura-global.js +204 -0
- package/scripts/lib/longmemeval-runner.js +125 -125
- package/scripts/lib/metricas-dora.js +204 -204
- package/scripts/lib/notificaciones-telegram.js +1 -0
- package/scripts/lib/npm-version.js +1 -0
- package/scripts/lib/paquetes-conocidos.js +50 -50
- package/scripts/lib/plan-lock.js +61 -13
- package/scripts/lib/policy-broker.js +338 -0
- package/scripts/lib/policy-bundle.js +342 -0
- package/scripts/lib/policy-context-provider.js +310 -0
- package/scripts/lib/policy-contract.js +479 -0
- package/scripts/lib/policy-verifier-utils.js +65 -0
- package/scripts/lib/pr-analyzer.js +399 -399
- package/scripts/lib/principal-verifier.js +178 -0
- package/scripts/lib/prompt-builder.js +264 -264
- package/scripts/lib/resolver-plan-fase.js +37 -37
- package/scripts/lib/rrf-fusion.js +175 -175
- package/scripts/lib/runtime-adapter-contract.js +267 -0
- package/scripts/lib/runtime-artifact-verifier.js +426 -0
- package/scripts/lib/runtime-build-attestation.js +127 -0
- package/scripts/lib/runtime-bundle-installer.js +586 -0
- package/scripts/lib/runtime-compiler.js +327 -0
- package/scripts/lib/runtime-conformance.js +202 -0
- package/scripts/lib/runtime-doctor-core3.js +567 -0
- package/scripts/lib/runtime-doctor-input.js +59 -0
- package/scripts/lib/runtime-operation-adapter.js +267 -0
- package/scripts/lib/schema-version.js +164 -164
- package/scripts/lib/semantic-search.js +252 -252
- package/scripts/lib/signed-envelope.js +545 -0
- package/scripts/lib/single-use-store.js +359 -0
- package/scripts/lib/skills-externas.js +31 -0
- package/scripts/lib/toml-merge.js +204 -204
- package/scripts/lib/transformadores/codex.js +15 -8
- package/scripts/lib/transformadores/gemini.js +79 -5
- package/scripts/lib/w4-attestation-adapter.js +158 -0
- package/scripts/lib/w4-canario.js +337 -0
- package/scripts/lib/w4-claims.js +182 -0
- package/scripts/lib/w4-corpus-generador.js +542 -0
- package/scripts/lib/w4-gate-c5.js +115 -0
- package/scripts/lib/w4-harness-bajo-prueba.js +155 -0
- package/scripts/lib/w4-matriz-combos.js +55 -0
- package/scripts/lib/w4-motor-mutacion.js +1348 -0
- package/scripts/lib/w4-motor-replay.js +735 -0
- package/scripts/lib/w4-pin-origen.js +54 -0
- package/scripts/lib/w4-publicar-request.js +132 -0
- package/scripts/lib/w4-revocacion.js +62 -0
- package/scripts/lib/w4-runtimes-core3.js +38 -0
- package/scripts/lib/w4-scorer-certificacion.js +692 -0
- package/scripts/lib/w4-superficie-candidato.js +49 -0
- package/scripts/lib/w4-veredicto.js +452 -0
- package/scripts/lib/w4-verificar-veredicto.js +302 -0
- package/scripts/limpiar-artefactos-python.js +131 -131
- package/scripts/mcp-server/auth.js +105 -105
- package/scripts/mcp-server/cache.js +106 -106
- package/scripts/migrar-csv-a-array.js +168 -168
- package/scripts/migrar-fase-dominio.js +200 -200
- package/scripts/migrar-gates-legacy.js +108 -0
- package/scripts/publicar-certification-request.js +115 -0
- package/scripts/runtime-doctor.js +107 -0
- package/scripts/tui/componentes/selector-multi.js +189 -189
- package/scripts/tui/componentes/selector-unico.js +158 -158
- package/scripts/tui/ejecutores.js +375 -375
- package/scripts/tui/lib/colores.js +129 -129
- package/scripts/tui/lib/render.js +264 -264
- package/scripts/tui/lib/teclas.js +113 -113
- package/scripts/tui/pantallas/install-wizard.js +408 -403
- package/scripts/tui/pantallas/menu-principal.js +52 -52
- package/scripts/tui/pantallas/progreso.js +274 -274
- package/scripts/tui/pantallas/resumen.js +132 -132
- package/scripts/validar-userland-vacio.js +110 -110
- package/scripts/verificar-aislamiento-swl-eval.js +87 -0
- package/scripts/verificar-empaquetado-downstream.js +375 -0
- package/scripts/verificar-loop-constructor.js +215 -0
- package/scripts/verificar-trazabilidad.js +13 -6
- package/scripts/verificar-veredicto-real.js +84 -0
- package/instintos/.backups/perfil-usuario.yaml.2026-07-10-165128.bak +0 -53
- package/instintos/.backups/proyecto.yaml.2026-07-10-165128.bak +0 -372
package/scripts/lib/plan-lock.js
CHANGED
|
@@ -10,11 +10,9 @@
|
|
|
10
10
|
* la ejecución. Cierra el hueco "el plan puede mutar tras aprobación" que
|
|
11
11
|
* dejaba SDD en ~60%.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* se ejecuta con advertencia, sin bloqueo. Solo los planes firmados vía
|
|
17
|
-
* `/swl:aprobar-plan` (post-Fase 09) exigen coincidencia de hash.
|
|
13
|
+
* Desde 3.0.0, un PLAN aprobado sin lock bloquea. Los planes pre-Fase 09 sólo
|
|
14
|
+
* pueden convertirse mediante `migrar-gates-legacy`, que deja un lock v2 ligado
|
|
15
|
+
* a una approval firmada y a un evento de integridad anclado.
|
|
18
16
|
*
|
|
19
17
|
* MODELO DE AMENAZA (gate G1): el lock detecta MUTACIÓN ACCIDENTAL o no
|
|
20
18
|
* aprobada del PLAN tras su firma, y planes alterados por un agente que
|
|
@@ -52,6 +50,8 @@ try {
|
|
|
52
50
|
}
|
|
53
51
|
|
|
54
52
|
const LOCK_VERSION = 1;
|
|
53
|
+
const LOCK_KEYS = ['archivo', 'firmadoEn', 'firmadoPor', 'sha256', 'version'];
|
|
54
|
+
const MIGRATED_LOCK_KEYS = [...LOCK_KEYS, 'migration'];
|
|
55
55
|
|
|
56
56
|
// Basename válido de un PLAN de fase: `PLAN.md` o `0N-PLAN.md`. Evita que
|
|
57
57
|
// `firmarPlan` produzca locks de archivos arbitrarios (falsearía el audit
|
|
@@ -70,6 +70,14 @@ function sha256(data) {
|
|
|
70
70
|
return crypto.createHash('sha256').update(data).digest('hex');
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
function tieneClavesExactas(value, expected) {
|
|
74
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
75
|
+
const actual = Object.keys(value).sort();
|
|
76
|
+
const wanted = [...expected].sort();
|
|
77
|
+
return actual.length === wanted.length
|
|
78
|
+
&& actual.every((key, index) => key === wanted[index]);
|
|
79
|
+
}
|
|
80
|
+
|
|
73
81
|
/**
|
|
74
82
|
* Extrae el campo `estado:` del frontmatter YAML del PLAN.
|
|
75
83
|
* Reutiliza el patrón CRLF-safe de scripts/generar-skills-lock.js:46-55.
|
|
@@ -161,6 +169,12 @@ function firmarPlan(planPath, opciones = {}) {
|
|
|
161
169
|
};
|
|
162
170
|
}
|
|
163
171
|
const buffer = fs.readFileSync(planPath);
|
|
172
|
+
if (leerEstado(buffer.toString('utf8')) !== 'aprobado') {
|
|
173
|
+
return {
|
|
174
|
+
ok: false,
|
|
175
|
+
motivo: 'el PLAN debe tener estado aprobado antes de firmarse',
|
|
176
|
+
};
|
|
177
|
+
}
|
|
164
178
|
const hash = sha256(buffer);
|
|
165
179
|
|
|
166
180
|
const lock = {
|
|
@@ -180,9 +194,11 @@ function firmarPlan(planPath, opciones = {}) {
|
|
|
180
194
|
*
|
|
181
195
|
* Modos de retorno:
|
|
182
196
|
* - `firmado` : existe lock y el hash coincide -> ok: true
|
|
183
|
-
* - `legacy
|
|
197
|
+
* - `legacy-bloqueado`: NO existe lock pero estado:aprobado -> ok: false
|
|
198
|
+
* - `migrado` : existe lock v2 de migración y el hash coincide -> ok: true
|
|
184
199
|
* - `mutado` : existe lock y el hash NO coincide -> ok: false
|
|
185
200
|
* - `lock-corrupto`: el lock existe pero no es JSON válido -> ok: false
|
|
201
|
+
* - `estado-invalido`: existe lock pero el PLAN no está aprobado -> ok: false
|
|
186
202
|
* - `sin-firmar` : NO existe lock y estado != aprobado -> ok: false
|
|
187
203
|
* - `sin-planning`: el PLAN no tiene `.planning` ancestro -> ok: false
|
|
188
204
|
* - `no-existe` : el PLAN no existe en disco -> ok: false
|
|
@@ -204,15 +220,14 @@ function verificarPlan(planPath) {
|
|
|
204
220
|
}
|
|
205
221
|
const buffer = fs.readFileSync(planPath);
|
|
206
222
|
const hashActual = sha256(buffer);
|
|
223
|
+
const estado = leerEstado(buffer.toString('utf8'));
|
|
207
224
|
|
|
208
225
|
if (!fs.existsSync(lockPath)) {
|
|
209
|
-
// Cláusula de gracia D-05: plan aprobado antes de que existiera el lock.
|
|
210
|
-
const estado = leerEstado(buffer.toString('utf8'));
|
|
211
226
|
if (estado === 'aprobado') {
|
|
212
227
|
return {
|
|
213
|
-
ok:
|
|
214
|
-
modo: 'legacy',
|
|
215
|
-
motivo: 'plan aprobado
|
|
228
|
+
ok: false,
|
|
229
|
+
modo: 'legacy-bloqueado',
|
|
230
|
+
motivo: 'plan aprobado sin lock; requiere migración legacy explícita',
|
|
216
231
|
hashActual,
|
|
217
232
|
lockPath,
|
|
218
233
|
};
|
|
@@ -226,6 +241,16 @@ function verificarPlan(planPath) {
|
|
|
226
241
|
};
|
|
227
242
|
}
|
|
228
243
|
|
|
244
|
+
if (estado !== 'aprobado') {
|
|
245
|
+
return {
|
|
246
|
+
ok: false,
|
|
247
|
+
modo: 'estado-invalido',
|
|
248
|
+
motivo: `un lock no aprueba el PLAN (estado: ${estado || 'ausente'})`,
|
|
249
|
+
hashActual,
|
|
250
|
+
lockPath,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
229
254
|
let lock;
|
|
230
255
|
try {
|
|
231
256
|
lock = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
|
|
@@ -240,7 +265,11 @@ function verificarPlan(planPath) {
|
|
|
240
265
|
}
|
|
241
266
|
|
|
242
267
|
const hashEsperado = lock && typeof lock.sha256 === 'string' ? lock.sha256 : null;
|
|
243
|
-
|
|
268
|
+
const expectedKeys = lock && lock.version === 2 ? MIGRATED_LOCK_KEYS : LOCK_KEYS;
|
|
269
|
+
const baseValida = tieneClavesExactas(lock, expectedKeys) && [1, 2].includes(lock.version)
|
|
270
|
+
&& lock.archivo === path.basename(planPath)
|
|
271
|
+
&& typeof lock.firmadoEn === 'string' && typeof lock.firmadoPor === 'string';
|
|
272
|
+
if (!hashEsperado || !baseValida) {
|
|
244
273
|
return {
|
|
245
274
|
ok: false,
|
|
246
275
|
modo: 'lock-corrupto',
|
|
@@ -250,8 +279,27 @@ function verificarPlan(planPath) {
|
|
|
250
279
|
};
|
|
251
280
|
}
|
|
252
281
|
|
|
282
|
+
if (lock.version === 2) {
|
|
283
|
+
const migration = lock.migration;
|
|
284
|
+
const migrationValida = migration && typeof migration === 'object'
|
|
285
|
+
&& Object.keys(migration).sort().join(',') === [
|
|
286
|
+
'approvalDigest', 'contextDigest', 'cutoff', 'eventHeadHash',
|
|
287
|
+
'eventSequence', 'migrationId',
|
|
288
|
+
].sort().join(',')
|
|
289
|
+
&& typeof migration.migrationId === 'string'
|
|
290
|
+
&& /^[a-f0-9]{64}$/u.test(migration.approvalDigest)
|
|
291
|
+
&& /^[a-f0-9]{64}$/u.test(migration.contextDigest)
|
|
292
|
+
&& /^[a-f0-9]{64}$/u.test(migration.eventHeadHash)
|
|
293
|
+
&& Number.isInteger(migration.eventSequence) && migration.eventSequence > 0
|
|
294
|
+
&& migration.cutoff === '2027-01-15T00:00:00.000Z';
|
|
295
|
+
if (!migrationValida) {
|
|
296
|
+
return { ok: false, modo: 'lock-corrupto', motivo: 'lock migrado inválido', hashActual, lockPath };
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
253
300
|
if (hashEsperado === hashActual) {
|
|
254
|
-
|
|
301
|
+
const modo = lock.version === 2 ? 'migrado' : 'firmado';
|
|
302
|
+
return { ok: true, modo, hashEsperado, hashActual, lockPath };
|
|
255
303
|
}
|
|
256
304
|
|
|
257
305
|
return {
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/** Autoriza efectos canónicos con default-deny dentro de una sola transacción. */
|
|
4
|
+
|
|
5
|
+
const crypto = require('node:crypto');
|
|
6
|
+
const fs = require('node:fs');
|
|
7
|
+
const path = require('node:path');
|
|
8
|
+
|
|
9
|
+
const { exactKeys, fail, freezeDeep, plainObject } = require('./policy-verifier-utils');
|
|
10
|
+
const { canonicalizarIJson } = require('./signed-envelope');
|
|
11
|
+
|
|
12
|
+
const APPROVAL_CAPABILITIES = new Set([
|
|
13
|
+
'delegate', 'filesystem.mutate', 'memory.write', 'network.access',
|
|
14
|
+
'shell.exec', 'skill.invoke',
|
|
15
|
+
]);
|
|
16
|
+
const EXPECTED_APPROVAL_ERRORS = new Set([
|
|
17
|
+
'APPROVAL_BINDING_INVALID', 'APPROVAL_EXPIRED', 'APPROVAL_INVALID',
|
|
18
|
+
'APPROVAL_TRUST_INVALID', 'PRINCIPAL_EXPIRED', 'PRINCIPAL_TRUST_INVALID',
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
function sha256(value) {
|
|
22
|
+
return crypto.createHash('sha256').update(value).digest('hex');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function hitFault(point) {
|
|
26
|
+
if (process.env.SWL_SINGLE_USE_FAULT !== point) return;
|
|
27
|
+
if (process.env.NODE_ENV !== 'test' || process.env.SWL_INTEGRITY_TEST_MODE !== '1') {
|
|
28
|
+
fail('FAULT_CONFIG_INVALID', 'fault injection fuera del modo de pruebas');
|
|
29
|
+
}
|
|
30
|
+
fail('FAULT_INJECTED', `falla inyectada: ${point}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function safeOptions(options) {
|
|
34
|
+
if (options === undefined) return Object.freeze({ approval: null });
|
|
35
|
+
plainObject(options, 'POLICY_OPTIONS_INVALID', 'opciones de autorización');
|
|
36
|
+
exactKeys(options, ['approval'], 'POLICY_OPTIONS_INVALID', 'opciones de autorización');
|
|
37
|
+
return Object.freeze({ approval: options.approval });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function isInside(base, target, style) {
|
|
41
|
+
const module = style === 'win32' ? path.win32 : path.posix;
|
|
42
|
+
const relative = module.relative(base, target);
|
|
43
|
+
if (style === 'win32') {
|
|
44
|
+
const folded = relative.toLowerCase();
|
|
45
|
+
return folded === '' || (!folded.startsWith('..\\') && folded !== '..'
|
|
46
|
+
&& !module.isAbsolute(relative));
|
|
47
|
+
}
|
|
48
|
+
return relative === '' || (!relative.startsWith('../') && relative !== '..');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function nativeStyle(workspaceRoot) {
|
|
52
|
+
return /^[A-Za-z]:\\/u.test(workspaceRoot) ? 'win32' : 'posix';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function assertSafeAncestors(workspaceRoot, target, style) {
|
|
56
|
+
const module = style === 'win32' ? path.win32 : path.posix;
|
|
57
|
+
const relative = module.relative(workspaceRoot, target);
|
|
58
|
+
let current = workspaceRoot;
|
|
59
|
+
for (const segment of relative.split(style === 'win32' ? '\\' : '/')) {
|
|
60
|
+
if (!segment) continue;
|
|
61
|
+
current = module.join(current, segment);
|
|
62
|
+
if (!fs.existsSync(current)) continue;
|
|
63
|
+
if (fs.lstatSync(current).isSymbolicLink()) {
|
|
64
|
+
fail('PATH_UNSAFE', 'ancestro simbólico o reparse no permitido');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function assertWorkspaceScope(operation, workspaceRoot) {
|
|
70
|
+
const style = nativeStyle(workspaceRoot);
|
|
71
|
+
if ((operation.effect.pathStyle && operation.effect.pathStyle !== style)
|
|
72
|
+
|| !isInside(workspaceRoot, operation.cwd, style)) {
|
|
73
|
+
fail('PATH_OUTSIDE_WORKSPACE', 'cwd fuera del workspace');
|
|
74
|
+
}
|
|
75
|
+
assertSafeAncestors(workspaceRoot, operation.cwd, style);
|
|
76
|
+
if (operation.effect.kind !== 'filesystem') return;
|
|
77
|
+
if (!isInside(workspaceRoot, operation.effect.absolutePath, style)) {
|
|
78
|
+
fail('PATH_OUTSIDE_WORKSPACE', 'efecto fuera del workspace');
|
|
79
|
+
}
|
|
80
|
+
assertSafeAncestors(workspaceRoot, operation.effect.absolutePath, style);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function assertDirectProcess(effect) {
|
|
84
|
+
if (effect.kind !== 'process') return;
|
|
85
|
+
fail('SHELL_OPAQUE', 'process queda denegado hasta contar con adaptadores code-owned');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function policyMatchesContext(view, liveBundle) {
|
|
89
|
+
const context = view.context;
|
|
90
|
+
const globalDigest = sha256(canonicalizarIJson(liveBundle.globalPolicy));
|
|
91
|
+
return context.corpusDigest === liveBundle.corpusDigest
|
|
92
|
+
&& context.policyVersion === liveBundle.policyVersion
|
|
93
|
+
&& context.globalPolicyDigest === globalDigest
|
|
94
|
+
&& view.bundle.corpusDigest === liveBundle.corpusDigest;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function assertCapability(view, liveBundle, operation) {
|
|
98
|
+
if (!view.context.allowedCapabilities.includes(operation.capability)) {
|
|
99
|
+
fail('CAPABILITY_DENIED', 'capability fuera de la intersección efectiva');
|
|
100
|
+
}
|
|
101
|
+
if (operation.effect.kind === 'skill'
|
|
102
|
+
&& !view.context.allowedSkillNodeIds.includes(operation.effect.skillNodeId)) {
|
|
103
|
+
fail('SKILL_DENIED', 'skill fuera de la intersección efectiva');
|
|
104
|
+
}
|
|
105
|
+
if (operation.effect.kind !== 'delegation') return;
|
|
106
|
+
const capabilities = new Set(view.context.allowedCapabilities);
|
|
107
|
+
const target = liveBundle.policies.find(({ nodeId }) => (
|
|
108
|
+
nodeId === operation.effect.targetAgentNodeId
|
|
109
|
+
));
|
|
110
|
+
if (!target || target.disposition !== 'allow'
|
|
111
|
+
|| operation.effect.capabilities.some((item) => !capabilities.has(item))) {
|
|
112
|
+
fail('DELEGATION_DENIED', 'delegación fuera de policy');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function mapPolicyError(error) {
|
|
117
|
+
const mappings = {
|
|
118
|
+
CAPABILITY_DENIED: 'CAPABILITY_DENIED',
|
|
119
|
+
CONTEXT_BINDING_INVALID: 'CONTEXT_MISMATCH',
|
|
120
|
+
CONTEXT_EXPIRED: 'CONTEXT_INVALID',
|
|
121
|
+
CONTEXT_INVALID: 'CONTEXT_INVALID',
|
|
122
|
+
DELEGATION_DENIED: 'DELEGATION_DENIED',
|
|
123
|
+
GATE_G1_EXPIRED: 'GATE_NOT_SATISFIED',
|
|
124
|
+
GATE_NOT_SATISFIED: 'GATE_NOT_SATISFIED',
|
|
125
|
+
GATE_PHASE_UNKNOWN: 'GATE_PHASE_UNKNOWN',
|
|
126
|
+
GATE_TASK_UNKNOWN: 'GATE_NOT_SATISFIED',
|
|
127
|
+
GATE_VERSION_MISMATCH: 'GATE_VERSION_MISMATCH',
|
|
128
|
+
PATH_OUTSIDE_WORKSPACE: 'PATH_OUTSIDE_WORKSPACE',
|
|
129
|
+
PATH_UNSAFE: 'PATH_UNSAFE',
|
|
130
|
+
PLAN_DRIFT: 'GATE_NOT_SATISFIED',
|
|
131
|
+
SHELL_OPAQUE: 'SHELL_OPAQUE',
|
|
132
|
+
SKILL_DENIED: 'SKILL_DENIED',
|
|
133
|
+
};
|
|
134
|
+
return mappings[error?.codigo] || null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function baseDecision(authority, operation, context, reasonCode) {
|
|
138
|
+
return {
|
|
139
|
+
kind: 'policy-enforcement-decision', schemaVersion: '1.0.0',
|
|
140
|
+
outcome: 'deny', reasonCodes: [reasonCode],
|
|
141
|
+
operationDigest: operation?.operationDigest || null,
|
|
142
|
+
contextDigest: context?.contextDigest || null,
|
|
143
|
+
gateAuthorizationDigest: null, approvalDigest: null, grantDigest: null,
|
|
144
|
+
evidenceDigest: null, timestamp: authority.observedAt,
|
|
145
|
+
expiresAt: authority.observedAt,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function finalizeDecision(base) {
|
|
150
|
+
const digest = sha256(canonicalizarIJson(base));
|
|
151
|
+
return freezeDeep({ ...base, decisionId: `decision:${digest}`, decisionDigest: digest });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function approvalMatchesGate(components, approval, operation, gate) {
|
|
155
|
+
if (!components.grantIssuer.isVerifiedApproval(approval)) return false;
|
|
156
|
+
return approval.schemaVersion === '1.2.0'
|
|
157
|
+
&& approval.phaseId === operation.phaseId
|
|
158
|
+
&& approval.taskId === operation.taskId
|
|
159
|
+
&& approval.planDigest === gate.planDigest
|
|
160
|
+
&& approval.g1ApprovalDigest === gate.g1ApprovalDigest;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function createAllowedBase(authority, operation, view, gate, approval) {
|
|
164
|
+
const expiresAt = [
|
|
165
|
+
view.context.expiresAt, gate.g1ExpiresAt, approval?.expiresAt,
|
|
166
|
+
].filter(Boolean).sort()[0];
|
|
167
|
+
const evidence = {
|
|
168
|
+
contextDigest: view.context.contextDigest,
|
|
169
|
+
gateAuthorizationDigest: gate.gateAuthorizationDigest,
|
|
170
|
+
operationDigest: operation.operationDigest,
|
|
171
|
+
};
|
|
172
|
+
return {
|
|
173
|
+
...baseDecision(authority, operation, view.context, 'ALLOWED'),
|
|
174
|
+
outcome: 'allow',
|
|
175
|
+
reasonCodes: [approval ? 'APPROVAL_ACCEPTED' : 'ALLOWED'],
|
|
176
|
+
gateAuthorizationDigest: gate.gateAuthorizationDigest,
|
|
177
|
+
approvalDigest: approval?.approvalDigest || null,
|
|
178
|
+
evidenceDigest: sha256(canonicalizarIJson(evidence)), expiresAt,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function decisionEntry(state, decision, approvalClaim, grant) {
|
|
183
|
+
return {
|
|
184
|
+
expectedSequence: state.sequence, expectedHeadHash: state.headHash,
|
|
185
|
+
eventType: 'authorization.committed',
|
|
186
|
+
payload: {
|
|
187
|
+
schemaVersion: '2.0.0', approvalClaim,
|
|
188
|
+
decision: structuredClone(decision), grant: grant ? structuredClone(grant) : null,
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function deniedEvaluation(authority, operation, context, reason) {
|
|
194
|
+
const decision = finalizeDecision(baseDecision(authority, operation, context, reason));
|
|
195
|
+
return { approvalClaim: null, decision, grant: null };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function evaluatePrerequisites(components, state, authority, operation, context) {
|
|
199
|
+
let view;
|
|
200
|
+
try {
|
|
201
|
+
view = components.contextReader.read(context, authority);
|
|
202
|
+
if (view.principal.operationDigest !== operation.operationDigest
|
|
203
|
+
|| view.context.phaseId !== operation.phaseId) {
|
|
204
|
+
fail('CONTEXT_BINDING_INVALID', 'contexto ligado a otra operación o fase');
|
|
205
|
+
}
|
|
206
|
+
const liveBundle = components.compileBundle();
|
|
207
|
+
if (!policyMatchesContext(view, liveBundle)) fail('POLICY_DRIFT', 'policy cambió');
|
|
208
|
+
assertWorkspaceScope(operation, components.workspaceRoot);
|
|
209
|
+
assertDirectProcess(operation.effect);
|
|
210
|
+
const gate = components.gateReader.read(state, authority, operation);
|
|
211
|
+
assertCapability(view, liveBundle, operation);
|
|
212
|
+
return { gate, view };
|
|
213
|
+
} catch (error) {
|
|
214
|
+
const reason = error?.codigo === 'POLICY_DRIFT' ? 'POLICY_DRIFT' : mapPolicyError(error);
|
|
215
|
+
if (!reason) throw error;
|
|
216
|
+
return { denied: deniedEvaluation(
|
|
217
|
+
authority, operation, view?.context || null, reason
|
|
218
|
+
) };
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function issueGrant(components, state, authority, operation, view, approval) {
|
|
223
|
+
try {
|
|
224
|
+
return { issued: components.grantIssuer.issueApprovalGrant(state, authority, {
|
|
225
|
+
approval, principal: view.principal, operation,
|
|
226
|
+
}) };
|
|
227
|
+
} catch (error) {
|
|
228
|
+
if (error?.codigo !== 'APPROVAL_ALREADY_USED'
|
|
229
|
+
&& !EXPECTED_APPROVAL_ERRORS.has(error?.codigo)) throw error;
|
|
230
|
+
const reason = error.codigo === 'APPROVAL_ALREADY_USED'
|
|
231
|
+
? 'APPROVAL_USED' : 'APPROVAL_INVALID';
|
|
232
|
+
return { denied: deniedEvaluation(authority, operation, view.context, reason) };
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function issueDirectGrant(components, state, authority, operation, prerequisites) {
|
|
237
|
+
const expiresAt = [
|
|
238
|
+
prerequisites.view.context.expiresAt, prerequisites.gate.g1ExpiresAt,
|
|
239
|
+
].sort()[0];
|
|
240
|
+
return components.grantIssuer.issuePolicyGrant(state, authority, {
|
|
241
|
+
expiresAt, gate: prerequisites.gate,
|
|
242
|
+
principal: prerequisites.view.principal, operation,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function evaluateApproval(components, state, authority, operation, approval, prerequisites) {
|
|
247
|
+
const { gate, view } = prerequisites;
|
|
248
|
+
if (APPROVAL_CAPABILITIES.has(operation.capability) && !approval) {
|
|
249
|
+
const base = baseDecision(authority, operation, view.context, 'APPROVAL_REQUIRED');
|
|
250
|
+
return { decision: finalizeDecision({
|
|
251
|
+
...base, outcome: 'require_approval',
|
|
252
|
+
gateAuthorizationDigest: gate.gateAuthorizationDigest,
|
|
253
|
+
}), grant: null, approvalClaim: null };
|
|
254
|
+
}
|
|
255
|
+
if (approval && !approvalMatchesGate(components, approval, operation, gate)) {
|
|
256
|
+
return deniedEvaluation(authority, operation, view.context, 'APPROVAL_STALE');
|
|
257
|
+
}
|
|
258
|
+
const result = approval
|
|
259
|
+
? issueGrant(components, state, authority, operation, view, approval)
|
|
260
|
+
: { issued: { approvalClaim: null, grant: issueDirectGrant(
|
|
261
|
+
components, state, authority, operation, prerequisites
|
|
262
|
+
) } };
|
|
263
|
+
if (result.denied) return result.denied;
|
|
264
|
+
const { issued } = result;
|
|
265
|
+
hitFault('after-approval-claim-before-decision');
|
|
266
|
+
const allowed = createAllowedBase(authority, operation, view, gate, approval);
|
|
267
|
+
const grantDigest = issued.grant.grantDigest;
|
|
268
|
+
const decision = finalizeDecision({ ...allowed, grantDigest });
|
|
269
|
+
hitFault('after-decision-before-grant');
|
|
270
|
+
return {
|
|
271
|
+
decision,
|
|
272
|
+
grant: issued.grant,
|
|
273
|
+
approvalClaim: issued.approvalClaim,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function evaluateLocked(components, state, authority, operation, context, approval) {
|
|
278
|
+
if (!components.isVerifiedOperation(operation)) {
|
|
279
|
+
return deniedEvaluation(authority, null, null, 'OPERATION_INVALID');
|
|
280
|
+
}
|
|
281
|
+
if (operation.schemaVersion !== '1.1.0') {
|
|
282
|
+
return deniedEvaluation(authority, operation, null, 'OPERATION_SCOPE_UNVERIFIABLE');
|
|
283
|
+
}
|
|
284
|
+
const prerequisites = evaluatePrerequisites(
|
|
285
|
+
components, state, authority, operation, context
|
|
286
|
+
);
|
|
287
|
+
if (prerequisites.denied) return prerequisites.denied;
|
|
288
|
+
return evaluateApproval(
|
|
289
|
+
components, state, authority, operation, approval, prerequisites
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function createReceipt(decision, grant, appendReceipt, decisions) {
|
|
294
|
+
const receipt = freezeDeep({
|
|
295
|
+
...structuredClone(decision), authorizationGrant: grant,
|
|
296
|
+
sequence: appendReceipt.sequence, headHash: appendReceipt.headHash,
|
|
297
|
+
});
|
|
298
|
+
decisions.add(receipt);
|
|
299
|
+
return receipt;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function authorize(components, decisions, operation, context, options) {
|
|
303
|
+
const { approval } = safeOptions(options);
|
|
304
|
+
let evaluated;
|
|
305
|
+
let appendReceipt;
|
|
306
|
+
try {
|
|
307
|
+
appendReceipt = components.writer.transact((state, authority) => {
|
|
308
|
+
evaluated = evaluateLocked(
|
|
309
|
+
components, state, authority, operation, context, approval
|
|
310
|
+
);
|
|
311
|
+
return decisionEntry(
|
|
312
|
+
state, evaluated.decision, evaluated.approvalClaim, evaluated.grant
|
|
313
|
+
);
|
|
314
|
+
});
|
|
315
|
+
} catch (cause) {
|
|
316
|
+
const error = new Error('autorización no pudo persistirse de forma atómica', { cause });
|
|
317
|
+
error.codigo = 'POLICY_AUTHORIZATION_FAILED';
|
|
318
|
+
throw error;
|
|
319
|
+
}
|
|
320
|
+
return createReceipt(evaluated.decision, evaluated.grant, appendReceipt, decisions);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function createPolicyBroker(components) {
|
|
324
|
+
plainObject(components, 'POLICY_BROKER_INVALID', 'componentes del broker');
|
|
325
|
+
exactKeys(components, [
|
|
326
|
+
'compileBundle', 'contextReader', 'gateReader', 'grantIssuer',
|
|
327
|
+
'isVerifiedOperation', 'workspaceRoot', 'writer',
|
|
328
|
+
], 'POLICY_BROKER_INVALID', 'componentes del broker');
|
|
329
|
+
const decisions = new WeakSet();
|
|
330
|
+
return Object.freeze({
|
|
331
|
+
authorize: (operation, context, options) => (
|
|
332
|
+
authorize(components, decisions, operation, context, options)
|
|
333
|
+
),
|
|
334
|
+
isPolicyDecision: (value) => decisions.has(value),
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
module.exports = { createPolicyBroker };
|