@semacode/cli 1.2.9 → 1.2.12

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.
Files changed (32) hide show
  1. package/README.md +2 -2
  2. package/dist/drift.d.ts +1 -1
  3. package/dist/drift.js +213 -2
  4. package/dist/drift.js.map +1 -1
  5. package/dist/index.js +66 -8
  6. package/dist/index.js.map +1 -1
  7. package/docs/sintaxe.md +95 -1
  8. package/node_modules/@sema/gerador-dart/package.json +1 -1
  9. package/node_modules/@sema/gerador-lua/package.json +1 -1
  10. package/node_modules/@sema/gerador-python/package.json +1 -1
  11. package/node_modules/@sema/gerador-typescript/package.json +1 -1
  12. package/node_modules/@sema/nucleo/dist/ast/tipos.d.ts +7 -1
  13. package/node_modules/@sema/nucleo/dist/formatador/index.js +65 -21
  14. package/node_modules/@sema/nucleo/dist/formatador/index.js.map +1 -1
  15. package/node_modules/@sema/nucleo/dist/ir/conversor.js +91 -1
  16. package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -1
  17. package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +71 -0
  18. package/node_modules/@sema/nucleo/dist/lexer/tokens.js +6 -0
  19. package/node_modules/@sema/nucleo/dist/lexer/tokens.js.map +1 -1
  20. package/node_modules/@sema/nucleo/dist/parser/parser.js +12 -0
  21. package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
  22. package/node_modules/@sema/nucleo/dist/semantico/analisador.js +409 -8
  23. package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +1 -1
  24. package/node_modules/@sema/nucleo/dist/semantico/estruturas.d.ts +6 -1
  25. package/node_modules/@sema/nucleo/dist/semantico/estruturas.js +63 -13
  26. package/node_modules/@sema/nucleo/dist/semantico/estruturas.js.map +1 -1
  27. package/node_modules/@sema/nucleo/dist/semantico/seguranca.d.ts +91 -0
  28. package/node_modules/@sema/nucleo/dist/semantico/seguranca.js +258 -0
  29. package/node_modules/@sema/nucleo/dist/semantico/seguranca.js.map +1 -0
  30. package/node_modules/@sema/nucleo/package.json +1 -1
  31. package/node_modules/@sema/padroes/package.json +1 -1
  32. package/package.json +7 -7
package/README.md CHANGED
@@ -36,7 +36,7 @@ sema --help
36
36
  ## Instalacao via tarball da release
37
37
 
38
38
  ```bash
39
- npm install -g ./sema-cli-1.2.9.tgz
39
+ npm install -g ./sema-cli-1.2.12.tgz
40
40
  ```
41
41
 
42
42
  Ou direto da GitHub Release:
@@ -55,7 +55,7 @@ npx sema --help
55
55
  Ou, se voce estiver testando um tarball local:
56
56
 
57
57
  ```bash
58
- npm install ./sema-cli-1.2.9.tgz
58
+ npm install ./sema-cli-1.2.12.tgz
59
59
  npx sema --help
60
60
  ```
61
61
 
package/dist/drift.d.ts CHANGED
@@ -12,7 +12,7 @@ interface RegistroConsumerBridgeDrift {
12
12
  simbolo: string;
13
13
  }
14
14
  export interface DiagnosticoDrift {
15
- tipo: "impl_quebrado" | "task_sem_impl" | "rota_divergente" | "recurso_divergente" | "vinculo_quebrado";
15
+ tipo: "impl_quebrado" | "task_sem_impl" | "rota_divergente" | "recurso_divergente" | "vinculo_quebrado" | "seguranca_frouxa";
16
16
  modulo: string;
17
17
  task?: string;
18
18
  route?: string;
package/dist/drift.js CHANGED
@@ -117,8 +117,14 @@ function encontrarAncoraSuperficie(ir, superficie, simbolos, mapaImpl, arquivos)
117
117
  return undefined;
118
118
  }
