<?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: ANA CECILIA ESTEBAN RAMOS</title>
    <description>The latest articles on DEV Community by ANA CECILIA ESTEBAN RAMOS (@ana_ceciliaestebanramos).</description>
    <link>https://dev.to/ana_ceciliaestebanramos</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%2F4162654%2F82c67db5-29b5-4d0d-979c-affdb1256a72.png</url>
      <title>DEV Community: ANA CECILIA ESTEBAN RAMOS</title>
      <link>https://dev.to/ana_ceciliaestebanramos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ana_ceciliaestebanramos"/>
    <language>en</language>
    <item>
      <title>Integración de DevSecOps con Bearer SAST y GitHub Actions: detección, bloqueo y remediación de vulnerabilidades</title>
      <dc:creator>ANA CECILIA ESTEBAN RAMOS</dc:creator>
      <pubDate>Mon, 05 Oct 2026 17:25:47 +0000</pubDate>
      <link>https://dev.to/ana_ceciliaestebanramos/integracion-de-devsecops-con-bearer-sast-y-github-actions-deteccion-bloqueo-y-remediacion-de-45ko</link>
      <guid>https://dev.to/ana_ceciliaestebanramos/integracion-de-devsecops-con-bearer-sast-y-github-actions-deteccion-bloqueo-y-remediacion-de-45ko</guid>
      <description>&lt;p&gt;&lt;strong&gt;Autores:&lt;/strong&gt; Saúl José Alvarado Urbano y Ana Cecilia Esteban Ramos&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Repositorio:&lt;/strong&gt; &lt;a href="https://github.com/saulalvarado1/Bearer_Articulo" rel="noopener noreferrer"&gt;github.com/saulalvarado1/Bearer_Articulo&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;API en producción:&lt;/strong&gt; &lt;a href="https://bearer-articulo.onrender.com" rel="noopener noreferrer"&gt;bearer-articulo.onrender.com&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Resumen
&lt;/h2&gt;

&lt;p&gt;En el desarrollo de software moderno, la seguridad no debería incorporarse únicamente al final del proyecto o antes de publicar una aplicación en producción. El enfoque &lt;strong&gt;Shift-Left&lt;/strong&gt; propone integrar controles de seguridad desde las primeras etapas del ciclo de vida del desarrollo de software.&lt;/p&gt;

&lt;p&gt;En este artículo presentamos la implementación práctica de un flujo &lt;strong&gt;DevSecOps&lt;/strong&gt; aplicado a una API REST desarrollada con &lt;strong&gt;Node.js y Express&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Para automatizar el análisis de seguridad se configuró un pipeline de Integración Continua mediante &lt;strong&gt;GitHub Actions&lt;/strong&gt;, incorporando &lt;strong&gt;Bearer CLI&lt;/strong&gt; como herramienta de análisis estático de seguridad de aplicaciones o &lt;strong&gt;SAST&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;El objetivo fue comprobar cómo una vulnerabilidad introducida intencionalmente dentro del código puede ser detectada automáticamente antes de continuar con el proceso de despliegue.&lt;/p&gt;

&lt;p&gt;Para la demostración se simuló la exposición de información sensible dentro de los logs de autenticación. Bearer detectó el problema, marcó el hallazgo con severidad alta y provocó que el pipeline finalizara con error.&lt;/p&gt;

&lt;p&gt;Posteriormente se realizó la corrección del código y se ejecutó nuevamente el análisis hasta obtener un pipeline exitoso, permitiendo continuar con el flujo de despliegue de la aplicación en Render.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. Arquitectura y stack tecnológico
&lt;/h2&gt;

&lt;p&gt;La solución integra desarrollo, control de versiones, análisis estático de seguridad, automatización y despliegue en la nube.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ Desarrollador ]
        │
        │ git push
        ▼
[ Repositorio GitHub ]
        │
        │ Trigger del Workflow
        ▼
[ GitHub Actions ]
        │
        ├──► Checkout del código
        │
        ├──► Escaneo SAST con Bearer CLI
        │         │
        │         ├── HIGH / CRITICAL
        │         │         ▼
        │         │   ❌ Pipeline fallido
        │         │
        │         └── Sin hallazgos graves
        │                   ▼
        │             ✅ Pipeline exitoso
        ▼
