<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rodriguez Patrick</title>
    <description>The latest articles on DEV Community by Rodriguez Patrick (@dejameingresar).</description>
    <link>https://dev.to/dejameingresar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160479%2Ff9daea6f-ff33-446e-9e40-4ce41fe8e1ea.jpg</url>
      <title>DEV Community: Rodriguez Patrick</title>
      <link>https://dev.to/dejameingresar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dejameingresar"/>
    <language>en</language>
    <item>
      <title>Detectar vulnerabilidades en Go con gosec</title>
      <dc:creator>Rodriguez Patrick</dc:creator>
      <pubDate>Sun, 04 Oct 2026 01:44:36 +0000</pubDate>
      <link>https://dev.to/dejameingresar/detectar-vulnerabilidades-en-go-con-gosec-2h46</link>
      <guid>https://dev.to/dejameingresar/detectar-vulnerabilidades-en-go-con-gosec-2h46</guid>
      <description>&lt;p&gt;En los laboratorios analizamos el código de una aplicación con SonarCloud,&lt;br&gt;
Snyk y Semgrep. En este ejercicio el punto de mira es el mismo código fuente,&lt;br&gt;
pero con una herramienta que no usamos en los labs: &lt;strong&gt;gosec&lt;/strong&gt;, el analizador&lt;br&gt;
estático estándar del ecosistema de Go, que publica reglas mapeadas a CWE de&lt;br&gt;
la OWASP.&lt;/p&gt;

&lt;p&gt;Para demostrar que la herramienta funciona de verdad, la aplicamos a una&lt;br&gt;
aplicación escrita a propósito con los fallos más comunes. El resultado son&lt;br&gt;
&lt;strong&gt;17 hallazgos&lt;/strong&gt;, cinco de ellos de severidad alta.&lt;/p&gt;


&lt;h2&gt;
  
  
  La idea detrás de gosec
&lt;/h2&gt;

