Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1c8438c
Create CI/CD actions file
PawRot Oct 27, 2025
a915d35
Add vulnerability scanning and security analysis to CI/CD pipeline us…
PawRot Oct 27, 2025
d13b38a
Added linting and testing to CI/CD
PawRot Oct 27, 2025
9a5d74f
Fix branch names
PawRot Oct 27, 2025
914fa85
Add Dockerfile for backend
PawRot Oct 27, 2025
0e29e65
Add Dockerfile for frontend
PawRot Oct 27, 2025
95d365c
Add build, push and scand for frontend and backend
PawRot Nov 1, 2025
b497e33
Update CodeQL SARIF upload action to v4
PawRot Nov 1, 2025
3a15770
Add env variables from secrets
PawRot Nov 1, 2025
2467216
Fix env mapping
PawRot Nov 1, 2025
806768c
Fix bandit command
PawRot Nov 1, 2025
d5348a6
Fix env variables
PawRot Nov 1, 2025
acd8f3b
Fix dependency in front-end build job
PawRot Nov 1, 2025
70b7b70
Lock Python version to 3.13
PawRot Nov 1, 2025
2c95e2a
Fix indentation
PawRot Nov 1, 2025
0e5297f
Install bandit sarif extras
PawRot Nov 1, 2025
976020f
Fix
PawRot Nov 1, 2025
83c5acf
Fix bandit
PawRot Nov 1, 2025
50dc5f2
Update upload action to v4
PawRot Nov 1, 2025
cba3814
Fix locating built image for trivy scan
PawRot Nov 1, 2025
fe123de
Fix tags
PawRot Nov 1, 2025
21896d8
Fix passing docker image to trivy
PawRot Nov 1, 2025
1772968
Fix trivy action not lowercasing image ref automatically
PawRot Nov 1, 2025
8caace4
Separate flow into multiple files
PawRot Nov 1, 2025
038ba24
Refactor to use reusable workflows
PawRot Nov 1, 2025
1b81bd0
Create a single workflow
PawRot Nov 1, 2025
b360cf7
Remove the separate workflows (now using reusable workflows)
PawRot Nov 1, 2025
c110aca
Add workflow_dispatch to trigger workflow manually
PawRot Nov 1, 2025
0159f92
Add workflow_dispatch to trigger workflow manually
PawRot Nov 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: CI/CD Pipeline

on:
workflow_dispatch:
push:
branches:
[master, develop]
pull_request:
branches:
[master, develop]

jobs:
# Testing jobs
test-backend:
name: Test Backend
uses: ./.github/workflows/reusable-test.yml
with:
service: back-end
secrets: inherit

test-frontend:
name: Test Frontend
uses: ./.github/workflows/reusable-test.yml
with:
service: front-end
secrets: inherit

# Linting jobs
lint-backend:
name: Lint Backend
uses: ./.github/workflows/reusable-lint.yml
with:
service: back-end

lint-frontend:
name: Lint Frontend
uses: ./.github/workflows/reusable-lint.yml
with:
service: front-end

# Security scanning jobs
scan-backend:
name: Security Scan Backend
uses: ./.github/workflows/reusable-security.yml
with:
service: back-end

scan-frontend:
name: Security Scan Frontend
uses: ./.github/workflows/reusable-security.yml
with:
service: front-end

# Build jobs - only run after all checks pass
build-backend:
name: Build Backend
needs: [test-backend, lint-backend, scan-backend]
uses: ./.github/workflows/reusable-build.yml
with:
service: back-end

build-frontend:
name: Build Frontend
needs: [test-frontend, lint-frontend, scan-frontend]
uses: ./.github/workflows/reusable-build.yml
with:
service: front-end

65 changes: 65 additions & 0 deletions .github/workflows/reusable-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Reusable Build and Push Workflow

on:
workflow_call:
inputs:
service:
description: 'Service to build (back-end or front-end)'
required: true
type: string

jobs:
build-push:
name: build and push ${{ inputs.service }} image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
security-events: write
steps:
- uses: actions/checkout@v5

- name: log in to container registry
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@v4
with:
images: ghcr.io/${{ github.repository }}/${{ inputs.service }}
tags: |
type=sha
type=ref,event=branch
type=raw,value= ${{ github.sha }}
type=raw,value=latest,enable={{is_default_branch}}