[ Despliegue en Render ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Componentes principales
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Node.js y Express.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Herramienta SAST:&lt;/strong&gt; Bearer CLI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integración continua:&lt;/strong&gt; GitHub Actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repositorio de código:&lt;/strong&gt; GitHub.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entorno Cloud / PaaS:&lt;/strong&gt; Render.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tipo de análisis:&lt;/strong&gt; Static Application Security Testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La integración de estas tecnologías permite detectar determinados problemas de seguridad durante el desarrollo y antes de que el código vulnerable llegue al entorno productivo.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Configuración del pipeline de seguridad
&lt;/h2&gt;

&lt;p&gt;Para automatizar la verificación de seguridad en cada cambio realizado sobre el repositorio se creó el archivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.github/workflows/bearer-scan.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El workflow utilizado fue el siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bearer SAST Scan &amp;amp; Security Pipeline&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;master"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;master"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;security_scan&lt;/span&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;Bearer SAST Security Analysis&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&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;Checkout Repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&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;Run Bearer CLI Scanner&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bearer/bearer-action@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high,critical"&lt;/span&gt;
          &lt;span class="na"&gt;diff&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este workflow se activa automáticamente cuando se realiza un &lt;code&gt;push&lt;/code&gt; o un &lt;code&gt;pull request&lt;/code&gt; sobre las ramas configuradas.&lt;/p&gt;

&lt;p&gt;GitHub Actions descarga el código fuente mediante &lt;code&gt;actions/checkout&lt;/code&gt; y posteriormente ejecuta Bearer para analizar posibles vulnerabilidades.&lt;/p&gt;

&lt;p&gt;La opción:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high,critical"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;permite considerar especialmente los hallazgos clasificados con severidad alta o crítica.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. ¿Por qué utilizar Bearer?
&lt;/h2&gt;

&lt;p&gt;Bearer es una herramienta orientada al análisis estático de seguridad.&lt;/p&gt;

&lt;p&gt;Su utilidad dentro de un flujo DevSecOps consiste en analizar el código fuente y detectar patrones relacionados con problemas de seguridad y manejo inadecuado de información sensible.&lt;/p&gt;

&lt;p&gt;Entre los elementos que puede ayudar a analizar se encuentran:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Datos personales.&lt;/li&gt;
&lt;li&gt;Credenciales.&lt;/li&gt;
&lt;li&gt;Información sensible.&lt;/li&gt;
&lt;li&gt;Entradas provenientes de usuarios.&lt;/li&gt;
&lt;li&gt;Flujos de información hacia puntos potencialmente inseguros.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esto permite incorporar seguridad dentro del proceso normal de desarrollo en lugar de dejar el análisis únicamente para una etapa final.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Introducción intencional de una vulnerabilidad
&lt;/h2&gt;

&lt;p&gt;Para comprobar el funcionamiento del pipeline se introdujo intencionalmente una vulnerabilidad dentro del endpoint de autenticación:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/api/login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El problema consistía en almacenar dentro de los logs tanto el correo electrónico como la contraseña ingresada por el usuario.&lt;/p&gt;

&lt;h3&gt;
  
  
  Código vulnerable
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email y contraseña requeridos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Datos sensibles enviados directamente a los logs&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`[AUTH-LOG] Intento de login para usuario: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; con credencial: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Autenticación exitosa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jwt-simulated-token-bearer-demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Credenciales inválidas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La parte problemática se encuentra en:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`[AUTH-LOG] Intento de login para usuario: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; con credencial: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La contraseña y otros datos proporcionados por el usuario son enviados directamente a los logs.&lt;/p&gt;

&lt;p&gt;Esto representa un riesgo porque los registros de una aplicación pueden almacenarse durante largos periodos, ser consultados por administradores o integrarse con servicios externos de monitoreo.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Detección automática de la vulnerabilidad
&lt;/h2&gt;

&lt;p&gt;Después de introducir el código vulnerable se realizó un nuevo &lt;code&gt;push&lt;/code&gt; al repositorio remoto.&lt;/p&gt;

&lt;p&gt;GitHub Actions detectó el cambio y ejecutó automáticamente el workflow configurado.&lt;/p&gt;

&lt;p&gt;Bearer analizó el proyecto y detectó un hallazgo de severidad &lt;strong&gt;HIGH&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resultado del análisis
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HIGH: Unsanitized user input in format string [CWE-134]

File: server.js:54

54  console.log(
      `[AUTH-LOG] Intento de login para usuario: ${email}
      con credencial: ${password}`
    );

87 checks, 1 findings

CRITICAL: 0
HIGH: 1 (CWE-134)

Error: Process completed with exit code 1.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Al detectar el hallazgo, el proceso terminó con código de salida &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El flujo quedó de la siguiente manera:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Código vulnerable
      │
      ▼
GitHub Actions
      │
      ▼
Bearer SAST
      │
      ▼
Hallazgo HIGH
      │
      ▼
❌ Pipeline fallido
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este comportamiento permite utilizar el análisis de seguridad como una &lt;strong&gt;compuerta de calidad&lt;/strong&gt;, evitando que determinados cambios inseguros continúen normalmente dentro del flujo de integración.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Impacto del problema detectado
&lt;/h2&gt;

&lt;p&gt;Registrar credenciales o información sensible directamente dentro de los logs puede provocar exposición de datos.&lt;/p&gt;

&lt;p&gt;Por ejemplo, una contraseña escrita en texto claro podría quedar disponible para:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Administradores del sistema.&lt;/li&gt;
&lt;li&gt;Plataformas de monitoreo.&lt;/li&gt;
&lt;li&gt;Herramientas de agregación de logs.&lt;/li&gt;
&lt;li&gt;Personal con permisos sobre el entorno.&lt;/li&gt;
&lt;li&gt;Copias históricas de registros.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por esta razón, los logs deben almacenar únicamente la información necesaria para diagnosticar eventos sin revelar datos privados o credenciales.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Remediación de la vulnerabilidad
&lt;/h2&gt;

&lt;p&gt;Después de identificar el problema se modificó el código del endpoint de autenticación.&lt;/p&gt;

&lt;p&gt;La corrección se basó en tres medidas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Eliminar el registro de contraseñas.&lt;/li&gt;
&lt;li&gt;Evitar enviar información sensible directamente hacia los logs.&lt;/li&gt;
&lt;li&gt;Registrar solamente el evento necesario para mantener trazabilidad.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Código corregido
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email y contraseña requeridos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Registro del evento sin exponer información sensible&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[AUTH-LOG] Intento de login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Autenticación exitosa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jwt-simulated-token-bearer-demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Credenciales inválidas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora el sistema únicamente registra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[AUTH-LOG] Intento de login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De esta forma se mantiene la trazabilidad del evento sin guardar directamente la contraseña ni otros datos sensibles.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Verificación de la remediación
&lt;/h2&gt;

&lt;p&gt;La corrección fue enviada al repositorio mediante el commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fix: remove sensitive login data from logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Después del nuevo &lt;code&gt;push&lt;/code&gt;, GitHub Actions volvió a ejecutar automáticamente Bearer sobre el proyecto.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resultado del nuevo análisis
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Checks ejecutados:&lt;/strong&gt; 87&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hallazgos críticos:&lt;/strong&gt; 0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hallazgos altos:&lt;/strong&gt; 0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estado final del pipeline:&lt;/strong&gt; SUCCESS ✅&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El flujo resultante fue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Código corregido
      │
      ▼
git push
      │
      ▼
GitHub Actions
      │
      ▼
Bearer SAST
      │
      ▼
0 HIGH / 0 CRITICAL
      │
      ▼
✅ Pipeline exitoso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El resultado demuestra cómo una herramienta SAST puede utilizarse para detectar un problema, bloquear el flujo y posteriormente verificar que la vulnerabilidad haya sido corregida.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Despliegue en la nube
&lt;/h2&gt;

&lt;p&gt;Una vez corregido el código y aprobado el análisis de seguridad, la aplicación puede continuar dentro del flujo de despliegue.&lt;/p&gt;

&lt;p&gt;La API se encuentra publicada en Render:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bearer-articulo.onrender.com" rel="noopener noreferrer"&gt;https://bearer-articulo.onrender.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El proceso completo implementado puede resumirse así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Desarrollo
    │
    ▼
GitHub
    │
    ▼
GitHub Actions
    │
    ▼
Bearer SAST
    │
    ├── Vulnerabilidad detectada
    │          │
    │          ▼
    │      ❌ Bloqueo
    │
    └── Código aprobado
               │
               ▼
         ✅ Pipeline exitoso
               │
               ▼
             Render
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De esta manera, el análisis de seguridad forma parte del flujo de desarrollo y automatización.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Lecciones aprendidas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Seguridad desde etapas tempranas
&lt;/h3&gt;

&lt;p&gt;Incorporar herramientas de análisis durante el desarrollo permite identificar determinados problemas antes de que lleguen al entorno de producción.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automatización
&lt;/h3&gt;

&lt;p&gt;GitHub Actions permite ejecutar el análisis de manera repetible cada vez que se realizan cambios importantes en el repositorio.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protección de datos sensibles
&lt;/h3&gt;

&lt;p&gt;Las contraseñas, tokens y credenciales no deben almacenarse directamente dentro de los logs de una aplicación.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compuertas de seguridad
&lt;/h3&gt;

&lt;p&gt;Configurar el pipeline para detectar hallazgos de severidad alta o crítica permite detener el flujo cuando se identifica un problema relevante.&lt;/p&gt;

&lt;h3&gt;
  
  
  Seguridad integrada al desarrollo
&lt;/h3&gt;

&lt;p&gt;El enfoque DevSecOps permite incorporar la seguridad como una actividad continua dentro del ciclo de desarrollo y no únicamente como una revisión final.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. Resultado final
&lt;/h2&gt;

&lt;p&gt;La implementación permitió comprobar un flujo completo de detección y corrección:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Se desarrolla la API
        │
        ▼
2. Se introduce una vulnerabilidad
        │
        ▼
3. Se realiza git push
        │
        ▼
4. GitHub Actions ejecuta Bearer
        │
        ▼
5. Bearer detecta HIGH
        │
        ▼
6. Pipeline falla ❌
        │
        ▼
7. Se corrige el código
        │
        ▼
8. Se realiza nuevo push
        │
        ▼
9. Bearer analiza nuevamente
        │
        ▼
10. 0 HIGH / 0 CRITICAL
        │
        ▼
11. Pipeline exitoso ✅
        │
        ▼
12. Aplicación disponible en Render
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;La implementación permitió demostrar de manera práctica cómo integrar &lt;strong&gt;DevSecOps&lt;/strong&gt; dentro de un proyecto utilizando &lt;strong&gt;GitHub Actions y Bearer SAST&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;La vulnerabilidad introducida intencionalmente permitió comprobar que Bearer podía detectar un problema relacionado con el manejo de información proveniente del usuario y provocar que el pipeline finalizara con error.&lt;/p&gt;

&lt;p&gt;Después de aplicar la remediación, el nuevo análisis finalizó correctamente sin hallazgos altos o críticos.&lt;/p&gt;

&lt;p&gt;Este proceso demuestra la utilidad de incorporar análisis estático de seguridad dentro de la Integración Continua.&lt;/p&gt;

&lt;p&gt;GitHub Actions permite automatizar la ejecución del análisis, mientras que Bearer proporciona una capa adicional de revisión del código antes de continuar con el proceso de entrega.&lt;/p&gt;

&lt;p&gt;Finalmente, la aplicación fue publicada en Render, completando un flujo que integra &lt;strong&gt;desarrollo, control de versiones, análisis SAST, remediación, validación y despliegue en la nube&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recursos y enlaces
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Código fuente completo:&lt;/strong&gt; &lt;a href="https://github.com/saulalvarado1/Bearer_Articulo" rel="noopener noreferrer"&gt;GitHub - saulalvarado1/Bearer_Articulo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aplicación en vivo:&lt;/strong&gt; &lt;a href="https://bearer-articulo.onrender.com" rel="noopener noreferrer"&gt;https://bearer-articulo.onrender.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentación oficial de Bearer:&lt;/strong&gt; &lt;a href="https://docs.bearer.com/" rel="noopener noreferrer"&gt;https://docs.bearer.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CWE-134 - Use of Externally-Controlled Format String:&lt;/strong&gt; &lt;a href="https://cwe.mitre.org/data/definitions/134.html" rel="noopener noreferrer"&gt;https://cwe.mitre.org/data/definitions/134.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CWE-532 - Insertion of Sensitive Information into Log File:&lt;/strong&gt; &lt;a href="https://cwe.mitre.org/data/definitions/532.html" rel="noopener noreferrer"&gt;https://cwe.mitre.org/data/definitions/532.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Autores
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Saúl José Alvarado Urbano&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Ana Cecilia Esteban Ramos&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Escuela Profesional de Ingeniería de Sistemas&lt;br&gt;&lt;br&gt;
Curso de Calidad de Software&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>devops</category>
      <category>github</category>
      <category>security</category>
    </item>
    <item>
      <title>Estrategias de respaldo de bases de datos con PostgreSQL, Django y despliegue automatizado en la nube</title>
      <dc:creator>ANA CECILIA ESTEBAN RAMOS</dc:creator>
      <pubDate>Mon, 05 Oct 2026 02:02:20 +0000</pubDate>
      <link>https://dev.to/ana_ceciliaestebanramos/estrategias-de-respaldo-de-bases-de-datos-con-postgresql-django-y-despliegue-automatizado-en-la-57id</link>
      <guid>https://dev.to/ana_ceciliaestebanramos/estrategias-de-respaldo-de-bases-de-datos-con-postgresql-django-y-despliegue-automatizado-en-la-57id</guid>
      <description>&lt;p&gt;&lt;strong&gt;Autora:&lt;/strong&gt; Ana Cecilia Esteban Ramos&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Proyecto desarrollado con:&lt;/strong&gt; Saúl José Alvarado Urbano&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Repositorio:&lt;/strong&gt; &lt;a href="https://github.com/anaesteban1/database-backup-strategies" rel="noopener noreferrer"&gt;github.com/anaesteban1/database-backup-strategies&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Aplicación en vivo:&lt;/strong&gt; &lt;a href="https://database-backup-strategies.onrender.com" rel="noopener noreferrer"&gt;database-backup-strategies.onrender.com&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Base de datos:&lt;/strong&gt; PostgreSQL&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Cloud / PaaS:&lt;/strong&gt; Render  &lt;/p&gt;


&lt;h2&gt;
  
  
  Resumen
&lt;/h2&gt;

&lt;p&gt;La protección de la información es una responsabilidad fundamental en cualquier sistema que utilice una base de datos. Una eliminación accidental, un error de aplicación, una falla de infraestructura o una operación incorrecta pueden ocasionar pérdida de información si no existe una estrategia adecuada de respaldo y recuperación.&lt;/p&gt;

&lt;p&gt;En este artículo presentamos la implementación práctica de una estrategia de &lt;strong&gt;respaldo y restauración de bases de datos utilizando PostgreSQL&lt;/strong&gt;, evitando Microsoft SQL Server. Para ello desarrollamos una aplicación web con &lt;strong&gt;Python y Django&lt;/strong&gt;, utilizamos &lt;strong&gt;GitHub&lt;/strong&gt; como repositorio público, implementamos respaldos lógicos mediante &lt;code&gt;pg_dump&lt;/code&gt;, documentamos el proceso de recuperación con &lt;code&gt;pg_restore&lt;/code&gt; y publicamos la solución en &lt;strong&gt;Render&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Además, el repositorio se encuentra integrado con Render mediante &lt;strong&gt;Auto-Deploy&lt;/strong&gt;, permitiendo que cada cambio enviado a la rama principal genere automáticamente una nueva versión de la aplicación desplegada en la nube.&lt;/p&gt;

&lt;p&gt;El proyecto permite demostrar que el respaldo de una base de datos y el despliegue automatizado son procesos diferentes, pero complementarios dentro de una solución orientada a disponibilidad, recuperación y continuidad del servicio.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. Arquitectura y stack tecnológico
&lt;/h2&gt;

&lt;p&gt;La solución desarrollada separa la aplicación web, la base de datos, el proceso de respaldo y el flujo de despliegue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ Usuario ]
     │
     ▼
[ Aplicación Django ]
     │
     ▼
[ PostgreSQL ]
     │
     ├────────────► pg_dump
     │                  │
     │                  ▼
     │          [ Archivo de respaldo ]
     │                  │
     │                  ▼
     └────────────► pg_restore
                        │
                        ▼
             [ Base de datos recuperada ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De manera paralela, el despliegue de la aplicación sigue el siguiente flujo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ Desarrollador ]
       │
       │ git push
       ▼
[ GitHub Repository ]
       │
       │ Detecta nuevo commit
       ▼
[ Render Auto-Deploy ]
       │
       ├─► Build
       ├─► Migraciones
       ├─► Deploy
       │
       ▼
[ Aplicación en Producción ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Componentes principales
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Python + Django.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base de datos:&lt;/strong&gt; PostgreSQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Herramienta de respaldo:&lt;/strong&gt; &lt;code&gt;pg_dump&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Herramienta de restauración:&lt;/strong&gt; &lt;code&gt;pg_restore&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control de versiones:&lt;/strong&gt; Git.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repositorio público:&lt;/strong&gt; GitHub.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plataforma Cloud / PaaS:&lt;/strong&gt; Render.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatización del despliegue:&lt;/strong&gt; Render Auto-Deploy.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Repositorio público del proyecto
&lt;/h2&gt;

&lt;p&gt;Uno de los requisitos principales del proyecto consiste en mantener el código fuente de la aplicación dentro de un repositorio público.&lt;/p&gt;

&lt;p&gt;El proyecto completo se encuentra disponible en GitHub:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Repositorio:&lt;/strong&gt; &lt;a href="https://github.com/anaesteban1/database-backup-strategies" rel="noopener noreferrer"&gt;anaesteban1/database-backup-strategies&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dentro del repositorio se encuentran los principales componentes de la solución:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;database-backup-strategies/
│
├── backup_project/
├── backups/
├── scripts/
│   └── backup_postgres.ps1
├── templates/
│   └── backups/
├── manage.py
├── requirements.txt
├── render.yaml
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El repositorio también conserva el historial de commits realizados durante el desarrollo, permitiendo evidenciar las contribuciones realizadas por los integrantes del equipo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Importancia de GitHub:&lt;/strong&gt; además de almacenar el código fuente, permite conservar trazabilidad sobre los cambios realizados y facilita la integración con herramientas de despliegue continuo.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. Estrategia de respaldo con PostgreSQL
&lt;/h2&gt;

&lt;p&gt;La estrategia implementada utiliza las herramientas nativas de PostgreSQL para generar respaldos lógicos de la información.&lt;/p&gt;

&lt;p&gt;Se consideraron tres aspectos principales:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Respaldo lógico completo.&lt;/li&gt;
&lt;li&gt;Automatización mediante script.&lt;/li&gt;
&lt;li&gt;Retención de diferentes versiones del respaldo.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  3.1. Respaldo lógico completo con &lt;code&gt;pg_dump&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;PostgreSQL proporciona la herramienta &lt;code&gt;pg_dump&lt;/code&gt;, utilizada para exportar una base de datos y generar un respaldo lógico.&lt;/p&gt;

&lt;p&gt;En PowerShell se puede ejecutar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;pg_dump&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--dbname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;custom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;postgres_backup.dump&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La opción:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--format=custom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;genera un archivo en formato personalizado de PostgreSQL.&lt;/p&gt;

&lt;p&gt;El resultado será un archivo similar a:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;postgres_backup.dump
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este formato es especialmente útil porque posteriormente puede utilizarse con &lt;code&gt;pg_restore&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flujo del respaldo
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ PostgreSQL ]
      │
      ▼
   pg_dump
      │
      ▼
