diff --git a/.github/actions/setup_environment/action.yaml b/.github/actions/setup_environment/action.yaml index 106e3c6..0a04845 100644 --- a/.github/actions/setup_environment/action.yaml +++ b/.github/actions/setup_environment/action.yaml @@ -6,6 +6,10 @@ inputs: description: "Task version" required: true default: "3.33.1" + trivy-version: + description: "Trivy version" + required: true + default: "v0.57.1" python-version: description: "Python version" required: true @@ -23,6 +27,11 @@ runs: with: version: ${{ inputs.task-version }} + - name: Install Trivy + uses: aquasecurity/setup-trivy@v0.2.2 + with: + version: ${{ inputs.trivy-version }} + - name: Set up Python uses: actions/setup-python@v4 with: diff --git a/.github/workflows/check-pr.yaml b/.github/workflows/check-pr.yaml index 7474af2..503bd0e 100644 --- a/.github/workflows/check-pr.yaml +++ b/.github/workflows/check-pr.yaml @@ -13,6 +13,7 @@ jobs: permissions: contents: read + pull-requests: write steps: - name: Checkout repository @@ -33,3 +34,27 @@ jobs: working-directory: backend run: | task test-container + + - name: Build backend image + working-directory: backend + run: | + task image-build + + - name: Scan backend image + id: scan + uses: ovsds/run-with-output-action@v1 + continue-on-error: true + with: + run: task backend:image-scan + + - name: Report vulnerabilities + uses: ovsds/create-or-update-unique-comment-action@v1 + with: + issue-number: ${{ github.event.number }} + body: | + ## Vulnerabilities found + ``` + ${{ steps.scan.outputs.stdout }} + ``` + unique-body-includes: "## Vulnerabilities found" + delete: ${{ steps.scan.outputs.exit_code == 0 }} diff --git a/.github/workflows/release-scan.yaml b/.github/workflows/release-scan.yaml new file mode 100644 index 0000000..611f411 --- /dev/null +++ b/.github/workflows/release-scan.yaml @@ -0,0 +1,47 @@ +name: 🔒 Security Scan + +on: + schedule: + # Every Sunday at 00:00 UTC + - cron: 0 0 * * 0 + workflow_dispatch: + +jobs: + scan: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup_environment + + - name: Get latest image tag + id: get_tag + uses: pozetroninc/github-action-get-latest-release@v0.8.0 + with: + owner: ${{ github.repository_owner }} + repo: ${{ github.event.repository.name }} + excludes: prerelease, draft + + - name: Scan image for vulnerabilities + id: scan + run: | + task backend:ci-image-scan + env: + IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }} + IMAGE_NAME: ${{ github.event.repository.name }} + IMAGE_TAG: ${{ steps.get_tag.outputs.release }} + + - name: Report vulnerabilities + uses: ovsds/create-or-update-unique-issue-action@v1 + with: + title: "Security scan issues for ${{ steps.get_tag.outputs.release }}" + body: | + ## Vulnerabilities found + ``` + ${{ steps.scan.outputs.stdout }} + ``` + unique-title-includes: "Security scan issues for " + close: ${{ steps.scan.outputs.exit_code == 0 }} diff --git a/backend/Dockerfile b/backend/Dockerfile index 78f4eae..6df4ca9 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -23,11 +23,11 @@ COPY lib /opt/app/lib WORKDIR /opt/app CMD [".venv/bin/python", "-m", "bin.main"] -FROM builder as builder_dev +FROM builder AS builder_dev RUN poetry install --with dev -FROM ${BASE_RUNTIME_IMAGE} as runtime_dev +FROM ${BASE_RUNTIME_IMAGE} AS runtime_dev RUN mkdir --parents /opt/app COPY --from=builder_dev /opt/app/.venv /opt/app/.venv diff --git a/backend/Taskfile.yaml b/backend/Taskfile.yaml index fb2c771..15f1b4e 100644 --- a/backend/Taskfile.yaml +++ b/backend/Taskfile.yaml @@ -116,16 +116,26 @@ tasks: image-build: desc: Build image target for local usage - requires: - vars: - - TARGET cmds: - echo 'Building image {{.TARGET}} target...' - docker build --tag {{.IMAGE_NAME}}:{{.TARGET}} {{ if .TAG }}--tag {{.TAG}}{{ end }} --target {{.TARGET}} + --load . + vars: + TARGET: '{{.TARGET | default "runtime"}}' + + image-scan: + desc: Scan image for vulnerabilities + cmds: + - echo 'Scanning image for vulnerabilities...' + - trivy image + --config trivy.yaml + {{.IMAGE_NAME}}:{{.TARGET}} + vars: + TARGET: '{{.TARGET | default "runtime"}}' test: desc: Run tests @@ -245,3 +255,15 @@ tasks: cmds: - echo 'Uploading backend image...' - docker push {{.IMAGE_REGISTRY}}/{{.IMAGE_NAME}}:{{.IMAGE_TAG}} + + ci-image-scan: + desc: Scan image for vulnerabilities + requires: + vars: + - IMAGE_TAG + - IMAGE_REGISTRY + cmds: + - echo 'Scanning image for vulnerabilities...' + - trivy image + --config trivy.yaml + {{.IMAGE_REGISTRY}}/{{.IMAGE_NAME}}:{{.IMAGE_TAG}} diff --git a/backend/trivy.yaml b/backend/trivy.yaml new file mode 100644 index 0000000..0336b17 --- /dev/null +++ b/backend/trivy.yaml @@ -0,0 +1,11 @@ +scan: + scanners: + - vuln + - misconfig + - secret + +severity: + - HIGH + - CRITICAL + +exit-code: 1