From 985b9b20e46112da04837d42b5eb58b2ae0f73e4 Mon Sep 17 00:00:00 2001 From: Lucas Pampolha Date: Fri, 19 Sep 2025 23:23:50 -0300 Subject: [PATCH 01/27] Desafio 2 --- .github/workflows/02-tests-ci.yml | 22 ++++++++++++++++------ package-lock.json | 3 +-- package.json | 8 ++++---- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/.github/workflows/02-tests-ci.yml b/.github/workflows/02-tests-ci.yml index 3a9801b..59b8cd7 100644 --- a/.github/workflows/02-tests-ci.yml +++ b/.github/workflows/02-tests-ci.yml @@ -7,7 +7,7 @@ env: NODE_VERSION: '18' CHALLENGE_LEVEL: 2 CHALLENGE_NAME: "testes-automatizados" - COVERAGE_MIN: 80 # Cobertura mínima exigida em porcentagem + COVERAGE_MIN: 99 # Cobertura mínima exigida em porcentagem jobs: tests-and-coverage: @@ -20,10 +20,15 @@ jobs: - name: "Checkout do código" uses: actions/checkout@v4 - # INSIRA AQUI A LÓGICA PARA RODAR OS TESTES E VERIFICAR A COBERTURA - ### - ### - ### + - name: "Setup Node" + uses: actions/setup-node@v5 + with: + node-version: ${{env.NODE_VERSION}} + + - name: "Instalar dependências" + run: npm ci + - name: "Executar testes" + run: npm run tests - name: "Extrair porcentagem de cobertura" # Esse step será validado pelo desafio, não altere o nome. No final, ele deve gerar o output "coverage" com a porcentagem de cobertura. id: coverage @@ -31,7 +36,12 @@ jobs: COVERAGE=$(npx nyc report --reporter=text-summary | grep -oP 'Statements\s*:\s*\K[0-9\.]+(?=%)' | head -1) echo "Coverage: $COVERAGE%" echo "coverage=$COVERAGE" >> $GITHUB_OUTPUT - + + - name: "Validar se os testes passaram" + if: ${{steps.coverage.outputs.coverage < env.COVERAGE_MIN}} + run: | + echo "Cobertura mínima não atendida: Esperado - ${{ env.COVERAGE_MIN }}%. Atingido: ${{ steps.coverage.outputs.coverage }}%" + exit 1 generate-certificate: # DAQUI PARA BAIXO, NÃO ALTERAR name: "Desafio Nível 2 - Certificado" runs-on: ubuntu-latest diff --git a/package-lock.json b/package-lock.json index ef1322c..b2c7d57 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "cors": "^2.8.5", "dotenv": "^16.3.1", - "express": "^4.18.2", + "express": "^4.21.2", "helmet": "^7.0.0", "node-fetch": "^3.3.2" }, @@ -2040,7 +2040,6 @@ "version": "4.21.2", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", diff --git a/package.json b/package.json index 2175daf..1326318 100644 --- a/package.json +++ b/package.json @@ -19,16 +19,16 @@ "author": "LINUXtips", "license": "MIT", "dependencies": { - "express": "^4.18.2", "cors": "^2.8.5", - "helmet": "^7.0.0", "dotenv": "^16.3.1", + "express": "^4.21.2", + "helmet": "^7.0.0", "node-fetch": "^3.3.2" }, "devDependencies": { "jest": "^29.7.0", - "supertest": "^6.3.4", - "nyc": "^17.1.0" + "nyc": "^17.1.0", + "supertest": "^6.3.4" }, "engines": { "node": ">=16.0.0" From ecda900db24890340a791cdc22b0120160f5c2de Mon Sep 17 00:00:00 2001 From: Lucas Pampolha Date: Thu, 2 Oct 2025 23:03:33 -0300 Subject: [PATCH 02/27] Desafio-3 --- .github/workflows/03-build-containers.yml | 42 +++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index cbddc24..a6ffb98 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -17,11 +17,49 @@ env: jobs: build-scan-and-push: name: "Build, Lint, Trivy Scan e Push no GHCR" - if: #???? + if: github.event.pull_request.merged == true runs-on: ubuntu-latest steps: - # AQUI VAI O CÓDIGO DO DESAFIO :) + - name: Checkout do código + uses: actions/checkout@v3 + + - name: Login no GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build da imagem Docker + run: | + docker build -t ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} . + + - name: Lint do Dockerfile com Hadolint + run: | + hadolint Dockerfile --format tty | tee lint-report.txt + if grep -q "DL3006\|DL3008" lint-report.txt; then + exit 1 + fi + + - name: Scan de vulnerabilidades com Trivy + uses: aquasecurity/trivy-action@0.28.0 + with: + image-ref: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} + format: sarif + output: trivy-report.txt + severity: CRITICAL + exit-code: 1 + + - name: Publicar imagem no GHCR + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} generate-certificate: # DAQUI PARA BAIXO, NÃO ALTERAR name: "Desafio Nível 3 - Certificado" From 115050d16879b87e09a91cd0cbb58aaef2536417 Mon Sep 17 00:00:00 2001 From: Lucas Pampolha Date: Fri, 3 Oct 2025 22:36:15 -0300 Subject: [PATCH 03/27] Desafio-3-var --- .github/workflows/03-build-containers.yml | 27 ++++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index a6ffb98..c15234d 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -3,7 +3,8 @@ name: "Nível 3: Containers e Segurança" on: pull_request: types: [closed] - branches: [ desafio-nivel-3 ] + branches: + - desafio-nivel-3 permissions: contents: read @@ -19,7 +20,6 @@ jobs: name: "Build, Lint, Trivy Scan e Push no GHCR" if: github.event.pull_request.merged == true runs-on: ubuntu-latest - steps: - name: Checkout do código uses: actions/checkout@v3 @@ -61,7 +61,19 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - generate-certificate: # DAQUI PARA BAIXO, NÃO ALTERAR + - name: Upload do relatório de lint + uses: actions/upload-artifact@v4 + with: + name: lint-report + path: lint-report.txt + + - name: Upload do relatório de vulnerabilidades + uses: actions/upload-artifact@v4 + with: + name: trivy-report + path: trivy-report.txt + + generate-certificate: name: "Desafio Nível 3 - Certificado" needs: build-scan-and-push if: success() @@ -72,29 +84,22 @@ jobs: mkdir -p certificates cat > certificates/level-3-certificate.md << EOF # Certificado de Conclusão - Nível 3 - **Descomplicando Github Actions - GitHub Actions Edition** --- - Este certificado atesta que **${{ github.actor }}** concluiu com sucesso: ## Nível 3: Containers e Segurança - **Competências desenvolvidas:** - Build de imagem Docker - Lint de Dockerfile com Hadolint - Scan de vulnerabilidades com Trivy (CRITICAL = 0) - Relatório de vulnerabilidades como artefato - - Smoke test de execução do container - Publicação no GitHub Container Registry (GHCR) condicionada ao scan - Boas práticas de supply chain - **Data de conclusão:** $(date) **Repositório:** ${{ github.repository }} **Workflow:** ${{ github.run_id }} - --- **Badge conquistado:** Containers e Segurança - --- *Certificado gerado automaticamente pelo GitHub Actions* *LINUXtips* @@ -105,4 +110,4 @@ jobs: with: name: level-3-certificate path: certificates/ - retention-days: 30 + retention-days: 30 \ No newline at end of file From a7a663e0cd15d58b6e839d6dd33e472890d3a7e6 Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 22:43:53 -0300 Subject: [PATCH 04/27] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7bb74fc..894cdef 100644 --- a/README.md +++ b/README.md @@ -86,5 +86,5 @@ Ao completar cada workflow com sucesso, você ganha os badges: --- **Feito pela comunidade LINUXtips.** - +#VAIIII From 61696c3957b86da03442a573fcfa94370ac04aae Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 22:52:40 -0300 Subject: [PATCH 05/27] Update 02-tests-ci.yml --- .github/workflows/02-tests-ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/02-tests-ci.yml b/.github/workflows/02-tests-ci.yml index 59b8cd7..bee57ae 100644 --- a/.github/workflows/02-tests-ci.yml +++ b/.github/workflows/02-tests-ci.yml @@ -1,7 +1,9 @@ name: "Nível 2: Testes Automatizados" on: pull_request: - branches: [ main ] + branches: + - main + - desafio-nivel-3 env: NODE_VERSION: '18' From caa8dce56a26e3f393ceac6f8ad43b8092a6847b Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 22:55:05 -0300 Subject: [PATCH 06/27] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 894cdef..f396e2a 100644 --- a/README.md +++ b/README.md @@ -86,5 +86,5 @@ Ao completar cada workflow com sucesso, você ganha os badges: --- **Feito pela comunidade LINUXtips.** -#VAIIII +#VAIIIII From 7f4da2617813326c9a7de407356ee15917f7a5b9 Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 22:56:27 -0300 Subject: [PATCH 07/27] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f396e2a..61cab9c 100644 --- a/README.md +++ b/README.md @@ -86,5 +86,5 @@ Ao completar cada workflow com sucesso, você ganha os badges: --- **Feito pela comunidade LINUXtips.** -#VAIIIII +#VAIIIIII From df2b4545b6b31001f7b76857ade440d7d1cde61f Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 22:58:12 -0300 Subject: [PATCH 08/27] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 61cab9c..ce64f1b 100644 --- a/README.md +++ b/README.md @@ -87,4 +87,5 @@ Ao completar cada workflow com sucesso, você ganha os badges: **Feito pela comunidade LINUXtips.** #VAIIIIII +Teste123 From 2b60755f69f458cc2b0854b25ae3e7ff31105e04 Mon Sep 17 00:00:00 2001 From: Lucas Pampolha Date: Fri, 3 Oct 2025 23:10:18 -0300 Subject: [PATCH 09/27] Desafio-3-readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ce64f1b..500a195 100644 --- a/README.md +++ b/README.md @@ -87,5 +87,5 @@ Ao completar cada workflow com sucesso, você ganha os badges: **Feito pela comunidade LINUXtips.** #VAIIIIII -Teste123 +Teste123! From d58f76f6cc1bd455276e9d4fd00a0065326ce92d Mon Sep 17 00:00:00 2001 From: Lucas Pampolha Date: Fri, 3 Oct 2025 23:26:12 -0300 Subject: [PATCH 10/27] Desafio-3-readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 500a195..ce64f1b 100644 --- a/README.md +++ b/README.md @@ -87,5 +87,5 @@ Ao completar cada workflow com sucesso, você ganha os badges: **Feito pela comunidade LINUXtips.** #VAIIIIII -Teste123! +Teste123 From a648a51ec3b0c43e23dc3c503680c9f750aff016 Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 23:28:57 -0300 Subject: [PATCH 11/27] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ce64f1b..c5f3c6d 100644 --- a/README.md +++ b/README.md @@ -87,5 +87,5 @@ Ao completar cada workflow com sucesso, você ganha os badges: **Feito pela comunidade LINUXtips.** #VAIIIIII -Teste123 + From bbc0867e0a0d958ae903a352858d67f09954dc00 Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 23:38:19 -0300 Subject: [PATCH 12/27] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c5f3c6d..c8c078a 100644 --- a/README.md +++ b/README.md @@ -87,5 +87,6 @@ Ao completar cada workflow com sucesso, você ganha os badges: **Feito pela comunidade LINUXtips.** #VAIIIIII +Teste123 From 18e1e7515e90df0b815f0c7dfc0e5a695d70fd3f Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 23:46:10 -0300 Subject: [PATCH 13/27] Update 03-build-containers.yml --- .github/workflows/03-build-containers.yml | 120 ++++++++-------------- 1 file changed, 40 insertions(+), 80 deletions(-) diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index c15234d..3784fc7 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -1,113 +1,73 @@ -name: "Nível 3: Containers e Segurança" +name: Nível 3 - Containers e Segurança on: pull_request: types: [closed] - branches: - - desafio-nivel-3 - -permissions: - contents: read - packages: write - -env: - CHALLENGE_LEVEL: 3 - CHALLENGE_NAME: "containers-e-seguranca" - REGISTRY: ghcr.io + branches: [desafio-nivel-3] jobs: build-scan-and-push: - name: "Build, Lint, Trivy Scan e Push no GHCR" if: github.event.pull_request.merged == true runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: - - name: Checkout do código - uses: actions/checkout@v3 + - name: Checkout code + uses: actions/checkout@v4 - - name: Login no GHCR + - name: Login to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build da imagem Docker + - name: Lint Dockerfile run: | - docker build -t ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} . - - - name: Lint do Dockerfile com Hadolint - run: | - hadolint Dockerfile --format tty | tee lint-report.txt - if grep -q "DL3006\|DL3008" lint-report.txt; then + docker run --rm -i hadolint/hadolint < Dockerfile > lint-report.txt 2>&1 || true + if grep -q 'DL3006\|DL3008' lint-report.txt; then + echo "::error::Falha no lint: DL3006 ou DL3008 detectados" exit 1 fi - - name: Scan de vulnerabilidades com Trivy - uses: aquasecurity/trivy-action@0.28.0 - with: - image-ref: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} - format: sarif - output: trivy-report.txt - severity: CRITICAL - exit-code: 1 - - - name: Publicar imagem no GHCR + - name: Build Docker image uses: docker/build-push-action@v6 + id: build with: context: . - push: true - tags: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + tags: | + ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }}:${{ github.sha }} + outputs: type=image,name=ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }} - - name: Upload do relatório de lint - uses: actions/upload-artifact@v4 + - name: Trivy vulnerability scan + uses: aquasecurity/trivy-action@0.28.0 with: - name: lint-report - path: lint-report.txt + image-ref: ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }}:${{ github.sha }} + format: table + exit-code: 1 + severity: CRITICAL + output: trivy-report.txt - - name: Upload do relatório de vulnerabilidades - uses: actions/upload-artifact@v4 + - name: Push to GHCR + if: success() + uses: docker/build-push-action@v6 with: - name: trivy-report - path: trivy-report.txt + push: true + tags: ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }}:${{ github.sha }} - generate-certificate: - name: "Desafio Nível 3 - Certificado" - needs: build-scan-and-push - if: success() - runs-on: ubuntu-latest - steps: - - name: "Gerar certificado" + - name: Generate certificate run: | - mkdir -p certificates - cat > certificates/level-3-certificate.md << EOF - # Certificado de Conclusão - Nível 3 - **Descomplicando Github Actions - GitHub Actions Edition** - --- - Este certificado atesta que **${{ github.actor }}** concluiu com sucesso: - ## Nível 3: Containers e Segurança - **Competências desenvolvidas:** - - Build de imagem Docker - - Lint de Dockerfile com Hadolint - - Scan de vulnerabilidades com Trivy (CRITICAL = 0) - - Relatório de vulnerabilidades como artefato - - Publicação no GitHub Container Registry (GHCR) condicionada ao scan - - Boas práticas de supply chain - **Data de conclusão:** $(date) - **Repositório:** ${{ github.repository }} - **Workflow:** ${{ github.run_id }} - --- - **Badge conquistado:** Containers e Segurança - --- - *Certificado gerado automaticamente pelo GitHub Actions* - *LINUXtips* - EOF + echo "# Certificado Nível 3 - Containers e Segurança" > level-3-certificate.md + echo "**Data**: $(date +'%d/%m/%Y %H:%M')" >> level-3-certificate.md + echo "**Commit**: ${{ github.sha }}" >> level-3-certificate.md - - name: "Upload do certificado" + - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: level-3-certificate - path: certificates/ - retention-days: 30 \ No newline at end of file + name: security-reports + path: | + lint-report.txt + trivy-report.txt + level-3-certificate.md From 5eacc1c2d0019abc5f87611a1ad752345131b2e1 Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 23:46:55 -0300 Subject: [PATCH 14/27] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index c8c078a..c5f3c6d 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,5 @@ Ao completar cada workflow com sucesso, você ganha os badges: **Feito pela comunidade LINUXtips.** #VAIIIIII -Teste123 From dc8953ee9976d4cd888042bbd1bbb2a62cab2fba Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 23:51:05 -0300 Subject: [PATCH 15/27] Update 03-build-containers.yml --- .github/workflows/03-build-containers.yml | 120 ++++++++++++++-------- 1 file changed, 80 insertions(+), 40 deletions(-) diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index 3784fc7..6bd80e4 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -1,73 +1,113 @@ -name: Nível 3 - Containers e Segurança +name: "Nível 3: Containers e Segurança" on: pull_request: types: [closed] - branches: [desafio-nivel-3] + branches: + - desafio-nivel-3 + +permissions: + contents: read + packages: write + +env: + CHALLENGE_LEVEL: 3 + CHALLENGE_NAME: "containers-e-seguranca" + REGISTRY: ghcr.io jobs: build-scan-and-push: + name: "Build, Lint, Trivy Scan e Push no GHCR" if: github.event.pull_request.merged == true runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout code - uses: actions/checkout@v4 + - name: Checkout do código + uses: actions/checkout@v3 - - name: Login to GHCR + - name: Login no GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Lint Dockerfile + - name: Build da imagem Docker run: | - docker run --rm -i hadolint/hadolint < Dockerfile > lint-report.txt 2>&1 || true - if grep -q 'DL3006\|DL3008' lint-report.txt; then - echo "::error::Falha no lint: DL3006 ou DL3008 detectados" + docker build -t ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} . + + - name: Lint do Dockerfile com Hadolint + run: | + hadolint Dockerfile --format tty | tee lint-report.txt + if grep -q "DL3006\|DL3008" lint-report.txt; then exit 1 fi - - name: Build Docker image - uses: docker/build-push-action@v6 - id: build - with: - context: . - tags: | - ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }}:${{ github.sha }} - outputs: type=image,name=ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }} - - - name: Trivy vulnerability scan + - name: Scan de vulnerabilidades com Trivy uses: aquasecurity/trivy-action@0.28.0 with: - image-ref: ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }}:${{ github.sha }} - format: table - exit-code: 1 - severity: CRITICAL + image-ref: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} + format: sarif output: trivy-report.txt + severity: CRITICAL + exit-code: 1 - - name: Push to GHCR - if: success() + - name: Publicar imagem no GHCR uses: docker/build-push-action@v6 with: + context: . push: true - tags: ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }}:${{ github.sha }} + tags: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload do relatório de lint + uses: actions/upload-artifact@v4 + with: + name: lint-report + path: lint-report.txt + + - name: Upload do relatório de vulnerabilidades + uses: actions/upload-artifact@v4 + with: + name: trivy-report + path: trivy-report.txt - - name: Generate certificate + generate-certificate: + name: "Desafio Nível 3 - Certificado" + needs: build-scan-and-push + if: success() + runs-on: ubuntu-latest + steps: + - name: "Gerar certificado" run: | - echo "# Certificado Nível 3 - Containers e Segurança" > level-3-certificate.md - echo "**Data**: $(date +'%d/%m/%Y %H:%M')" >> level-3-certificate.md - echo "**Commit**: ${{ github.sha }}" >> level-3-certificate.md + mkdir -p certificates + cat > certificates/level-3-certificate.md << EOF + # Certificado de Conclusão - Nível 3 + **Descomplicando Github Actions - GitHub Actions Edition** + --- + Este certificado atesta que **${{ github.actor }}** concluiu com sucesso: + ## Nível 3: Containers e Segurança + **Competências desenvolvidas:** + - Build de imagem Docker + - Lint de Dockerfile com Hadolint + - Scan de vulnerabilidades com Trivy (CRITICAL = 0) + - Relatório de vulnerabilidades como artefato + - Publicação no GitHub Container Registry (GHCR) condicionada ao scan + - Boas práticas de supply chain + **Data de conclusão:** $(date) + **Repositório:** ${{ github.repository }} + **Workflow:** ${{ github.run_id }} + --- + **Badge conquistado:** Containers e Segurança + --- + *Certificado gerado automaticamente pelo GitHub Actions* + *LINUXtips* + EOF - - name: Upload artifacts + - name: "Upload do certificado" uses: actions/upload-artifact@v4 with: - name: security-reports - path: | - lint-report.txt - trivy-report.txt - level-3-certificate.md + name: level-3-certificate + path: certificates/ + retention-days: 30 From 995d3944e04fc5d3eb97aee5e060b0ecb5ef50c2 Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 23:52:25 -0300 Subject: [PATCH 16/27] Update 03-build-containers.yml --- .github/workflows/03-build-containers.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index 6bd80e4..efe51b9 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -4,20 +4,7 @@ on: pull_request: types: [closed] branches: - - desafio-nivel-3 -permissions: - contents: read - packages: write - -env: - CHALLENGE_LEVEL: 3 - CHALLENGE_NAME: "containers-e-seguranca" - REGISTRY: ghcr.io - -jobs: - build-scan-and-push: - name: "Build, Lint, Trivy Scan e Push no GHCR" if: github.event.pull_request.merged == true runs-on: ubuntu-latest steps: From 04c1d719c14b39998519a56a17e43b835b61ebdb Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 23:52:41 -0300 Subject: [PATCH 17/27] Update 03-build-containers.yml --- .github/workflows/03-build-containers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index c15234d..6bd80e4 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -110,4 +110,4 @@ jobs: with: name: level-3-certificate path: certificates/ - retention-days: 30 \ No newline at end of file + retention-days: 30 From fec3056aa1cac68a6a693584e2c14a8f611319f5 Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 23:56:05 -0300 Subject: [PATCH 18/27] Update 03-build-containers.yml --- .github/workflows/03-build-containers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index 6bd80e4..67f027b 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -64,7 +64,7 @@ jobs: - name: Upload do relatório de lint uses: actions/upload-artifact@v4 with: - name: lint-report + name path: lint-report.txt - name: Upload do relatório de vulnerabilidades From 4db97dee965403b285b90c77a2a1fcc38332f60d Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Fri, 3 Oct 2025 23:59:03 -0300 Subject: [PATCH 19/27] Update 03-build-containers.yml --- .github/workflows/03-build-containers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index 67f027b..6bd80e4 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -64,7 +64,7 @@ jobs: - name: Upload do relatório de lint uses: actions/upload-artifact@v4 with: - name + name: lint-report path: lint-report.txt - name: Upload do relatório de vulnerabilidades From 612d04470c8d547a8b6f5506c18ac663d4103a87 Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Sat, 4 Oct 2025 00:04:03 -0300 Subject: [PATCH 20/27] Update 03-build-containers.yml --- .github/workflows/03-build-containers.yml | 105 +++++++++++----------- 1 file changed, 50 insertions(+), 55 deletions(-) diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index 6bd80e4..4590f29 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -3,26 +3,20 @@ name: "Nível 3: Containers e Segurança" on: pull_request: types: [closed] - branches: - - desafio-nivel-3 - -permissions: - contents: read - packages: write - -env: - CHALLENGE_LEVEL: 3 - CHALLENGE_NAME: "containers-e-seguranca" - REGISTRY: ghcr.io + branches: [desafio-nivel-3] jobs: build-scan-and-push: - name: "Build, Lint, Trivy Scan e Push no GHCR" if: github.event.pull_request.merged == true runs-on: ubuntu-latest + permissions: + contents: read + packages: write + security-events: write + steps: - name: Checkout do código - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Login no GHCR uses: docker/login-action@v3 @@ -31,81 +25,82 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build da imagem Docker - run: | - docker build -t ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} . - - name: Lint do Dockerfile com Hadolint run: | - hadolint Dockerfile --format tty | tee lint-report.txt - if grep -q "DL3006\|DL3008" lint-report.txt; then + docker run --rm -i hadolint/hadolint < Dockerfile > lint-report.txt 2>&1 || true + if grep -q 'DL3006\|DL3008' lint-report.txt; then + echo "::error::Falha no lint: DL3006 (Always tag versions) ou DL3008 (Pin versions) detectados" exit 1 fi + - name: Build da imagem Docker + uses: docker/build-push-action@v6 + id: build + with: + context: . + tags: | + ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }}:${{ github.sha }} + outputs: type=image,name=ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }} + - name: Scan de vulnerabilidades com Trivy uses: aquasecurity/trivy-action@0.28.0 with: - image-ref: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} - format: sarif - output: trivy-report.txt - severity: CRITICAL + image-ref: ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }}:${{ github.sha }} + format: table exit-code: 1 + severity: CRITICAL + ignore-unfixed: true + output: trivy-report.txt - name: Publicar imagem no GHCR + if: success() uses: docker/build-push-action@v6 with: - context: . push: true - tags: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + tags: ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }}:${{ github.sha }} - - name: Upload do relatório de lint + - name: Upload de relatórios uses: actions/upload-artifact@v4 with: - name: lint-report - path: lint-report.txt - - - name: Upload do relatório de vulnerabilidades - uses: actions/upload-artifact@v4 - with: - name: trivy-report - path: trivy-report.txt + name: security-reports + path: | + lint-report.txt + trivy-report.txt generate-certificate: name: "Desafio Nível 3 - Certificado" - needs: build-scan-and-push + needs: [build-scan-and-push] if: success() runs-on: ubuntu-latest + steps: - - name: "Gerar certificado" + - name: Gerar certificado run: | mkdir -p certificates cat > certificates/level-3-certificate.md << EOF # Certificado de Conclusão - Nível 3 **Descomplicando Github Actions - GitHub Actions Edition** --- - Este certificado atesta que **${{ github.actor }}** concluiu com sucesso: - ## Nível 3: Containers e Segurança - **Competências desenvolvidas:** - - Build de imagem Docker - - Lint de Dockerfile com Hadolint - - Scan de vulnerabilidades com Trivy (CRITICAL = 0) - - Relatório de vulnerabilidades como artefato - - Publicação no GitHub Container Registry (GHCR) condicionada ao scan - - Boas práticas de supply chain - **Data de conclusão:** $(date) + **Participante:** ${{ github.actor }} **Repositório:** ${{ github.repository }} - **Workflow:** ${{ github.run_id }} - --- - **Badge conquistado:** Containers e Segurança + **Commit:** ${{ github.sha }} + **Data:** $(date +"%d/%m/%Y %H:%M:%S") + + ## Competências validadas: + - Build seguro de imagens Docker + - Análise estática de Dockerfile (Hadolint) + - Varredura de vulnerabilidades (Trivy) + - Publicação condicional no GHCR + - Gestão de artefatos de segurança + + **Workflow ID:** ${{ github.run_id }} + **Status:** Aprovado com sucesso --- - *Certificado gerado automaticamente pelo GitHub Actions* - *LINUXtips* + *Emitido automaticamente via GitHub Actions* + *LINUXtips | Supply Chain Security* EOF - - name: "Upload do certificado" + - name: Upload do certificado uses: actions/upload-artifact@v4 with: name: level-3-certificate From ffdc04c5ac297301e9efba010e67daa4d4bfdd8e Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Sat, 4 Oct 2025 00:11:07 -0300 Subject: [PATCH 21/27] Update 03-build-containers.yml --- .github/workflows/03-build-containers.yml | 104 ++++++++++++---------- 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index 01a580d..17fe1a9 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -7,16 +7,23 @@ on: - main - desafio-nivel-3 +permissions: + contents: read + packages: write + +env: + CHALLENGE_LEVEL: 3 + CHALLENGE_NAME: "containers-e-seguranca" + REGISTRY: ghcr.io + +jobs: + build-scan-and-push: + name: "Build, Lint, Trivy Scan e Push no GHCR" if: github.event.pull_request.merged == true runs-on: ubuntu-latest - permissions: - contents: read - packages: write - security-events: write - steps: - name: Checkout do código - uses: actions/checkout@v4 + uses: actions/checkout@v3 - name: Login no GHCR uses: docker/login-action@v3 @@ -25,82 +32,81 @@ on: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Build da imagem Docker + run: | + docker build -t ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} . + - name: Lint do Dockerfile com Hadolint run: | - docker run --rm -i hadolint/hadolint < Dockerfile > lint-report.txt 2>&1 || true - if grep -q 'DL3006\|DL3008' lint-report.txt; then - echo "::error::Falha no lint: DL3006 (Always tag versions) ou DL3008 (Pin versions) detectados" + hadolint Dockerfile --format tty | tee lint-report.txt + if grep -q "DL3006\|DL3008" lint-report.txt; then exit 1 fi - - name: Build da imagem Docker - uses: docker/build-push-action@v6 - id: build - with: - context: . - tags: | - ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }}:${{ github.sha }} - outputs: type=image,name=ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }} - - name: Scan de vulnerabilidades com Trivy uses: aquasecurity/trivy-action@0.28.0 with: - image-ref: ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }}:${{ github.sha }} - format: table - exit-code: 1 - severity: CRITICAL - ignore-unfixed: true + image-ref: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} + format: sarif output: trivy-report.txt + severity: CRITICAL + exit-code: 1 - name: Publicar imagem no GHCR - if: success() uses: docker/build-push-action@v6 with: + context: . push: true - tags: ghcr.io/${{ lower(github.repository_owner) }}/${{ lower(vars.IMAGE_NAME) }}:${{ github.sha }} + tags: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Upload de relatórios + - name: Upload do relatório de lint uses: actions/upload-artifact@v4 with: - name: security-reports - path: | - lint-report.txt - trivy-report.txt + name: lint-report + path: lint-report.txt + + - name: Upload do relatório de vulnerabilidades + uses: actions/upload-artifact@v4 + with: + name: trivy-report + path: trivy-report.txt generate-certificate: name: "Desafio Nível 3 - Certificado" - needs: [build-scan-and-push] + needs: build-scan-and-push if: success() runs-on: ubuntu-latest - steps: - - name: Gerar certificado + - name: "Gerar certificado" run: | mkdir -p certificates cat > certificates/level-3-certificate.md << EOF # Certificado de Conclusão - Nível 3 **Descomplicando Github Actions - GitHub Actions Edition** --- - **Participante:** ${{ github.actor }} + Este certificado atesta que **${{ github.actor }}** concluiu com sucesso: + ## Nível 3: Containers e Segurança + **Competências desenvolvidas:** + - Build de imagem Docker + - Lint de Dockerfile com Hadolint + - Scan de vulnerabilidades com Trivy (CRITICAL = 0) + - Relatório de vulnerabilidades como artefato + - Publicação no GitHub Container Registry (GHCR) condicionada ao scan + - Boas práticas de supply chain + **Data de conclusão:** $(date) **Repositório:** ${{ github.repository }} - **Commit:** ${{ github.sha }} - **Data:** $(date +"%d/%m/%Y %H:%M:%S") - - ## Competências validadas: - - Build seguro de imagens Docker - - Análise estática de Dockerfile (Hadolint) - - Varredura de vulnerabilidades (Trivy) - - Publicação condicional no GHCR - - Gestão de artefatos de segurança - - **Workflow ID:** ${{ github.run_id }} - **Status:** Aprovado com sucesso + **Workflow:** ${{ github.run_id }} + --- + **Badge conquistado:** Containers e Segurança --- - *Emitido automaticamente via GitHub Actions* - *LINUXtips | Supply Chain Security* + *Certificado gerado automaticamente pelo GitHub Actions* + *LINUXtips* EOF - - name: Upload do certificado + - name: "Upload do certificado" uses: actions/upload-artifact@v4 with: name: level-3-certificate From a937db8af5e2345452403752b14374e3f05c12f7 Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Sat, 4 Oct 2025 00:25:57 -0300 Subject: [PATCH 22/27] Update 03-build-containers.yml --- .github/workflows/03-build-containers.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index 17fe1a9..6bd80e4 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -4,7 +4,6 @@ on: pull_request: types: [closed] branches: - - main - desafio-nivel-3 permissions: From 4721bd4e42d0dcda028c3667afca9af4e6410065 Mon Sep 17 00:00:00 2001 From: lpampolha <43315774+lpampolha@users.noreply.github.com> Date: Sat, 4 Oct 2025 05:19:37 -0300 Subject: [PATCH 23/27] Update 03-build-containers.yml --- .github/workflows/03-build-containers.yml | 83 +++++++++++++---------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index 6bd80e4..095bebc 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -3,8 +3,7 @@ name: "Nível 3: Containers e Segurança" on: pull_request: types: [closed] - branches: - - desafio-nivel-3 + branches: [ desafio-nivel-3 ] permissions: contents: read @@ -20,60 +19,69 @@ jobs: name: "Build, Lint, Trivy Scan e Push no GHCR" if: github.event.pull_request.merged == true runs-on: ubuntu-latest + steps: - - name: Checkout do código + - name: Checkout repository uses: actions/checkout@v3 - - name: Login no GHCR - uses: docker/login-action@v3 + - name: Lint Dockerfile with Hadolint + uses: hadolint/hadolint-action@v2 with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build da imagem Docker - run: | - docker build -t ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} . + dockerfile: Dockerfile + format: tty + output-file: lint-report.txt + no-fail: true - - name: Lint do Dockerfile com Hadolint + - name: Check for DL3006 or DL3008 violations run: | - hadolint Dockerfile --format tty | tee lint-report.txt - if grep -q "DL3006\|DL3008" lint-report.txt; then - exit 1 + if grep -qE "DL3006|DL3008" lint-report.txt; then + echo "Linting failed due to DL3006 or DL3008." && exit 1; fi - - name: Scan de vulnerabilidades com Trivy - uses: aquasecurity/trivy-action@0.28.0 + - name: Upload lint report + uses: actions/upload-artifact@v3 with: - image-ref: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} - format: sarif - output: trivy-report.txt - severity: CRITICAL - exit-code: 1 + name: lint-report + path: lint-report.txt - - name: Publicar imagem no GHCR - uses: docker/build-push-action@v6 + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 with: - context: . - push: true - tags: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Upload do relatório de lint - uses: actions/upload-artifact@v4 + - name: Build Docker image + id: build-image + uses: docker/build-push-action@v6 with: - name: lint-report - path: lint-report.txt + context: . + file: ./Dockerfile + push: false + tags: ghcr.io/${{ github.repository_owner }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} + + - name: Scan Docker image for vulnerabilities with Trivy + id: scan-image + uses: aquasecurity/trivy-action@0.28.0 + with: + image-ref: ghcr.io/${{ github.repository_owner }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} + format: table + output: trivy-report.txt + + - name: Check for critical vulnerabilities + run: | + if grep -q "CRITICAL" trivy-report.txt; then + echo "Critical vulnerabilities found." && exit 1; + fi + shell: bash - - name: Upload do relatório de vulnerabilidades + - name: Upload Trivy report uses: actions/upload-artifact@v4 with: name: trivy-report path: trivy-report.txt - generate-certificate: + generate-certificate: # DAQUI PARA BAIXO, NÃO ALTERAR name: "Desafio Nível 3 - Certificado" needs: build-scan-and-push if: success() @@ -84,22 +92,29 @@ jobs: mkdir -p certificates cat > certificates/level-3-certificate.md << EOF # Certificado de Conclusão - Nível 3 + **Descomplicando Github Actions - GitHub Actions Edition** --- + Este certificado atesta que **${{ github.actor }}** concluiu com sucesso: ## Nível 3: Containers e Segurança + **Competências desenvolvidas:** - Build de imagem Docker - Lint de Dockerfile com Hadolint - Scan de vulnerabilidades com Trivy (CRITICAL = 0) - Relatório de vulnerabilidades como artefato + - Smoke test de execução do container - Publicação no GitHub Container Registry (GHCR) condicionada ao scan - Boas práticas de supply chain + **Data de conclusão:** $(date) **Repositório:** ${{ github.repository }} **Workflow:** ${{ github.run_id }} + --- **Badge conquistado:** Containers e Segurança + --- *Certificado gerado automaticamente pelo GitHub Actions* *LINUXtips* From 53dea9d79159009cc6100f189e0bce3df8d48040 Mon Sep 17 00:00:00 2001 From: Lucas Pampolha Date: Sat, 4 Oct 2025 05:39:41 -0300 Subject: [PATCH 24/27] Desafio-3 --- .github/workflows/02-tests-ci.yml | 4 +++- README.md | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/02-tests-ci.yml b/.github/workflows/02-tests-ci.yml index 59b8cd7..bee57ae 100644 --- a/.github/workflows/02-tests-ci.yml +++ b/.github/workflows/02-tests-ci.yml @@ -1,7 +1,9 @@ name: "Nível 2: Testes Automatizados" on: pull_request: - branches: [ main ] + branches: + - main + - desafio-nivel-3 env: NODE_VERSION: '18' diff --git a/README.md b/README.md index 7bb74fc..724fe2e 100644 --- a/README.md +++ b/README.md @@ -86,5 +86,6 @@ Ao completar cada workflow com sucesso, você ganha os badges: --- **Feito pela comunidade LINUXtips.** - +#VAIIIIII +Teste From 14e4b36c2b6ad07ccedbe400e3e66aeba9825eef Mon Sep 17 00:00:00 2001 From: Lucas Pampolha Date: Sat, 4 Oct 2025 05:42:29 -0300 Subject: [PATCH 25/27] Desafio-3 --- .github/workflows/02-tests-ci.yml | 26 ++++++--- .github/workflows/03-build-containers.yml | 69 ++++++++++++++++++----- DESAFIO-03.md | 60 ++++++++++++++++++++ README.md | 7 ++- package-lock.json | 3 +- package.json | 8 +-- 6 files changed, 146 insertions(+), 27 deletions(-) create mode 100644 DESAFIO-03.md diff --git a/.github/workflows/02-tests-ci.yml b/.github/workflows/02-tests-ci.yml index 3a9801b..bee57ae 100644 --- a/.github/workflows/02-tests-ci.yml +++ b/.github/workflows/02-tests-ci.yml @@ -1,13 +1,15 @@ name: "Nível 2: Testes Automatizados" on: pull_request: - branches: [ main ] + branches: + - main + - desafio-nivel-3 env: NODE_VERSION: '18' CHALLENGE_LEVEL: 2 CHALLENGE_NAME: "testes-automatizados" - COVERAGE_MIN: 80 # Cobertura mínima exigida em porcentagem + COVERAGE_MIN: 99 # Cobertura mínima exigida em porcentagem jobs: tests-and-coverage: @@ -20,10 +22,15 @@ jobs: - name: "Checkout do código" uses: actions/checkout@v4 - # INSIRA AQUI A LÓGICA PARA RODAR OS TESTES E VERIFICAR A COBERTURA - ### - ### - ### + - name: "Setup Node" + uses: actions/setup-node@v5 + with: + node-version: ${{env.NODE_VERSION}} + + - name: "Instalar dependências" + run: npm ci + - name: "Executar testes" + run: npm run tests - name: "Extrair porcentagem de cobertura" # Esse step será validado pelo desafio, não altere o nome. No final, ele deve gerar o output "coverage" com a porcentagem de cobertura. id: coverage @@ -31,7 +38,12 @@ jobs: COVERAGE=$(npx nyc report --reporter=text-summary | grep -oP 'Statements\s*:\s*\K[0-9\.]+(?=%)' | head -1) echo "Coverage: $COVERAGE%" echo "coverage=$COVERAGE" >> $GITHUB_OUTPUT - + + - name: "Validar se os testes passaram" + if: ${{steps.coverage.outputs.coverage < env.COVERAGE_MIN}} + run: | + echo "Cobertura mínima não atendida: Esperado - ${{ env.COVERAGE_MIN }}%. Atingido: ${{ steps.coverage.outputs.coverage }}%" + exit 1 generate-certificate: # DAQUI PARA BAIXO, NÃO ALTERAR name: "Desafio Nível 2 - Certificado" runs-on: ubuntu-latest diff --git a/.github/workflows/03-build-containers.yml b/.github/workflows/03-build-containers.yml index cbddc24..c15234d 100644 --- a/.github/workflows/03-build-containers.yml +++ b/.github/workflows/03-build-containers.yml @@ -3,7 +3,8 @@ name: "Nível 3: Containers e Segurança" on: pull_request: types: [closed] - branches: [ desafio-nivel-3 ] + branches: + - desafio-nivel-3 permissions: contents: read @@ -17,13 +18,62 @@ env: jobs: build-scan-and-push: name: "Build, Lint, Trivy Scan e Push no GHCR" - if: #???? + if: github.event.pull_request.merged == true runs-on: ubuntu-latest - steps: - # AQUI VAI O CÓDIGO DO DESAFIO :) + - name: Checkout do código + uses: actions/checkout@v3 + + - name: Login no GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build da imagem Docker + run: | + docker build -t ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} . + + - name: Lint do Dockerfile com Hadolint + run: | + hadolint Dockerfile --format tty | tee lint-report.txt + if grep -q "DL3006\|DL3008" lint-report.txt; then + exit 1 + fi + + - name: Scan de vulnerabilidades com Trivy + uses: aquasecurity/trivy-action@0.28.0 + with: + image-ref: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} + format: sarif + output: trivy-report.txt + severity: CRITICAL + exit-code: 1 - generate-certificate: # DAQUI PARA BAIXO, NÃO ALTERAR + - name: Publicar imagem no GHCR + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ghcr.io/${{ github.actor }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload do relatório de lint + uses: actions/upload-artifact@v4 + with: + name: lint-report + path: lint-report.txt + + - name: Upload do relatório de vulnerabilidades + uses: actions/upload-artifact@v4 + with: + name: trivy-report + path: trivy-report.txt + + generate-certificate: name: "Desafio Nível 3 - Certificado" needs: build-scan-and-push if: success() @@ -34,29 +84,22 @@ jobs: mkdir -p certificates cat > certificates/level-3-certificate.md << EOF # Certificado de Conclusão - Nível 3 - **Descomplicando Github Actions - GitHub Actions Edition** --- - Este certificado atesta que **${{ github.actor }}** concluiu com sucesso: ## Nível 3: Containers e Segurança - **Competências desenvolvidas:** - Build de imagem Docker - Lint de Dockerfile com Hadolint - Scan de vulnerabilidades com Trivy (CRITICAL = 0) - Relatório de vulnerabilidades como artefato - - Smoke test de execução do container - Publicação no GitHub Container Registry (GHCR) condicionada ao scan - Boas práticas de supply chain - **Data de conclusão:** $(date) **Repositório:** ${{ github.repository }} **Workflow:** ${{ github.run_id }} - --- **Badge conquistado:** Containers e Segurança - --- *Certificado gerado automaticamente pelo GitHub Actions* *LINUXtips* @@ -67,4 +110,4 @@ jobs: with: name: level-3-certificate path: certificates/ - retention-days: 30 + retention-days: 30 \ No newline at end of file diff --git a/DESAFIO-03.md b/DESAFIO-03.md new file mode 100644 index 0000000..a202ebd --- /dev/null +++ b/DESAFIO-03.md @@ -0,0 +1,60 @@ +# Desafio 03 – Containers e Segurança (GHCR) + +## Requisitos do pipeline + +- Deve existir um novo workflow do GitHub Actions para o Nível 3 (containers e segurança). +- O disparo deve acontecer quando um Pull Request para a branch `desafio-nivel-3` for fechado com merge (evento `pull_request`, `types: [closed]` + condição `github.event.pull_request.merged == true`). +- O workflow deve: + - Fazer login no GitHub Container Registry (GHCR) utilizando `GITHUB_TOKEN`. + - Montar a tag da imagem sempre com o SHA do commit, e com `owner`, `IMAGE_NAME` e `registry` em minúsculas. + - Buildar a imagem Docker para permitir o scan de vulnerabilidades. + - Executar lint do `Dockerfile` com Hadolint, salvando o resultado em `lint-report.txt` e falhando se forem encontrados os problemas DL3006 ou DL3008. + - Executar o scan de vulnerabilidades com Trivy na imagem construída. + - O resultado deve ser salvo em `trivy-report.txt` e publicado como artefato. + - O workflow deve falhar caso o Trivy encontre vulnerabilidades CRITICAL. + - Publicar no GHCR somente se todas as validações passarem. + - Gerar o artefato `level-3-certificate.md` (não alterar a seção do certificado, assim como nos desafios anteriores). + +### Importante: Proteção de branch + +Antes de executar, configure a proteção da branch `desafio-nivel-3` como mostramos na live de quarta. Isso garante a qualidade do ciclo de revisão e evita merges diretos na `desafio-nivel-3` sem validações. Veja a demonstração aqui: [AO VIVO - Descomplicando Github Actions - Resolvendo Desafio](https://www.youtube.com/watch?v=VihvfGx58IY). + +## Variável obrigatória + +- Crie uma variável de repositório chamada `IMAGE_NAME` (em: Settings > Secrets and variables > Actions > Variables) com o nome da aplicação a ser usada no nome da imagem (ex.: `desafio3-linuxtips-gha`). +- Essa variável é obrigatória e será utilizada para compor o nome final da imagem no GHCR. + +## Actions obrigatórias + +- `docker/login-action@v3` +- `docker/build-push-action@v6` +- `aquasecurity/trivy-action@0.28.0` + +### Política de lint (Hadolint) + +Para nós, os checks do Hadolint devem focar nos itens que mais impactam segurança e reprodutibilidade. Portanto, este pipeline deve falhar apenas quando forem detectadas as regras abaixo: + +- DL3006: uso consistente e fixação do gerenciador de pacotes/base da imagem (garante builds reprodutíveis); +- DL3008: instalação de pacotes sem pin de versões (evita deriva de dependências e janelas de vulnerabilidade). + +Por política da empresa e conformidade de supply chain, consideramos DL3006 e DL3008 bloqueadores. + +## Regras de publicação da imagem + +- Registry: `ghcr.io` +- Tag obrigatória: o SHA do commit (`${{ github.sha }}`) +- Nome completo (exemplo): `ghcr.io//:` +- O nome completo deve ser convertido para minúsculas para evitar erros no push. + +## Esqueleto mínimo do workflow + +No arquivo `.github/workflows/03-build-containers.yml`, deixe apenas o esqueleto mínimo dentro do job `build-scan-and-push`. Defina os nomes dos steps como dicas, mas sem implementação. + +## Critérios de aceite + +- [ ] Workflow Nível 3 dispara somente após PR mergeado na `desafio-nivel-3`. +- [ ] `Dockerfile` analisado com Hadolint; gerar artefato `lint-report.txt` e falhar em DL3006/DL3008. +- [ ] Imagem construída e escaneada com Trivy (CRITICAL = 0) com artefato `trivy-report.txt`. +- [ ] Push realizado no GHCR apenas se todas as verificações passarem. +- [ ] Tag da imagem é exatamente o SHA do commit e nome em minúsculas. +- [ ] Uso das actions nas versões exigidas. diff --git a/README.md b/README.md index 7bb74fc..70861d6 100644 --- a/README.md +++ b/README.md @@ -86,5 +86,10 @@ Ao completar cada workflow com sucesso, você ganha os badges: --- **Feito pela comunidade LINUXtips.** - +#VAIIIIII +<<<<<<< HEAD +Teste123! +======= +Teste +>>>>>>> lpampolha/desafio-nivel-3 diff --git a/package-lock.json b/package-lock.json index ef1322c..b2c7d57 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "cors": "^2.8.5", "dotenv": "^16.3.1", - "express": "^4.18.2", + "express": "^4.21.2", "helmet": "^7.0.0", "node-fetch": "^3.3.2" }, @@ -2040,7 +2040,6 @@ "version": "4.21.2", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", diff --git a/package.json b/package.json index 2175daf..1326318 100644 --- a/package.json +++ b/package.json @@ -19,16 +19,16 @@ "author": "LINUXtips", "license": "MIT", "dependencies": { - "express": "^4.18.2", "cors": "^2.8.5", - "helmet": "^7.0.0", "dotenv": "^16.3.1", + "express": "^4.21.2", + "helmet": "^7.0.0", "node-fetch": "^3.3.2" }, "devDependencies": { "jest": "^29.7.0", - "supertest": "^6.3.4", - "nyc": "^17.1.0" + "nyc": "^17.1.0", + "supertest": "^6.3.4" }, "engines": { "node": ">=16.0.0" From 70006fbeb0df59e2118ba19ab08771550d2c29f0 Mon Sep 17 00:00:00 2001 From: Lucas Pampolha Date: Sat, 4 Oct 2025 05:45:10 -0300 Subject: [PATCH 26/27] Desafio-3 --- README.md | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/README.md b/README.md index e69de29..724fe2e 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,91 @@ +# Descomplicando GitHub Actions + +Se inscreva na aula ao vivo e gratuita: https://quiz.linuxtips.io/github-actions + +Bem-vindo ao **Descomplicando GitHub Actions**! Este projeto foi criado pela comunidade **LINUXtips** para você aprender os conceitos básicos de CI/CD na prática de forma simples e direta. + +Este projeto foi desenhado para ser o material de apoio do vídeo "Descomplicando GitHub Actions" no [canal da LINUXtips no YouTube](https://youtube.com/linuxtips). A ideia é que você possa codificar junto e aprender na prática. + +## O que você vai aprender + +Neste projeto você aprenderá: + +- **Estrutura de um workflow**: jobs, steps, actions do marketplace +- **Como usar actions prontas**: `actions/checkout`, `actions/setup-node` +- **Executar comandos**: instalação de dependências, build, testes e cobertura +- **Health checks**: verificar se sua aplicação está funcionando +- **Artefatos**: gerar certificados de conclusão dos níveis 1 e 2 + +## Como Começar + +1. **Fork este Repositório:** + Clique no botão **"Fork"** no canto superior direito desta página para criar uma cópia deste projeto na sua própria conta do GitHub. + +2. **Clone o seu Fork:** + ```bash + git clone https://github.com/SEU-USUARIO-GITHUB/LINUXtips-github-actions.git + cd LINUXtips-github-actions + ``` + +3. **Habilite os GitHub Actions:** + Vá para a aba **"Actions"** do seu repositório e clique no botão verde **"I understand my workflows, go ahead and enable them"**. + +4. **Instale as Dependências:** + Você precisa do Node.js (versão 16 ou superior): + ```bash + npm install + ``` + +5. **Teste a Aplicação Localmente:** + ```bash + npm start + ``` + Acesse [http://localhost:3000](http://localhost:3000) no seu navegador. + +6. **Execute seu Primeiro Workflow:** + - Faça uma alteração simples (ex: adicione seu nome no README.md) + - Faça commit e push + - Vá para a aba "Actions" e veja seu primeiro workflow rodando! + +## O que acontece nos Workflows? + +O arquivo `01-basic-ci.yml` (Nível 1) demonstra: + +1. **Setup do Ambiente**: Configuração do Node.js +2. **Verificação da Estrutura**: Validação dos arquivos do projeto +3. **Build**: Executar o comando de build +4. **Health Check**: Testar se a aplicação inicia corretamente +5. **Certificado**: Gerar um artefato com seu certificado de conclusão (level-1-certificate) + +O arquivo `02-tests-ci.yml` (Nível 2) demonstra: + +1. **Testes Automatizados**: Executar Jest com cobertura +2. **Cobertura Mínima**: Validar cobertura mínima definida por `COVERAGE_MIN` (80%) +3. **Certificado**: Gerar um artefato com seu certificado do nível 2 (level-2-certificate) + +## Badges Conquistados + +Ao completar cada workflow com sucesso, você ganha os badges: + +![Desafio 01 Concluído](https://img.shields.io/badge/Desafio_01-Concluído-brightgreen?style=for-the-badge&logo=githubactions&logoColor=white) + +![Desafio 02 Concluído](https://img.shields.io/badge/Desafio_02-Concluído-8a2be2?style=for-the-badge&logo=github&logoColor=white) + +## Entendendo o Código + +- **`server.js`**: Aplicação Express simples com dashboard e API +- **`public/`**: Interface web que mostra seu progresso +- **`package.json`**: Dependências e scripts do Node.js +- **`.github/workflows/01-basic-ci.yml`**: Seu primeiro workflow do GitHub Actions + +## Agradecimentos + +- Ao **Jeferson e ao Fábio**, além de toda a comunidade **LINUXtips** por inspirar e fomentar a educação em tecnologia no Brasil. +- A todos os contribuidores que ajudarem a tornar este projeto ainda melhor. + +--- + +**Feito pela comunidade LINUXtips.** +#VAIIIIII +Teste + From 786968d309629be26e220ccffab450ed85bcf550 Mon Sep 17 00:00:00 2001 From: Lucas Pampolha Date: Sat, 4 Oct 2025 06:48:56 -0300 Subject: [PATCH 27/27] Desafio-3 --- LINUXtips-github-actions-main/.env.example | 21 ++ LINUXtips-github-actions-main/.eslintrc.js | 41 ++++ .../.github/workflows/01-basic-ci.yml | 230 ++++++++++++++++++ .../.github/workflows/02-tests-ci.yml | 93 +++++++ .../.github/workflows/03-build-containers.yml | 128 ++++++++++ LINUXtips-github-actions-main/.gitignore | 116 +++++++++ README.md | 9 +- package-lock.json | 3 +- package.json | 8 +- 9 files changed, 642 insertions(+), 7 deletions(-) create mode 100644 LINUXtips-github-actions-main/.env.example create mode 100644 LINUXtips-github-actions-main/.eslintrc.js create mode 100644 LINUXtips-github-actions-main/.github/workflows/01-basic-ci.yml create mode 100644 LINUXtips-github-actions-main/.github/workflows/02-tests-ci.yml create mode 100644 LINUXtips-github-actions-main/.github/workflows/03-build-containers.yml create mode 100644 LINUXtips-github-actions-main/.gitignore diff --git a/LINUXtips-github-actions-main/.env.example b/LINUXtips-github-actions-main/.env.example new file mode 100644 index 0000000..e1e9e55 --- /dev/null +++ b/LINUXtips-github-actions-main/.env.example @@ -0,0 +1,21 @@ +# Descomplicando Github Actions - Configuração de Ambiente + +# Porta do servidor (padrão: 3000) +PORT=3000 + +# Ambiente de execução +NODE_ENV=development + +# URL base da aplicação (para produção) +# BASE_URL=https://seu-dominio.com + +# Configurações de monitoramento (opcional) +# MONITORING_ENABLED=true +# WEBHOOK_URL=https://hooks.slack.com/services/... + +# GitHub Token para APIs (opcional - para funcionalidades avançadas) +# GITHUB_TOKEN=ghp_... + +# Configurações de deploy (opcional) +# DEPLOY_ENVIRONMENT=staging + diff --git a/LINUXtips-github-actions-main/.eslintrc.js b/LINUXtips-github-actions-main/.eslintrc.js new file mode 100644 index 0000000..07ae10b --- /dev/null +++ b/LINUXtips-github-actions-main/.eslintrc.js @@ -0,0 +1,41 @@ +module.exports = { + env: { + browser: true, + commonjs: true, + es2021: true, + node: true, + jest: true + }, + extends: [ + 'eslint:recommended' + ], + parserOptions: { + ecmaVersion: 12 + }, + rules: { + // Regras básicas de qualidade + 'indent': ['error', 2], + 'linebreak-style': ['error', 'unix'], + 'quotes': ['error', 'single'], + 'semi': ['error', 'always'], + + // Regras de segurança + 'no-eval': 'error', + 'no-implied-eval': 'error', + 'no-new-func': 'error', + 'no-script-url': 'error', + + // Regras de boas práticas + 'no-unused-vars': 'warn', + 'no-console': 'warn', + 'prefer-const': 'error', + 'no-var': 'error' + }, + ignorePatterns: [ + 'node_modules/', + 'coverage/', + 'dist/', + 'build/' + ] +}; + diff --git a/LINUXtips-github-actions-main/.github/workflows/01-basic-ci.yml b/LINUXtips-github-actions-main/.github/workflows/01-basic-ci.yml new file mode 100644 index 0000000..429e3d1 --- /dev/null +++ b/LINUXtips-github-actions-main/.github/workflows/01-basic-ci.yml @@ -0,0 +1,230 @@ +name: "Nível 1: Basic CI" + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + +env: + NODE_VERSION: '18' + CHALLENGE_LEVEL: 1 + CHALLENGE_NAME: "first-steps" + +jobs: + basic-setup: + name: "Setup & Basic Checks" + runs-on: ubuntu-latest + + outputs: + node-version: ${{ steps.setup.outputs.node-version }} + challenge-status: ${{ steps.challenge.outputs.status }} + + steps: + - name: "Checkout do código" + uses: actions/checkout@v4 + + - name: "Setup Node.js" + id: setup + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' + + - name: "Informações do ambiente" + run: | + echo "Runner: ${{ runner.os }}" + echo "Node.js: $(node --version)" + echo "NPM: $(npm --version)" + echo "Challenge: ${{ env.CHALLENGE_NAME }}" + echo "Data: $(date)" + + - name: "Instalar dependências" + run: | + echo "Instalando dependências..." + npm ci + echo "Dependências instaladas com sucesso!" + + - name: "Verificar estrutura do projeto" + run: | + echo "Verificando estrutura do projeto..." + ls -la + echo "" + echo "Arquivos principais encontrados:" + [ -f "package.json" ] && echo "package.json" + [ -f "server.js" ] && echo "server.js" + [ -f "server.test.js" ] && echo "server.test.js" + [ -d "public" ] && echo "diretório public/" + [ -d ".github/workflows" ] && echo "workflows configurados" + + - name: "Challenge Status" + id: challenge + run: | + echo "Parabéns! Você executou seu primeiro GitHub Action!" + echo "Status: INICIADO" + echo "Próximo passo: Execute os testes automatizados" + echo "status=started" >> $GITHUB_OUTPUT + + build: + name: "Build da Aplicação" + runs-on: ubuntu-latest + needs: basic-setup + + steps: + - name: "Checkout do código" + uses: actions/checkout@v4 + + - name: "Setup Node.js" + uses: actions/setup-node@v4 + with: + node-version: ${{ needs.basic-setup.outputs.node-version }} + cache: 'npm' + + - name: "Instalar dependências" + run: npm ci + + - name: "Build da aplicação" + run: | + echo "Iniciando build..." + npm run build + echo "Build concluído com sucesso!" + + - name: "Estatísticas do build" + run: | + echo "Estatísticas do build:" + echo "Tamanho do projeto: $(du -sh . | cut -f1)" + echo "Arquivos: $(find . -type f | wc -l)" + + health-check: + name: "Health Check" + runs-on: ubuntu-latest + needs: [basic-setup, build] + + steps: + - name: "Checkout do código" + uses: actions/checkout@v4 + + - name: "Setup Node.js" + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' + + - name: "Instalar dependências" + run: npm ci + + - name: "Iniciar servidor em background" + run: | + echo "Iniciando servidor..." + npm start & + SERVER_PID=$! + echo "SERVER_PID=$SERVER_PID" >> $GITHUB_ENV + sleep 10 + + - name: "Verificar health endpoint" + run: | + echo "Verificando health check..." + curl -f http://localhost:3000/health || exit 1 + echo "Health check passou!" + + - name: "Parar servidor" + if: always() + run: | + if [ ! -z "$SERVER_PID" ]; then + kill $SERVER_PID || true + fi + + challenge-complete: + name: "Desafio Nível 1 - Concluído!" + runs-on: ubuntu-latest + needs: [basic-setup, build, health-check] + if: success() + + steps: + - name: "Parabéns!" + run: | + echo "PARABÉNS! Você concluiu o Nível 1!" + echo "" + echo "O que você aprendeu:" + echo " • Como criar um workflow básico" + echo " • Usar actions do marketplace (checkout, setup-node)" + echo " • Definir jobs e steps" + echo " • Usar variáveis de ambiente" + echo " • Fazer build e health check" + echo "" + echo "Badge desbloqueado: First Steps 🚀" + echo "Próximo desafio: Nível 2 - Testing Master" + echo "" + echo "Veja seu progresso em: https://github.com/${{ github.repository }}/actions" + + - name: "Atualizar estatísticas" + run: | + echo "Atualizando estatísticas do desafio..." + echo "Challenge: ${{ env.CHALLENGE_NAME }}" + echo "Status: CONCLUÍDO" + echo "Data: $(date)" + echo "Usuário: ${{ github.actor }}" + + - name: "Gerar certificado" + run: | + mkdir -p certificates + cat > certificates/level-1-certificate.md << EOF + # Certificado de Conclusão - Nível 1 + + **Descomplicando Github Actions - GitHub Actions Edition** + + --- + + Este certificado atesta que **${{ github.actor }}** concluiu com sucesso: + + ## Nível 1: Primeiro Contato + + **Competências desenvolvidas:** + - Configuração de workflow básico + - Uso de actions do marketplace + - Definição de jobs e steps + - Variáveis de ambiente + - Build e health check automatizados + + **Data de conclusão:** $(date) + **Repositório:** ${{ github.repository }} + **Workflow:** ${{ github.run_id }} + + --- + + **Badge conquistado:** First Steps + + **Próximo desafio:** Nível 2 - Testing Master + + --- + + *Certificado gerado automaticamente pelo GitHub Actions* + *LINUXtips* + EOF + + - name: "Upload do certificado" + uses: actions/upload-artifact@v4 + with: + name: level-1-certificate + path: certificates/ + retention-days: 30 + + - name: "Notificar aplicação sobre conclusão" + run: | + echo "Notificando aplicação sobre a conclusão do workflow..." + + # Tentar notificar a aplicação local (se estiver rodando) + curl -X POST "http://localhost:3000/api/workflow-complete" \ + -H "Content-Type: application/json" \ + -d '{ + "username": "${{ github.actor }}", + "repository": "${{ github.event.repository.name }}", + "workflowName": "${{ github.workflow }}", + "runId": "${{ github.run_id }}", + "certificateGenerated": true + }' || echo "Aplicação local não encontrada (normal em ambiente de produção)" + + echo "Workflow concluído com sucesso!" + echo "Badge será desbloqueado automaticamente se a aplicação estiver rodando" + diff --git a/LINUXtips-github-actions-main/.github/workflows/02-tests-ci.yml b/LINUXtips-github-actions-main/.github/workflows/02-tests-ci.yml new file mode 100644 index 0000000..a5fad7b --- /dev/null +++ b/LINUXtips-github-actions-main/.github/workflows/02-tests-ci.yml @@ -0,0 +1,93 @@ +name: "Nível 2: Testes Automatizados" +on: + pull_request: + branches: + - main + - desafio-nivel-3 + +env: + NODE_VERSION: '18' + CHALLENGE_LEVEL: 2 + CHALLENGE_NAME: "testes-automatizados" + COVERAGE_MIN: 80 # Cobertura mínima exigida em porcentagem + +jobs: + tests-and-coverage: + name: "Testes e Cobertura" + runs-on: ubuntu-latest + outputs: + coverage: ${{ steps.coverage.outputs.coverage }} + + steps: + - name: "Checkout do código" + uses: actions/checkout@v4 + + - name: "Setup Node.js" + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: "Install dependencies" + run: npm ci + + - name: "Build" + run: npm run build + + - name: "Run tests with coverage" + run: npm run tests + + - name: "Extrair porcentagem de cobertura" # Esse step será validado pelo desafio, não altere o nome. No final, ele deve gerar o output "coverage" com a porcentagem de cobertura. + id: coverage + run: | + COVERAGE=$(npx nyc report --reporter=text-summary | grep -oP 'Statements\s*:\s*\K[0-9\.]+(?=%)' | head -1) + echo "Coverage: $COVERAGE%" + echo "coverage=$COVERAGE" >> $GITHUB_OUTPUT + if (( $(echo "$COVERAGE < $COVERAGE_MIN" | bc -l) )); then + echo "Cobertura ($COVERAGE) está abaixo do mínimo configurado de: $COVERAGE_MIN%." + exit 1 + fi + + generate-certificate: # DAQUI PARA BAIXO, NÃO ALTERAR + name: "Desafio Nível 2 - Certificado" + runs-on: ubuntu-latest + needs: tests-and-coverage + if: success() && needs.tests-and-coverage.outputs.coverage != '' + + steps: + - name: "Gerar certificado" + run: | + mkdir -p certificates + cat > certificates/level-2-certificate.md << EOF + # Certificado de Conclusão - Nível 2 + + **Descomplicando Github Actions - GitHub Actions Edition** + --- + + Este certificado atesta que **${{ github.actor }}** concluiu com sucesso: + ## Nível 2: Testes Automatizados + + **Competências desenvolvidas:** + - Automação de testes + - Análise de cobertura + - Lógica de validação com coverage mínimo + - Upload de artefatos + + **Cobertura:** >= ${{ env.COVERAGE_MIN }}% + **Data de conclusão:** $(date) + **Repositório:** ${{ github.repository }} + **Workflow:** ${{ github.run_id }} + + --- + **Badge conquistado:** Testes Automatizados + + --- + *Certificado gerado automaticamente pelo GitHub Actions* + *LINUXtips* + EOF + + - name: "Upload do certificado" + uses: actions/upload-artifact@v4 + with: + name: level-2-certificate + path: certificates/ + retention-days: 30 diff --git a/LINUXtips-github-actions-main/.github/workflows/03-build-containers.yml b/LINUXtips-github-actions-main/.github/workflows/03-build-containers.yml new file mode 100644 index 0000000..095bebc --- /dev/null +++ b/LINUXtips-github-actions-main/.github/workflows/03-build-containers.yml @@ -0,0 +1,128 @@ +name: "Nível 3: Containers e Segurança" + +on: + pull_request: + types: [closed] + branches: [ desafio-nivel-3 ] + +permissions: + contents: read + packages: write + +env: + CHALLENGE_LEVEL: 3 + CHALLENGE_NAME: "containers-e-seguranca" + REGISTRY: ghcr.io + +jobs: + build-scan-and-push: + name: "Build, Lint, Trivy Scan e Push no GHCR" + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Lint Dockerfile with Hadolint + uses: hadolint/hadolint-action@v2 + with: + dockerfile: Dockerfile + format: tty + output-file: lint-report.txt + no-fail: true + + - name: Check for DL3006 or DL3008 violations + run: | + if grep -qE "DL3006|DL3008" lint-report.txt; then + echo "Linting failed due to DL3006 or DL3008." && exit 1; + fi + + - name: Upload lint report + uses: actions/upload-artifact@v3 + with: + name: lint-report + path: lint-report.txt + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build Docker image + id: build-image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: false + tags: ghcr.io/${{ github.repository_owner }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} + + - name: Scan Docker image for vulnerabilities with Trivy + id: scan-image + uses: aquasecurity/trivy-action@0.28.0 + with: + image-ref: ghcr.io/${{ github.repository_owner }}/${{ vars.IMAGE_NAME }}:${{ github.sha }} + format: table + output: trivy-report.txt + + - name: Check for critical vulnerabilities + run: | + if grep -q "CRITICAL" trivy-report.txt; then + echo "Critical vulnerabilities found." && exit 1; + fi + shell: bash + + - name: Upload Trivy report + uses: actions/upload-artifact@v4 + with: + name: trivy-report + path: trivy-report.txt + + generate-certificate: # DAQUI PARA BAIXO, NÃO ALTERAR + name: "Desafio Nível 3 - Certificado" + needs: build-scan-and-push + if: success() + runs-on: ubuntu-latest + steps: + - name: "Gerar certificado" + run: | + mkdir -p certificates + cat > certificates/level-3-certificate.md << EOF + # Certificado de Conclusão - Nível 3 + + **Descomplicando Github Actions - GitHub Actions Edition** + --- + + Este certificado atesta que **${{ github.actor }}** concluiu com sucesso: + ## Nível 3: Containers e Segurança + + **Competências desenvolvidas:** + - Build de imagem Docker + - Lint de Dockerfile com Hadolint + - Scan de vulnerabilidades com Trivy (CRITICAL = 0) + - Relatório de vulnerabilidades como artefato + - Smoke test de execução do container + - Publicação no GitHub Container Registry (GHCR) condicionada ao scan + - Boas práticas de supply chain + + **Data de conclusão:** $(date) + **Repositório:** ${{ github.repository }} + **Workflow:** ${{ github.run_id }} + + --- + **Badge conquistado:** Containers e Segurança + + --- + *Certificado gerado automaticamente pelo GitHub Actions* + *LINUXtips* + EOF + + - name: "Upload do certificado" + uses: actions/upload-artifact@v4 + with: + name: level-3-certificate + path: certificates/ + retention-days: 30 diff --git a/LINUXtips-github-actions-main/.gitignore b/LINUXtips-github-actions-main/.gitignore new file mode 100644 index 0000000..e887b96 --- /dev/null +++ b/LINUXtips-github-actions-main/.gitignore @@ -0,0 +1,116 @@ +# Dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage +.grunt + +# Bower dependency directory +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons +build/Release + +# Dependency directories +jspm_packages/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# parcel-bundler cache +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ + +# Storybook build outputs +.out +.storybook-out + +# Temporary folders +tmp/ +temp/ + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Local development +.local + diff --git a/README.md b/README.md index 724fe2e..20a5bb9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +** Repo do Dvargas ** + # Descomplicando GitHub Actions Se inscreva na aula ao vivo e gratuita: https://quiz.linuxtips.io/github-actions @@ -22,6 +24,7 @@ Neste projeto você aprenderá: Clique no botão **"Fork"** no canto superior direito desta página para criar uma cópia deste projeto na sua própria conta do GitHub. 2. **Clone o seu Fork:** + ```bash git clone https://github.com/SEU-USUARIO-GITHUB/LINUXtips-github-actions.git cd LINUXtips-github-actions @@ -32,14 +35,17 @@ Neste projeto você aprenderá: 4. **Instale as Dependências:** Você precisa do Node.js (versão 16 ou superior): + ```bash npm install ``` 5. **Teste a Aplicação Localmente:** + ```bash npm start ``` + Acesse [http://localhost:3000](http://localhost:3000) no seu navegador. 6. **Execute seu Primeiro Workflow:** @@ -86,6 +92,5 @@ Ao completar cada workflow com sucesso, você ganha os badges: --- **Feito pela comunidade LINUXtips.** -#VAIIIIII -Teste +teste nivel3 diff --git a/package-lock.json b/package-lock.json index b2c7d57..ef1322c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "cors": "^2.8.5", "dotenv": "^16.3.1", - "express": "^4.21.2", + "express": "^4.18.2", "helmet": "^7.0.0", "node-fetch": "^3.3.2" }, @@ -2040,6 +2040,7 @@ "version": "4.21.2", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", diff --git a/package.json b/package.json index 1326318..2175daf 100644 --- a/package.json +++ b/package.json @@ -19,16 +19,16 @@ "author": "LINUXtips", "license": "MIT", "dependencies": { + "express": "^4.18.2", "cors": "^2.8.5", - "dotenv": "^16.3.1", - "express": "^4.21.2", "helmet": "^7.0.0", + "dotenv": "^16.3.1", "node-fetch": "^3.3.2" }, "devDependencies": { "jest": "^29.7.0", - "nyc": "^17.1.0", - "supertest": "^6.3.4" + "supertest": "^6.3.4", + "nyc": "^17.1.0" }, "engines": { "node": ">=16.0.0"