diff --git a/.github/.DS_Store b/.github/.DS_Store index efb2548..b31f6e2 100644 Binary files a/.github/.DS_Store and b/.github/.DS_Store differ diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml index 019d934..0a4c9a8 100644 --- a/.github/workflows/build-image.yml +++ b/.github/workflows/build-image.yml @@ -15,4 +15,5 @@ jobs: - name: Build Docker Image run: | - docker build -t awesome-fastapi:${{ github.sha }} . \ No newline at end of file + docker build -t awesome-fastapi:${{ github.sha }} . + \ No newline at end of file diff --git a/.github/workflows/lint-format.yml b/.github/workflows/lint-format.yml index 074d59f..304f28b 100644 --- a/.github/workflows/lint-format.yml +++ b/.github/workflows/lint-format.yml @@ -20,9 +20,8 @@ jobs: - name: Install dependencies run: | + pip install -r requirements.txt python -m pip install --upgrade pip - pip install pylint - pip install pylint black - name: Run pylint run: pylint . diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d205584..18e6d07 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,13 +1,14 @@ name: Main Workflow on: push: - branches: - - main + + workflow_dispatch: permissions: contents: read security-events: write actions: read + packages: write jobs: @@ -20,4 +21,8 @@ jobs: unit-sec-scan: uses: ./.github/workflows/unit-sec-test.yml - needs: lint-format \ No newline at end of file + needs: lint-format + + push-docker-image: + uses: ./.github/workflows/push-docker-image.yml + needs: unit-sec-scan diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index e71754b..8b5a2e0 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -1,6 +1,6 @@ name: PR Workflow on: - pull_request_target: + pull_request: types: - opened - edited diff --git a/.github/workflows/push-docker-image.yml b/.github/workflows/push-docker-image.yml new file mode 100644 index 0000000..1319ed0 --- /dev/null +++ b/.github/workflows/push-docker-image.yml @@ -0,0 +1,58 @@ +name: Push Docker Image + + +on: + workflow_call: + +env: + # Use docker.io for Docker Hub if empty + REGISTRY: ghcr.io + IMAGE_NAME: 'awesome-fastapi' + + +jobs: + Push_Image: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Set up Docker Buildx + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 + + # Extract metadata (tags, labels) for Docker + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v3 + with: + images: ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }} + + # Login against a Docker registry + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + + # Build and tag Docker Image + - name: Build Docker Image + run: | + docker build -t ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:${{ github.sha }} . + + - name: Tag Docker Image + run: | + docker tag ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:${{ github.sha }} ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:latest + docker tag ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:${{ github.sha }} ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:testing + + + # Push the Docker image to the registry + - name: Push Docker Image to GHCR + run: | + docker push ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:${{ github.sha }} + docker push ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:latest + docker push ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:testing diff --git a/.github/workflows/unit-sec-test.yml b/.github/workflows/unit-sec-test.yml index a518a30..4bbf447 100644 --- a/.github/workflows/unit-sec-test.yml +++ b/.github/workflows/unit-sec-test.yml @@ -13,42 +13,12 @@ jobs: uses: actions/checkout@v4 - name: Install dependencies - run: pip install -r requirements.txt - + run: | + pip install -r requirements.txt + - name: Run tests run: pytest tests/ - - - # Run snyk code scanning for vulnerabilities - snyk_scan: - permissions: - contents: read - security-events: write - actions: read - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.12.5" - - - name: Install dependencies - run: pip install -r requirements.txt - - - name: Install Snyk CLI - uses: snyk/actions/setup@806182742461562b67788a64410098c9d9b96adb - - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} - - name: Snyk Code test - run: snyk code test --sarif > snyk-cide.sarif - - - name: Snyk Test Dependencies - run: snyk test - - # Scan the contianer and lists all security vulnerabilities trivy_scans: name: Run Trivy security scanner against the image @@ -57,13 +27,16 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@7b7aa264d83dc58691451798b4d117d53d21edfe + - name: Build Docker Image + run: | + docker build -t awesome-fastapi:${{ github.sha }} . ###- This section needed to be added becasue the image was not persisting between jobs--## + + - name: Run Trivy Vulnerability Scanner + uses: aquasecurity/trivy-action@0.28.0 with: image-ref: 'awesome-fastapi:${{ github.sha }}' - format: 'template' - template: '@/contrib/sarif.tpl' - output: 'GitHub Actions/Trivy Automation' + format: 'sarif' + output: 'trivy-results.sarif' severity: 'CRITICAL,HIGH' - name: Upload Trivy scan results to GitHub Security tab @@ -75,17 +48,30 @@ jobs: runs-on: ubuntu-latest name: app scan steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: master - - - name: zap scan - uses: zaproxy/action-api-scan@v0.9.0 - with: - token: ${{ secrets.GITHUB_TOKEN}} - docker_name: 'ghcr.io/zaproxy/zaproxy:stable' - format: openapi - target: '' - rules_file_name: '.zap/rules.tsv' - cmd_options: '-a' + - name: Checkout + uses: actions/checkout@v4 + + # Build and Tag Image + # Run Docker Image in detached mode + - name: Build Docker Image + run: | + docker build -t awesome-fastapi:${{ github.sha }} . + docker run -d -p 8080:8080 awesome-fastapi:${{ github.sha }} + + - name: Wait for Docker container to be ready + run: sleep 30 + + - name: Confirm Docker container is running + run: docker ps + + # Run OWASP ZAP scan + - name: zap scan + uses: zaproxy/action-api-scan@v0.9.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + docker_name: 'ghcr.io/zaproxy/zaproxy:stable' + format: openapi + target: 'http://0.0.0.0:8080' + rules_file_name: '.zap/rules.tsv' + cmd_options: '-a' + allow_issue_writing: false diff --git a/DevSecOps-Pipeline.yml b/DevSecOps-Pipeline.yml deleted file mode 100644 index ba9ee5a..0000000 --- a/DevSecOps-Pipeline.yml +++ /dev/null @@ -1,124 +0,0 @@ -name: DevSecOps Pipeline -on: - pull_request: - branches: - - main - -permissions: - contents: read - security-events: write - actions: read - -jobs: - - # Build Docker Image - build: - name: Build Docker Image - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Build Docker Image - run: | - docker build -t awesome-fastapi:${{ github.sha }} . - - - # Run Pylint and Black formatter - lint_format: - name: Run lint and formatting checks with pylint and black - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.12", "3.13"] - - steps: - - uses: actions/checkout@v4 - - name: 'Setup Python ${{ matrix.python-version}}' - uses: actions/setup-python@v3 - with: - python-version: '${{ matrix.python-version}}' - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pylint - pip install pylint black - - - name: Run pylint - run: pylint $(git ls-files '*.py') - - - name: Run black - run: black --check . - - - # Run unit test cases for the Docker image - testing_phase: - name: Run unit test - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Install dependencies - run: pip install -r requirements.txt - - - name: Run tests - run: pytest - - - # Run snyk code scanning for vulnerabilities - snyk_scan: - permissions: - contents: read - security-events: write - actions: read - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: ["3.12", "3.13"] - - - - name: Install dependencies - run: pip install -r requirements.txt - - - name: Install Snyk CLI - uses: snyk/actions/setup@806182742461562b67788a64410098c9d9b96adb - - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} - - name: Snyk Code test - run: snyk code test --sarif > snyk-cide.sarif - - - name: Snyk Test Dependencies - run: snyk test - - - # Scan the contianer and lists all security vulnerabilities - trivy_scans: - name: Run Trivy security scanner against the image - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@7b7aa264d83dc58691451798b4d117d53d21edfe - with: - image-ref: 'awesome-fastapi:${{ github.sha }}' - format: 'template' - template: '@/contrib/sarif.tpl' - output: 'GitHub Actions/Trivy Automation' - severity: 'CRITICAL,HIGH' - - - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: 'trivy-results.sarif' - -