119
119
  function calcularRiscoOperacional(task) {
120
+ const dadosSensiveis = Boolean(task.dados.classificacaoPadrao && ["pii", "financeiro", "credencial", "segredo"].includes(task.dados.classificacaoPadrao)
121
+ || task.dados.campos.some((campo) => ["pii", "financeiro", "credencial", "segredo"].includes(campo.classificacao)));
122
+ const efeitoPrivilegiado = task.efeitosEstruturados.some((efeito) => ["db.read", "db.write", "queue.publish", "queue.consume", "fs.read", "fs.write", "network.egress", "secret.read", "shell.exec"].includes(efeito.categoria)
123
+ || ["alta", "critica"].includes(efeito.criticidade ?? ""));
120
124
  if (task.execucao.criticidadeOperacional === "alta"
121
125
  || task.execucao.criticidadeOperacional === "critica"
126
+ || dadosSensiveis
127
+ || efeitoPrivilegiado
122
128
  || task.efeitosEstruturados.some((efeito) => efeito.categoria === "persistencia" || efeito.criticidade === "critica")) {
123
129
  return "alto";
124
130
  }
@@ -153,7 +159,7 @@ function calcularScoreTask(task, implsValidos, implsQuebrados, vinculosValidos,
153
159
  }
154
160
  return Math.max(0, Math.min(100, score));
155
161
  }
156
- function resumirLacunasTask(task, semImplementacao, implsQuebrados, vinculosQuebrados) {
162
+ function resumirLacunasTask(task, semImplementacao, implsQuebrados, vinculosQuebrados, guardrails) {
157
163
  const lacunas = [];
158
164
  if (semImplementacao) {
159
165
  lacunas.push("sem_impl");
@@ -170,6 +176,33 @@ function resumirLacunasTask(task, semImplementacao, implsQuebrados, vinculosQueb
170
176
  if (!task.execucao.explicita) {
171
177
  lacunas.push("execucao_implicita");
172
178
  }
179
+ if (guardrails.publica && !task.execucao.explicita) {
180
+ lacunas.push("superficie_publica_sem_execucao");
181
+ }
182
+ if (guardrails.sensivel && !task.execucao.explicita) {
183
+ lacunas.push("execucao_critica_sem_bloco");
184
+ }
185
+ if ((guardrails.publica || guardrails.sensivel) && semImplementacao && task.vinculos.length === 0) {
186
+ lacunas.push("rastreabilidade_fraca");
187
+ }
188
+ if (guardrails.publica && !guardrails.auth) {
189
+ lacunas.push("auth_ausente");
190
+ }
191
+ if ((guardrails.publica || guardrails.sensivel || guardrails.efeitoPrivilegiado || guardrails.dadosSensiveis) && !guardrails.authz) {
192
+ lacunas.push("authz_frouxa");
193
+ }
194
+ if ((guardrails.publica || guardrails.sensivel || guardrails.efeitoPrivilegiado) && !guardrails.dados) {
195
+ lacunas.push("dados_nao_classificados");
196
+ }
197
+ if ((guardrails.publica || guardrails.sensivel || guardrails.efeitoPrivilegiado || guardrails.dadosSensiveis) && !guardrails.audit) {
198
+ lacunas.push("audit_ausente");
199
+ }
200
+ if (guardrails.exigeSegredos && !guardrails.segredos) {
201
+ lacunas.push("segredo_sem_governanca");
202
+ }
203
+ if ((guardrails.efeitoPrivilegiado || guardrails.dadosSensiveis) && !guardrails.forbidden) {
204
+ lacunas.push("proibicoes_ausentes");
205
+ }
173
206
  return lacunas;
174
207
  }
175
208
  function resumirOperacional(resultado) {
@@ -1378,6 +1411,7 @@ export async function analisarDriftLegado(contexto) {
1378
1411
  const diagnosticos = [];
1379
1412
  const tasksResumo = [];
1380
1413
  const taskPorChave = new Map();
1414
+ const guardrailsPorTask = new Map();
1381
1415
  const resumoVinculosPorTask = new Map();
1382
1416
  for (const item of contexto.modulosSelecionados) {
1383
1417
  const ir = item.resultado.ir;
@@ -1385,6 +1419,69 @@ export async function analisarDriftLegado(contexto) {
1385
1419
  continue;
1386
1420
  }
1387
1421
  const superficiesPorChave = new Map(ir.superficies.map((superficie) => [`${superficie.tipo}:${superficie.nome}`, superficie]));
1422
+ for (const task of ir.tasks) {
1423
+ guardrailsPorTask.set(`${ir.nome}:${task.nome}`, {
1424
+ publica: false,
1425
+ sensivel: calcularRiscoOperacional(task) === "alto",
1426
+ auth: task.auth.explicita,
1427
+ authz: task.authz.explicita,
1428
+ dados: task.dados.explicita,
1429
+ audit: task.audit.explicita,
1430
+ segredos: task.segredos.explicita,
1431
+ forbidden: task.forbidden.explicita,
1432
+ dadosSensiveis: Boolean(task.dados.classificacaoPadrao && ["pii", "financeiro", "credencial", "segredo"].includes(task.dados.classificacaoPadrao)
1433
+ || task.dados.campos.some((campo) => ["pii", "financeiro", "credencial", "segredo"].includes(campo.classificacao))),
1434
+ efeitoPrivilegiado: task.efeitosEstruturados.some((efeito) => ["db.read", "db.write", "queue.publish", "queue.consume", "fs.read", "fs.write", "network.egress", "secret.read", "shell.exec"].includes(efeito.categoria)
1435
+ || ["alta", "critica"].includes(efeito.criticidade ?? "")),
1436
+ exigeSegredos: task.efeitosEstruturados.some((efeito) => efeito.categoria === "secret.read")
1437
+ || Boolean(task.dados.classificacaoPadrao && ["credencial", "segredo"].includes(task.dados.classificacaoPadrao)
1438
+ || task.dados.campos.some((campo) => ["credencial", "segredo"].includes(campo.classificacao))),
1439
+ });
1440
+ }
1441
+ for (const route of ir.routes) {
1442
+ if (!route.task || route.perfilCompatibilidade !== "publico") {
1443
+ continue;
1444
+ }
1445
+ const guardrails = guardrailsPorTask.get(`${ir.nome}:${route.task}`);
1446
+ if (guardrails) {
1447
+ guardrails.publica = true;
1448
+ guardrails.auth = guardrails.auth || route.auth.explicita;
1449
+ guardrails.authz = guardrails.authz || route.authz.explicita;
1450
+ guardrails.dados = guardrails.dados || route.dados.explicita;
1451
+ guardrails.audit = guardrails.audit || route.audit.explicita;
1452
+ guardrails.segredos = guardrails.segredos || route.segredos.explicita;
1453
+ guardrails.forbidden = guardrails.forbidden || route.forbidden.explicita;
1454
+ guardrails.dadosSensiveis = guardrails.dadosSensiveis || Boolean(route.dados.classificacaoPadrao && ["pii", "financeiro", "credencial", "segredo"].includes(route.dados.classificacaoPadrao)
1455
+ || route.dados.campos.some((campo) => ["pii", "financeiro", "credencial", "segredo"].includes(campo.classificacao)));
1456
+ guardrails.efeitoPrivilegiado = guardrails.efeitoPrivilegiado || route.efeitosPublicos.some((efeito) => ["db.read", "db.write", "queue.publish", "queue.consume", "fs.read", "fs.write", "network.egress", "secret.read", "shell.exec"].includes(efeito.categoria)
1457
+ || ["alta", "critica"].includes(efeito.criticidade ?? ""));
1458
+ guardrails.exigeSegredos = guardrails.exigeSegredos || route.efeitosPublicos.some((efeito) => efeito.categoria === "secret.read")
1459
+ || Boolean(route.dados.classificacaoPadrao && ["credencial", "segredo"].includes(route.dados.classificacaoPadrao)
1460
+ || route.dados.campos.some((campo) => ["credencial", "segredo"].includes(campo.classificacao)));
1461
+ }
1462
+ }
1463
+ for (const superficie of ir.superficies) {
1464
+ if (!superficie.task || superficie.perfilCompatibilidade !== "publico") {
1465
+ continue;
1466
+ }
1467
+ const guardrails = guardrailsPorTask.get(`${ir.nome}:${superficie.task}`);
1468
+ if (guardrails) {
1469
+ guardrails.publica = true;
1470
+ guardrails.auth = guardrails.auth || superficie.auth.explicita;
1471
+ guardrails.authz = guardrails.authz || superficie.authz.explicita;
1472
+ guardrails.dados = guardrails.dados || superficie.dados.explicita;
1473
+ guardrails.audit = guardrails.audit || superficie.audit.explicita;
1474
+ guardrails.segredos = guardrails.segredos || superficie.segredos.explicita;
1475
+ guardrails.forbidden = guardrails.forbidden || superficie.forbidden.explicita;
1476
+ guardrails.dadosSensiveis = guardrails.dadosSensiveis || Boolean(superficie.dados.classificacaoPadrao && ["pii", "financeiro", "credencial", "segredo"].includes(superficie.dados.classificacaoPadrao)
1477
+ || superficie.dados.campos.some((campo) => ["pii", "financeiro", "credencial", "segredo"].includes(campo.classificacao)));
1478
+ guardrails.efeitoPrivilegiado = guardrails.efeitoPrivilegiado || superficie.effects.some((efeito) => ["db.read", "db.write", "queue.publish", "queue.consume", "fs.read", "fs.write", "network.egress", "secret.read", "shell.exec"].includes(efeito.categoria)
1479
+ || ["alta", "critica"].includes(efeito.criticidade ?? ""));
1480
+ guardrails.exigeSegredos = guardrails.exigeSegredos || superficie.effects.some((efeito) => efeito.categoria === "secret.read")
1481
+ || Boolean(superficie.dados.classificacaoPadrao && ["credencial", "segredo"].includes(superficie.dados.classificacaoPadrao)
1482
+ || superficie.dados.campos.some((campo) => ["credencial", "segredo"].includes(campo.classificacao)));
1483
+ }
1484
+ }
1388
1485
  for (const task of ir.tasks) {
1389
1486
  taskPorChave.set(`${ir.nome}:${task.nome}`, task);
1390
1487
  let validos = 0;
@@ -1500,6 +1597,29 @@ export async function analisarDriftLegado(contexto) {
1500
1597
  criticidadeOperacional: "media",
1501
1598
  explicita: false,
1502
1599
  },
1600
+ auth: {
1601
+ explicita: false,
1602
+ },
1603
+ authz: {
1604
+ explicita: false,
1605
+ papeis: [],
1606
+ escopos: [],
1607
+ },
1608
+ dados: {
1609
+ explicita: false,
1610
+ campos: [],
1611
+ },
1612
+ audit: {
1613
+ explicita: false,
1614
+ },
1615
+ segredos: {
1616
+ explicita: false,
1617
+ itens: [],
1618
+ },
1619
+ forbidden: {
1620
+ explicita: false,
1621
+ regras: [],
1622
+ },
1503
1623
  guarantees: [],
1504
1624
  garantiasEstruturadas: [],
1505
1625
  errors: {},
@@ -1644,6 +1764,19 @@ export async function analisarDriftLegado(contexto) {
1644
1764
  for (const resumo of tasksResumo) {
1645
1765
  const chaveTask = `${resumo.modulo}:${resumo.task}`;
1646
1766
  const task = taskPorChave.get(chaveTask);
1767
+ const guardrails = guardrailsPorTask.get(chaveTask) ?? {
1768
+ publica: false,
1769
+ sensivel: false,
1770
+ auth: false,
1771
+ authz: false,
1772
+ dados: false,
1773
+ audit: false,
1774
+ segredos: false,
1775
+ forbidden: false,
1776
+ dadosSensiveis: false,
1777
+ efeitoPrivilegiado: false,
1778
+ exigeSegredos: false,
1779
+ };
1647
1780
  const resumoVinculos = resumoVinculosPorTask.get(chaveTask) ?? {
1648
1781
  validos: 0,
1649
1782
  quebrados: 0,
@@ -1654,7 +1787,7 @@ export async function analisarDriftLegado(contexto) {
1654
1787
  }
1655
1788
  resumo.confiancaVinculo = calcularConfiancaTask(task, resumo.implsValidos, resumo.implsQuebrados, resumoVinculos.validos, resumoVinculos.quebrados);
1656
1789
  resumo.riscoOperacional = calcularRiscoOperacional(task);
1657
- resumo.lacunas = resumirLacunasTask(task, resumo.semImplementacao, resumo.implsQuebrados, resumoVinculos.quebrados);
1790
+ resumo.lacunas = resumirLacunasTask(task, resumo.semImplementacao, resumo.implsQuebrados, resumoVinculos.quebrados, guardrails);
1658
1791
  resumo.scoreSemantico = calcularScoreTask(task, resumo.implsValidos, resumo.implsQuebrados, resumoVinculos.validos, resumoVinculos.quebrados, resumo.semImplementacao);
1659
1792
  resumo.arquivosProvaveisEditar = [...new Set([
1660
1793
  ...resumo.arquivosReferenciados,
@@ -1665,7 +1798,85 @@ export async function analisarDriftLegado(contexto) {
1665
1798
  ...task.resumoAgente.checks,
1666
1799
  resumo.riscoOperacional !== "baixo" ? "revisar efeitos operacionais" : "",
1667
1800
  resumo.lacunas.includes("vinculo_quebrado") ? "corrigir vinculos rastreaveis" : "",
1801
+ resumo.lacunas.some((lacuna) => ["superficie_publica_sem_execucao", "execucao_critica_sem_bloco", "rastreabilidade_fraca"].includes(lacuna))
1802
+ ? "endurecer execucao e rastreabilidade para producao"
1803
+ : "",
1804
+ resumo.lacunas.some((lacuna) => ["auth_ausente", "authz_frouxa", "dados_nao_classificados", "audit_ausente", "segredo_sem_governanca", "proibicoes_ausentes"].includes(lacuna))
1805
+ ? "explicitar contratos de seguranca semantica"
1806
+ : "",
1668
1807
  ].filter(Boolean))];
1808
+ if (resumo.lacunas.includes("superficie_publica_sem_execucao")) {
1809
+ diagnosticos.push({
1810
+ tipo: "seguranca_frouxa",
1811
+ modulo: resumo.modulo,
1812
+ task: resumo.task,
1813
+ mensagem: `Task "${resumo.task}" alimenta superficie publica, mas ainda depende de execucao implicita.`,
1814
+ });
1815
+ }
1816
+ if (resumo.lacunas.includes("execucao_critica_sem_bloco")) {
1817
+ diagnosticos.push({
1818
+ tipo: "seguranca_frouxa",
1819
+ modulo: resumo.modulo,
1820
+ task: resumo.task,
1821
+ mensagem: `Task "${resumo.task}" opera com risco alto, mas ainda nao declarou execucao explicita.`,
1822
+ });
1823
+ }
1824
+ if (resumo.lacunas.includes("rastreabilidade_fraca")) {
1825
+ diagnosticos.push({
1826
+ tipo: "seguranca_frouxa",
1827
+ modulo: resumo.modulo,
1828
+ task: resumo.task,
1829
+ mensagem: `Task "${resumo.task}" exige producao mais rastreavel, mas ainda nao declara impl nem vinculos.`,
1830
+ });
1831
+ }
1832
+ if (resumo.lacunas.includes("auth_ausente")) {
1833
+ diagnosticos.push({
1834
+ tipo: "seguranca_frouxa",
1835
+ modulo: resumo.modulo,
1836
+ task: resumo.task,
1837
+ mensagem: `Task "${resumo.task}" chega em superficie publica sem auth explicita em task, route ou superficie associada.`,
1838
+ });
1839
+ }
1840
+ if (resumo.lacunas.includes("authz_frouxa")) {
1841
+ diagnosticos.push({
1842
+ tipo: "seguranca_frouxa",
1843
+ modulo: resumo.modulo,
1844
+ task: resumo.task,
1845
+ mensagem: `Task "${resumo.task}" opera com risco ou exposicao, mas ainda nao explicita authz suficiente.`,
1846
+ });
1847
+ }
1848
+ if (resumo.lacunas.includes("dados_nao_classificados")) {
1849
+ diagnosticos.push({
1850
+ tipo: "seguranca_frouxa",
1851
+ modulo: resumo.modulo,
1852
+ task: resumo.task,
1853
+ mensagem: `Task "${resumo.task}" ainda nao classifica dados de entrada/saida de forma semantica.`,
1854
+ });
1855
+ }
1856
+ if (resumo.lacunas.includes("audit_ausente")) {
1857
+ diagnosticos.push({
1858
+ tipo: "seguranca_frouxa",
1859
+ modulo: resumo.modulo,
1860
+ task: resumo.task,
1861
+ mensagem: `Task "${resumo.task}" ainda nao declara audit explicita para operacao sensivel ou publica.`,
1862
+ });
1863
+ }
1864
+ if (resumo.lacunas.includes("segredo_sem_governanca")) {
1865
+ diagnosticos.push({
1866
+ tipo: "seguranca_frouxa",
1867
+ modulo: resumo.modulo,
1868
+ task: resumo.task,
1869
+ mensagem: `Task "${resumo.task}" toca segredo ou credencial sem bloco segredos governando origem, escopo e rotacao.`,
1870
+ });
1871
+ }
1872
+ if (resumo.lacunas.includes("proibicoes_ausentes")) {
1873
+ diagnosticos.push({
1874
+ tipo: "seguranca_frouxa",
1875
+ modulo: resumo.modulo,
1876
+ task: resumo.task,
1877
+ mensagem: `Task "${resumo.task}" opera com efeito privilegiado ou dado sensivel sem forbidden explicito para conter abuso e vazamento.`,
1878
+ });
1879
+ }
1669
1880
  }
1670
1881
  const consumerSurfaces = [...indexTs.consumerSurfaces, ...indexDart.consumerSurfaces].sort((a, b) => a.rota.localeCompare(b.rota, "pt-BR")
1671
1882
  || a.tipoArquivo.localeCompare(b.tipoArquivo, "pt-BR")