@semacode/cli 1.2.0 → 1.2.11

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 (49) hide show
  1. package/README.md +2 -2
  2. package/SEMA_BRIEF.curto.txt +9 -9
  3. package/SEMA_BRIEF.md +49 -49
  4. package/SEMA_BRIEF.micro.txt +7 -7
  5. package/SEMA_INDEX.json +501 -546
  6. package/dist/drift.d.ts +3 -3
  7. package/dist/drift.js +213 -22
  8. package/dist/drift.js.map +1 -1
  9. package/dist/importador.d.ts +1 -1
  10. package/dist/importador.js +0 -60
  11. package/dist/importador.js.map +1 -1
  12. package/dist/index.js +1334 -1360
  13. package/dist/index.js.map +1 -1
  14. package/dist/projeto.js +0 -6
  15. package/dist/projeto.js.map +1 -1
  16. package/dist/tipos.d.ts +1 -1
  17. package/docs/AGENT_STARTER.md +102 -102
  18. package/docs/instalacao-e-primeiro-uso.md +196 -198
  19. package/docs/sintaxe.md +95 -1
  20. package/node_modules/@sema/gerador-dart/package.json +1 -1
  21. package/node_modules/@sema/gerador-lua/dist/index.js +49 -81
  22. package/node_modules/@sema/gerador-lua/dist/index.js.map +1 -1
  23. package/node_modules/@sema/gerador-lua/package.json +1 -1
  24. package/node_modules/@sema/gerador-python/package.json +1 -1
  25. package/node_modules/@sema/gerador-typescript/package.json +1 -1
  26. package/node_modules/@sema/nucleo/dist/ast/tipos.d.ts +8 -2
  27. package/node_modules/@sema/nucleo/dist/formatador/index.js +65 -21
  28. package/node_modules/@sema/nucleo/dist/formatador/index.js.map +1 -1
  29. package/node_modules/@sema/nucleo/dist/ir/conversor.js +91 -5
  30. package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -1
  31. package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +74 -3
  32. package/node_modules/@sema/nucleo/dist/lexer/tokens.js +6 -0
  33. package/node_modules/@sema/nucleo/dist/lexer/tokens.js.map +1 -1
  34. package/node_modules/@sema/nucleo/dist/parser/parser.js +12 -2
  35. package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
  36. package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +2 -2
  37. package/node_modules/@sema/nucleo/dist/semantico/analisador.js +410 -11
  38. package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +1 -1
  39. package/node_modules/@sema/nucleo/dist/semantico/estruturas.d.ts +6 -1
  40. package/node_modules/@sema/nucleo/dist/semantico/estruturas.js +63 -13
  41. package/node_modules/@sema/nucleo/dist/semantico/estruturas.js.map +1 -1
  42. package/node_modules/@sema/nucleo/dist/semantico/seguranca.d.ts +91 -0
  43. package/node_modules/@sema/nucleo/dist/semantico/seguranca.js +258 -0
  44. package/node_modules/@sema/nucleo/dist/semantico/seguranca.js.map +1 -0
  45. package/node_modules/@sema/nucleo/package.json +1 -1
  46. package/node_modules/@sema/padroes/dist/index.js +18 -1
  47. package/node_modules/@sema/padroes/dist/index.js.map +1 -1
  48. package/node_modules/@sema/padroes/package.json +1 -1
  49. package/package.json +7 -7
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;
@@ -21,7 +21,7 @@ export interface DiagnosticoDrift {
21
21
  interface RegistroImplDrift {
22
22
  modulo: string;
23
23
  task: string;
24
- origem: "ts" | "py" | "dart" | "lua" | "cs" | "java" | "go" | "rust" | "cpp";
24
+ origem: "ts" | "py" | "dart" | "cs" | "java" | "go" | "rust" | "cpp";
25
25
  caminho: string;
26
26
  arquivo?: string;
27
27
  simbolo?: string;
@@ -47,7 +47,7 @@ interface RegistroRecursoDrift {
47
47
  status: "resolvido" | "divergente";
48
48
  }
49
49
  interface SimboloCandidatoDrift {
50
- origem: "ts" | "py" | "dart" | "lua" | "cs" | "java" | "go" | "rust" | "cpp";
50
+ origem: "ts" | "py" | "dart" | "cs" | "java" | "go" | "rust" | "cpp";
51
51
  caminho: string;
52
52
  arquivo: string;
53
53
  simbolo: string;
package/dist/drift.js CHANGED
@@ -5,7 +5,6 @@ import { extrairSimbolosCpp } from "./cpp-symbols.js";
5
5
  import { extrairRotasDotnet, extrairSimbolosDotnet } from "./dotnet-http.js";
6
6
  import { extrairRotasGo, extrairSimbolosGo } from "./go-http.js";
7
7
  import { extrairRotasJava, extrairSimbolosJava } from "./java-http.js";
8
- import { extrairSimbolosLua } from "./lua-symbols.js";
9
8
  import { contarIndentacaoPython, extrairRotasFlaskDecoradas, normalizarCaminhoFlask } from "./python-http.js";
10
9
  import { extrairRotasRust, extrairSimbolosRust } from "./rust-http.js";
11
10
  import { extrairRotasTypeScriptHttp } from "./typescript-http.js";
@@ -118,8 +117,14 @@ function encontrarAncoraSuperficie(ir, superficie, simbolos, mapaImpl, arquivos)
118
117
  return undefined;
119
118
  }
120
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 ?? ""));
121
124
  if (task.execucao.criticidadeOperacional === "alta"
122
125
  || task.execucao.criticidadeOperacional === "critica"
126
+ || dadosSensiveis
127
+ || efeitoPrivilegiado
123
128
  || task.efeitosEstruturados.some((efeito) => efeito.categoria === "persistencia" || efeito.criticidade === "critica")) {
124
129
  return "alto";
125
130
  }
@@ -154,7 +159,7 @@ function calcularScoreTask(task, implsValidos, implsQuebrados, vinculosValidos,
154
159
  }
155
160
  return Math.max(0, Math.min(100, score));
156
161
  }
157
- function resumirLacunasTask(task, semImplementacao, implsQuebrados, vinculosQuebrados) {
162
+ function resumirLacunasTask(task, semImplementacao, implsQuebrados, vinculosQuebrados, guardrails) {
158
163
  const lacunas = [];
159
164
  if (semImplementacao) {
160
165
  lacunas.push("sem_impl");
@@ -171,6 +176,33 @@ function resumirLacunasTask(task, semImplementacao, implsQuebrados, vinculosQueb
171
176
  if (!task.execucao.explicita) {
172
177
  lacunas.push("execucao_implicita");
173
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
+ }
174
206
  return lacunas;
175
207
  }
176
208
  function resumirOperacional(resultado) {
@@ -979,22 +1011,6 @@ async function indexarDart(diretorios) {
979
1011
  || a.arquivo.localeCompare(b.arquivo, "pt-BR")),
980
1012
  };
981
1013
  }
982
- async function indexarLua(diretorios) {
983
- const simbolos = new Map();
984
- for (const diretorio of diretorios) {
985
- const arquivos = (await listarArquivosRecursivos(diretorio, [".lua"]))
986
- .filter((arquivo) => !/(^|[\\/])(spec|specs|test|tests)([\\/]|$)/i.test(arquivo))
987
- .filter((arquivo) => !/[_-](spec|test)\.lua$/i.test(arquivo));
988
- for (const arquivo of arquivos) {
989
- const texto = await readFile(arquivo, "utf8");
990
- const basesSimbolicas = caminhosSimbolicos(diretorio, arquivo);
991
- for (const simbolo of extrairSimbolosLua(texto)) {
992
- registrarSimboloGenerico(simbolos, "lua", basesSimbolicas, arquivo, simbolo.simbolo);
993
- }
994
- }
995
- }
996
- return { simbolos: [...simbolos.values()], rotas: [] };
997
- }
998
1014
  function registrarSimboloGenerico(simbolos, origem, basesSimbolicas, arquivo, simbolo) {
999
1015
  for (const baseSimbolica of basesSimbolicas) {
1000
1016
  const caminho = `${baseSimbolica}.${simbolo}`;
@@ -1345,7 +1361,6 @@ export async function analisarDriftLegado(contexto) {
1345
1361
  const indexTs = await indexarTypeScript(contexto.diretoriosCodigo);
1346
1362
  const indexPy = await indexarPython(contexto.diretoriosCodigo);
1347
1363
  const indexDart = await indexarDart(contexto.diretoriosCodigo);
1348
- const indexLua = await indexarLua(contexto.diretoriosCodigo);
1349
1364
  const indexDotnet = await indexarDotnet(contexto.diretoriosCodigo);
1350
1365
  const indexJava = await indexarJava(contexto.diretoriosCodigo);
1351
1366
  const indexGo = await indexarGo(contexto.diretoriosCodigo);
@@ -1355,7 +1370,6 @@ export async function analisarDriftLegado(contexto) {
1355
1370
  ...indexTs.simbolos,
1356
1371
  ...indexPy.simbolos,
1357
1372
  ...indexDart.simbolos,
1358
- ...indexLua.simbolos,
1359
1373
  ...indexDotnet.simbolos,
1360
1374
  ...indexJava.simbolos,
1361
1375
  ...indexGo.simbolos,
@@ -1366,7 +1380,6 @@ export async function analisarDriftLegado(contexto) {
1366
1380
  ...indexTs.simbolos.map((item) => [item.caminho, item]),
1367
1381
  ...indexPy.simbolos.map((item) => [item.caminho, item]),
1368
1382
  ...indexDart.simbolos.map((item) => [item.caminho, item]),
1369
- ...indexLua.simbolos.map((item) => [item.caminho, item]),
1370
1383
  ...indexDotnet.simbolos.map((item) => [item.caminho, item]),
1371
1384
  ...indexJava.simbolos.map((item) => [item.caminho, item]),
1372
1385
  ...indexGo.simbolos.map((item) => [item.caminho, item]),
@@ -1398,6 +1411,7 @@ export async function analisarDriftLegado(contexto) {
1398
1411
  const diagnosticos = [];
1399
1412
  const tasksResumo = [];
1400
1413
  const taskPorChave = new Map();
1414
+ const guardrailsPorTask = new Map();
1401
1415
  const resumoVinculosPorTask = new Map();
1402
1416
  for (const item of contexto.modulosSelecionados) {
1403
1417
  const ir = item.resultado.ir;
@@ -1405,6 +1419,69 @@ export async function analisarDriftLegado(contexto) {
1405
1419
  continue;
1406
1420
  }
1407
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
+ }
1408
1485
  for (const task of ir.tasks) {
1409
1486
  taskPorChave.set(`${ir.nome}:${task.nome}`, task);
1410
1487
  let validos = 0;
@@ -1520,6 +1597,29 @@ export async function analisarDriftLegado(contexto) {
1520
1597
  criticidadeOperacional: "media",
1521
1598
  explicita: false,
1522
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
+ },
1523
1623
  guarantees: [],
1524
1624
  garantiasEstruturadas: [],
1525
1625
  errors: {},
@@ -1664,6 +1764,19 @@ export async function analisarDriftLegado(contexto) {
1664
1764
  for (const resumo of tasksResumo) {
1665
1765
  const chaveTask = `${resumo.modulo}:${resumo.task}`;
1666
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
+ };
1667
1780
  const resumoVinculos = resumoVinculosPorTask.get(chaveTask) ?? {
1668
1781
  validos: 0,
1669
1782
  quebrados: 0,
@@ -1674,7 +1787,7 @@ export async function analisarDriftLegado(contexto) {
1674
1787
  }
1675
1788
  resumo.confiancaVinculo = calcularConfiancaTask(task, resumo.implsValidos, resumo.implsQuebrados, resumoVinculos.validos, resumoVinculos.quebrados);
1676
1789
  resumo.riscoOperacional = calcularRiscoOperacional(task);
1677
- resumo.lacunas = resumirLacunasTask(task, resumo.semImplementacao, resumo.implsQuebrados, resumoVinculos.quebrados);
1790
+ resumo.lacunas = resumirLacunasTask(task, resumo.semImplementacao, resumo.implsQuebrados, resumoVinculos.quebrados, guardrails);
1678
1791
  resumo.scoreSemantico = calcularScoreTask(task, resumo.implsValidos, resumo.implsQuebrados, resumoVinculos.validos, resumoVinculos.quebrados, resumo.semImplementacao);
1679
1792
  resumo.arquivosProvaveisEditar = [...new Set([
1680
1793
  ...resumo.arquivosReferenciados,
@@ -1685,7 +1798,85 @@ export async function analisarDriftLegado(contexto) {
1685
1798
  ...task.resumoAgente.checks,
1686
1799
  resumo.riscoOperacional !== "baixo" ? "revisar efeitos operacionais" : "",
1687
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
+ : "",
1688
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
+ }
1689
1880
  }
1690
1881
  const consumerSurfaces = [...indexTs.consumerSurfaces, ...indexDart.consumerSurfaces].sort((a, b) => a.rota.localeCompare(b.rota, "pt-BR")
1691
1882
  || a.tipoArquivo.localeCompare(b.tipoArquivo, "pt-BR")