From 08bcc0eecb3a30debca1c687daa56d0542f7e1ad Mon Sep 17 00:00:00 2001 From: stephenminakian Date: Thu, 3 Jul 2025 09:32:35 -0600 Subject: [PATCH] Debug sbom upload and security tag --- .gitea/workflows/ci-cd.yml | 292 +++++++++++++++++++++---------------- 1 file changed, 165 insertions(+), 127 deletions(-) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index cbf4b46..9990be6 100644 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -14,180 +14,218 @@ env: jobs: # Job 1: Lint and Test - # test: - # name: ๐Ÿงช Test & Lint - # runs-on: ubuntu-latest - # steps: - # - name: Checkout code - # uses: actions/checkout@v4 + test: + name: ๐Ÿงช Test & Lint + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 - # - name: Setup Node.js - # uses: actions/setup-node@v4 - # with: - # node-version: ${{ env.NODE_VERSION }} - # cache: 'npm' + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' - # - name: Install dependencies - # run: npm ci + - name: Install dependencies + run: npm ci - # - name: Run linting - # run: npm run lint + - name: Run linting + run: npm run lint - # - name: Run tests - # run: npm run test:coverage + - name: Run tests + run: npm run test:coverage - # - name: Upload test results - # uses: actions/upload-artifact@v3 - # if: always() - # with: - # name: test-results - # path: | - # coverage/ - # test-results.xml + - name: Upload test results + uses: actions/upload-artifact@v3 + if: always() + with: + name: test-results + path: | + coverage/ + test-results.xml - # # Job 2: Security Scan - # security: - # name: ๐Ÿ”’ Security Scan - # runs-on: ubuntu-latest - # steps: - # - name: Checkout code - # uses: actions/checkout@v4 + # Job 2: Security Scan + security: + name: ๐Ÿ”’ Security Scan + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 - # - name: Setup Node.js - # uses: actions/setup-node@v4 - # with: - # node-version: ${{ env.NODE_VERSION }} - # cache: 'npm' + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' - # - name: Install dependencies - # run: npm ci + - name: Install dependencies + run: npm ci - # - name: Run security audit - # run: npm audit --audit-level=high + - name: Run security audit + run: npm audit --audit-level=high - # - name: Check for vulnerabilities - # run: | - # if npm audit --audit-level=moderate --json | jq '.vulnerabilities | length' | grep -v '^0$'; then - # echo "Vulnerabilities found!" - # npm audit --audit-level=moderate - # exit 1 - # fi + - name: Check for vulnerabilities + run: | + if npm audit --audit-level=moderate --json | jq '.vulnerabilities | length' | grep -v '^0$'; then + echo "Vulnerabilities found!" + npm audit --audit-level=moderate + exit 1 + fi # Job 3: Build and Push Docker Image build: name: ๐Ÿ—๏ธ Build & Push Image runs-on: ubuntu-latest - # needs: [test, security] + outputs: + digest: ${{ steps.build.outputs.digest }} + needs: [test, security] if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' - # outputs: - # image-tag: ${{ steps.meta.outputs.tags }} - # image-digest: ${{ steps.build.outputs.digest }} + outputs: + image-tag: ${{ steps.meta.outputs.tags }} + image-digest: ${{ steps.build.outputs.digest }} steps: - # - name: Checkout code - # uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v4 - # - name: Set up Docker Buildx - # uses: docker/setup-buildx-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - # - name: Login to Harbor Registry - # uses: docker/login-action@v3 - # with: - # registry: ${{ env.REGISTRY }} - # username: ${{ secrets.HARBOR_USERNAME }} - # password: ${{ secrets.HARBOR_TOKEN }} + - name: Login to Harbor Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.HARBOR_USERNAME }} + password: ${{ secrets.HARBOR_TOKEN }} - # - name: Extract metadata - # id: meta - # uses: docker/metadata-action@v5 - # with: - # images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - # tags: | - # type=ref,event=branch - # type=ref,event=pr - # type=sha,prefix={{branch}}- - # type=raw,value=latest,enable={{is_default_branch}} - # type=raw,value={{date 'YYYYMMDD-HHmmss'}} + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=sha,prefix={{branch}}- + type=raw,value=latest,enable={{is_default_branch}} + type=raw,value={{date 'YYYYMMDD-HHmmss'}} - # - name: Build and push Docker image - # id: build - # uses: docker/build-push-action@v5 - # with: - # context: . - # platforms: linux/amd64,linux/arm64 - # push: true - # tags: ${{ steps.meta.outputs.tags }} - # labels: ${{ steps.meta.outputs.labels }} - # cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache - # cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max + - name: Build and push Docker image + id: build + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache + cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max - name: Generate SBOM run: | # Install syft curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin - + echo "${{ secrets.HARBOR_TOKEN }}" + echo "${{ env.REGISTRY }}" + echo "${{ secrets.HARBOR_USERNAME }}" + echo "${{ env.IMAGE_NAME }}" # Login to registry - use the REGISTRY variable for the URL echo "${{ secrets.HARBOR_TOKEN }}" | docker login ${{ env.REGISTRY }} -u '${{ secrets.HARBOR_USERNAME }}' --password-stdin - # Generate SBOM using latest tag syft ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest -o spdx-json > sbom.spdx.json - # Verify SBOM was created if [ ! -f sbom.spdx.json ]; then echo "Failed to generate SBOM" exit 1 fi - echo "SBOM generated successfully" - - - name: Upload SBOM to Harbor + + - name: Attach SBOM to Docker image run: | # Install ORAS curl -LO https://github.com/oras-project/oras/releases/download/v1.1.0/oras_1.1.0_linux_amd64.tar.gz tar -xzf oras_1.1.0_linux_amd64.tar.gz sudo mv oras /usr/local/bin/ - # Push SBOM as an artifact to Harbor - oras push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest-sbom \ + # Get the image digest from the build step + IMAGE_DIGEST="${{ steps.build.outputs.digest }}" + + # Attach SBOM to the specific image digest + oras attach ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${IMAGE_DIGEST} \ --artifact-type application/spdx+json \ sbom.spdx.json:application/spdx+json - echo "SBOM uploaded successfully to Harbor" + echo "SBOM attached successfully to image digest: ${IMAGE_DIGEST}" # Job 4: Image Security Scan - # scan: - # name: ๐Ÿ›ก๏ธ Image Security Scan - # runs-on: ubuntu-latest - # needs: build - # if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' - # steps: - # - name: Login to Harbor Registry - # uses: docker/login-action@v3 - # with: - # registry: ${{ env.REGISTRY }} - # username: ${{ secrets.HARBOR_USERNAME }} - # password: ${{ secrets.HARBOR_TOKEN }} - - # - name: Run Trivy vulnerability scanner - # uses: aquasecurity/trivy-action@master - # with: - # image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} - # format: 'sarif' - # output: 'trivy-results.sarif' - - # - name: Upload Trivy scan results - # uses: actions/upload-artifact@v3 - # with: - # name: trivy-scan-results - # path: trivy-results.sarif - - # - name: Check for HIGH/CRITICAL vulnerabilities - # uses: aquasecurity/trivy-action@master - # with: - # image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} - # format: 'json' - # output: 'trivy-results.json' - # exit-code: '1' - # severity: 'HIGH,CRITICAL' +scan: + name: ๐Ÿ›ก๏ธ Image Security Scan + runs-on: ubuntu-latest + needs: build + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + steps: + - name: Login to Harbor Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.HARBOR_USERNAME }} + password: ${{ secrets.HARBOR_TOKEN }} + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} + format: 'sarif' + output: 'trivy-results.sarif' + + - name: Generate JSON scan results + uses: aquasecurity/trivy-action@master + with: + image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} + format: 'json' + output: 'trivy-results.json' + + - name: Upload scan results artifacts + uses: actions/upload-artifact@v3 + with: + name: trivy-scan-results + path: | + trivy-results.sarif + trivy-results.json + + - name: Attach scan results to Harbor image + run: | + # Install ORAS + curl -LO https://github.com/oras-project/oras/releases/download/v1.1.0/oras_1.1.0_linux_amd64.tar.gz + tar -xzf oras_1.1.0_linux_amd64.tar.gz + sudo mv oras /usr/local/bin/ + + # Get the image digest from the build job + IMAGE_DIGEST="${{ needs.build.outputs.digest }}" + + # Attach SARIF scan results + oras attach ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${IMAGE_DIGEST} \ + --artifact-type application/sarif+json \ + trivy-results.sarif:application/sarif+json + + # Attach JSON scan results + oras attach ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${IMAGE_DIGEST} \ + --artifact-type application/json \ + trivy-results.json:application/json \ + --annotation "scan.type=vulnerability" \ + --annotation "scan.tool=trivy" + + echo "Scan results attached successfully to image digest: ${IMAGE_DIGEST}" + + - name: Check for HIGH/CRITICAL vulnerabilities + uses: aquasecurity/trivy-action@master + with: + image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} + format: 'json' + output: 'trivy-critical.json' + exit-code: '1' + severity: 'HIGH,CRITICAL' # # Job 5: Deploy to Development # deploy-dev: