@saulwade/swl-ses 2.6.1 → 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 +14 -2
- package/README.md +65 -18
- package/agentes/_intent-spec.md +73 -73
- package/agentes/_propose-step.md +90 -90
- package/bin/swl-ses.js +10 -0
- package/comandos/swl/brainstorm.md +1 -0
- package/comandos/swl/briefing.md +119 -119
- package/comandos/swl/contribuir.md +233 -233
- package/comandos/swl/deuda-codigo.md +97 -97
- package/comandos/swl/mcp-status.md +1 -0
- package/gateway/lib/event-channel.js +191 -191
- package/habilidades/agent-deep-links/SKILL.md +148 -148
- package/habilidades/backend-async-postgres-testing/SKILL.md +216 -216
- 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/checklist-seguridad/recursos/stride-cobertura.md +60 -60
- package/habilidades/ci-cd-pipelines/SKILL.md +5 -1
- package/habilidades/css-moderno/SKILL.md +7 -1
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
- package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +57 -57
- package/habilidades/extractor-de-aprendizajes/SKILL.md +5 -1
- package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
- package/habilidades/harness-claude-code/SKILL.md +3 -2
- 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/prevencion-sobreingenieria/recursos/EXAMPLES.md +580 -580
- package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -166
- package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -85
- 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-intent-engineering/SKILL.md +269 -269
- package/habilidades/proceso-modular-split/SKILL.md +256 -256
- 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/recursos/gherkin-bdd.md +111 -111
- package/hooks/calidad-pre-commit.js +159 -10
- package/hooks/ciclo-evolucion-subagente.js +26 -26
- package/hooks/ciclo-evolucion.js +26 -26
- package/hooks/contexto-subagente.js +68 -68
- package/hooks/lib/auto-consolidator.js +335 -335
- 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/notificacion-formato.js +45 -11
- package/hooks/lib/provenance-tracker.js +191 -191
- package/hooks/lib/raiz-proyecto.js +35 -4
- package/hooks/lib/resource-quota.js +122 -122
- package/hooks/lib/retry-jitter.js +165 -165
- package/hooks/lib/security-net.js +201 -201
- 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/text-similarity.js +241 -241
- package/hooks/lib/toon-compressor.js +245 -245
- package/hooks/notificacion-telegram.js +5 -11
- package/hooks/session-briefing.js +12 -4
- package/instintos/autonomia.yaml +27 -27
- package/instintos/prompt-appendices.yaml +57 -57
- package/llms.txt +1 -1
- package/manifiestos/agent-output-schemas.json +57 -57
- package/manifiestos/canonical-hashes.json +662 -0
- package/manifiestos/harness-ir.json +47536 -0
- package/manifiestos/hooks-config.json +469 -469
- package/manifiestos/invariantes-criticos.json +30 -30
- 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 +43 -43
- package/package.json +2 -2
- 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 +2 -2
- 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/bootstrap-instintos.js +3 -0
- package/scripts/cli/aprobar-plan.js +73 -73
- package/scripts/cli/briefing.js +23 -23
- package/scripts/cli/ciclo-evolucion.js +26 -26
- 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/liberar-fase.js +42 -42
- package/scripts/cli/mark-evolved.js +56 -56
- 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/propose-step.js +29 -29
- 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 -36
- 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 +26 -7
- 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/yaml-instintos.js +56 -0
- 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/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 +45 -2
- 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/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/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 +12 -7
- 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
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/** Contratos opacos de operación y bootstrap del kernel W2. */
|
|
4
|
+
|
|
5
|
+
const crypto = require('node:crypto');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
const util = require('node:util');
|
|
8
|
+
|
|
9
|
+
const POLICY_SCHEMA = require('../../schemas/policy-bundle.schema.json');
|
|
10
|
+
const {
|
|
11
|
+
canonicalizarIJson,
|
|
12
|
+
esEnvelopeVerificado,
|
|
13
|
+
parsearIJson,
|
|
14
|
+
validarTimestampIso,
|
|
15
|
+
} = require('./signed-envelope');
|
|
16
|
+
const SCHEMA_VERSION = '1.0.0';
|
|
17
|
+
const SHA256 = /^[a-f0-9]{64}$/u;
|
|
18
|
+
const IDENTIFICADOR = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
19
|
+
const DNS_LABEL = '[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?';
|
|
20
|
+
const ASCII_HOST = new RegExp(`^(?:${DNS_LABEL})(?:\\.(?:${DNS_LABEL}))*$`, 'u');
|
|
21
|
+
const CAPABILITIES = new Set(POLICY_SCHEMA.$defs.capability.enum);
|
|
22
|
+
const EFFECT_KINDS = new Set(['access', 'delegate', 'execute', 'invoke', 'mutate', 'read']);
|
|
23
|
+
const OPERATION_KEYS = [
|
|
24
|
+
'schemaVersion', 'operationId', 'capability', 'effectKind', 'payloadDigest', 'scope',
|
|
25
|
+
'cwd', 'fsmVersion', 'timestamp',
|
|
26
|
+
];
|
|
27
|
+
const OPERATION_KEYS_V11 = [...OPERATION_KEYS, 'phaseId', 'taskId', 'effect'];
|
|
28
|
+
const EFFECT_KINDS_CANONICAL = new Set([
|
|
29
|
+
'filesystem', 'process', 'network', 'memory', 'delegation', 'skill',
|
|
30
|
+
]);
|
|
31
|
+
const UNSAFE_TEXT = /[\u0000-\u001F\u007F\u001B\u200B-\u200F\u202A-\u202E\u2060-\u206F]/u;
|
|
32
|
+
const BOOTSTRAP_KEYS = [
|
|
33
|
+
'kind', 'schemaVersion', 'trustEpoch', 'trustDigest', 'providers', 'trustPath',
|
|
34
|
+
'signerPath', 'anchorPath', 'issuedAt', 'expiresAt', 'nonce',
|
|
35
|
+
];
|
|
36
|
+
const PROVIDERS = Object.freeze({
|
|
37
|
+
clock: 'builtin:clock-v1',
|
|
38
|
+
randomSource: 'builtin:random-source-v1',
|
|
39
|
+
processInspector: 'builtin:process-inspector-v1',
|
|
40
|
+
integrityProvider: 'builtin:integrity-provider-v1',
|
|
41
|
+
stateAnchorProvider: 'builtin:state-anchor-provider-v1',
|
|
42
|
+
});
|
|
43
|
+
const VERIFIED_OPERATIONS = new WeakSet();
|
|
44
|
+
const VERIFIED_BOOTSTRAPS = new WeakSet();
|
|
45
|
+
const BOOTSTRAP_METADATA = new WeakMap();
|
|
46
|
+
const KERNEL_DEPENDENCIES = new WeakSet();
|
|
47
|
+
|
|
48
|
+
function crearError(codigo, mensaje) {
|
|
49
|
+
const error = new Error(mensaje);
|
|
50
|
+
error.codigo = codigo;
|
|
51
|
+
return error;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function fallar(codigo, mensaje) {
|
|
55
|
+
throw crearError(codigo, mensaje);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function validarObjeto(valor, etiqueta) {
|
|
59
|
+
if (!valor || typeof valor !== 'object' || Array.isArray(valor) || util.types.isProxy(valor)) {
|
|
60
|
+
fallar('CONTRACT_INVALID', `${etiqueta} inválido`);
|
|
61
|
+
}
|
|
62
|
+
const proto = Object.getPrototypeOf(valor);
|
|
63
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
64
|
+
fallar('CONTRACT_INVALID', `${etiqueta} inválido`);
|
|
65
|
+
}
|
|
66
|
+
if (Object.getOwnPropertySymbols(valor).length > 0) {
|
|
67
|
+
fallar('CONTRACT_INVALID', `${etiqueta} inválido`);
|
|
68
|
+
}
|
|
69
|
+
const descriptores = Object.values(Object.getOwnPropertyDescriptors(valor));
|
|
70
|
+
if (descriptores.some((item) => !item.enumerable || !('value' in item))) {
|
|
71
|
+
fallar('CONTRACT_INVALID', `${etiqueta} inválido`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function validarClaves(valor, esperadas, etiqueta) {
|
|
76
|
+
const actuales = Object.keys(valor).sort();
|
|
77
|
+
const objetivo = [...esperadas].sort();
|
|
78
|
+
if (JSON.stringify(actuales) !== JSON.stringify(objetivo)) {
|
|
79
|
+
fallar('CONTRACT_INVALID', `${etiqueta} inválida`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function validarIdentificador(valor, etiqueta) {
|
|
84
|
+
if (typeof valor !== 'string' || !IDENTIFICADOR.test(valor)) {
|
|
85
|
+
fallar('CONTRACT_INVALID', `${etiqueta} inválido`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function congelarProfundo(valor) {
|
|
90
|
+
if (!valor || typeof valor !== 'object' || Object.isFrozen(valor)) return valor;
|
|
91
|
+
Object.values(valor).forEach(congelarProfundo);
|
|
92
|
+
return Object.freeze(valor);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function validarScope(scope) {
|
|
96
|
+
validarObjeto(scope, 'scope');
|
|
97
|
+
validarClaves(scope, ['digest'], 'scope');
|
|
98
|
+
if (!SHA256.test(scope.digest)) fallar('CONTRACT_INVALID', 'operación con scope inválido');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function validarTextoCanonico(valor, etiqueta, maximo = 4096, permitirVacio = false) {
|
|
102
|
+
if (typeof valor !== 'string' || (!permitirVacio && valor.length === 0)
|
|
103
|
+
|| valor.length > maximo
|
|
104
|
+
|| valor.normalize('NFKC') !== valor || UNSAFE_TEXT.test(valor)) {
|
|
105
|
+
fallar('CONTRACT_INVALID', `${etiqueta} inválido`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function validarSegmentosPosix(resto) {
|
|
110
|
+
const segmentos = resto.split('/');
|
|
111
|
+
if (segmentos.some((item) => !item || item === '.' || item === '..')) {
|
|
112
|
+
fallar('CONTRACT_INVALID', 'path canónico inválido');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function validarSegmentosWindows(resto) {
|
|
117
|
+
const segmentos = resto.split('\\');
|
|
118
|
+
if (segmentos.some((item) => !item || item === '.' || item === '..'
|
|
119
|
+
|| item.includes(':') || /[. ]$/u.test(item) || /~\d+/u.test(item)
|
|
120
|
+
|| /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(item))) {
|
|
121
|
+
fallar('CONTRACT_INVALID', 'path canónico inválido');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function validarPathCanonico(style, absolutePath) {
|
|
126
|
+
validarTextoCanonico(absolutePath, 'path');
|
|
127
|
+
if (style === 'posix') {
|
|
128
|
+
if (!absolutePath.startsWith('/') || absolutePath.startsWith('//')
|
|
129
|
+
|| absolutePath.includes('\\')) fallar('CONTRACT_INVALID', 'path POSIX inválido');
|
|
130
|
+
validarSegmentosPosix(absolutePath.slice(1));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (style !== 'win32' || !/^[A-Z]:\\/u.test(absolutePath)
|
|
134
|
+
|| /^[A-Z]:\\[\\?.]/u.test(absolutePath) || absolutePath.includes('/')) {
|
|
135
|
+
fallar('CONTRACT_INVALID', 'path Windows inválido');
|
|
136
|
+
}
|
|
137
|
+
validarSegmentosWindows(absolutePath.slice(3));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function validarCwdV11(effect, cwd) {
|
|
141
|
+
const style = ['filesystem', 'process'].includes(effect.kind)
|
|
142
|
+
? effect.pathStyle
|
|
143
|
+
: (cwd.startsWith('/') ? 'posix' : 'win32');
|
|
144
|
+
validarPathCanonico(style, cwd);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function validarFilesystemEffect(effect) {
|
|
148
|
+
validarClaves(effect, ['kind', 'pathStyle', 'absolutePath', 'access'], 'effect');
|
|
149
|
+
if (!['posix', 'win32'].includes(effect.pathStyle)
|
|
150
|
+
|| !['read', 'mutate', 'delete'].includes(effect.access)) {
|
|
151
|
+
fallar('CONTRACT_INVALID', 'effect filesystem inválido');
|
|
152
|
+
}
|
|
153
|
+
validarPathCanonico(effect.pathStyle, effect.absolutePath);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function validarProcessEffect(effect) {
|
|
157
|
+
validarClaves(effect, ['kind', 'mode', 'pathStyle', 'executablePath', 'argv'], 'effect');
|
|
158
|
+
if (effect.mode !== 'direct' || !['posix', 'win32'].includes(effect.pathStyle)
|
|
159
|
+
|| !Array.isArray(effect.argv) || effect.argv.length > 256) {
|
|
160
|
+
fallar('CONTRACT_INVALID', 'effect process inválido');
|
|
161
|
+
}
|
|
162
|
+
validarPathCanonico(effect.pathStyle, effect.executablePath);
|
|
163
|
+
effect.argv.forEach((item) => validarTextoCanonico(item, 'argv', 8192, true));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function validarNetworkEffect(effect) {
|
|
167
|
+
validarClaves(effect, ['kind', 'scheme', 'asciiHost', 'port'], 'effect');
|
|
168
|
+
if (!['http', 'https'].includes(effect.scheme)
|
|
169
|
+
|| typeof effect.asciiHost !== 'string'
|
|
170
|
+
|| !ASCII_HOST.test(effect.asciiHost)
|
|
171
|
+
|| !Number.isInteger(effect.port) || effect.port < 1 || effect.port > 65535) {
|
|
172
|
+
fallar('CONTRACT_INVALID', 'effect network inválido');
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function validarMemoryEffect(effect) {
|
|
177
|
+
validarClaves(effect, ['kind', 'namespace', 'resourceId', 'access'], 'effect');
|
|
178
|
+
validarIdentificador(effect.namespace, 'namespace');
|
|
179
|
+
validarIdentificador(effect.resourceId, 'resourceId');
|
|
180
|
+
if (!['read', 'write'].includes(effect.access)) {
|
|
181
|
+
fallar('CONTRACT_INVALID', 'effect memory inválido');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function validarDelegationEffect(effect) {
|
|
186
|
+
validarClaves(effect, ['kind', 'targetAgentNodeId', 'capabilities'], 'effect');
|
|
187
|
+
if (!/^agent:[a-f0-9]{64}$/u.test(effect.targetAgentNodeId)
|
|
188
|
+
|| !Array.isArray(effect.capabilities) || effect.capabilities.length === 0
|
|
189
|
+
|| effect.capabilities.some((item) => !CAPABILITIES.has(item))
|
|
190
|
+
|| effect.capabilities.some((item, index) => (
|
|
191
|
+
index > 0 && effect.capabilities[index - 1] >= item
|
|
192
|
+
))) {
|
|
193
|
+
fallar('CONTRACT_INVALID', 'effect delegation inválido');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function validarSkillEffect(effect) {
|
|
198
|
+
validarClaves(effect, ['kind', 'skillNodeId'], 'effect');
|
|
199
|
+
if (!/^skill:[a-f0-9]{64}$/u.test(effect.skillNodeId)) {
|
|
200
|
+
fallar('CONTRACT_INVALID', 'effect skill inválido');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function validarEffectShape(effect) {
|
|
205
|
+
validarObjeto(effect, 'effect');
|
|
206
|
+
validarTextoCanonico(effect.kind, 'effect kind', 32);
|
|
207
|
+
if (!EFFECT_KINDS_CANONICAL.has(effect.kind)) {
|
|
208
|
+
fallar('CONTRACT_INVALID', 'effect desconocido');
|
|
209
|
+
}
|
|
210
|
+
if (effect.kind === 'filesystem') validarFilesystemEffect(effect);
|
|
211
|
+
else if (effect.kind === 'process') validarProcessEffect(effect);
|
|
212
|
+
else if (effect.kind === 'network') validarNetworkEffect(effect);
|
|
213
|
+
else if (effect.kind === 'memory') validarMemoryEffect(effect);
|
|
214
|
+
else if (effect.kind === 'delegation') validarDelegationEffect(effect);
|
|
215
|
+
else validarSkillEffect(effect);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function validarEffectBinding(valor) {
|
|
219
|
+
const effect = valor.effect;
|
|
220
|
+
const expected = {
|
|
221
|
+
filesystem: {
|
|
222
|
+
capability: effect.access === 'read' ? 'filesystem.read' : 'filesystem.mutate',
|
|
223
|
+
effectKind: effect.access === 'read' ? 'read' : 'mutate',
|
|
224
|
+
},
|
|
225
|
+
process: { capability: 'shell.exec', effectKind: 'execute' },
|
|
226
|
+
network: { capability: 'network.access', effectKind: 'access' },
|
|
227
|
+
memory: {
|
|
228
|
+
capability: effect.access === 'read' ? 'memory.read' : 'memory.write',
|
|
229
|
+
effectKind: effect.access === 'read' ? 'read' : 'mutate',
|
|
230
|
+
},
|
|
231
|
+
delegation: { capability: 'delegate', effectKind: 'delegate' },
|
|
232
|
+
skill: { capability: 'skill.invoke', effectKind: 'invoke' },
|
|
233
|
+
}[effect.kind];
|
|
234
|
+
if (valor.capability !== expected.capability || valor.effectKind !== expected.effectKind) {
|
|
235
|
+
fallar('CONTRACT_INVALID', 'binding de effect inválido');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function validarOperationV11(valor) {
|
|
240
|
+
validarEffectShape(valor.effect);
|
|
241
|
+
validarCwdV11(valor.effect, valor.cwd);
|
|
242
|
+
validarEffectBinding(valor);
|
|
243
|
+
const digest = crypto.createHash('sha256')
|
|
244
|
+
.update(canonicalizarIJson(valor.effect), 'utf8').digest('hex');
|
|
245
|
+
if (digest !== valor.scope.digest) fallar('CONTRACT_INVALID', 'preimagen scope inválida');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function validarOperacion(valor) {
|
|
249
|
+
validarObjeto(valor, 'operación');
|
|
250
|
+
const esV11 = valor.schemaVersion === '1.1.0';
|
|
251
|
+
validarClaves(valor, esV11 ? OPERATION_KEYS_V11 : OPERATION_KEYS, 'operación');
|
|
252
|
+
if (![SCHEMA_VERSION, '1.1.0'].includes(valor.schemaVersion)) {
|
|
253
|
+
fallar('CONTRACT_INVALID', 'operación futura');
|
|
254
|
+
}
|
|
255
|
+
validarIdentificador(valor.operationId, 'operationId');
|
|
256
|
+
if (!CAPABILITIES.has(valor.capability)) {
|
|
257
|
+
fallar('CONTRACT_INVALID', 'operación capability inválida');
|
|
258
|
+
}
|
|
259
|
+
if (!EFFECT_KINDS.has(valor.effectKind)) fallar('CONTRACT_INVALID', 'operación effect inválido');
|
|
260
|
+
if (!SHA256.test(valor.payloadDigest)) fallar('CONTRACT_INVALID', 'operación digest inválido');
|
|
261
|
+
validarScope(valor.scope);
|
|
262
|
+
if (!esV11 && (typeof valor.cwd !== 'string'
|
|
263
|
+
|| valor.cwd.length === 0 || valor.cwd.length > 4096)) {
|
|
264
|
+
fallar('CONTRACT_INVALID', 'operación cwd inválido');
|
|
265
|
+
}
|
|
266
|
+
if (!Number.isInteger(valor.fsmVersion) || valor.fsmVersion < 0) {
|
|
267
|
+
fallar('CONTRACT_INVALID', 'operación FSM inválida');
|
|
268
|
+
}
|
|
269
|
+
validarTimestampIso(valor.timestamp, 'operación timestamp');
|
|
270
|
+
if (esV11) {
|
|
271
|
+
validarIdentificador(valor.phaseId, 'phaseId');
|
|
272
|
+
if (!/^T-[0-9]{2}$/u.test(valor.taskId)) fallar('CONTRACT_INVALID', 'taskId inválido');
|
|
273
|
+
validarOperationV11(valor);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function verificarOperacionInterna(rawBytes) {
|
|
278
|
+
let valor;
|
|
279
|
+
try {
|
|
280
|
+
valor = parsearIJson(rawBytes);
|
|
281
|
+
validarOperacion(valor);
|
|
282
|
+
} catch (error) {
|
|
283
|
+
if (error.codigo === 'RAW_BYTES_INVALID') {
|
|
284
|
+
throw crearError('OPERATION_INVALID', 'raw bytes inválidos');
|
|
285
|
+
}
|
|
286
|
+
if (error.codigo === 'IJSON_DUPLICATE') {
|
|
287
|
+
throw crearError('OPERATION_INVALID', 'operación con clave duplicada');
|
|
288
|
+
}
|
|
289
|
+
throw crearError('OPERATION_INVALID', 'operación inválida');
|
|
290
|
+
}
|
|
291
|
+
return valor;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function verifyOperation(rawBytes) {
|
|
295
|
+
const valor = verificarOperacionInterna(rawBytes);
|
|
296
|
+
const operationDigest = crypto.createHash('sha256')
|
|
297
|
+
.update(canonicalizarIJson(valor), 'utf8')
|
|
298
|
+
.digest('hex');
|
|
299
|
+
congelarProfundo(valor);
|
|
300
|
+
const operation = Object.freeze({ ...valor, operationDigest });
|
|
301
|
+
VERIFIED_OPERATIONS.add(operation);
|
|
302
|
+
return operation;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function isVerifiedOperation(valor) {
|
|
306
|
+
return VERIFIED_OPERATIONS.has(valor);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function isKernelDependencies(valor) {
|
|
310
|
+
return KERNEL_DEPENDENCIES.has(valor);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function validarOpcionesBootstrap(opciones) {
|
|
314
|
+
try {
|
|
315
|
+
validarObjeto(opciones, 'opciones bootstrap');
|
|
316
|
+
validarClaves(opciones, ['workspaceRoot', 'now'], 'opciones bootstrap');
|
|
317
|
+
} catch {
|
|
318
|
+
fallar('BOOTSTRAP_INVALID', 'opciones bootstrap inválidas');
|
|
319
|
+
}
|
|
320
|
+
if (!esRutaLocalAbsoluta(opciones.workspaceRoot)) {
|
|
321
|
+
fallar('BOOTSTRAP_INVALID', 'workspace bootstrap inválido');
|
|
322
|
+
}
|
|
323
|
+
validarTimestampIso(opciones.now, 'bootstrap now');
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function validarProvider(nombre, valor) {
|
|
327
|
+
validarObjeto(valor, 'provider bootstrap');
|
|
328
|
+
validarClaves(valor, ['implementation', 'fingerprint'], 'provider bootstrap');
|
|
329
|
+
if (valor.implementation !== PROVIDERS[nombre] || !SHA256.test(valor.fingerprint)) {
|
|
330
|
+
fallar('BOOTSTRAP_INVALID', 'provider bootstrap inválido');
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function validarProviders(providers) {
|
|
335
|
+
validarObjeto(providers, 'providers bootstrap');
|
|
336
|
+
validarClaves(providers, Object.keys(PROVIDERS), 'providers bootstrap');
|
|
337
|
+
for (const nombre of Object.keys(PROVIDERS)) validarProvider(nombre, providers[nombre]);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function esRutaInterna(ruta, workspaceRoot) {
|
|
341
|
+
const workspace = path.resolve(workspaceRoot);
|
|
342
|
+
const destino = path.resolve(ruta);
|
|
343
|
+
const relativa = path.relative(workspace, destino);
|
|
344
|
+
return relativa === '' || (!relativa.startsWith('..') && !path.isAbsolute(relativa));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function esRutaLocalAbsoluta(ruta) {
|
|
348
|
+
if (typeof ruta !== 'string' || !path.isAbsolute(ruta) || ruta.includes('\0')) return false;
|
|
349
|
+
if (/^[\\/]{2}|^[A-Za-z]:[^\\/]/u.test(ruta)) return false;
|
|
350
|
+
if (ruta.normalize('NFKC') !== ruta) return false;
|
|
351
|
+
if (/[\u200B-\u200F\u202A-\u202E\u2060-\u206F]/u.test(ruta)) return false;
|
|
352
|
+
const resto = ruta.slice(path.parse(ruta).root.length);
|
|
353
|
+
if (resto.includes(':')) return false;
|
|
354
|
+
return resto.split(/[\\/]/u).every((segmento) => {
|
|
355
|
+
if (!segmento || /[. ]$/u.test(segmento) || /~\d+/u.test(segmento)) return false;
|
|
356
|
+
return !/^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(segmento);
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function validarRutaExterna(ruta, workspaceRoot) {
|
|
361
|
+
if (!esRutaLocalAbsoluta(ruta) || esRutaInterna(ruta, workspaceRoot)) {
|
|
362
|
+
fallar('BOOTSTRAP_INVALID', 'path bootstrap inválido');
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function validarBootstrapClaims(claims, envelope, opciones) {
|
|
367
|
+
validarObjeto(claims, 'bootstrap claims');
|
|
368
|
+
validarClaves(claims, BOOTSTRAP_KEYS, 'bootstrap claims');
|
|
369
|
+
if (claims.kind !== 'kernel-bootstrap' || claims.schemaVersion !== SCHEMA_VERSION) {
|
|
370
|
+
fallar('BOOTSTRAP_INVALID', 'bootstrap futuro o inválido');
|
|
371
|
+
}
|
|
372
|
+
if (claims.trustEpoch !== envelope.trustEpoch || claims.trustDigest !== envelope.trustDigest) {
|
|
373
|
+
fallar('BOOTSTRAP_INVALID', 'bootstrap trust binding inválido');
|
|
374
|
+
}
|
|
375
|
+
validarProviders(claims.providers);
|
|
376
|
+
for (const campo of ['trustPath', 'signerPath', 'anchorPath']) {
|
|
377
|
+
validarRutaExterna(claims[campo], opciones.workspaceRoot);
|
|
378
|
+
}
|
|
379
|
+
validarTimestampIso(claims.issuedAt, 'bootstrap issuedAt');
|
|
380
|
+
validarTimestampIso(claims.expiresAt, 'bootstrap expiresAt');
|
|
381
|
+
validarIdentificador(claims.nonce, 'bootstrap nonce');
|
|
382
|
+
if (opciones.now < claims.issuedAt || opciones.now > claims.expiresAt) {
|
|
383
|
+
fallar('BOOTSTRAP_INVALID', 'bootstrap fuera de vigencia');
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function validarEnvelopeBootstrap(envelope) {
|
|
388
|
+
if (
|
|
389
|
+
!esEnvelopeVerificado(envelope)
|
|
390
|
+
|| envelope.type !== 'integrity'
|
|
391
|
+
|| envelope.verifiedScope !== 'kernel:bootstrap'
|
|
392
|
+
) {
|
|
393
|
+
fallar('BOOTSTRAP_INVALID', 'bootstrap no verificado');
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function crearBootstrapReceipt(envelope, opciones) {
|
|
398
|
+
const receipt = Object.freeze({
|
|
399
|
+
kind: 'verified-kernel-bootstrap-receipt',
|
|
400
|
+
trustEpoch: envelope.trustEpoch, trustDigest: envelope.trustDigest,
|
|
401
|
+
rootKeyDigest: envelope.rootKeyDigest, providers: envelope.claims.providers,
|
|
402
|
+
trustPath: envelope.claims.trustPath, signerPath: envelope.claims.signerPath,
|
|
403
|
+
anchorPath: envelope.claims.anchorPath, issuedAt: envelope.claims.issuedAt,
|
|
404
|
+
expiresAt: envelope.claims.expiresAt, nonce: envelope.claims.nonce,
|
|
405
|
+
});
|
|
406
|
+
congelarProfundo(receipt);
|
|
407
|
+
VERIFIED_BOOTSTRAPS.add(receipt);
|
|
408
|
+
BOOTSTRAP_METADATA.set(receipt, Object.freeze({
|
|
409
|
+
workspaceRoot: opciones.workspaceRoot, signerKeyId: envelope.keyId,
|
|
410
|
+
signerPublicKeyDigest: envelope.signerPublicKeyDigest,
|
|
411
|
+
}));
|
|
412
|
+
return receipt;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function verifyKernelBootstrapReceipt(envelope, opciones) {
|
|
416
|
+
validarEnvelopeBootstrap(envelope);
|
|
417
|
+
validarOpcionesBootstrap(opciones);
|
|
418
|
+
try {
|
|
419
|
+
validarBootstrapClaims(envelope.claims, envelope, opciones);
|
|
420
|
+
} catch (error) {
|
|
421
|
+
if (error.codigo === 'BOOTSTRAP_INVALID') throw error;
|
|
422
|
+
throw crearError('BOOTSTRAP_INVALID', 'bootstrap inválido');
|
|
423
|
+
}
|
|
424
|
+
return crearBootstrapReceipt(envelope, opciones);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function isVerifiedKernelBootstrapReceipt(valor) {
|
|
428
|
+
return VERIFIED_BOOTSTRAPS.has(valor);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const { bindContractValidators } = require('./policy-verifier-utils');
|
|
432
|
+
bindContractValidators({ isKernelDependencies, isVerifiedOperation });
|
|
433
|
+
|
|
434
|
+
const runtimeModule = require('./integrity-ledger');
|
|
435
|
+
const createBuiltInKernelRuntime = runtimeModule.createBuiltInKernelRuntime;
|
|
436
|
+
delete runtimeModule.createBuiltInKernelRuntime;
|
|
437
|
+
Object.freeze(runtimeModule);
|
|
438
|
+
|
|
439
|
+
function componerRuntime(receipt, metadata) {
|
|
440
|
+
try {
|
|
441
|
+
return createBuiltInKernelRuntime({
|
|
442
|
+
receipt, workspaceRoot: metadata.workspaceRoot,
|
|
443
|
+
signerKeyId: metadata.signerKeyId,
|
|
444
|
+
signerPublicKeyDigest: metadata.signerPublicKeyDigest,
|
|
445
|
+
});
|
|
446
|
+
} catch (error) {
|
|
447
|
+
if (error.codigo) throw error;
|
|
448
|
+
throw crearError('KERNEL_DEPENDENCIES_INVALID', 'composición del kernel inválida');
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function crearDependencies(runtime) {
|
|
453
|
+
const dependencies = congelarProfundo(Object.freeze({
|
|
454
|
+
kind: 'kernel-dependencies', providers: runtime.providers,
|
|
455
|
+
gateEngine: runtime.gateEngine,
|
|
456
|
+
integrityLedger: runtime.integrityLedger,
|
|
457
|
+
policyBroker: runtime.policyBroker,
|
|
458
|
+
policyContextProvider: runtime.policyContextProvider,
|
|
459
|
+
singleUseStore: runtime.singleUseStore,
|
|
460
|
+
}));
|
|
461
|
+
KERNEL_DEPENDENCIES.add(dependencies);
|
|
462
|
+
return dependencies;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function createKernelDependencies(receipt) {
|
|
466
|
+
const autorizado = arguments.length === 1 && VERIFIED_BOOTSTRAPS.has(receipt);
|
|
467
|
+
if (!autorizado) fallar('KERNEL_DEPENDENCIES_INVALID', 'bootstrap receipt no autorizado');
|
|
468
|
+
const metadata = BOOTSTRAP_METADATA.get(receipt);
|
|
469
|
+
return crearDependencies(componerRuntime(receipt, metadata));
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
module.exports = {
|
|
473
|
+
createKernelDependencies,
|
|
474
|
+
isKernelDependencies,
|
|
475
|
+
isVerifiedKernelBootstrapReceipt,
|
|
476
|
+
isVerifiedOperation,
|
|
477
|
+
verifyKernelBootstrapReceipt,
|
|
478
|
+
verifyOperation,
|
|
479
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/** Primitivas puras compartidas por los verificadores de capabilities W2. */
|
|
4
|
+
|
|
5
|
+
const util = require('node:util');
|
|
6
|
+
|
|
7
|
+
let contractValidators = null;
|
|
8
|
+
|
|
9
|
+
function fail(code, message) {
|
|
10
|
+
const error = new Error(message);
|
|
11
|
+
error.codigo = code;
|
|
12
|
+
throw error;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function plainObject(value, code, label) {
|
|
16
|
+
if (!value || typeof value !== 'object' || Array.isArray(value) || util.types.isProxy(value)) {
|
|
17
|
+
fail(code, `${label} inválido`);
|
|
18
|
+
}
|
|
19
|
+
const proto = Object.getPrototypeOf(value);
|
|
20
|
+
const descriptors = Object.values(Object.getOwnPropertyDescriptors(value));
|
|
21
|
+
if ((proto !== Object.prototype && proto !== null)
|
|
22
|
+
|| Object.getOwnPropertySymbols(value).length > 0
|
|
23
|
+
|| descriptors.some((item) => !item.enumerable || !('value' in item))) {
|
|
24
|
+
fail(code, `${label} inválido`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function exactKeys(value, keys, code, label) {
|
|
29
|
+
if (JSON.stringify(Object.keys(value).sort()) !== JSON.stringify([...keys].sort())) {
|
|
30
|
+
fail(code, `${label} con propiedades inválidas`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function freezeDeep(value) {
|
|
35
|
+
if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value;
|
|
36
|
+
Object.values(value).forEach(freezeDeep);
|
|
37
|
+
return Object.freeze(value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function bindContractValidators(validators) {
|
|
41
|
+
plainObject(validators, 'KERNEL_BINDING_INVALID', 'predicados del contrato');
|
|
42
|
+
exactKeys(
|
|
43
|
+
validators, ['isKernelDependencies', 'isVerifiedOperation'],
|
|
44
|
+
'KERNEL_BINDING_INVALID', 'predicados del contrato'
|
|
45
|
+
);
|
|
46
|
+
if (Object.values(validators).some((validator) => typeof validator !== 'function')) {
|
|
47
|
+
fail('KERNEL_BINDING_INVALID', 'predicados del contrato inválidos');
|
|
48
|
+
}
|
|
49
|
+
const hasConflict = contractValidators && Object.keys(contractValidators)
|
|
50
|
+
.some((key) => contractValidators[key] !== validators[key]);
|
|
51
|
+
if (hasConflict) {
|
|
52
|
+
fail('KERNEL_BINDING_CONFLICT', 'predicados del contrato ya ligados');
|
|
53
|
+
}
|
|
54
|
+
contractValidators ||= Object.freeze({ ...validators });
|
|
55
|
+
return contractValidators;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getContractValidators() {
|
|
59
|
+
if (!contractValidators) fail('KERNEL_BINDING_MISSING', 'predicados del contrato no ligados');
|
|
60
|
+
return contractValidators;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = {
|
|
64
|
+
bindContractValidators, exactKeys, fail, freezeDeep, getContractValidators, plainObject,
|
|
65
|
+
};
|