feat: rename file #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Source: https://github.com/Josep-Andreu/segur_cloud/blob/main/build-and-push.yaml | |
| name: Build, Fix and Push to Quay | |
| on: | |
| push: | |
| branches: | |
| - main | |
| env: | |
| FULL_IMAGE: quay.io/mguzman98/jboss_lab:v1.0.0 | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| full_image: quay.io/mguzman98/jboss_lab:v1.0.0 | |
| steps: | |
| - name: 🧩 Checkout code | |
| uses: actions/checkout@v4 | |
| - name: 🔧 Build container image | |
| run: | | |
| docker build -t ${{ env.FULL_IMAGE }} . | |
| - name: 💾 Save image to tar | |
| run: | | |
| docker save ${{ env.FULL_IMAGE }} -o image.tar | |
| - name: 📤 Upload image artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docker-image | |
| path: image.tar | |
| retention-days: 1 | |
| scan: | |
| runs-on: ubuntu-latest | |
| needs: build | |
| outputs: | |
| needs_remediation: ${{ steps.check_vulns.outputs.needs_remediation }} | |
| full_image: ${{ needs.build.outputs.full_image }} | |
| steps: | |
| - name: ⬇️ Download image artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: docker-image | |
| - name: 📦 Load image from tar | |
| run: | | |
| docker load -i image.tar | |
| - name: 🔍 Scan image with Trivy | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.FULL_IMAGE }} | |
| severity: HIGH,CRITICAL | |
| exit-code: 0 | |
| ignore-unfixed: true | |
| # 🧾 Generate SBOM with Syft (syft-json format) | |
| - name: 🧾 Generate SBOM (Syft) | |
| run: | | |
| docker run --rm \ | |
| -v /var/run/docker.sock:/var/run/docker.sock \ | |
| -v "$PWD":/work \ | |
| anchore/syft:latest "${{ env.FULL_IMAGE }}" -o syft-json > sbom.syft.json | |
| test -s sbom.syft.json && echo "SBOM created: sbom.syft.json" | |
| - name: 📤 Upload SBOM artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sbom-syft-json | |
| path: sbom.syft.json | |
| if-no-files-found: error | |
| retention-days: 14 | |
| # 🛡 Evaluate SBOM with Grype (fail build on HIGH or CRITICAL vulns) | |
| - name: 🛡 Vulnerability scan (Grype on SBOM) | |
| id: check_vulns | |
| run: | | |
| set +e | |
| docker run --rm \ | |
| -v "$PWD":/work \ | |
| anchore/grype:latest /work/sbom.syft.json \ | |
| --fail-on high \ | |
| --only-fixed=false \ | |
| --add-cpes-if-none \ | |
| -o json > grype_report.json | |
| # obtener salida de grype | |
| docker run --rm \ | |
| -v "$PWD":/work \ | |
| anchore/grype:latest /work/sbom.syft.json \ | |
| --fail-on high,critical > /dev/null | |
| GRYPE_EXIT_CODE=$? | |
| # 3. Decisiones basadas en el código de salida | |
| if [ $GRYPE_EXIT_CODE -ne 0 ]; then | |
| echo "❌ VULNERABILIDADES CRÍTICAS/ALTAS ENCONTRADAS." | |
| echo "needs_remediation=true" >> $GITHUB_OUTPUT | |
| # --- LÓGICA DE GENERACIÓN DEL SCRIPT DE REMEDIACIÓN --- | |
| # Aquí generamos el script que se usará en el siguiente Job | |
| # (Se necesita el comando jq para extraer los parches del JSON. Necesitas JQ instalado en el runner.) | |
| cat grype_report.json | jq -r ' | |
| .matches[] | | |
| # Filtra por severidad (High/Critical) y por fix disponible | |
| select(.vulnerability.severity == "High" or .vulnerability.severity == "Critical") | | |
| select(.vulnerability.fix.versions | length > 0) | | |
| { | |
| name: .artifact.name, | |
| fixedVersion: .vulnerability.fix.versions[0] | |
| } | | |
| # Genera el comando 'yum update' específico (asumiendo que estás en un sistema RPM) | |
| "yum update " + .name + "-" + .fixedVersion + " -y" | |
| ' | sort -u > remediacion.sh | |
| else | |
| echo "✅ IMAGEN SEGURA. Lista para el push." | |
| echo "needs_remediation=false" >> $GITHUB_OUTPUT | |
| # Crea un archivo vacío si no hay nada que remediar | |
| touch remediacion.sh | |
| fi | |
| - name: 📤 Subir Script de Remediación | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: remediation-commands | |
| path: remediacion.sh | |
| retention-days: 1 # Se borra rápidamente ya que es un archivo temporal | |
| remediate: | |
| runs-on: ubuntu-latest | |
| needs: scan # Depende del Job anterior | |
| outputs: | |
| final_remediated_tag: ${{ steps.fix_img.outputs.remediated_tag }} | |
| if: needs.scan.outputs.needs_remediation == 'true' | |
| env: | |
| FULL_IMAGE: ${{ needs.scan.outputs.full_image }} | |
| steps: | |
| - name: ⬇️ Checkout del Código | |
| uses: actions/checkout@v4 | |
| - name: ⬇️ Download remediation script | |
| if: ${{ needs.scan.outputs.needs_remediation == 'true' }} | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: remediation-commands | |
| - name: 🔨 Ruta Remediada (Aplicar Parche y Reconstruir) | |
| id: fix_img | |
| if: ${{ needs.scan.outputs.needs_remediation == 'true' }} | |
| run: | | |
| REMEDIATED_TAG="${{ env.FULL_IMAGE }}-remediated" | |
| echo "Aplicando parches y reconstruyendo en ${REMEDIATED_TAG}..." | |
| # ASUME QUE EL DOCKERFILE AHORA TIENE LA INSTRUCCIÓN: | |
| # COPY remediacion.sh . | |
| # RUN sh remediacion.sh && rm remediacion.sh | |
| docker build -t $REMEDIATED_TAG . | |
| # 💡 Paso 1: Guardar la imagen en un archivo .tar | |
| docker save -o final_image.tar $REMEDIATED_TAG | |
| echo "remediated_tag=$REMEDIATED_TAG" >> $GITHUB_OUTPUT | |
| - name: 📤 Subir Imagen como Artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: final-docker-image | |
| path: final_image.tar | |
| retention-days: 1 | |
| push-sign: | |
| runs-on: ubuntu-latest | |
| # CRÍTICO: Depende de AMBOS jobs anteriores | |
| needs: [scan, remediate] | |
| # CRÍTICO: Se ejecuta si 'scan' pasó, incluso si 'remediate' fue skipped (failure() cubre skip) | |
| if: success() || failure() | |
| steps: | |
| - name: ⬇️ Descargar Imagen Artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: final-docker-image | |
| - name: 📦 Cargar Imagen desde tar | |
| run: | | |
| docker load -i final_image.tar | |
| - name: 🎯 Determinar la Imagen a Desplegar | |
| id: determine_image | |
| run: | | |
| NEEDS_FIX="${{ needs.scan.outputs.needs_remediation }}" | |
| if [ "$NEEDS_FIX" == "true" ]; then | |
| # Si se remedió, usamos la etiqueta de salida del job 'remediate' | |
| FINAL_TAG="${{ needs.remediate.outputs.final_remediated_tag }}" | |
| echo "La imagen final es la remediada: $FINAL_TAG" | |
| else | |
| # Si NO se remedió, usamos la etiqueta original del job 'scan' | |
| FINAL_TAG="${{ needs.scan.outputs.full_image }}" | |
| echo "La imagen final es la original (segura): $FINAL_TAG" | |
| fi | |
| echo "FINAL_TAG=$FINAL_TAG" >> $GITHUB_ENV | |
| - name: 🔑 Login to Quay.io | |
| run: | | |
| docker login quay.io -u "${{ secrets.QUAY_USER }}" -p "${{ secrets.QUAY_PASSWORD }}" | |
| - name: 🚀 Push Imagen Final a Quay.io | |
| run: | | |
| docker push $FINAL_TAG | |
| - name: Install cosign | |
| run: | | |
| curl -LO https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 | |
| chmod +x cosign-linux-amd64 | |
| sudo mv cosign-linux-amd64 /usr/local/bin/cosign | |
| - name: Sign the image | |
| env: | |
| COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }} | |
| COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }} | |
| run: | | |
| printf '%s' "$COSIGN_PRIVATE_KEY" > cosign.key | |
| cosign sign --key cosign.key $FINAL_TAG | |
| shred -u cosign.key || rm -f cosign.key |