@dozimple/abap-adt 1.0.0-rc.1

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 (75) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +19 -0
  4. package/README.es.md +356 -0
  5. package/README.md +356 -0
  6. package/SECURITY.md +68 -0
  7. package/THIRD_PARTY_NOTICES.md +134 -0
  8. package/config/systems.example.json +39 -0
  9. package/dist/core/activation.js +18 -0
  10. package/dist/core/atc.js +94 -0
  11. package/dist/core/audit.js +93 -0
  12. package/dist/core/catalog.en.js +92 -0
  13. package/dist/core/catalog.js +139 -0
  14. package/dist/core/checks.js +19 -0
  15. package/dist/core/config.js +136 -0
  16. package/dist/core/confirm.js +43 -0
  17. package/dist/core/connection.js +159 -0
  18. package/dist/core/credentials.js +44 -0
  19. package/dist/core/datapolicy.js +175 -0
  20. package/dist/core/diff.js +115 -0
  21. package/dist/core/edits.js +31 -0
  22. package/dist/core/errors.js +68 -0
  23. package/dist/core/feeds.js +60 -0
  24. package/dist/core/notes.js +18 -0
  25. package/dist/core/objects.js +143 -0
  26. package/dist/core/output.js +27 -0
  27. package/dist/core/policy.js +126 -0
  28. package/dist/core/prompts.js +89 -0
  29. package/dist/core/registry.js +316 -0
  30. package/dist/core/revisions.js +97 -0
  31. package/dist/core/sidecar.js +85 -0
  32. package/dist/core/sql.js +54 -0
  33. package/dist/core/telemetry.js +42 -0
  34. package/dist/core/tool.js +5 -0
  35. package/dist/core/transport.js +109 -0
  36. package/dist/index.js +55 -0
  37. package/dist/scripts/audit-verify.js +19 -0
  38. package/dist/scripts/smoke.js +87 -0
  39. package/dist/tools/core/activate.js +27 -0
  40. package/dist/tools/core/api_release_state.js +58 -0
  41. package/dist/tools/core/atc_quickfix.js +159 -0
  42. package/dist/tools/core/co_change.js +73 -0
  43. package/dist/tools/core/create_transport.js +44 -0
  44. package/dist/tools/core/ddic_type_info.js +81 -0
  45. package/dist/tools/core/dumps.js +55 -0
  46. package/dist/tools/core/edit_preflight.js +112 -0
  47. package/dist/tools/core/function_modules.js +75 -0
  48. package/dist/tools/core/gateway_errors.js +45 -0
  49. package/dist/tools/core/get_source.js +70 -0
  50. package/dist/tools/core/inactive_objects.js +29 -0
  51. package/dist/tools/core/object_versions.js +35 -0
  52. package/dist/tools/core/package_contents.js +59 -0
  53. package/dist/tools/core/run_atc.js +117 -0
  54. package/dist/tools/core/run_unit_tests.js +60 -0
  55. package/dist/tools/core/search_objects.js +26 -0
  56. package/dist/tools/core/sql_query.js +25 -0
  57. package/dist/tools/core/support.js +95 -0
  58. package/dist/tools/core/syntax_check.js +35 -0
  59. package/dist/tools/core/table_contents.js +57 -0
  60. package/dist/tools/core/text_elements.js +108 -0
  61. package/dist/tools/core/transaction_info.js +43 -0
  62. package/dist/tools/core/transport_contents.js +49 -0
  63. package/dist/tools/core/transport_diff.js +111 -0
  64. package/dist/tools/core/where_used.js +37 -0
  65. package/dist/tools/core/write_source.js +95 -0
  66. package/dist/tools/docs/docs.js +159 -0
  67. package/dist/tools/local/growth.js +104 -0
  68. package/dist/tools/local/sap_systems.js +65 -0
  69. package/dist/tools/transport-risk/_service.js +63 -0
  70. package/dist/tools/transport-risk/risk_extras.js +90 -0
  71. package/dist/tools/transport-risk/transport_risk.js +42 -0
  72. package/docs/THREAT_MODEL.md +70 -0
  73. package/docs/TOOLS.md +980 -0
  74. package/package.json +68 -0
  75. package/scripts/set-password.sh +31 -0
@@ -0,0 +1,90 @@
1
+ import { z } from "zod";
2
+ import { assertTrkorr } from "../../core/policy.js";
3
+ import { defineTool } from "../../core/tool.js";
4
+ import { callRiskService, RISK_MODULE, sidParam } from "./_service.js";
5
+ /**
6
+ * El resto de modos del servicio /sap/bc/zdz_risk (DoZimple Transport Risk).
7
+ * Todos son de solo lectura y devuelven JSON.
8
+ */
9
+ const months = z.number().int().min(0).max(120).optional().describe("Ventana en meses; 0 = todo el historial");
10
+ const importHealth = defineTool({
11
+ name: "import_health",
12
+ title: "Salud de importaciones",
13
+ description: "Salud de las importaciones de un destino (calidad o productivo): responde «¿cómo van los pases a productivo?». " +
14
+ "Códigos de retorno: 0 limpio, 4 avisos (normal), ≥8 errores.",
15
+ access: "read",
16
+ requires: { module: RISK_MODULE },
17
+ input: { target: sidParam("Destino a revisar"), max: z.number().int().min(1).max(500).optional() },
18
+ run: ({ target, max }, { system }) => callRiskService(system, { mode: "DEV", health: target, max: max?.toString() }),
19
+ });
20
+ const failureRanking = defineTool({
21
+ name: "failure_ranking",
22
+ title: "Objetos que más fallan al importar",
23
+ description: "Ranking de objetos por historial de fallos de importación en un destino. Sirve para saber qué objetos " +
24
+ "vigilar en un pase y dónde se concentra el riesgo.",
25
+ access: "read",
26
+ requires: { module: RISK_MODULE },
27
+ input: { target: sidParam("Destino"), months },
28
+ run: ({ target, months: m }, { system }) => callRiskService(system, { mode: "DEV", ranking: target, months: m?.toString() }),
29
+ });
30
+ const changeAudit = defineTool({
31
+ name: "change_audit",
32
+ title: "Evidencia de auditoría de cambios",
33
+ description: "Evidencia para una auditoría de gestión de cambios en un destino: qué entró, con qué ticket, de qué " +
34
+ "iniciativa y origen. `tickets`, `iniciativas` y `origenes` son lo que la organización declara y el sistema no " +
35
+ "puede deducir (p. ej. tickets «CHG,INC,^RFC»; iniciativas «10001=Proyecto demo,^BC=Basis»).",
36
+ access: "read",
37
+ requires: { module: RISK_MODULE },
38
+ input: {
39
+ target: sidParam("Destino auditado"),
40
+ months,
41
+ tickets: z.string().optional(),
42
+ iniciativas: z.string().optional(),
43
+ origenes: z.string().optional(),
44
+ },
45
+ run: (a, { system }) => callRiskService(system, {
46
+ mode: "DEV",
47
+ audit: a.target,
48
+ months: a.months?.toString(),
49
+ tickets: a.tickets,
50
+ iniciativas: a.iniciativas,
51
+ origenes: a.origenes,
52
+ }),
53
+ });
54
+ const objectHistory = defineTool({
55
+ name: "object_transport_history",
56
+ title: "Historial de transportes de un objeto",
57
+ description: "Qué órdenes han tocado un objeto, cuándo, y cuáles llegaron ya al destino. Útil para «¿esto ya está en productivo?» " +
58
+ "y para encontrar la orden que introdujo un cambio.",
59
+ access: "read",
60
+ requires: { module: RISK_MODULE },
61
+ input: {
62
+ object: z.string().min(1).describe("Nombre del objeto"),
63
+ object_type: z.string().optional().describe("Tipo E071 (REPS, CLAS, FUNC, TABL…). Por defecto REPS"),
64
+ target: sidParam("Destino contra el que mirar qué llegó"),
65
+ },
66
+ run: ({ object, object_type, target }, { system }) => callRiskService(system, { mode: "DEV", history: target, object: object.toUpperCase(), type: object_type?.toUpperCase() }),
67
+ });
68
+ const remoteSource = defineTool({
69
+ name: "remote_source",
70
+ title: "Fuente en el destino",
71
+ description: "La fuente de un objeto TAL COMO ESTÁ en calidad o productivo, leída por el canal de TMS (como «Traer versiones remotas»). " +
72
+ "Compárala con get_source en DEV para ver qué cambia de verdad con un pase.",
73
+ access: "read",
74
+ requires: { module: RISK_MODULE },
75
+ input: { object: z.string().min(1), target: sidParam("Sistema del que traer la fuente") },
76
+ run: ({ object, target }, { system }) => callRiskService(system, { mode: "DEV", remote_source: target, object: object.toUpperCase() }),
77
+ });
78
+ const sourceCheck = defineTool({
79
+ name: "transport_source_check",
80
+ title: "Código de una orden contra el destino",
81
+ description: "Compara el código de los objetos de una orden con el del destino: objetos que no existen allí (R3.4) y deriva " +
82
+ "de versión — firmas, campos o parámetros distintos que no viajan en la orden (R3.5). Necesita el agente en el " +
83
+ "destino con S_RFC: si viene `comprobaciones_fallidas`, NO se comprobó (no es «sin riesgos»).",
84
+ access: "read",
85
+ requires: { module: RISK_MODULE },
86
+ input: { transport_id: z.string(), target: sidParam("Destino") },
87
+ run: ({ transport_id, target }, { system }) => callRiskService(system, { mode: "DEV", srccheck: target, trkorr: assertTrkorr(transport_id, "transport_id") }),
88
+ });
89
+ export default [importHealth, failureRanking, changeAudit, objectHistory, remoteSource, sourceCheck];
90
+ //# sourceMappingURL=risk_extras.js.map
@@ -0,0 +1,42 @@
1
+ import { z } from "zod";
2
+ import { ToolError } from "../../core/errors.js";
3
+ import { defineTool } from "../../core/tool.js";
4
+ import { callRiskService, RISK_MODULE, sidParam } from "./_service.js";
5
+ /** Analizador de riesgo de transportes (DoZimple Transport Risk). */
6
+ export default defineTool({
7
+ name: "analyze_transport_risk",
8
+ title: "Riesgo de transporte",
9
+ description: "Dice si una orden (o un pase de varias, separadas por coma) es segura para pasar a calidad o productivo: tareas " +
10
+ "sin liberar, estado de importación, dependencias que no viajan, acceso posicional, bloqueos del CTS, cola de " +
11
+ "importación. Primera llamada siempre sin include_source. Un pase se analiza junto, no orden a orden. " +
12
+ "Con queue_system analiza la cola completa de un destino.",
13
+ access: "read",
14
+ requires: { module: RISK_MODULE },
15
+ input: {
16
+ transport_id: z.string().optional().describe("Orden o lista separada por coma: DEVK900123,DEVK900124"),
17
+ check_mode: sidParam("Contra qué sistema comparar: DEV (el propio) o el SID del destino. Si el usuario no lo dice, pregúntalo").default("DEV"),
18
+ include_source: z.boolean().default(false),
19
+ include_where_used: z.boolean().default(false).describe("Solo si la orden lleva tablas o estructuras: es lo más caro"),
20
+ queue_system: sidParam("Analizar la cola de importación de este destino en vez de órdenes").optional(),
21
+ queue_max: z.number().int().min(1).optional(),
22
+ },
23
+ async run(args, { system }) {
24
+ const ids = String(args.transport_id ?? "")
25
+ .split(/[,;\s]+/)
26
+ .map((t) => t.trim().toUpperCase())
27
+ .filter(Boolean)
28
+ .join(",");
29
+ if (args.queue_system) {
30
+ return callRiskService(system, { mode: args.check_mode, queue: args.queue_system, max: args.queue_max?.toString() });
31
+ }
32
+ if (!ids)
33
+ throw new ToolError("INPUT", "Indica transport_id, o queue_system para analizar la cola de un destino.");
34
+ return callRiskService(system, {
35
+ mode: args.check_mode,
36
+ trkorr: ids,
37
+ source: args.include_source ? "X" : undefined,
38
+ where_used: args.include_where_used ? "X" : undefined,
39
+ });
40
+ },
41
+ });
42
+ //# sourceMappingURL=transport_risk.js.map
@@ -0,0 +1,70 @@
1
+ # Modelo de amenazas — abap-adt-doZimple
2
+
3
+ Resumen de controles: [SECURITY.md](../SECURITY.md). Este documento explica **contra qué** se diseñaron y **qué
4
+ queda fuera**.
5
+
6
+ ## Alcance y fronteras de confianza
7
+
8
+ ```mermaid
9
+ flowchart LR
10
+ U["Persona usuaria"] --> C["Cliente MCP<br/>(Claude Code, Kiro…)"]
11
+ C -- "stdio" --> S["abap-adt-doZimple<br/>(proceso local)"]
12
+ S -- "HTTPS + usuario SAP personal" --> SAP["Sistemas SAP<br/>DEV / QAS / PRD"]
13
+ S -- "stdio, entorno mínimo" --> D["Componente de documentación<br/>(proceso aislado)"]
14
+ D -. "solo si allowOnline y la consulta pasa el filtro" .-> W["Documentación pública"]
15
+ S --> K["Llavero del SO"]
16
+ S --> L["Estado local 700/600<br/>uso · huecos · auditoría"]
17
+ ```
18
+
19
+ | Frontera | Qué la cruza | Supuesto |
20
+ |---|---|---|
21
+ | Cliente ↔ servidor | Llamadas a tools y sus respuestas | El modelo **no es de confianza**: puede equivocarse o haber sido manipulado por contenido que leyó |
22
+ | Servidor ↔ SAP | Lecturas y, en DEV habilitado, escrituras | Las autorizaciones SAP del usuario son el límite superior; el servidor solo resta |
23
+ | Servidor ↔ componente de documentación | Consultas conceptuales | El componente es código de terceros: sin credenciales, sin entorno, filtrado |
24
+ | Servidor ↔ internet | Solo consultas de documentación filtradas | Nada del cliente sale; el contenido que entra es no confiable |
25
+ | Equipo local | Configuración, llavero, registros | El equipo y la cuenta del usuario están bajo control del usuario |
26
+
27
+ ## STRIDE
28
+
29
+ | Amenaza | Escenario | Control | Residual |
30
+ |---|---|---|---|
31
+ | **S**uplantación | Otro proceso lee la contraseña del llavero | Llavero del SO; `--strict` (opt-in) exige confirmación en cada lectura | Sin `--strict`, un proceso del mismo usuario que invoque `security` puede leerla. Solución de raíz prevista: certificado de cliente / SSO (roadmap) |
32
+ | **S**uplantación | TLS interceptado | Verificación TLS; `caFile` | `allowSelfSigned` sigue existiendo como último recurso, marcado |
33
+ | **T**ampering | Cambiar `systems.json` para habilitar escritura o redirigir a otro host | Rechazo si es modificable por otros o de otro usuario | Un proceso del propio usuario puede modificarlo |
34
+ | **T**ampering | Retocar el registro de auditoría | Cadena de hash verificable | Un atacante con la cuenta del usuario puede reescribir la cadena entera; para evidencia fuerte, enviar el registro a un almacén externo (ver roadmap) |
35
+ | **R**epudio | «La IA lo cambió sola» o «no hay constancia de ese cambio» | Confirmación humana con vista previa + auditoría con forma de confirmación y huella del contenido. **Fail-closed**: la intención se registra antes de tocar SAP, y si no se puede registrar (disco lleno, permiso denegado, ruta inválida) la escritura no se ejecuta. Si lo que falla es solo el registro del resultado, la respuesta lo avisa explícitamente. Cubierto por tests que simulan ENOSPC y EACCES | El registro es local; un corte de energía entre intención y resultado deja una intención sin resultado, que se interpreta como «estado desconocido, verificar en SAP» |
36
+ | **I**nformation disclosure | Leer hashes, almacén seguro, PSE, OAuth, dumps | Veto directo y a través de vistas y CDS | Tablas Z que copien esos datos no se detectan por nombre |
37
+ | **I**nformation disclosure | Volcar datos personales al proveedor LLM | Clase de datos, enmascarado, tope de filas | Columnas personales con nombres no estándar (Z) no se enmascaran; el tope limita el volumen |
38
+ | **I**nformation disclosure | Nombres de cliente u objetos Z hacia internet | Online apagado; filtro de consultas e ids | Un concepto puede describir un proceso de negocio sin nombrarlo |
39
+ | **D**enegación de servicio | Consultas enormes o bucles del agente contra SAP | Topes de filas, de salida (80k) y de objetos; timeouts | Un where-used masivo sigue costando ~1 min al servidor SAP |
40
+ | **E**levación de privilegios | Escribir en QAS/PRD o ejecutar código fuera de DEV | Política por rol independiente de la configuración de escritura | — |
41
+ | **E**levación de privilegios | Test ABAP Unit peligroso | Solo HARMLESS / SHORT | Un test mal clasificado por su autor como HARMLESS |
42
+
43
+ ## OWASP Top 10 para aplicaciones LLM (2025)
44
+
45
+ | Riesgo | Cómo aplica a un MCP de SAP | Control |
46
+ |---|---|---|
47
+ | LLM01 Prompt injection | Comentarios en fuente ABAP, textos, datos de tablas, documentación o posts de comunidad con instrucciones | Marca de «dato, nunca instrucciones» en toda respuesta; ninguna escritura sin confirmación humana; tools de escritura destructivas para el cliente |
48
+ | LLM02 Divulgación de información sensible | Datos personales y material de seguridad en respuestas que llegan al proveedor | Vetos, enmascarado, tope de filas, filtro de salida a internet |
49
+ | LLM03 Cadena de suministro | Dependencias npm, MCP de terceros | Versiones exactas, firmas, SBOM, `ignore-scripts`, terceros aislados tras revisión |
50
+ | LLM05 Manejo inadecuado de la salida | El agente usa una respuesta como si fuera verdad | Errores tipados que nunca parecen vacíos; «tope alcanzado» explícito; calidad de la evidencia en diffs |
51
+ | LLM06 Agencia excesiva | El agente escribe, activa o crea órdenes por su cuenta | Mínimo privilegio por tool y rol; escritura desactivada por defecto; confirmación con vista previa; sin liberar, importar ni borrar |
52
+ | LLM07 Filtrado del prompt de sistema | — | El servidor no tiene prompts secretos; las recetas guiadas son públicas |
53
+ | LLM08 Debilidades de vectores y embeddings | Índice local de documentación | Solo documentación pública; ningún dato del cliente se indexa |
54
+ | LLM09 Desinformación | Afirmar que algo está en productivo sin comprobarlo | Honestidad de errores; comprobación real contra SAP (sintaxis, versiones, cola de importación) |
55
+ | LLM10 Consumo sin límites | Respuestas enormes, bucles | Topes de salida, filas y objetos |
56
+
57
+ ## Fuera de alcance
58
+
59
+ - Compromiso de la cuenta del usuario o del equipo.
60
+ - Autorizaciones SAP mal diseñadas: el servidor no las sustituye.
61
+ - Lo que el proveedor del modelo haga con las respuestas: se reduce lo que se le envía, no se controla su lado.
62
+ - Transportes y cambios hechos fuera de este servidor (SE80, Eclipse, abap-fs).
63
+
64
+ ## Roadmap de seguridad
65
+
66
+ - **Autenticación sin contraseña reutilizable** (Sprint 2): certificado de cliente X.509 y SSO (SAML / principal
67
+ propagation) hacia ADT, para que no exista un secreto que leer del llavero.
68
+ - Envío opcional del registro de auditoría a un almacén externo o SIEM (append-only fuera del equipo).
69
+ - Diccionario de columnas personales ampliable por configuración (campos Z).
70
+ - Firma de las versiones publicadas (procedencia npm / Sigstore) si se distribuye como paquete.