[ Archivo .dump ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3.2. Identificación de respaldos mediante fecha y hora
&lt;/h2&gt;

&lt;p&gt;Si todos los respaldos utilizaran exactamente el mismo nombre, una nueva ejecución podría reemplazar una copia anterior.&lt;/p&gt;

&lt;p&gt;Para evitarlo se utiliza una marca de tiempo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$timestamp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Get-Date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yyyy-MM-dd_HH-mm-ss"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$backupFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgres_backup_&lt;/span&gt;&lt;span class="nv"&gt;$timestamp&lt;/span&gt;&lt;span class="s2"&gt;.dump"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto permite generar archivos como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;postgres_backup_2026-10-03_18-30-15.dump
postgres_backup_2026-10-04_09-15-32.dump
postgres_backup_2026-10-04_18-40-22.dump
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De esta manera se pueden conservar diferentes versiones e identificar fácilmente cuándo fue generado cada respaldo.&lt;/p&gt;




&lt;h2&gt;
  
  
  3.3. Automatización del respaldo
&lt;/h2&gt;

&lt;p&gt;Realizar respaldos únicamente de manera manual puede representar un riesgo, debido a que el proceso depende de que una persona recuerde ejecutarlo.&lt;/p&gt;

&lt;p&gt;Por esta razón se implementó el script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scripts/backup_postgres.ps1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El flujo del script es el siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ Inicio ]
    │
    ▼
