@semacode/cli 2.1.0 → 2.3.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/README.md +107 -4
- package/dist/agentContext.d.ts +1 -1
- package/dist/agentContextPack.js +6 -1
- package/dist/agentContextTipos.d.ts +4 -2
- package/dist/agentContextTipos.js +7 -0
- package/dist/agentEntryPoints.js +70 -19
- package/dist/comandos.js +6 -0
- package/dist/discovery/catalog.d.ts +11 -0
- package/dist/discovery/catalog.js +521 -0
- package/dist/discovery/command.d.ts +11 -0
- package/dist/discovery/command.js +226 -0
- package/dist/discovery/index.d.ts +5 -0
- package/dist/discovery/index.js +8 -0
- package/dist/discovery/ranker.d.ts +3 -0
- package/dist/discovery/ranker.js +310 -0
- package/dist/discovery/redaction.d.ts +2 -0
- package/dist/discovery/redaction.js +21 -0
- package/dist/discovery/render.d.ts +2 -0
- package/dist/discovery/render.js +100 -0
- package/dist/discovery/types.d.ts +119 -0
- package/dist/discovery/types.js +13 -0
- package/dist/execucoesExternas.js +19 -5
- package/dist/exemplosOficiais.js +29 -8
- package/dist/iaPrompts.d.ts +1 -1
- package/dist/iaPrompts.js +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +24 -5
- package/dist/index.part01.d.ts +1 -1
- package/dist/index.part01.js +47 -3
- package/dist/index.part06.js +3 -0
- package/dist/initTemplatesBase.js +3 -2
- package/dist/pipelineConteudo/adapters.d.ts +84 -0
- package/dist/pipelineConteudo/adapters.js +449 -0
- package/dist/pipelineConteudo/canonical.d.ts +18 -0
- package/dist/pipelineConteudo/canonical.js +107 -0
- package/dist/pipelineConteudo/command.d.ts +3 -0
- package/dist/pipelineConteudo/command.js +572 -0
- package/dist/pipelineConteudo/index.d.ts +9 -0
- package/dist/pipelineConteudo/index.js +12 -0
- package/dist/pipelineConteudo/ledger.d.ts +68 -0
- package/dist/pipelineConteudo/ledger.js +732 -0
- package/dist/pipelineConteudo/planner.d.ts +12 -0
- package/dist/pipelineConteudo/planner.js +366 -0
- package/dist/pipelineConteudo/projection.d.ts +16 -0
- package/dist/pipelineConteudo/projection.js +57 -0
- package/dist/pipelineConteudo/state.d.ts +23 -0
- package/dist/pipelineConteudo/state.js +615 -0
- package/dist/pipelineConteudo/trust.d.ts +17 -0
- package/dist/pipelineConteudo/trust.js +750 -0
- package/dist/pipelineConteudo/types.d.ts +331 -0
- package/dist/pipelineConteudo/types.js +4 -0
- package/dist/profileArtefatoValidadores.d.ts +3 -2
- package/dist/profileArtefatoValidadores.js +81 -0
- package/dist/profileAuthorTipos.d.ts +4 -3
- package/dist/profileCatalogo.d.ts +5 -5
- package/dist/profileCatalogo.js +30 -0
- package/dist/profileCommand.d.ts +8 -2
- package/dist/profileCommand.js +15 -5
- package/dist/profileRegras.d.ts +5 -5
- package/dist/profileRegras.js +13 -1
- package/dist/profileRulePacks.js +68 -0
- package/dist/sistemasInterativos/adapterProtocol.d.ts +3 -0
- package/dist/sistemasInterativos/adapterProtocol.js +240 -0
- package/dist/sistemasInterativos/advancedCatalog.d.ts +5 -0
- package/dist/sistemasInterativos/advancedCatalog.js +442 -0
- package/dist/sistemasInterativos/autonomy.d.ts +230 -0
- package/dist/sistemasInterativos/autonomy.js +753 -0
- package/dist/sistemasInterativos/canonical.d.ts +3 -0
- package/dist/sistemasInterativos/canonical.js +43 -0
- package/dist/sistemasInterativos/catalog.d.ts +116 -0
- package/dist/sistemasInterativos/catalog.js +543 -0
- package/dist/sistemasInterativos/command.d.ts +7 -0
- package/dist/sistemasInterativos/command.js +311 -0
- package/dist/sistemasInterativos/controlRun.d.ts +56 -0
- package/dist/sistemasInterativos/controlRun.js +391 -0
- package/dist/sistemasInterativos/evidence.d.ts +5 -0
- package/dist/sistemasInterativos/evidence.js +306 -0
- package/dist/sistemasInterativos/experienceIr.d.ts +12 -0
- package/dist/sistemasInterativos/experienceIr.js +895 -0
- package/dist/sistemasInterativos/experienceIrSemantics.d.ts +30 -0
- package/dist/sistemasInterativos/experienceIrSemantics.js +368 -0
- package/dist/sistemasInterativos/experienceIrTypes.d.ts +370 -0
- package/dist/sistemasInterativos/experienceIrTypes.js +5 -0
- package/dist/sistemasInterativos/extensionCommand.d.ts +391 -0
- package/dist/sistemasInterativos/extensionCommand.js +383 -0
- package/dist/sistemasInterativos/index.d.ts +19 -0
- package/dist/sistemasInterativos/index.js +22 -0
- package/dist/sistemasInterativos/operations.d.ts +40 -0
- package/dist/sistemasInterativos/operations.js +1167 -0
- package/dist/sistemasInterativos/operationsTypes.d.ts +297 -0
- package/dist/sistemasInterativos/operationsTypes.js +11 -0
- package/dist/sistemasInterativos/planner.d.ts +2 -0
- package/dist/sistemasInterativos/planner.js +159 -0
- package/dist/sistemasInterativos/portability.d.ts +164 -0
- package/dist/sistemasInterativos/portability.js +539 -0
- package/dist/sistemasInterativos/render.d.ts +3 -0
- package/dist/sistemasInterativos/render.js +179 -0
- package/dist/sistemasInterativos/temporal.d.ts +183 -0
- package/dist/sistemasInterativos/temporal.js +543 -0
- package/dist/sistemasInterativos/types.d.ts +215 -0
- package/dist/sistemasInterativos/types.js +4 -0
- package/dist/sistemasInterativos/validator.d.ts +2 -0
- package/dist/sistemasInterativos/validator.js +305 -0
- package/docs/README.md +9 -0
- package/docs/ai-integration.md +7 -1
- package/docs/ai-workflow.md +5 -4
- package/docs/commands.md +43 -1
- package/docs/descoberta-capacidades.md +106 -0
- package/docs/documentation.md +11 -2
- package/docs/pipeline-conteudo.md +246 -0
- package/docs/profiles.md +11 -2
- package/docs/sistemas-interativos.md +381 -0
- package/docs/testing.md +11 -2
- package/exemplos/pipeline-conteudo/README.md +44 -0
- package/exemplos/pipeline-conteudo/alvos.json +23 -0
- package/exemplos/pipeline-conteudo/definicao.json +136 -0
- package/exemplos/profile_simulation.sema +211 -0
- package/exemplos/sistemas-interativos/README.md +100 -0
- package/exemplos/sistemas-interativos/advanced/acceptance-context-evaluate-valid.json +5 -0
- package/exemplos/sistemas-interativos/advanced/acceptance-lock-valid.json +16 -0
- package/exemplos/sistemas-interativos/advanced/asset-provenance-valid.json +32 -0
- package/exemplos/sistemas-interativos/advanced/autonomy-repair-valid.json +93 -0
- package/exemplos/sistemas-interativos/advanced/control-run-definition-valid.json +78 -0
- package/exemplos/sistemas-interativos/advanced/control-run-valid.json +27 -0
- package/exemplos/sistemas-interativos/advanced/distributed-workers-valid.json +79 -0
- package/exemplos/sistemas-interativos/advanced/editor-state-valid.json +42 -0
- package/exemplos/sistemas-interativos/advanced/engine-snapshot-after-valid.json +32 -0
- package/exemplos/sistemas-interativos/advanced/engine-snapshot-before-valid.json +23 -0
- package/exemplos/sistemas-interativos/advanced/job-orchestration-valid.json +39 -0
- package/exemplos/sistemas-interativos/advanced/multimodal-evidence-valid.json +46 -0
- package/exemplos/sistemas-interativos/advanced/multiplayer-authority-valid.json +39 -0
- package/exemplos/sistemas-interativos/advanced/playtest-fuzz-valid.json +37 -0
- package/exemplos/sistemas-interativos/advanced/portability-valid.json +104 -0
- package/exemplos/sistemas-interativos/advanced/temporal-evidence-valid.json +27 -0
- package/exemplos/sistemas-interativos/advanced/temporal-valid.json +118 -0
- package/exemplos/sistemas-interativos/experience-ir-valid.json +459 -0
- package/exemplos/sistemas-interativos/game-2d.json +83 -0
- package/exemplos/sistemas-interativos/game-3d-human.json +81 -0
- package/exemplos/sistemas-interativos/game-pixel-16-bit.json +97 -0
- package/exemplos/sistemas-interativos/game-pixel-8-bit.json +94 -0
- package/exemplos/sistemas-interativos/game-xr-human.json +80 -0
- package/exemplos/sistemas-interativos/hybrid-2-5d.json +108 -0
- package/exemplos/sistemas-interativos/protocol-mutating-rollback-valid.json +75 -0
- package/exemplos/sistemas-interativos/protocol-read-only-valid.json +58 -0
- package/exemplos/sistemas-interativos/simulation-2d-controlled.json +97 -0
- package/exemplos/sistemas-interativos/simulation-3d-calibrated-autonomous.json +141 -0
- package/exemplos/sistemas-interativos/simulation-headless-autonomous-batch.json +112 -0
- package/exemplos/sistemas-interativos/simulation-pixel-16-bit.json +103 -0
- package/exemplos/sistemas-interativos/simulation-text-controlled.json +95 -0
- package/node_modules/@sema/gerador-lua/dist/index.js +78 -4
- package/node_modules/@sema/gerador-lua/dist/index.js.map +1 -1
- package/node_modules/@sema/gerador-php/dist/index.js +8 -0
- package/node_modules/@sema/gerador-php/dist/index.js.map +1 -1
- package/package.json +8 -1
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
// SEMA-GOVERNED: sema.produto.pipeline_conteudo.adaptadores
|
|
2
|
+
// Descricao: validacao e planejamento declarativo de destinos abertos do pipeline de conteudo.
|
|
3
|
+
import { digestJsonCanonico } from "./canonical.js";
|
|
4
|
+
/**
|
|
5
|
+
* Vocabulário inicial para definições usuais. O validador aceita qualquer
|
|
6
|
+
* capability opaca não vazia; esta lista não é uma whitelist.
|
|
7
|
+
*/
|
|
8
|
+
export const CAPABILITIES_CONTEUDO_PADRAO = Object.freeze([
|
|
9
|
+
"content.topic.plan",
|
|
10
|
+
"content.research.collect",
|
|
11
|
+
"content.master.compose",
|
|
12
|
+
"content.target.adapt",
|
|
13
|
+
"content.qa.deterministic",
|
|
14
|
+
"content.qa.semantic",
|
|
15
|
+
"content.target.deliver",
|
|
16
|
+
"content.target.confirm",
|
|
17
|
+
]);
|
|
18
|
+
export const CONSTRAINTS_DETERMINISTICAS_SUPORTADAS = Object.freeze([
|
|
19
|
+
"artifact.bytes.min",
|
|
20
|
+
"artifact.bytes.max",
|
|
21
|
+
"media.duration.min",
|
|
22
|
+
"media.duration.max",
|
|
23
|
+
"text.length.min",
|
|
24
|
+
"text.length.max",
|
|
25
|
+
]);
|
|
26
|
+
const VERSOES_FLUTUANTES = new Set(["*", "current", "latest", "stable"]);
|
|
27
|
+
const CONSTRAINTS_SUPORTADAS = new Set(CONSTRAINTS_DETERMINISTICAS_SUPORTADAS);
|
|
28
|
+
const DECLARACOES_NAO_CONFIAVEIS = new Set([
|
|
29
|
+
"executor_declared",
|
|
30
|
+
"executor_declaration",
|
|
31
|
+
"runner_declared",
|
|
32
|
+
"runner_declaration",
|
|
33
|
+
]);
|
|
34
|
+
const CHAVES_METADATA_SENSIVEIS = new Set([
|
|
35
|
+
"apikey", "accesstoken", "refreshtoken", "authorization", "bearer", "password", "passwd",
|
|
36
|
+
"secret", "clientsecret", "privatekey", "credential", "credentials", "apitoken",
|
|
37
|
+
"awssecretaccesskey", "sessioncookie", "sessiontoken", "authcookie", "signingkey",
|
|
38
|
+
]);
|
|
39
|
+
const PADROES_VALOR_SENSIVEL = [
|
|
40
|
+
/-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/u,
|
|
41
|
+
/\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/iu,
|
|
42
|
+
/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/u,
|
|
43
|
+
/\b(?:github_pat_|gh[pousr]_|xox[baprs]-|sk_(?:live|test)_|sk-|AIza)[A-Za-z0-9_-]{12,}\b/u,
|
|
44
|
+
/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/u,
|
|
45
|
+
];
|
|
46
|
+
const ACCOUNT_SCOPE = /^account:[a-z0-9][a-z0-9._-]{0,63}$/u;
|
|
47
|
+
function textoOpaco(valor) {
|
|
48
|
+
return typeof valor === "string" && valor.length > 0 && valor === valor.trim() && !/[\s\u0000-\u001f\u007f]/u.test(valor);
|
|
49
|
+
}
|
|
50
|
+
function textosUnicosNaoVazios(valores) {
|
|
51
|
+
return valores.every(textoOpaco) && new Set(valores).size === valores.length;
|
|
52
|
+
}
|
|
53
|
+
function clonarJson(valor) {
|
|
54
|
+
if (Array.isArray(valor)) {
|
|
55
|
+
return valor.map((item) => clonarJson(item));
|
|
56
|
+
}
|
|
57
|
+
if (valor !== null && typeof valor === "object") {
|
|
58
|
+
return Object.fromEntries(Object.entries(valor).map(([chave, item]) => [chave, clonarJson(item)]));
|
|
59
|
+
}
|
|
60
|
+
return valor;
|
|
61
|
+
}
|
|
62
|
+
function chaveMetadataNormalizada(chave) {
|
|
63
|
+
return chave.replace(/([a-z0-9])([A-Z])/gu, "$1_$2").toLowerCase().replace(/[^a-z0-9]/gu, "");
|
|
64
|
+
}
|
|
65
|
+
function chaveMetadataSensivel(chave) {
|
|
66
|
+
const normalizada = chaveMetadataNormalizada(chave);
|
|
67
|
+
if (CHAVES_METADATA_SENSIVEIS.has(normalizada))
|
|
68
|
+
return true;
|
|
69
|
+
if (/(?:token|secret|password|passwd|credential|authorization|bearer|cookie|privatekey)/u.test(normalizada)) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
return /(?:api|access|aws|client|private|signing|encryption).*key/u.test(normalizada);
|
|
73
|
+
}
|
|
74
|
+
function valorPareceSegredo(valor) {
|
|
75
|
+
return PADROES_VALOR_SENSIVEL.some((padrao) => padrao.test(valor));
|
|
76
|
+
}
|
|
77
|
+
export function validarReferenciaAccountScopeConteudo(valor) {
|
|
78
|
+
if (typeof valor !== "string" || !ACCOUNT_SCOPE.test(valor))
|
|
79
|
+
return ["account_scope_referencia_invalida"];
|
|
80
|
+
if (valorPareceSegredo(valor))
|
|
81
|
+
return ["account_scope_contem_possivel_credencial"];
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
/** Metadata de target e publica no plano/ledger/projecao; segredos sao sempre externos. */
|
|
85
|
+
export function validarMetadataPublicaConteudo(valor) {
|
|
86
|
+
const bloqueios = [];
|
|
87
|
+
const visitar = (atual) => {
|
|
88
|
+
if (typeof atual === "string" && valorPareceSegredo(atual)) {
|
|
89
|
+
bloqueios.push("valor_sensivel_em_metadata");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (Array.isArray(atual)) {
|
|
93
|
+
atual.forEach((item) => visitar(item));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (atual === null || typeof atual !== "object")
|
|
97
|
+
return;
|
|
98
|
+
for (const [chave, item] of Object.entries(atual)) {
|
|
99
|
+
if (chaveMetadataSensivel(chave) || valorPareceSegredo(chave)) {
|
|
100
|
+
bloqueios.push("chave_sensivel_em_metadata");
|
|
101
|
+
}
|
|
102
|
+
visitar(item);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
visitar(valor);
|
|
106
|
+
return [...new Set(bloqueios)];
|
|
107
|
+
}
|
|
108
|
+
function chaveIsolamento(alvo) {
|
|
109
|
+
return `target:${encodeURIComponent(alvo.targetId)}:account:${encodeURIComponent(alvo.accountScope)}`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Escopo exato e injetivo para autorização target-bound. Alterar execução,
|
|
113
|
+
* target ou conta sempre altera o escopo.
|
|
114
|
+
*/
|
|
115
|
+
export function escopoAutorizacaoAlvo(runId, alvo) {
|
|
116
|
+
if (!textoOpaco(runId) ||
|
|
117
|
+
!textoOpaco(alvo.targetId) ||
|
|
118
|
+
validarReferenciaAccountScopeConteudo(alvo.accountScope).length > 0) {
|
|
119
|
+
throw new TypeError("escopo_autorizacao_alvo_invalido");
|
|
120
|
+
}
|
|
121
|
+
return `run:${encodeURIComponent(runId)}:target:${encodeURIComponent(alvo.targetId)}:account:${encodeURIComponent(alvo.accountScope)}`;
|
|
122
|
+
}
|
|
123
|
+
export function escopoAutorizacaoGlobal(runId) {
|
|
124
|
+
if (!textoOpaco(runId))
|
|
125
|
+
throw new TypeError("escopo_autorizacao_global_invalido");
|
|
126
|
+
return `run:${encodeURIComponent(runId)}:global`;
|
|
127
|
+
}
|
|
128
|
+
function numeroFinitoNaoNegativo(valor) {
|
|
129
|
+
return typeof valor === "number" && Number.isFinite(valor) && valor >= 0;
|
|
130
|
+
}
|
|
131
|
+
function chavesLimiteConstraint(constraint) {
|
|
132
|
+
return constraint.kind.endsWith(".min")
|
|
133
|
+
? ["value", "limit", "min", "minimum"]
|
|
134
|
+
: ["value", "limit", "max", "maximum"];
|
|
135
|
+
}
|
|
136
|
+
function validarConfigConstraint(constraint) {
|
|
137
|
+
const config = constraint.config;
|
|
138
|
+
if (config === undefined
|
|
139
|
+
|| config === null
|
|
140
|
+
|| typeof config !== "object"
|
|
141
|
+
|| Array.isArray(config)
|
|
142
|
+
|| ![Object.prototype, null].includes(Object.getPrototypeOf(config))) {
|
|
143
|
+
return ["adapter_constraint_config_invalida"];
|
|
144
|
+
}
|
|
145
|
+
if (validarMetadataPublicaConteudo(config).length > 0) {
|
|
146
|
+
return ["adapter_constraint_config_sensivel"];
|
|
147
|
+
}
|
|
148
|
+
const chaves = Object.keys(config);
|
|
149
|
+
const permitidas = new Set(chavesLimiteConstraint(constraint));
|
|
150
|
+
if (chaves.length !== 1 || !permitidas.has(chaves[0])) {
|
|
151
|
+
return ["adapter_constraint_config_campos_invalidos"];
|
|
152
|
+
}
|
|
153
|
+
return numeroFinitoNaoNegativo(config[chaves[0]])
|
|
154
|
+
? []
|
|
155
|
+
: ["adapter_constraint_limite_invalido"];
|
|
156
|
+
}
|
|
157
|
+
function limiteConstraint(constraint) {
|
|
158
|
+
const config = constraint.config;
|
|
159
|
+
if (!config)
|
|
160
|
+
return undefined;
|
|
161
|
+
for (const chave of chavesLimiteConstraint(constraint)) {
|
|
162
|
+
if (numeroFinitoNaoNegativo(config[chave]))
|
|
163
|
+
return config[chave];
|
|
164
|
+
}
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
function valorEmCaminho(fonte, caminho) {
|
|
168
|
+
let atual = fonte;
|
|
169
|
+
for (const segmento of caminho) {
|
|
170
|
+
if (atual === null || typeof atual !== "object" || Array.isArray(atual))
|
|
171
|
+
return undefined;
|
|
172
|
+
atual = atual[segmento];
|
|
173
|
+
}
|
|
174
|
+
return atual;
|
|
175
|
+
}
|
|
176
|
+
function primeiraMedicaoValida(fontes, caminhos) {
|
|
177
|
+
for (const fonte of fontes) {
|
|
178
|
+
for (const caminho of caminhos) {
|
|
179
|
+
const valor = valorEmCaminho(fonte, caminho);
|
|
180
|
+
if (numeroFinitoNaoNegativo(valor))
|
|
181
|
+
return valor;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
function medicaoConstraint(kind, artefato, observacoes) {
|
|
187
|
+
// Metadado do artefato e declaracao do produtor. Somente observacao
|
|
188
|
+
// independente pode satisfazer uma constraint canonica.
|
|
189
|
+
const fontes = [observacoes];
|
|
190
|
+
if (kind.startsWith("artifact.bytes.")) {
|
|
191
|
+
return primeiraMedicaoValida(fontes, [["artifactBytes"], ["artifact.bytes"], ["artifact", "bytes"], ["bytes"]]);
|
|
192
|
+
}
|
|
193
|
+
if (kind.startsWith("media.duration.")) {
|
|
194
|
+
return primeiraMedicaoValida(fontes, [["mediaDuration"], ["mediaDurationSeconds"], ["media.duration"], ["media", "duration"], ["duration"]]);
|
|
195
|
+
}
|
|
196
|
+
return primeiraMedicaoValida(fontes, [["textLength"], ["text.length"], ["text", "length"]]);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Avalia somente medições fornecidas. Não lê arquivos, não chama ferramentas e
|
|
200
|
+
* nunca trata um kind desconhecido como aprovação implícita.
|
|
201
|
+
*/
|
|
202
|
+
export function avaliarConstraintsDeterministicasConteudo(artefato, constraints, observacoes = {}) {
|
|
203
|
+
const constraintsDigest = digestJsonCanonico(constraints);
|
|
204
|
+
const resultados = [];
|
|
205
|
+
const bloqueios = [];
|
|
206
|
+
for (const constraint of constraints) {
|
|
207
|
+
const bloqueiosConstraint = [];
|
|
208
|
+
if (!CONSTRAINTS_SUPORTADAS.has(constraint.kind)) {
|
|
209
|
+
bloqueiosConstraint.push(`constraint_kind_nao_suportado:${constraint.constraintId}:${constraint.kind}`);
|
|
210
|
+
resultados.push({
|
|
211
|
+
constraintId: constraint.constraintId,
|
|
212
|
+
kind: constraint.kind,
|
|
213
|
+
observed: null,
|
|
214
|
+
limit: null,
|
|
215
|
+
passed: false,
|
|
216
|
+
bloqueios: bloqueiosConstraint,
|
|
217
|
+
});
|
|
218
|
+
bloqueios.push(...bloqueiosConstraint);
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
const kind = constraint.kind;
|
|
222
|
+
const limit = limiteConstraint(constraint);
|
|
223
|
+
const observed = medicaoConstraint(kind, artefato, observacoes);
|
|
224
|
+
if (limit === undefined)
|
|
225
|
+
bloqueiosConstraint.push(`constraint_limite_invalido:${constraint.constraintId}`);
|
|
226
|
+
if (observed === undefined)
|
|
227
|
+
bloqueiosConstraint.push(`constraint_observacao_ausente:${constraint.constraintId}`);
|
|
228
|
+
const passed = bloqueiosConstraint.length === 0
|
|
229
|
+
&& (kind.endsWith(".min") ? observed >= limit : observed <= limit);
|
|
230
|
+
if (!passed && bloqueiosConstraint.length === 0) {
|
|
231
|
+
bloqueiosConstraint.push(`constraint_nao_satisfeita:${constraint.constraintId}`);
|
|
232
|
+
}
|
|
233
|
+
resultados.push({
|
|
234
|
+
constraintId: constraint.constraintId,
|
|
235
|
+
kind,
|
|
236
|
+
observed: observed ?? null,
|
|
237
|
+
limit: limit ?? null,
|
|
238
|
+
passed,
|
|
239
|
+
bloqueios: bloqueiosConstraint,
|
|
240
|
+
});
|
|
241
|
+
bloqueios.push(...bloqueiosConstraint);
|
|
242
|
+
}
|
|
243
|
+
const resultsDigest = digestJsonCanonico({
|
|
244
|
+
schemaVersion: "1.0",
|
|
245
|
+
artifactId: artefato.artifactId,
|
|
246
|
+
artifactDigest: artefato.digest,
|
|
247
|
+
runId: artefato.runId,
|
|
248
|
+
targetId: artefato.targetId ?? null,
|
|
249
|
+
constraintsDigest,
|
|
250
|
+
observedMediaType: observacoes.observedMediaType ?? null,
|
|
251
|
+
resultados,
|
|
252
|
+
});
|
|
253
|
+
return {
|
|
254
|
+
valido: bloqueios.length === 0 && resultados.every((resultado) => resultado.passed),
|
|
255
|
+
artifactDigest: artefato.digest,
|
|
256
|
+
constraintsDigest,
|
|
257
|
+
resultsDigest,
|
|
258
|
+
resultados,
|
|
259
|
+
bloqueios,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/** Valida somente propriedades declarativas; nenhuma capability é executada. */
|
|
263
|
+
export function validarAdaptadorConteudo(adapter) {
|
|
264
|
+
const bloqueios = [];
|
|
265
|
+
if (!textoOpaco(adapter.adapterId)) {
|
|
266
|
+
bloqueios.push("adapter_id_invalido");
|
|
267
|
+
}
|
|
268
|
+
if (!textoOpaco(adapter.version) || VERSOES_FLUTUANTES.has(adapter.version.toLowerCase())) {
|
|
269
|
+
bloqueios.push("adapter_version_nao_fixada");
|
|
270
|
+
}
|
|
271
|
+
if (!Array.isArray(adapter.capabilities) || adapter.capabilities.length === 0 || !textosUnicosNaoVazios(adapter.capabilities)) {
|
|
272
|
+
bloqueios.push("adapter_capabilities_invalidas");
|
|
273
|
+
}
|
|
274
|
+
if (!Array.isArray(adapter.acceptedMediaTypes)
|
|
275
|
+
|| adapter.acceptedMediaTypes.length === 0
|
|
276
|
+
|| !textosUnicosNaoVazios(adapter.acceptedMediaTypes)) {
|
|
277
|
+
bloqueios.push("adapter_media_types_invalidos");
|
|
278
|
+
}
|
|
279
|
+
if (!Array.isArray(adapter.formatProfiles) || adapter.formatProfiles.length === 0 || !textosUnicosNaoVazios(adapter.formatProfiles)) {
|
|
280
|
+
bloqueios.push("adapter_format_profiles_invalidos");
|
|
281
|
+
}
|
|
282
|
+
if (!Array.isArray(adapter.deterministicConstraints) || adapter.deterministicConstraints.length === 0) {
|
|
283
|
+
bloqueios.push("adapter_constraints_deterministicas_ausentes");
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
const ids = new Set();
|
|
287
|
+
for (const constraint of adapter.deterministicConstraints) {
|
|
288
|
+
if (!textoOpaco(constraint.constraintId) || !textoOpaco(constraint.kind)) {
|
|
289
|
+
bloqueios.push("adapter_constraint_invalida");
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
if (valorPareceSegredo(constraint.constraintId) || valorPareceSegredo(constraint.kind)) {
|
|
293
|
+
bloqueios.push("adapter_constraint_identificador_sensivel");
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
if (ids.has(constraint.constraintId)) {
|
|
297
|
+
bloqueios.push(`adapter_constraint_id_duplicado:${constraint.constraintId}`);
|
|
298
|
+
}
|
|
299
|
+
ids.add(constraint.constraintId);
|
|
300
|
+
if (!CONSTRAINTS_SUPORTADAS.has(constraint.kind)) {
|
|
301
|
+
bloqueios.push(`adapter_constraint_kind_nao_suportado:${constraint.constraintId}:${constraint.kind}`);
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
bloqueios.push(...validarConfigConstraint(constraint));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (!Array.isArray(adapter.requiredMetadata) || !textosUnicosNaoVazios(adapter.requiredMetadata)) {
|
|
309
|
+
bloqueios.push("adapter_required_metadata_invalido");
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
for (const campo of adapter.requiredMetadata) {
|
|
313
|
+
if (chaveMetadataSensivel(campo) || valorPareceSegredo(campo)) {
|
|
314
|
+
bloqueios.push("adapter_required_metadata_sensivel");
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (!Array.isArray(adapter.optionalMetadata) || !textosUnicosNaoVazios(adapter.optionalMetadata)) {
|
|
319
|
+
bloqueios.push("adapter_optional_metadata_invalido");
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
for (const campo of adapter.optionalMetadata) {
|
|
323
|
+
if (chaveMetadataSensivel(campo) || valorPareceSegredo(campo)) {
|
|
324
|
+
bloqueios.push("adapter_optional_metadata_sensivel");
|
|
325
|
+
}
|
|
326
|
+
if (adapter.requiredMetadata.includes(campo))
|
|
327
|
+
bloqueios.push("adapter_metadata_required_optional_sobreposta");
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (!Array.isArray(adapter.confirmationPredicates)
|
|
331
|
+
|| adapter.confirmationPredicates.length === 0
|
|
332
|
+
|| !textosUnicosNaoVazios(adapter.confirmationPredicates)) {
|
|
333
|
+
bloqueios.push("adapter_confirmation_predicates_invalidos");
|
|
334
|
+
}
|
|
335
|
+
else if (adapter.confirmationPredicates.some((item) => DECLARACOES_NAO_CONFIAVEIS.has(item.toLowerCase()))) {
|
|
336
|
+
bloqueios.push("adapter_confirmacao_baseada_em_declaracao_do_executor");
|
|
337
|
+
}
|
|
338
|
+
return { valido: bloqueios.length === 0, bloqueios };
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Materializa um plano isolado por targetId/accountScope. Os planos carregam
|
|
342
|
+
* instruções e referências; credenciais e chamadas de ferramenta ficam no
|
|
343
|
+
* runner externo.
|
|
344
|
+
*/
|
|
345
|
+
export function planejarAlvosConteudo(alvos, adapters, artefatosMestre) {
|
|
346
|
+
const planosAdaptacao = [];
|
|
347
|
+
const bloqueiosPorAlvo = [];
|
|
348
|
+
const adicionarBloqueio = (targetId, codigo) => {
|
|
349
|
+
bloqueiosPorAlvo.push({ targetId, codigo });
|
|
350
|
+
};
|
|
351
|
+
if (alvos.length === 0) {
|
|
352
|
+
adicionarBloqueio("*", "alvos_ausentes");
|
|
353
|
+
return { planosAdaptacao, bloqueiosPorAlvo };
|
|
354
|
+
}
|
|
355
|
+
const contagemTargets = new Map();
|
|
356
|
+
for (const alvo of alvos) {
|
|
357
|
+
contagemTargets.set(alvo.targetId, (contagemTargets.get(alvo.targetId) ?? 0) + 1);
|
|
358
|
+
}
|
|
359
|
+
const adaptersPorId = new Map();
|
|
360
|
+
for (const adapter of adapters) {
|
|
361
|
+
const encontrados = adaptersPorId.get(adapter.adapterId) ?? [];
|
|
362
|
+
encontrados.push(adapter);
|
|
363
|
+
adaptersPorId.set(adapter.adapterId, encontrados);
|
|
364
|
+
}
|
|
365
|
+
for (const alvo of alvos) {
|
|
366
|
+
const targetId = textoOpaco(alvo.targetId) ? alvo.targetId : "<target-invalido>";
|
|
367
|
+
const bloqueiosAntes = bloqueiosPorAlvo.length;
|
|
368
|
+
if (!textoOpaco(alvo.targetId)) {
|
|
369
|
+
adicionarBloqueio(targetId, "target_id_invalido");
|
|
370
|
+
}
|
|
371
|
+
else if ((contagemTargets.get(alvo.targetId) ?? 0) > 1) {
|
|
372
|
+
adicionarBloqueio(targetId, "target_id_duplicado");
|
|
373
|
+
}
|
|
374
|
+
for (const bloqueio of validarReferenciaAccountScopeConteudo(alvo.accountScope)) {
|
|
375
|
+
adicionarBloqueio(targetId, bloqueio);
|
|
376
|
+
}
|
|
377
|
+
if (!textoOpaco(alvo.formatProfileId)) {
|
|
378
|
+
adicionarBloqueio(targetId, "format_profile_id_invalido");
|
|
379
|
+
}
|
|
380
|
+
if (!textoOpaco(alvo.locale)) {
|
|
381
|
+
adicionarBloqueio(targetId, "locale_invalido");
|
|
382
|
+
}
|
|
383
|
+
if (alvo.metadata === null || typeof alvo.metadata !== "object" || Array.isArray(alvo.metadata)) {
|
|
384
|
+
adicionarBloqueio(targetId, "metadata_invalido");
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
for (const valor of Object.values(alvo.metadata)) {
|
|
388
|
+
if (valor !== null && !["string", "number", "boolean"].includes(typeof valor)) {
|
|
389
|
+
adicionarBloqueio(targetId, "metadata_valor_nao_escalar");
|
|
390
|
+
}
|
|
391
|
+
else if (typeof valor === "number" && !Number.isFinite(valor)) {
|
|
392
|
+
adicionarBloqueio(targetId, "metadata_numero_nao_finito");
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
for (const bloqueio of validarMetadataPublicaConteudo(alvo.metadata)) {
|
|
396
|
+
adicionarBloqueio(targetId, bloqueio);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
const candidatos = adaptersPorId.get(alvo.adapterId) ?? [];
|
|
400
|
+
if (candidatos.length === 0) {
|
|
401
|
+
adicionarBloqueio(targetId, "adapter_nao_encontrado");
|
|
402
|
+
}
|
|
403
|
+
else if (candidatos.length > 1) {
|
|
404
|
+
adicionarBloqueio(targetId, "adapter_id_ambiguo_na_definicao");
|
|
405
|
+
}
|
|
406
|
+
const adapter = candidatos.length === 1 ? candidatos[0] : undefined;
|
|
407
|
+
if (adapter) {
|
|
408
|
+
const resultadoAdapter = validarAdaptadorConteudo(adapter);
|
|
409
|
+
for (const bloqueio of resultadoAdapter.bloqueios) {
|
|
410
|
+
adicionarBloqueio(targetId, `adapter_invalido:${bloqueio}`);
|
|
411
|
+
}
|
|
412
|
+
if (!adapter.formatProfiles.includes(alvo.formatProfileId)) {
|
|
413
|
+
adicionarBloqueio(targetId, "format_profile_nao_declarado_no_adapter");
|
|
414
|
+
}
|
|
415
|
+
for (const campo of adapter.requiredMetadata) {
|
|
416
|
+
if (!Object.prototype.hasOwnProperty.call(alvo.metadata, campo)) {
|
|
417
|
+
adicionarBloqueio(targetId, "metadata_obrigatorio_ausente");
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
const permitidos = new Set([...adapter.requiredMetadata, ...adapter.optionalMetadata]);
|
|
421
|
+
for (const campo of Object.keys(alvo.metadata)) {
|
|
422
|
+
if (!permitidos.has(campo))
|
|
423
|
+
adicionarBloqueio(targetId, "metadata_nao_declarado_no_adapter");
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
if (bloqueiosPorAlvo.length !== bloqueiosAntes || !adapter) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
planosAdaptacao.push({
|
|
430
|
+
targetId: alvo.targetId,
|
|
431
|
+
adapterId: adapter.adapterId,
|
|
432
|
+
adapterVersion: adapter.version,
|
|
433
|
+
accountScope: alvo.accountScope,
|
|
434
|
+
isolationKey: chaveIsolamento(alvo),
|
|
435
|
+
formatProfileId: alvo.formatProfileId,
|
|
436
|
+
locale: alvo.locale,
|
|
437
|
+
capabilities: [...adapter.capabilities],
|
|
438
|
+
acceptedMediaTypes: [...adapter.acceptedMediaTypes],
|
|
439
|
+
deterministicConstraints: clonarJson(adapter.deterministicConstraints),
|
|
440
|
+
requiredMetadata: [...adapter.requiredMetadata],
|
|
441
|
+
optionalMetadata: [...adapter.optionalMetadata],
|
|
442
|
+
confirmationPredicates: [...adapter.confirmationPredicates],
|
|
443
|
+
metadata: clonarJson(alvo.metadata),
|
|
444
|
+
masterArtifacts: [...artefatosMestre],
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
return { planosAdaptacao, bloqueiosPorAlvo };
|
|
448
|
+
}
|
|
449
|
+
//# sourceMappingURL=adapters.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type KeyLike } from "node:crypto";
|
|
2
|
+
import type { EnvelopeAssinadoConteudo, EnvelopeAssinavelConteudo } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Serializa somente o subconjunto JSON, ordenando chaves recursivamente.
|
|
5
|
+
* Valores que JSON descartaria silenciosamente sao rejeitados para evitar
|
|
6
|
+
* assinaturas ambiguas.
|
|
7
|
+
*/
|
|
8
|
+
export declare function canonicalizarJson(valor: unknown): string;
|
|
9
|
+
export declare function digestSha256(conteudo: string | Uint8Array): string;
|
|
10
|
+
export declare function digestJsonCanonico(valor: unknown): string;
|
|
11
|
+
/** Alias de dominio usado por planner, ledger e projecoes. */
|
|
12
|
+
export declare const hashCanonicoConteudo: typeof digestJsonCanonico;
|
|
13
|
+
export declare function dadosAssinaveisEnvelopeConteudo<TPayload>(envelope: EnvelopeAssinavelConteudo<TPayload>): EnvelopeAssinavelConteudo<TPayload>;
|
|
14
|
+
export declare function serializarEnvelopeAssinavelConteudo<TPayload>(envelope: EnvelopeAssinavelConteudo<TPayload>): string;
|
|
15
|
+
/** A chave privada e usada somente nesta chamada e jamais integra o retorno. */
|
|
16
|
+
export declare function assinarEnvelopeConteudo<TPayload>(envelope: EnvelopeAssinavelConteudo<TPayload>, privateKey: KeyLike): EnvelopeAssinadoConteudo<TPayload>;
|
|
17
|
+
export declare function verificarAssinaturaEnvelopeConteudo<TPayload>(envelope: EnvelopeAssinadoConteudo<TPayload>, publicKey: KeyLike): boolean;
|
|
18
|
+
export declare function digestEnvelopeConteudo(envelope: EnvelopeAssinadoConteudo<unknown>): string;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// SEMA-GOVERNED: sema.produto.pipeline_conteudo.confianca
|
|
2
|
+
// Descricao: serializacao JSON deterministica, digests SHA-256 e envelopes Ed25519 sem persistir chave privada.
|
|
3
|
+
import { createHash, sign, verify } from "node:crypto";
|
|
4
|
+
function falharCanonico(motivo, _caminho) {
|
|
5
|
+
throw new TypeError(`json_canonico_invalido:${motivo}`);
|
|
6
|
+
}
|
|
7
|
+
function serializarCanonico(valor, caminho, visitados) {
|
|
8
|
+
if (valor === null)
|
|
9
|
+
return "null";
|
|
10
|
+
if (typeof valor === "string" || typeof valor === "boolean") {
|
|
11
|
+
return JSON.stringify(valor);
|
|
12
|
+
}
|
|
13
|
+
if (typeof valor === "number") {
|
|
14
|
+
if (!Number.isFinite(valor))
|
|
15
|
+
falharCanonico("numero_nao_finito", caminho);
|
|
16
|
+
return Object.is(valor, -0) ? "0" : JSON.stringify(valor);
|
|
17
|
+
}
|
|
18
|
+
if (typeof valor !== "object") {
|
|
19
|
+
return falharCanonico(`tipo_${typeof valor}_nao_suportado`, caminho);
|
|
20
|
+
}
|
|
21
|
+
if (visitados.has(valor))
|
|
22
|
+
falharCanonico("referencia_ciclica", caminho);
|
|
23
|
+
visitados.add(valor);
|
|
24
|
+
try {
|
|
25
|
+
if (Array.isArray(valor)) {
|
|
26
|
+
const itens = [];
|
|
27
|
+
for (let indice = 0; indice < valor.length; indice += 1) {
|
|
28
|
+
if (!Object.hasOwn(valor, indice))
|
|
29
|
+
falharCanonico("array_esparso", `${caminho}[${indice}]`);
|
|
30
|
+
itens.push(serializarCanonico(valor[indice], `${caminho}[${indice}]`, visitados));
|
|
31
|
+
}
|
|
32
|
+
return `[${itens.join(",")}]`;
|
|
33
|
+
}
|
|
34
|
+
const prototipo = Object.getPrototypeOf(valor);
|
|
35
|
+
if (prototipo !== Object.prototype && prototipo !== null) {
|
|
36
|
+
return falharCanonico("objeto_nao_plano", caminho);
|
|
37
|
+
}
|
|
38
|
+
const objeto = valor;
|
|
39
|
+
const campos = Object.keys(objeto)
|
|
40
|
+
.sort()
|
|
41
|
+
.map((chave) => `${JSON.stringify(chave)}:${serializarCanonico(objeto[chave], `${caminho}.${chave}`, visitados)}`);
|
|
42
|
+
return `{${campos.join(",")}}`;
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
visitados.delete(valor);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Serializa somente o subconjunto JSON, ordenando chaves recursivamente.
|
|
50
|
+
* Valores que JSON descartaria silenciosamente sao rejeitados para evitar
|
|
51
|
+
* assinaturas ambiguas.
|
|
52
|
+
*/
|
|
53
|
+
export function canonicalizarJson(valor) {
|
|
54
|
+
return serializarCanonico(valor, "$", new Set());
|
|
55
|
+
}
|
|
56
|
+
export function digestSha256(conteudo) {
|
|
57
|
+
return `sha256:${createHash("sha256").update(conteudo).digest("hex")}`;
|
|
58
|
+
}
|
|
59
|
+
export function digestJsonCanonico(valor) {
|
|
60
|
+
return digestSha256(canonicalizarJson(valor));
|
|
61
|
+
}
|
|
62
|
+
/** Alias de dominio usado por planner, ledger e projecoes. */
|
|
63
|
+
export const hashCanonicoConteudo = digestJsonCanonico;
|
|
64
|
+
export function dadosAssinaveisEnvelopeConteudo(envelope) {
|
|
65
|
+
return {
|
|
66
|
+
schemaVersion: envelope.schemaVersion,
|
|
67
|
+
payloadType: envelope.payloadType,
|
|
68
|
+
payload: envelope.payload,
|
|
69
|
+
principalId: envelope.principalId,
|
|
70
|
+
keyId: envelope.keyId,
|
|
71
|
+
issuedAt: envelope.issuedAt,
|
|
72
|
+
nonce: envelope.nonce,
|
|
73
|
+
signatureAlgorithm: envelope.signatureAlgorithm,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export function serializarEnvelopeAssinavelConteudo(envelope) {
|
|
77
|
+
return canonicalizarJson(dadosAssinaveisEnvelopeConteudo(envelope));
|
|
78
|
+
}
|
|
79
|
+
/** A chave privada e usada somente nesta chamada e jamais integra o retorno. */
|
|
80
|
+
export function assinarEnvelopeConteudo(envelope, privateKey) {
|
|
81
|
+
if (envelope.signatureAlgorithm !== "Ed25519") {
|
|
82
|
+
throw new TypeError("algoritmo_assinatura_nao_suportado");
|
|
83
|
+
}
|
|
84
|
+
const mensagem = Buffer.from(serializarEnvelopeAssinavelConteudo(envelope), "utf8");
|
|
85
|
+
const signature = sign(null, mensagem, privateKey).toString("base64");
|
|
86
|
+
return { ...dadosAssinaveisEnvelopeConteudo(envelope), signature };
|
|
87
|
+
}
|
|
88
|
+
export function verificarAssinaturaEnvelopeConteudo(envelope, publicKey) {
|
|
89
|
+
if (envelope.signatureAlgorithm !== "Ed25519")
|
|
90
|
+
return false;
|
|
91
|
+
if (!/^[A-Za-z0-9+/]+={0,2}$/.test(envelope.signature))
|
|
92
|
+
return false;
|
|
93
|
+
try {
|
|
94
|
+
const assinatura = Buffer.from(envelope.signature, "base64");
|
|
95
|
+
if (assinatura.length !== 64 || assinatura.toString("base64") !== envelope.signature)
|
|
96
|
+
return false;
|
|
97
|
+
const mensagem = Buffer.from(serializarEnvelopeAssinavelConteudo(envelope), "utf8");
|
|
98
|
+
return verify(null, mensagem, publicKey, assinatura);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export function digestEnvelopeConteudo(envelope) {
|
|
105
|
+
return digestJsonCanonico(envelope);
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=canonical.js.map
|