diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml new file mode 100644 index 0000000..e3e2ba0 --- /dev/null +++ b/.github/workflows/pipeline.yml @@ -0,0 +1,67 @@ +name: Lab 2 Container Registry + +on: [push] + +permissions: + contents: read + packages: write + +env: + APP_NAME: ecommerce-app + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set lower case owner name + run: echo "OWNER_LC=${OWNER,,}" >> ${GITHUB_ENV} + env: + OWNER: '${{ github.repository_owner }}' + + - name: Set Image Name + run: echo "IMAGE_NAME=ghcr.io/${{ env.OWNER_LC }}/${{ env.APP_NAME }}" >> ${GITHUB_ENV} + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest + type=sha,prefix=sha-,format=short + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: ./back + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + image-ref: ${{ env.IMAGE_NAME }}:latest + format: table + exit-code: '1' + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL' + + - name: Run Master Validation Script + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + chmod +x ./tests/lab2_test.sh + ./tests/lab2_test.sh \ No newline at end of file diff --git a/back/Dockerfile b/back/Dockerfile index dd39415..e32f30a 100644 --- a/back/Dockerfile +++ b/back/Dockerfile @@ -1,4 +1,4 @@ -#Stage 1 +# Stage 1 FROM node:20-alpine AS builder WORKDIR /app @@ -15,10 +15,13 @@ RUN npm run build FROM node:20-alpine WORKDIR /app +RUN apk update && apk upgrade + COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist COPY --from=builder /app/package*.json ./ COPY --from=builder /app/prisma ./prisma EXPOSE 8080 + CMD ["node", "dist/main.js"] \ No newline at end of file diff --git a/tests/lab2_test.sh b/tests/lab2_test.sh new file mode 100644 index 0000000..0f7ebb8 --- /dev/null +++ b/tests/lab2_test.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# Lecturer's Master Validation Script for Lab 2 +set -e + +OWNER_LC=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]') +PACKAGE_NAME="ecommerce-app" + +echo "--- Starting Lab 2 Grading (GHCR Check) ---" + +# 1. Checking package presence via GitHub API +echo "Step 1: Requesting package metadata from GHCR..." +RESPONSE=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \ + "https://api.github.com/users/${GITHUB_REPOSITORY_OWNER}/packages/container/${PACKAGE_NAME}") + +if echo "$RESPONSE" | grep -q "Not Found"; then + echo "❌ Error: Package '${PACKAGE_NAME}' not found in GHCR." + echo "Make sure your image name is: ghcr.io/${OWNER_LC}/${PACKAGE_NAME}" + exit 1 +fi + +# 2. Verifying Tags (latest + SHA) +echo "Step 2: Verifying tags..." +VERSIONS=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \ + "https://api.github.com/users/${GITHUB_REPOSITORY_OWNER}/packages/container/${PACKAGE_NAME}/versions") + +TAGS=$(echo "$VERSIONS" | jq -r '.[0].metadata.container.tags[]') + +if [[ ! "$TAGS" =~ "latest" ]]; then + echo "❌ Error: 'latest' tag is missing." + exit 1 +fi + +if [[ ! "$TAGS" =~ "sha-" ]]; then + echo "❌ Error: Git SHA tag (sha-xxxxxxx) is missing." + exit 1 +fi + +echo "✅ SUCCESS: Lab 2 is passed!" \ No newline at end of file