¿Existe DATABASE_URL?
    │
    ▼
¿Está disponible pg_dump?
    │
    ▼
Generar timestamp
    │
    ▼
Ejecutar pg_dump
    │
    ▼
Crear archivo .dump
    │
    ▼
Verificar resultado
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una parte esencial del script es:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Falta la variable DATABASE_URL."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$timestamp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Get-Date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yyyy-MM-dd_HH-mm-ss"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$backupFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Join-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;$OutputDirectory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;"postgres_backup_&lt;/span&gt;&lt;span class="nv"&gt;$timestamp&lt;/span&gt;&lt;span class="s2"&gt;.dump"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;pg_dump&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;--dbname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;custom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;--file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$backupFile&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El script permite estandarizar el proceso de respaldo y puede integrarse posteriormente con un mecanismo de programación de tareas.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; el proyecto implementa el script necesario para automatizar el proceso. La periodicidad puede definirse posteriormente mediante un programador de tareas, un flujo CI/CD o un servicio especializado de automatización.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  4. Estrategia de retención
&lt;/h2&gt;

&lt;p&gt;Generar un respaldo no es suficiente. También es necesario determinar durante cuánto tiempo deberían conservarse las diferentes copias.&lt;/p&gt;

&lt;p&gt;Una posible política de retención podría ser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Respaldos diarios    → 7 días
Respaldos semanales  → 4 semanas
Respaldos mensuales  → 12 meses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estos tiempos son únicamente un ejemplo de política y deben adaptarse a las necesidades reales de cada organización.&lt;/p&gt;

&lt;p&gt;En el proyecto, la utilización de fecha y hora en el nombre de cada archivo constituye la base necesaria para conservar múltiples versiones.&lt;/p&gt;

&lt;p&gt;En un entorno productivo también sería recomendable almacenar las copias importantes en una ubicación diferente del servidor principal.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Buena práctica:&lt;/strong&gt; mantener la aplicación y todos sus respaldos en el mismo servidor puede provocar que una sola falla afecte tanto a los datos originales como a sus copias.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  5. Restauración mediante &lt;code&gt;pg_restore&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Un respaldo solamente resulta útil si puede utilizarse para recuperar la información.&lt;/p&gt;

&lt;p&gt;Los archivos generados mediante &lt;code&gt;pg_dump&lt;/code&gt; en formato personalizado pueden restaurarse utilizando &lt;code&gt;pg_restore&lt;/code&gt;.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;pg_restore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--dbname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;postgres_backup.dump&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El proceso completo puede representarse así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ PostgreSQL ]
      │
      ▼
   pg_dump
      │
      ▼
[ Backup .dump ]
      │
      ▼
  pg_restore
      │
      ▼
[ PostgreSQL restaurado ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Además de generar respaldos, una estrategia correcta debería realizar periódicamente pruebas de recuperación.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Principio importante:&lt;/strong&gt; la existencia de un archivo de respaldo no garantiza por sí sola que la información pueda recuperarse. La restauración también debe ser comprobada.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  6. Despliegue automatizado con GitHub y Render
&lt;/h2&gt;

&lt;p&gt;Otro requisito del proyecto consiste en desplegar la aplicación mediante un mecanismo automatizado.&lt;/p&gt;

&lt;p&gt;Para ello se conectó directamente el repositorio de GitHub con &lt;strong&gt;Render&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;El flujo implementado es:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ Proyecto local ]
       │
       ▼
git add .
       │
       ▼
git commit
       │
       ▼
git push origin main
       │
       ▼
[ GitHub ]
       │
       ▼
[ Render Auto-Deploy ]
       │
       ├─► Construcción
       ├─► Instalación de dependencias
       ├─► Migraciones
       └─► Deploy
       │
       ▼