- name: build and push ${{ inputs.service }} image
uses: docker/build-push-action@v4
with:
context: ./${{ inputs.service }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

- name: lowercase repository name
id: repo
run: echo "name=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT

- name: run trivy ${{ inputs.service }} scan
uses: aquasecurity/trivy-action@master
with:
image-ref: ghcr.io/${{ steps.repo.outputs.name }}/${{ inputs.service }}:${{ github.sha }}
format: 'sarif'
output: 'trivy-${{ inputs.service }}-image.sarif'

- name: upload trivy ${{ inputs.service }} scan
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: trivy-${{ inputs.service }}-image.sarif
category: 'trivy ${{ inputs.service }}'

30 changes: 30 additions & 0 deletions .github/workflows/reusable-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Reusable Lint Workflow

on:
workflow_call:
inputs:
service:
description: 'Service to lint (back-end or front-end)'
required: true
type: string

jobs:
lint:
name: lint ${{ inputs.service }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: python setup
uses: actions/setup-python@v6
with:
python-version: '3.13'

- name: install flake8
run: pip install flake8

- name: lint ${{ inputs.service }}
run: |
flake8 ${{ inputs.service }}/ --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 ${{ inputs.service }}/ --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

41 changes: 41 additions & 0 deletions .github/workflows/reusable-security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Reusable Security Scan Workflow

on:
workflow_call:
inputs:
service:
description: 'Service to scan (back-end or front-end)'
required: true
type: string

jobs:
scan:
name: security scan ${{ inputs.service }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: python setup
uses: actions/setup-python@v6
with:
python-version: '3.13'

- name: pip-audit install
run: pip install pip-audit

- name: ${{ inputs.service }} audit
run: pip-audit -r ${{ inputs.service }}/requirements.txt --desc

- name: bandit install
run: pip install bandit[sarif]

- name: ${{ inputs.service }} bandit scan
run: bandit -r ${{ inputs.service }}/ -f sarif -o bandit-${{ inputs.service }}.sarif --exit-zero

- name: upload ${{ inputs.service }} bandit report
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: bandit-${{ inputs.service }}.sarif
category: 'bandit ${{ inputs.service }}'

44 changes: 44 additions & 0 deletions .github/workflows/reusable-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Reusable Test Workflow

on:
workflow_call:
inputs:
service:
description: 'Service to test (back-end or front-end)'
required: true
type: string

jobs:
test:
name: ${{ inputs.service }} tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: python setup
uses: actions/setup-python@v6
with:
python-version: '3.13'

- name: install dependencies
working-directory: ./${{ inputs.service }}
run: |
pip install -r requirements.txt
pip install -r requirements_test.txt

- name: run tests
env:
POSTGRES_DB: ${{ secrets.POSTGRES_DB }}
POSTGRES_USER: ${{ secrets.POSTGRES_USER }}
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
POSTGRES_HOST: ${{ secrets.POSTGRES_HOST }}
PORT: ${{ secrets.PORT }}
JWT_KEY: ${{ secrets.JWT_KEY }}
APP_PORT: ${{ secrets.APP_PORT }}
BACKEND_HOSTNAME: ${{ secrets.BACKEND_HOSTNAME }}
BACKEND_PORT: ${{ secrets.BACKEND_PORT }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
SERVER_PORT: ${{ secrets.SERVER_PORT }}
working-directory: ./${{ inputs.service }}
run: pytest test_app.py -v

27 changes: 26 additions & 1 deletion back-end/Dockerfile
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
# ADD YOUR OWN DOCKERFILE
FROM python:3.13-slim

WORKDIR /app

ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1

RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl && \
rm -rf /var/lib/apt/lists/*

COPY requirements.txt .

RUN pip install --upgrade pip && \
pip install -r requirements.txt

COPY . .

EXPOSE 5000

HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD curl -f http://localhost:5000/liveness || exit 1

CMD ["python", "app.py"]
27 changes: 26 additions & 1 deletion front-end/Dockerfile
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
# ADD YOUR OWN DOCKERFILE
FROM python:3.13-slim

WORKDIR /app

ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1

RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl && \
rm -rf /var/lib/apt/lists/*

COPY requirements.txt .

RUN pip install --upgrade pip && \
pip install -r requirements.txt

COPY . .

EXPOSE 8000

HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8000/ || exit 1

CMD ["python", "app.py"]