&lt;p&gt;gosec analiza el código buscando patrones que se sabe que son peligrosos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;credenciales o claves privadas escritas en el fuente&lt;/li&gt;
&lt;li&gt;comandos del sistema construidos con variables&lt;/li&gt;
&lt;li&gt;rutas de archivo tomadas de entrada externa&lt;/li&gt;
&lt;li&gt;algoritmos de hash débiles&lt;/li&gt;
&lt;li&gt;consultas SQL por concatenación de cadenas&lt;/li&gt;
&lt;li&gt;redirecciones y plantillas construidas con datos del usuario&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cada regla tiene un identificador (&lt;code&gt;G###&lt;/code&gt;), una severidad y un CWE asociado,&lt;br&gt;
así que el resultado se puede mapear a lo que exige la norma y no quedarse en&lt;br&gt;
un "algo está mal aquí".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSfL&lt;/span&gt; https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh
gosec &lt;span class="nt"&gt;-no-fail&lt;/span&gt; &lt;span class="nt"&gt;-fmt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;json &lt;span class="nt"&gt;-out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;informe.json ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Un detalle que puede arruinar el resultado: gosec necesita el compilador de Go&lt;br&gt;
instalado. Sin él termina sin errores y reporta &lt;code&gt;Files: 0&lt;/code&gt;, lo que parece un&lt;br&gt;
escaneo limpio cuando en realidad no analysó nada.&lt;/p&gt;
&lt;h2&gt;
  
  
  La aplicación de prueba
&lt;/h2&gt;

&lt;p&gt;Es un servidor web pequeño, en un solo archivo, con seis rutas. Cada una contiene&lt;br&gt;
un fallo deliberado:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ruta&lt;/th&gt;
&lt;th&gt;Fallo introducido&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/saludo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;plantilla HTML sin escapar y redirección con datos del usuario&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/descarga&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;escritura en ruta construida sin restringir&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/archivo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;lectura de archivo con ruta de la petición&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/token&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;secreto concatenado sin validar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/tipo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;comando del sistema con valor del usuario&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/hash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;MD5 y SHA1 para derivar contraseñas&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No está publicada en ningún servicio y no debe usarse con datos reales. Es un&lt;br&gt;
caso de estudio, no una aplicación de producción.&lt;/p&gt;
&lt;h2&gt;
  
  
  Los 17 hallazgos
&lt;/h2&gt;

&lt;p&gt;Resultado real de &lt;code&gt;gosec -no-fail -fmt=json&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Severidad&lt;/th&gt;
&lt;th&gt;Regla&lt;/th&gt;
&lt;th&gt;Línea&lt;/th&gt;
&lt;th&gt;Hallazgo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;G101&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;Credencial escrita en el código&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;G101&lt;/td&gt;
&lt;td&gt;33-35&lt;/td&gt;
&lt;td&gt;Clave privada RSA embebida&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;G702&lt;/td&gt;
&lt;td&gt;39&lt;/td&gt;
&lt;td&gt;Inyección de comandos por análisis de taint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;G703&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;Recorrido de rutas por análisis de taint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;G703&lt;/td&gt;
&lt;td&gt;51&lt;/td&gt;
&lt;td&gt;Recorrido de rutas por análisis de taint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;G112&lt;/td&gt;
&lt;td&gt;138-143&lt;/td&gt;
&lt;td&gt;Slowloris: falta &lt;code&gt;ReadHeaderTimeout&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;G202&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;td&gt;Concatenación de cadenas en SQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;G204&lt;/td&gt;
&lt;td&gt;39&lt;/td&gt;
&lt;td&gt;Subproceso lanzado con variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;G304&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;Inclusión de archivo vía variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;G401&lt;/td&gt;
&lt;td&gt;70-71&lt;/td&gt;
&lt;td&gt;Primitiva criptográfica débil&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;G401&lt;/td&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;td&gt;Primitiva criptográfica débil&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;G501&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;Import bloqueado &lt;code&gt;crypto/md5&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;G505&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;Import bloqueado &lt;code&gt;crypto/sha1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;G705&lt;/td&gt;
&lt;td&gt;117&lt;/td&gt;
&lt;td&gt;XSS por análisis de taint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;G705&lt;/td&gt;
&lt;td&gt;122&lt;/td&gt;
&lt;td&gt;XSS por análisis de taint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;G710&lt;/td&gt;
&lt;td&gt;77&lt;/td&gt;
&lt;td&gt;Redirección abierta por análisis de taint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LOW&lt;/td&gt;
&lt;td&gt;G104&lt;/td&gt;
&lt;td&gt;117&lt;/td&gt;
&lt;td&gt;Errores sin manejar&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Resumen:&lt;/strong&gt; 5 HIGH, 11 MEDIUM, 1 LOW. 17 en total.&lt;/p&gt;
&lt;h2&gt;
  
  
  Lo que las reglas de taint aportan
&lt;/h2&gt;

&lt;p&gt;Cuatro de los hallazgos (G702, G703, G705, G710) no vienen de buscar una palabra&lt;br&gt;
clave: gosec sigue el valor desde que entra en la función hasta donde se usa.&lt;/p&gt;

&lt;p&gt;En &lt;code&gt;/tipo&lt;/code&gt;, el valor de &lt;code&gt;mime&lt;/code&gt; llega de &lt;code&gt;r.URL.Query().Get("mime")&lt;/code&gt; y acaba como&lt;br&gt;
argumento de &lt;code&gt;exec.Command&lt;/code&gt;. G204 lo marca como "subproceso con variable", que es&lt;br&gt;
correcto pero genérico. &lt;strong&gt;G702 lo marca como inyección de comandos&lt;/strong&gt;, porque&lt;br&gt;
sabe que ese valor no se ha validado. La misma línea, dos reglas, y la segunda&lt;br&gt;
es la que dice qué hacer.&lt;/p&gt;

&lt;p&gt;Lo mismo con G703: &lt;code&gt;G304&lt;/code&gt; dice "inclusión de archivo vía variable", y &lt;strong&gt;G703 dice&lt;br&gt;
recorrido de rutas&lt;/strong&gt;, siguiendo que &lt;code&gt;ruta&lt;/code&gt; viene de la petición sin comprobar.&lt;/p&gt;

&lt;p&gt;Es la diferencia entre un filtro por patrón y un análisis de flujo de datos.&lt;/p&gt;
&lt;h2&gt;
  
  
  Integrarlo en la automatización
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gosec&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;gosec -no-fail -fmt=json -out=gosec.json ./...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;-no-fail&lt;/code&gt; deja que el escaneo termine y muestre el informe completo. Para que&lt;br&gt;
el pipeline falle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gosec ./... &lt;span class="nt"&gt;-severity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;HIGH           &lt;span class="c"&gt;# falla si hay hallazgos altos&lt;/span&gt;
gosec &lt;span class="nt"&gt;-no-fail&lt;/span&gt; ./... &lt;span class="nt"&gt;-severity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;HIGH  &lt;span class="c"&gt;# solo informa&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para un error justificado hay una directiva en la misma línea:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ruta&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;validarComoInterno&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ruta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// #nosec G304 -- ya sanitizada arriba&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La convención es no abusar de ella: cada &lt;code&gt;#nosec&lt;/code&gt; es una excepción que alguien&lt;br&gt;
tiene que leer y justificar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sobre los falsos negativos
&lt;/h2&gt;

&lt;p&gt;gosec analiza el flujo de información dentro del archivo y entre archivos del&lt;br&gt;
mismo paquete. Hay casos que se le escapan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lógica de negocio incorrecta&lt;/strong&gt; sin ningún patrón peligroso.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vulnerabilidades en dependencias&lt;/strong&gt;, que es otro problema: para eso está
OWASP Dependency-Check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Código generado automáticamente&lt;/strong&gt;, que normalmente no se revisa.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Otro lenguaje&lt;/strong&gt;: gosec solo analiza Go.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El informe incluye el CWE de cada hallazgo, que permite priorizar por lo que la&lt;br&gt;
norma exige y no por la severidad que le asigne la herramienta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;El ejercicio deja un resultado concreto: 17 hallazgos correctamente&lt;br&gt;
clasificados, cinco de ellos de severidad alta, sobre una aplicación escrita&lt;br&gt;
para contenerlos.&lt;/p&gt;

&lt;p&gt;Lo que demuestra el análisis de taint es lo más aprovechable. Una herramienta&lt;br&gt;
que dice "aquí hay un &lt;code&gt;exec.Command&lt;/code&gt; con variable" obliga a revisar; una que&lt;br&gt;
dice "el valor llega desde la petición sin validar" dice cuál es el problema.&lt;/p&gt;

&lt;p&gt;Ningún análisis estático sustituye a revisar el diseño, y un resultado limpio&lt;br&gt;
no significa que el código sea correcto: significa que esta herramienta no&lt;br&gt;
encontró nada. La diferencia entre las dos afirmaciones es la que hace que un&lt;br&gt;
informe sirva para algo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enlaces
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Repositorio con el código y el informe: &lt;a href="https://github.com/UPT-FAING-EPIS/si784-2026-ii-si784-2026-ii-examen-u1-dejameingresar" rel="noopener noreferrer"&gt;https://github.com/UPT-FAING-EPIS/si784-2026-ii-si784-2026-ii-examen-u1-dejameingresar&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;gosec: &lt;a href="https://github.com/securego/gosec" rel="noopener noreferrer"&gt;https://github.com/securego/gosec&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CWE de la OWASP: &lt;a href="https://cwe.mitre.org/" rel="noopener noreferrer"&gt;https://cwe.mitre.org/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>gosec</category>
      <category>go</category>
      <category>staticanalysis</category>
    </item>
    <item>
      <title>Auditar dependencias con OWASP Dependency-Check</title>
      <dc:creator>Rodriguez Patrick</dc:creator>
      <pubDate>Sun, 04 Oct 2026 01:43:35 +0000</pubDate>
      <link>https://dev.to/dejameingresar/auditar-dependencias-con-owasp-dependency-check-ei8</link>
      <guid>https://dev.to/dejameingresar/auditar-dependencias-con-owasp-dependency-check-ei8</guid>
      <description>&lt;p&gt;En los laboratorios anteriores revisamos el código con SonarCloud, Snyk y&lt;br&gt;
Semgrep. Pero ese código se apoya en cientos de librerías de terceros que nadie&lt;br&gt;
del equipo escribió ni revisó. Esta vez cambiamos el punto de mira: en lugar del&lt;br&gt;
código propio, analizamos &lt;strong&gt;las dependencias&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;La herramienta es &lt;a href="https://owasp.org/www-project-dependency-check/" rel="noopener noreferrer"&gt;OWASP Dependency-Check&lt;/a&gt;,&lt;br&gt;
del OWASP Foundation, y su criterio es la base de datos de avisos que la propia&lt;br&gt;
fundación mantiene.&lt;/p&gt;


&lt;h2&gt;
  
  
  El problema
&lt;/h2&gt;

&lt;p&gt;Cuando escribes &lt;code&gt;dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL&lt;/code&gt;, lo&lt;br&gt;
que llega a tu proyecto son decenas de paquetes transitivos. Cada uno es código&lt;br&gt;
de otra persona que se ejecuta con los privilegios de tu aplicación.&lt;/p&gt;

&lt;p&gt;Una dependencia vulnerable no se ve leyendo tu repositorio. Se ve consultando&lt;br&gt;
qué versiones publicadas tienen avisos de seguridad asociados.&lt;/p&gt;
&lt;h2&gt;
  
  
  Qué revisamos
&lt;/h2&gt;

&lt;p&gt;El proyecto de ejemplo es una API en ASP.NET Core 8 con PostgreSQL. Su grafo de&lt;br&gt;
dependencias tiene &lt;strong&gt;20 paquetes transitivos&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Microsoft.EntityFrameworkCore                8.0.10
Npgsql.EntityFrameworkCore.PostgreSQL        8.0.10
Microsoft.AspNetCore.Authentication.JwtBearer 8.0.10
Swashbuckle.AspNetCore                       6.9.0
Microsoft.IdentityModel.Tokens               7.1.2
Npgsql                                       8.0.5
System.Collections.Immutable                 6.0.0
... (14 más)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La herramienta de NuGet consulta esa misma base de vulnerabilidades:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet list TaskFlow.Api/TaskFlow.Api.csproj package &lt;span class="se"&gt;\&lt;/span&gt;
                 &lt;span class="nt"&gt;--include-transitive&lt;/span&gt; &lt;span class="nt"&gt;--vulnerable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The given project `TaskFlow.Api` has no vulnerable packages
given the current sources.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cero vulnerabilidades conocidas&lt;/strong&gt; en el grafo completo, incluidas las&lt;br&gt;
dependencias transitivas.&lt;/p&gt;
&lt;h2&gt;
  
  
  La herramienta de la OWASP
&lt;/h2&gt;

&lt;p&gt;Dependency-Check hace lo mismo pero con su propia base de datos, que es la&lt;br&gt;
Daily CVE Project de la OWASP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dependency-check &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="s2"&gt;"TaskFlow API"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                 &lt;span class="nt"&gt;--scan&lt;/span&gt; TaskFlow.Api &lt;span class="se"&gt;\&lt;/span&gt;
                 &lt;span class="nt"&gt;--out&lt;/span&gt; informes/dependencias &lt;span class="se"&gt;\&lt;/span&gt;
                 &lt;span class="nt"&gt;--format&lt;/span&gt; HTML &lt;span class="nt"&gt;--format&lt;/span&gt; SARIF &lt;span class="se"&gt;\&lt;/span&gt;
                 &lt;span class="nt"&gt;--failOnCVSS&lt;/span&gt; 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dos diferencias con la herramienta de NuGet:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La base es de la OWASP, no de NuGet.&lt;/strong&gt; NuGet solo conoce los paquetes que él&lt;br&gt;
publica; Dependency-Check también cubre registros privados y otras fuentes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Puede generar SARIF&lt;/strong&gt;, que GitHub interpreta y muestra anotado en el pull&lt;br&gt;
request. Eso convierte un informe que nadie lee en algo que se ve al revisar el&lt;br&gt;
cambio.&lt;/p&gt;

&lt;h3&gt;
  
  
  Una nota sobre el tiempo de la primera ejecución
&lt;/h3&gt;

&lt;p&gt;La base de avisos de la NVD contiene, a la fecha, más de &lt;strong&gt;400.000 registros&lt;/strong&gt;.&lt;br&gt;
Sin una API key de la NVD, la descarga inicial tarda varias horas. Con una key&lt;br&gt;
—gratuita— baja a minutos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nvd.nist.gov/developers/request-an-api-key" rel="noopener noreferrer"&gt;https://nvd.nist.gov/developers/request-an-api-key&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Las ejecuciones siguientes usan la copia en caché. Por eso el escaneo va&lt;br&gt;
programado en el pipeline y no como un paso manual.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cómo se integra en la automatización
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OWASP Dependency-Check&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;dependency-check \&lt;/span&gt;
      &lt;span class="s"&gt;--project "TaskFlow API" \&lt;/span&gt;
      &lt;span class="s"&gt;--scan TaskFlow.Api \&lt;/span&gt;
      &lt;span class="s"&gt;--out ./informes/dependencias \&lt;/span&gt;
      &lt;span class="s"&gt;--format HTML \&lt;/span&gt;
      &lt;span class="s"&gt;--format SARIF \&lt;/span&gt;
      &lt;span class="s"&gt;--data ~/.gradle/caches \&lt;/span&gt;
      &lt;span class="s"&gt;--failOnCVSS 7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tres decisiones:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;--failOnCVSS 7&lt;/code&gt;.&lt;/strong&gt; El escenario falla solo ante vulnerabilidades altas o&lt;br&gt;
críticas. Un aviso medio en una dependencia transitiva no debe bloquear un&lt;br&gt;
push; uno crítico sí.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;--format SARIF&lt;/code&gt;.&lt;/strong&gt; El resultado se sube a GitHub Security y aparece anotado&lt;br&gt;
en el diff del pull request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ejecución semanal.&lt;/strong&gt; La base de avisos cambia a diario: una vulnerabilidad&lt;br&gt;
puede publicarse después del último push. El workflow tiene un &lt;code&gt;cron&lt;/code&gt; semanal&lt;br&gt;
además del disparo por &lt;code&gt;push&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitación honesta
&lt;/h2&gt;

&lt;p&gt;Un escaneo de dependencias solo ve lo que la base de datos conoce. Tres casos se&lt;br&gt;
le escapan:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Paquetes sin CVE.&lt;/strong&gt; Una vulnerabilidad nueva o todavía sin CVE publicado
no aparece. Queda una ventana de días o semanas entre la publicación del
fallo y su registro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vulnerabilidades de lógica.&lt;/strong&gt; Que un paquete no tenga CVE no significa que
su uso sea correcto. Un ORM con inyección SQL es un paquete limpio usado mal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolución distinta a la esperada.&lt;/strong&gt; Si el paquete se instala desde un
registro privado o un mirror, la resolución puede diferir de lo que el
análisis asume.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Por eso el escaneo de dependencias no reemplaza al análisis de código. Cubren&lt;br&gt;
cosas distintas y ambos hacen falta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Cero vulnerabilidades conocidas en 20 paquetes transitivos no significa que el&lt;br&gt;
proyecto esté libre de ellas. Lo que sí sabemos es concreto: se consultó la base&lt;br&gt;
de avisos y no encontró nada, y eso se puede volver a comprobar en cada push.&lt;/p&gt;

&lt;p&gt;El valor de la automatización no está en el primer resultado, sino en que el&lt;br&gt;
mismo control se repite sin que nadie tenga que acordarse de ejecutarlo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enlaces
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Repositorio: &lt;a href="https://github.com/UPT-FAING-EPIS/si784-2026-ii-si784-2026-ii-examen-u1-dejameingresar" rel="noopener noreferrer"&gt;https://github.com/UPT-FAING-EPIS/si784-2026-ii-si784-2026-ii-examen-u1-dejameingresar&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OWASP Dependency-Check: &lt;a href="https://owasp.org/www-project-dependency-check/" rel="noopener noreferrer"&gt;https://owasp.org/www-project-dependency-check/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Base de datos OWASP: &lt;a href="https://github.com/dependency-check/DependencyCheck" rel="noopener noreferrer"&gt;https://github.com/dependency-check/DependencyCheck&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>owasp</category>
      <category>dependencycheck</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Seis estrategias de respaldo para bases de datos NoSQL, y qué falla de verdad</title>
      <dc:creator>Rodriguez Patrick</dc:creator>
      <pubDate>Sun, 04 Oct 2026 01:03:50 +0000</pubDate>
      <link>https://dev.to/dejameingresar/seis-estrategias-de-respaldo-para-bases-de-datos-nosql-y-que-falla-de-verdad-5hce</link>
      <guid>https://dev.to/dejameingresar/seis-estrategias-de-respaldo-para-bases-de-datos-nosql-y-que-falla-de-verdad-5hce</guid>
      <description>&lt;h1&gt;
  
  
  Seis estrategias de respaldo para bases de datos NoSQL, y qué falla de verdad
&lt;/h1&gt;

&lt;p&gt;No uso MS SQL Server: el enunciado lo excluye y, además, el problema que quiero&lt;br&gt;
estudiar es el de los motores NoSQL, donde cada familia de motor tiene una forma&lt;br&gt;
distinta de persistir y, sobre todo, una forma distinta de romperse.&lt;/p&gt;

&lt;p&gt;Lo que hice fue construir una aplicación que ejecuta seis estrategias de respaldo&lt;br&gt;
sobre tres motores reales, restaura cada una y &lt;strong&gt;cuenta lo que vuelve&lt;/strong&gt;. No me&lt;br&gt;
conformé con que el comando terminara con código cero: varias veces terminó en&lt;br&gt;
cero sin haber restaurado nada.&lt;/p&gt;
&lt;h2&gt;
  
  
  Enlaces del proyecto
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repositorio público con el código y la documentación:&lt;/strong&gt;
&lt;a href="https://github.com/dejameingresar/dataforge-backup-nosql" rel="noopener noreferrer"&gt;https://github.com/dejameingresar/dataforge-backup-nosql&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aplicación desplegada en la nube (Render):&lt;/strong&gt;
&lt;a href="https://dataforge-backup-si783.onrender.com" rel="noopener noreferrer"&gt;https://dataforge-backup-si783.onrender.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video de construcción y demostración:&lt;/strong&gt; &lt;em&gt;(pendiente de publicar)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Los tres motores
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Motor&lt;/th&gt;
&lt;th&gt;Versión&lt;/th&gt;
&lt;th&gt;Modelo de datos&lt;/th&gt;
&lt;th&gt;Rol en el proyecto&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MongoDB&lt;/td&gt;
&lt;td&gt;7.0.14&lt;/td&gt;
&lt;td&gt;documentos en colecciones&lt;/td&gt;
&lt;td&gt;base documental con índices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redis&lt;/td&gt;
&lt;td&gt;7.0.15&lt;/td&gt;
&lt;td&gt;pares clave-valor en memoria&lt;/td&gt;
&lt;td&gt;claves de cinco tipos distintos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Neo4j&lt;/td&gt;
&lt;td&gt;5.24.0&lt;/td&gt;
&lt;td&gt;grafos (nodos y relaciones)&lt;/td&gt;
&lt;td&gt;grafo con tres tipos de arista&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Las seis estrategias, con las cifras medidas
&lt;/h2&gt;

&lt;p&gt;Cada número de esta tabla salió de una corrida real: se genera el respaldo, se&lt;br&gt;
calcula su SHA-256, se destruyen los datos, se restaura y se cuenta lo que volvió.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Motor&lt;/th&gt;
&lt;th&gt;Estrategia&lt;/th&gt;
&lt;th&gt;Artefacto&lt;/th&gt;
&lt;th&gt;Tamaño&lt;/th&gt;
&lt;th&gt;Duración&lt;/th&gt;
&lt;th&gt;Round-trip&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MongoDB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;logico_mongodump&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*.bson.gz&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;30.8 KiB&lt;/td&gt;
&lt;td&gt;343 ms&lt;/td&gt;
&lt;td&gt;1400 → 1400 docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MongoDB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fisico_wiredtiger&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;snapshot_wiredtiger.tar.gz&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.11 MiB&lt;/td&gt;
&lt;td&gt;2.44 s&lt;/td&gt;
&lt;td&gt;1400 → 1400 docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redis&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rdb_dump&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dump.rdb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;11.3 KiB&lt;/td&gt;
&lt;td&gt;154 ms&lt;/td&gt;
&lt;td&gt;240 → 240 claves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redis&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aof_append&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;appendonlydir/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;11.4 KiB&lt;/td&gt;
&lt;td&gt;2.15 s&lt;/td&gt;
&lt;td&gt;240 → 240 claves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Neo4j&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dump_binario&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;neo4j.dump&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;509.1 KiB&lt;/td&gt;
&lt;td&gt;3.48 s&lt;/td&gt;
&lt;td&gt;200/594 → 200/594&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Neo4j&lt;/td&gt;
&lt;td&gt;&lt;code&gt;exportacion_cypher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JSON Lines&lt;/td&gt;
&lt;td&gt;104.0 KiB&lt;/td&gt;
&lt;td&gt;420 ms&lt;/td&gt;
&lt;td&gt;200/594 → 200/594&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;6 de 6&lt;/strong&gt; restauraron exactamente lo que había. Ese "exactamente" es lo que&lt;br&gt;
importa: varias veces costó llegar ahí.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. MongoDB, &lt;code&gt;mongodump&lt;/code&gt;: el lógico
&lt;/h3&gt;

&lt;p&gt;Exporta cada colección a BSON comprimido. Habla el protocolo de red, así que&lt;br&gt;
funciona &lt;strong&gt;con el servidor encendido&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongodump &lt;span class="nt"&gt;--uri&lt;/span&gt; mongodb://127.0.0.1:27017/dataforge_backup &lt;span class="nt"&gt;--out&lt;/span&gt; DIR &lt;span class="nt"&gt;--gzip&lt;/span&gt;
mongorestore &lt;span class="nt"&gt;--uri&lt;/span&gt; mongodb://127.0.0.1:27017 &lt;span class="nt"&gt;--gzip&lt;/span&gt; DIR/dataforge_backup/clientes.bson.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Protege los documentos y los índices. No protege los usuarios, los roles, el&lt;br&gt;
oplog ni el estado interno de WiredTiger: eso va aparte.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. MongoDB, copia en frío de WiredTiger
&lt;/h3&gt;

&lt;p&gt;Con el motor &lt;strong&gt;detenido&lt;/strong&gt;, se copia el &lt;code&gt;dbpath&lt;/code&gt; entero: los &lt;code&gt;.wt&lt;/code&gt;, el catálogo,&lt;br&gt;
&lt;code&gt;WiredTiger.turtle&lt;/code&gt;, &lt;code&gt;sizeStorer&lt;/code&gt; y el &lt;code&gt;journal&lt;/code&gt;. Es una foto del almacenamiento.&lt;/p&gt;

&lt;p&gt;Aquí está la primera limitación que vale la pena entender: &lt;strong&gt;el archivo es del&lt;br&gt;
motor completo, no de una base&lt;/strong&gt;. Al probarlo, el &lt;code&gt;dbpath&lt;/code&gt; tenía tres bases y el&lt;br&gt;
respaldo se llevó las tres. Si lo que quieres es respaldar &lt;em&gt;una&lt;/em&gt; base, esta&lt;br&gt;
estrategia no sirve, y esa es exactamente la razón por la que existe&lt;br&gt;
&lt;code&gt;mongodump&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Redis, volcado RDB
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli &lt;span class="nt"&gt;-p&lt;/span&gt; 6379 &lt;span class="nt"&gt;--rdb&lt;/span&gt; dump.rdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Un punto de control binario de toda la base. Redis 7 usa &lt;em&gt;copy-on-write&lt;/em&gt;:&lt;br&gt;
mientras se copia, las páginas modificadas se duplican, así que el archivo es&lt;br&gt;
consistente aunque el servidor siga recibiendo escrituras.&lt;/p&gt;

&lt;p&gt;No protege los comandos ejecutados entre puntos de control: la ventana de pérdida&lt;br&gt;
es de segundos.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Redis, copia del AOF
&lt;/h3&gt;

&lt;p&gt;El AOF es un registro de &lt;strong&gt;órdenes de escritura&lt;/strong&gt;, no de estado. Su ventana de&lt;br&gt;
pérdida es mucho menor que la del RDB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli &lt;span class="nt"&gt;-p&lt;/span&gt; 6379 BGREWRITEAOF
&lt;span class="c"&gt;# esperar a que termine:&lt;/span&gt;
redis-cli &lt;span class="nt"&gt;-p&lt;/span&gt; 6379 INFO persistence   &lt;span class="c"&gt;# aof_rewrite_in_progress == 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con Redis 7 el AOF ya no es un archivo suelto: es un &lt;strong&gt;directorio&lt;/strong&gt; con un&lt;br&gt;
manifiesto y varios &lt;code&gt;.base.rdb&lt;/code&gt; e &lt;code&gt;.incr.aof&lt;/code&gt;. Copiar solo el &lt;code&gt;.aof&lt;/code&gt; deja fuera&lt;br&gt;
los incrementales y se pierde lo escrito después.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Neo4j, dump binario
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;neo4j-admin database dump neo4j &lt;span class="nt"&gt;--to-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;DESTINO
neo4j-admin database load neo4j &lt;span class="nt"&gt;--from-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;DESTINO &lt;span class="nt"&gt;--overwrite-destination&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Empaqueta todo en un &lt;code&gt;.dump&lt;/code&gt;. En la edición &lt;strong&gt;Community exige que la base esté&lt;br&gt;
detenida&lt;/strong&gt; para el dump y para la carga: es una ventana sin servicio, y la&lt;br&gt;
ficha de la estrategia lo declara en vez de esconderlo.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Neo4j, exportación a JSON Lines
&lt;/h3&gt;

&lt;p&gt;Nodos y aristas como texto, con los identificadores internos reemplazados por&lt;br&gt;
claves de negocio. Es la única que &lt;strong&gt;corre en caliente&lt;/strong&gt; y la única que se puede&lt;br&gt;
revisar a mano, versionar en un repositorio o comparar entre versiones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que falló de verdad
&lt;/h2&gt;

&lt;p&gt;Esta es la parte que más aporta, porque no aparece en los manuales.&lt;/p&gt;

&lt;h3&gt;
  
  
  Un respaldo que "tiene éxito" y no restaura nada
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;mongorestore&lt;/code&gt; &lt;strong&gt;no acepta un directorio&lt;/strong&gt;. Si se le pasa la carpeta del dump&lt;br&gt;
devuelve código de salida &lt;code&gt;0&lt;/code&gt; y restaura &lt;strong&gt;cero documentos&lt;/strong&gt;, con un mensaje&lt;br&gt;
apodable: &lt;code&gt;don't know what to do with file ... skipping&lt;/code&gt;. Hay que pasarle cada&lt;br&gt;
&lt;code&gt;.bson.gz&lt;/code&gt; individual.&lt;/p&gt;

&lt;p&gt;Lo detecté porque conté los documentos después de restaurar. Si hubiera confiado&lt;br&gt;
en el código de salida, habría publicado un respaldo que no restauraba nada.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redis 7 ya no permite elegir dónde guardar el RDB
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;CONFIG SET dir&lt;/code&gt; falla con &lt;code&gt;can't set protected config&lt;/code&gt;. La salida es usar&lt;br&gt;
&lt;code&gt;redis-cli --rdb DESTINO&lt;/code&gt;, que además &lt;strong&gt;no detiene el servidor&lt;/strong&gt;: usa replicación&lt;br&gt;
en modo &lt;code&gt;rdb-only&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Neo4j: las etiquetas no se pueden añadir después
&lt;/h3&gt;

&lt;p&gt;Neo4j 5 rechaza &lt;code&gt;SET n:Etiqueta&lt;/code&gt; con un error de sintaxis: eso exige el plugin&lt;br&gt;
APOC, que no viene instalado. La forma sin plugins es crear el nodo con sus&lt;br&gt;
etiquetas desde el &lt;code&gt;CREATE&lt;/code&gt; (&lt;code&gt;CREATE (n:Uno:Dos {...})&lt;/code&gt;), lo que obliga a agrupar&lt;br&gt;
las filas por su conjunto exacto de etiquetas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Neo4j: &lt;code&gt;MERGE&lt;/code&gt; colapsa las aristas repetidas
&lt;/h3&gt;

&lt;p&gt;En un grafo puede haber &lt;strong&gt;varias aristas del mismo tipo entre el mismo par de&lt;br&gt;
nodos&lt;/strong&gt;, con propiedades distintas. &lt;code&gt;MERGE&lt;/code&gt; las funde en una sola. Al medir el&lt;br&gt;
round-trip me faltaban 4 relaciones: 590 de 594. Parecía "casi bien", y por eso&lt;br&gt;
lo investigué en vez de anotarlo como una pérdida menor. Con &lt;code&gt;CREATE&lt;/code&gt; se&lt;br&gt;
conservan todas.&lt;/p&gt;

&lt;p&gt;La tentación era relajar la comparación para que el número cuadrara. Eso habría&lt;br&gt;
convertido un defecto real en un falso positivo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Una ventana sin servicio
&lt;/h3&gt;

&lt;p&gt;Las dos estrategias físicas (&lt;code&gt;fisico_wiredtiger&lt;/code&gt; y &lt;code&gt;dump_binario&lt;/code&gt;) exigen el&lt;br&gt;
motor detenido. En un sistema en producción eso no es un detalle de&lt;br&gt;
implementación: es una decisión de arquitectura. Para la misma base, la&lt;br&gt;
exportación lógica de Neo4j corría en caliente en 420 ms, frente a los 3.48 s del&lt;br&gt;
dump con el servidor parado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integración continua
&lt;/h2&gt;

&lt;p&gt;Cada &lt;code&gt;push&lt;/code&gt; a &lt;code&gt;main&lt;/code&gt; ejecuta la suite. Los casos que necesitan motores reales no&lt;br&gt;
pueden correr en el runner de GitHub Actions, así que &lt;strong&gt;fallan de forma&lt;br&gt;
explícita&lt;/strong&gt; en vez de devolver un resultado inventado; la verificación completa se&lt;br&gt;
hace contra los motores locales. El despliegue en Render es un &lt;code&gt;render.yaml&lt;/code&gt; con&lt;br&gt;
&lt;code&gt;autoDeploy&lt;/code&gt; por commit y el health check en &lt;code&gt;/api/salud&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La aplicación usa solo la biblioteca estándar de Python: sin &lt;code&gt;requirements.txt&lt;/code&gt;,&lt;br&gt;
sin instalación, sin cadena de dependencias. En la nube los motores aparecen como&lt;br&gt;
&lt;code&gt;n/d&lt;/code&gt;, porque un servicio público no expone puertos de base de datos; en local&lt;br&gt;
responden de verdad.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Un respaldo no es un archivo: es una cadena.&lt;/strong&gt; Backup, verificación por
hash, restauración y conteo. Saltaba un eslabón, el resultado no servía.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;El código de salida no es evidencia.&lt;/strong&gt; Dos de los fallos más caros de este
proyecto salían con &lt;code&gt;0&lt;/code&gt;. Contar lo que volvió sí lo es.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cada familia de motor tiene su propia restricción&lt;/strong&gt;, y la operación más
cara no siempre es la que parece: la física es más rápida de escribir pero te
quita el servicio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;El respaldo físico es del motor; el lógico, de la base.&lt;/strong&gt; Esa diferencia
decide qué estrategia sirve y cuál no.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentar lo que no protege&lt;/strong&gt; es más útil que documentar lo que sí. Una
ficha de estrategia que solo enumera ventajas no sirve para decidir.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Código
&lt;/h2&gt;

&lt;p&gt;El repositorio incluye los tres adaptadores, la batería de 27 pruebas con el&lt;br&gt;
ciclo completo contra un motor real, el smoke test en navegador y el&lt;br&gt;
&lt;code&gt;render.yaml&lt;/code&gt; del despliegue.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>redis</category>
      <category>nosql</category>
      <category>backup</category>
    </item>
  </channel>
</rss>