[ Aplicación Live ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para comprobar el funcionamiento se realizó el siguiente commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;commit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Verifica despliegue automatico desde GitHub"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Después del &lt;code&gt;push&lt;/code&gt;, Render detectó automáticamente el nuevo commit y generó un nuevo despliegue.&lt;/p&gt;

&lt;p&gt;El historial de Render mostró:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Verifica despliegue automatico desde GitHub

Trigger: Auto-Deploy
Estado: Live
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto permitió verificar experimentalmente el requisito de &lt;strong&gt;Deploy through automation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Posteriormente, un commit realizado por Saúl Alvarado para documentar el proceso de restauración también activó un nuevo Auto-Deploy.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Publicación en nube pública
&lt;/h2&gt;

&lt;p&gt;La aplicación fue desplegada públicamente utilizando &lt;strong&gt;Render&lt;/strong&gt;, una plataforma como servicio que permite alojar aplicaciones web.&lt;/p&gt;

&lt;p&gt;La aplicación está disponible en:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Producción:&lt;/strong&gt; &lt;a href="https://database-backup-strategies.onrender.com" rel="noopener noreferrer"&gt;https://database-backup-strategies.onrender.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En la interfaz se muestra el estado actual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Aplicación activa ✅
Despliegue automático GitHub → Render ✅
Motor actual: POSTGRESQL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La aplicación permite registrar información de prueba que posteriormente puede formar parte de los respaldos realizados sobre la base de datos.&lt;/p&gt;

&lt;p&gt;Con esto se cumplen dos de los requisitos principales del proyecto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ Aplicación publicada en nube pública
✅ Uso de PostgreSQL en lugar de Microsoft SQL Server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  8. Variables de entorno y protección de credenciales
&lt;/h2&gt;

&lt;p&gt;Debido a que el repositorio es público, las credenciales de la base de datos no deben almacenarse directamente dentro del código fuente.&lt;/p&gt;

&lt;p&gt;La aplicación utiliza variables de entorno:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE_URL
SECRET_KEY
DEBUG
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DATABASES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dj_database_url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sqlite:///&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BASE_DIR&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;db.sqlite3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;conn_max_age&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;conn_health_checks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La variable &lt;code&gt;DATABASE_URL&lt;/code&gt; permite proporcionar la conexión de PostgreSQL desde el entorno cloud sin publicar directamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Usuario
Contraseña
Host
Puerto
Nombre de la base de datos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Buena práctica:&lt;/strong&gt; las credenciales y secretos nunca deberían almacenarse directamente dentro de un repositorio público.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  9. Diferencia entre respaldo y Auto-Deploy
&lt;/h2&gt;

&lt;p&gt;Durante el desarrollo también fue importante diferenciar dos conceptos que pueden confundirse: &lt;strong&gt;respaldo de base de datos&lt;/strong&gt; y &lt;strong&gt;despliegue automatizado&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Auto-Deploy
&lt;/h3&gt;

&lt;p&gt;Protege y automatiza el proceso de entrega del software:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nuevo código
    │
    ▼
GitHub
    │
    ▼
Render
    │
    ▼
Nueva versión de la aplicación
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Backup
&lt;/h3&gt;

&lt;p&gt;Protege la información almacenada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Datos
  │
  ▼
PostgreSQL
  │
  ▼
pg_dump
  │
  ▼
Archivo de respaldo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El Auto-Deploy permite publicar nuevas versiones de la aplicación, pero &lt;strong&gt;no reemplaza un respaldo de la base de datos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Una solución confiable debe considerar ambos procesos.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Resultado final
&lt;/h2&gt;

&lt;p&gt;Al finalizar la implementación se obtuvo el siguiente resultado:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repositorio público:&lt;/strong&gt; ✅ GitHub.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aplicación web:&lt;/strong&gt; ✅ Django.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base de datos:&lt;/strong&gt; ✅ PostgreSQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft SQL Server:&lt;/strong&gt; ❌ No utilizado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Respaldo lógico:&lt;/strong&gt; ✅ &lt;code&gt;pg_dump&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Restauración:&lt;/strong&gt; ✅ &lt;code&gt;pg_restore&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Script de respaldo:&lt;/strong&gt; ✅ PowerShell.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud público:&lt;/strong&gt; ✅ Render.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Despliegue automático:&lt;/strong&gt; ✅ GitHub → Render.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aplicación pública:&lt;/strong&gt; ✅ Online.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La solución completa queda representada de la siguiente manera:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    ┌──────────────────────┐
                    │    Desarrollador     │
                    └──────────┬───────────┘
                               │
                            git push
                               │
                               ▼
                    ┌──────────────────────┐
                    │        GitHub        │
                    └──────────┬───────────┘
                               │
                         Auto-Deploy
                               │
                               ▼
                    ┌──────────────────────┐
                    │        Render        │
                    │       Django         │
                    └──────────┬───────────┘
                               │
                               ▼
                    ┌──────────────────────┐
                    │     PostgreSQL       │
                    └──────────┬───────────┘
                               │
                   ┌───────────┴───────────┐
                   │                       │
                   ▼                       ▼
               pg_dump                pg_restore
                   │                       │
                   ▼                       ▼
             Backup .dump             Recuperación
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  11. Demostración en video
&lt;/h2&gt;

&lt;p&gt;Como parte de la actividad se realizará un video público de una duración máxima de &lt;strong&gt;5 minutos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;En el video se mostrará:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El repositorio público del proyecto.&lt;/li&gt;
&lt;li&gt;La estructura de la aplicación Django.&lt;/li&gt;
&lt;li&gt;La utilización de PostgreSQL.&lt;/li&gt;
&lt;li&gt;El script de respaldo.&lt;/li&gt;
&lt;li&gt;El uso de &lt;code&gt;pg_dump&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;El proceso de restauración mediante &lt;code&gt;pg_restore&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;El Auto-Deploy desde GitHub.&lt;/li&gt;
&lt;li&gt;El servicio desplegado en Render.&lt;/li&gt;
&lt;li&gt;La aplicación funcionando públicamente.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎥 &lt;strong&gt;Video de demostración:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;PENDIENTE - AGREGAR ENLACE DE YOUTUBE&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Esta URL se agregará antes de realizar la publicación definitiva del artículo.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  12. Lecciones aprendidas y buenas prácticas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Un respaldo debe ser recuperable:&lt;/strong&gt; generar archivos de respaldo no es suficiente; también debe comprobarse el proceso de restauración.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;La automatización reduce errores humanos:&lt;/strong&gt; utilizar scripts permite ejecutar procedimientos repetibles y disminuye la dependencia de acciones manuales.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Los respaldos necesitan retención:&lt;/strong&gt; conservar distintas versiones facilita recuperar información de diferentes momentos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Las credenciales deben permanecer fuera del repositorio:&lt;/strong&gt; las variables de entorno permiten proteger información sensible cuando el código fuente es público.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Backup y deployment cumplen objetivos diferentes:&lt;/strong&gt; el despliegue automatizado actualiza el software, mientras que los respaldos protegen los datos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;La trazabilidad es importante:&lt;/strong&gt; Git y GitHub permiten mantener evidencia de los cambios realizados durante todo el desarrollo.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;La implementación permitió demostrar una estrategia práctica de respaldo utilizando &lt;strong&gt;PostgreSQL&lt;/strong&gt;, evitando Microsoft SQL Server según las condiciones establecidas para la actividad.&lt;/p&gt;

&lt;p&gt;El uso de &lt;code&gt;pg_dump&lt;/code&gt; permite generar respaldos lógicos de la información, mientras que &lt;code&gt;pg_restore&lt;/code&gt; proporciona el mecanismo necesario para recuperar archivos generados en formatos compatibles.&lt;/p&gt;

&lt;p&gt;Asimismo, la utilización de marcas de fecha y hora proporciona una base para mantener diferentes versiones de los respaldos y aplicar posteriormente políticas de retención.&lt;/p&gt;

&lt;p&gt;La integración entre &lt;strong&gt;GitHub y Render&lt;/strong&gt; permitió automatizar el despliegue de la aplicación, verificando que un cambio enviado mediante &lt;code&gt;git push&lt;/code&gt; puede producir automáticamente una nueva versión disponible públicamente.&lt;/p&gt;

&lt;p&gt;Finalmente, este proyecto demuestra que una solución completa debe proteger tanto el &lt;strong&gt;código fuente&lt;/strong&gt; como los &lt;strong&gt;datos almacenados&lt;/strong&gt;. El control de versiones, los respaldos, la restauración, las variables de entorno y el despliegue automatizado constituyen prácticas complementarias para mejorar la confiabilidad de una aplicación.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recursos y enlaces
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Código fuente completo:&lt;/strong&gt; &lt;a href="https://github.com/anaesteban1/database-backup-strategies" rel="noopener noreferrer"&gt;GitHub - anaesteban1/database-backup-strategies&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aplicación en vivo (Producción):&lt;/strong&gt; &lt;a href="https://database-backup-strategies.onrender.com" rel="noopener noreferrer"&gt;https://database-backup-strategies.onrender.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentación oficial de PostgreSQL:&lt;/strong&gt; &lt;a href="https://www.postgresql.org/docs/" rel="noopener noreferrer"&gt;https://www.postgresql.org/docs/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentación de &lt;code&gt;pg_dump&lt;/code&gt;:&lt;/strong&gt; &lt;a href="https://www.postgresql.org/docs/current/app-pgdump.html" rel="noopener noreferrer"&gt;https://www.postgresql.org/docs/current/app-pgdump.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentación de &lt;code&gt;pg_restore&lt;/code&gt;:&lt;/strong&gt; &lt;a href="https://www.postgresql.org/docs/current/app-pgrestore.html" rel="noopener noreferrer"&gt;https://www.postgresql.org/docs/current/app-pgrestore.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup y Restore en PostgreSQL:&lt;/strong&gt; &lt;a href="https://www.postgresql.org/docs/current/backup.html" rel="noopener noreferrer"&gt;https://www.postgresql.org/docs/current/backup.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentación oficial de Django:&lt;/strong&gt; &lt;a href="https://docs.djangoproject.com/" rel="noopener noreferrer"&gt;https://docs.djangoproject.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Despliegue de Django en Render:&lt;/strong&gt; &lt;a href="https://render.com/docs/deploy-django" rel="noopener noreferrer"&gt;https://render.com/docs/deploy-django&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentación de Deploys en Render:&lt;/strong&gt; &lt;a href="https://render.com/docs/deploys" rel="noopener noreferrer"&gt;https://render.com/docs/deploys&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video de demostración:&lt;/strong&gt; &lt;code&gt;PENDIENTE - AGREGAR ENLACE DE YOUTUBE&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Autora
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Ana Cecilia Esteban Ramos&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Universidad Privada de Tacna&lt;br&gt;&lt;br&gt;
Escuela Profesional de Ingeniería de Sistemas&lt;br&gt;&lt;br&gt;
Curso: Base de Datos II&lt;/p&gt;

</description>
      <category>database</category>
      <category>django</category>
      <category>postgres</category>
      <category>python</category>
    </item>
  </channel>
</rss>
