Skip to content

Commit 08c4b8d

Browse files
ci: add GitHub Actions workflows for CI/CD
- Add CI workflow for automated testing across Python 3.10, 3.11, 3.12 - Add code quality workflow (Black, isort, Flake8, Pylint) - Add security scanning workflow (Safety, Bandit, pip-audit, CodeQL) - Add Docker build and push workflow with Trivy scanning - Add deployment workflow for staging and production environments
1 parent eed67fc commit 08c4b8d

5 files changed

Lines changed: 333 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main, develop ]
8+
9+
jobs:
10+
test:
11+
name: Test Python ${{ matrix.python-version }}
12+
runs-on: ubuntu-latest
13+
14+
strategy:
15+
matrix:
16+
python-version: ['3.10', '3.11', '3.12']
17+
18+
services:
19+
redis:
20+
image: redis:7-alpine
21+
options: >-
22+
--health-cmd "redis-cli ping"
23+
--health-interval 10s
24+
--health-timeout 5s
25+
--health-retries 5
26+
ports:
27+
- 6379:6379
28+
29+
steps:
30+
- name: Checkout code
31+
uses: actions/checkout@v4
32+
33+
- name: Set up Python ${{ matrix.python-version }}
34+
uses: actions/setup-python@v5
35+
with:
36+
python-version: ${{ matrix.python-version }}
37+
cache: 'pip'
38+
39+
- name: Install dependencies
40+
run: |
41+
python -m pip install --upgrade pip
42+
pip install -r requirements.txt -r requirements-dev.txt
43+
44+
- name: Run migrations
45+
run: |
46+
python manage.py migrate
47+
env:
48+
DJANGO_SECRET_KEY: test-secret-key-for-ci
49+
DJANGO_DEBUG: 'False'
50+
REDIS_URL: redis://localhost:6379/0
51+
52+
- name: Run tests
53+
run: |
54+
pytest --cov=modbus_app --cov-report=xml --cov-report=html
55+
env:
56+
DJANGO_SECRET_KEY: test-secret-key-for-ci
57+
DJANGO_DEBUG: 'False'
58+
REDIS_URL: redis://localhost:6379/0
59+
60+
- name: Upload coverage to Codecov
61+
uses: codecov/codecov-action@v4
62+
if: matrix.python-version == '3.11'
63+
with:
64+
file: ./coverage.xml
65+
flags: unittests
66+
name: codecov-umbrella
67+
fail_ci_if_error: false

.github/workflows/code-quality.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Code Quality
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main, develop ]
8+
9+
jobs:
10+
lint:
11+
name: Linting and Code Style
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- name: Set up Python
19+
uses: actions/setup-python@v5
20+
with:
21+
python-version: '3.11'
22+
cache: 'pip'
23+
24+
- name: Install dependencies
25+
run: |
26+
python -m pip install --upgrade pip
27+
pip install -r requirements-dev.txt
28+
29+
- name: Run Black
30+
run: |
31+
black --check modbus_app/ modbus_webserver/
32+
33+
- name: Run isort
34+
run: |
35+
isort --check-only modbus_app/ modbus_webserver/
36+
37+
- name: Run Flake8
38+
run: |
39+
flake8 modbus_app/ modbus_webserver/ --max-line-length=120 --exclude=migrations
40+
41+
- name: Run Pylint
42+
run: |
43+
pylint modbus_app/ --disable=C0114,C0115,C0116 --max-line-length=120
44+
continue-on-error: true

.github/workflows/deploy.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: Deploy
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
tags:
7+
- 'v*'
8+
workflow_dispatch:
9+
10+
jobs:
11+
deploy-staging:
12+
name: Deploy to Staging
13+
runs-on: ubuntu-latest
14+
if: github.ref == 'refs/heads/main'
15+
environment:
16+
name: staging
17+
url: https://staging.example.com
18+
19+
steps:
20+
- name: Checkout code
21+
uses: actions/checkout@v4
22+
23+
- name: Deploy to staging server
24+
run: |
25+
echo "Deploying to staging environment"
26+
# Add your deployment commands here
27+
# Example: ssh user@staging-server "cd /app && git pull && docker-compose up -d"
28+
29+
# Uncomment and configure for actual deployment
30+
# - name: SSH Deploy
31+
# uses: appleboy/ssh-action@master
32+
# with:
33+
# host: ${{ secrets.STAGING_HOST }}
34+
# username: ${{ secrets.STAGING_USER }}
35+
# key: ${{ secrets.STAGING_SSH_KEY }}
36+
# script: |
37+
# cd /path/to/app
38+
# git pull origin main
39+
# docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
40+
41+
deploy-production:
42+
name: Deploy to Production
43+
runs-on: ubuntu-latest
44+
if: startsWith(github.ref, 'refs/tags/v')
45+
environment:
46+
name: production
47+
url: https://example.com
48+
needs: []
49+
50+
steps:
51+
- name: Checkout code
52+
uses: actions/checkout@v4
53+
54+
- name: Deploy to production server
55+
run: |
56+
echo "Deploying version ${{ github.ref_name }} to production"
57+
# Add your deployment commands here
58+
59+
# Uncomment and configure for actual deployment
60+
# - name: SSH Deploy
61+
# uses: appleboy/ssh-action@master
62+
# with:
63+
# host: ${{ secrets.PRODUCTION_HOST }}
64+
# username: ${{ secrets.PRODUCTION_USER }}
65+
# key: ${{ secrets.PRODUCTION_SSH_KEY }}
66+
# script: |
67+
# cd /path/to/app
68+
# git fetch --tags
69+
# git checkout ${{ github.ref_name }}
70+
# docker-compose -f docker-compose.yml -f docker-compose.prod.yml pull
71+
# docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
72+
73+
- name: Create Release
74+
uses: softprops/action-gh-release@v1
75+
if: startsWith(github.ref, 'refs/tags/v')
76+
with:
77+
generate_release_notes: true
78+
draft: false
79+
prerelease: false

.github/workflows/docker.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
name: Docker Build
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
tags:
7+
- 'v*'
8+
pull_request:
9+
branches: [ main ]
10+
11+
env:
12+
REGISTRY: ghcr.io
13+
IMAGE_NAME: ${{ github.repository }}
14+
15+
jobs:
16+
build:
17+
name: Build and Push Docker Image
18+
runs-on: ubuntu-latest
19+
permissions:
20+
contents: read
21+
packages: write
22+
23+
steps:
24+
- name: Checkout code
25+
uses: actions/checkout@v4
26+
27+
- name: Set up Docker Buildx
28+
uses: docker/setup-buildx-action@v3
29+
30+
- name: Log in to Container Registry
31+
if: github.event_name != 'pull_request'
32+
uses: docker/login-action@v3
33+
with:
34+
registry: ${{ env.REGISTRY }}
35+
username: ${{ github.actor }}
36+
password: ${{ secrets.GITHUB_TOKEN }}
37+
38+
- name: Extract metadata
39+
id: meta
40+
uses: docker/metadata-action@v5
41+
with:
42+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
43+
tags: |
44+
type=ref,event=branch
45+
type=ref,event=pr
46+
type=semver,pattern={{version}}
47+
type=semver,pattern={{major}}.{{minor}}
48+
type=sha
49+
50+
- name: Build and push Docker image
51+
uses: docker/build-push-action@v5
52+
with:
53+
context: .
54+
push: ${{ github.event_name != 'pull_request' }}
55+
tags: ${{ steps.meta.outputs.tags }}
56+
labels: ${{ steps.meta.outputs.labels }}
57+
cache-from: type=gha
58+
cache-to: type=gha,mode=max
59+
60+
- name: Run Trivy vulnerability scanner
61+
uses: aquasecurity/trivy-action@master
62+
if: github.event_name != 'pull_request'
63+
with:
64+
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
65+
format: 'sarif'
66+
output: 'trivy-results.sarif'
67+
68+
- name: Upload Trivy results to GitHub Security
69+
uses: github/codeql-action/upload-sarif@v3
70+
if: github.event_name != 'pull_request'
71+
with:
72+
sarif_file: 'trivy-results.sarif'

.github/workflows/security.yml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Security Scan
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main, develop ]
8+
schedule:
9+
- cron: '0 0 * * 1' # Weekly on Mondays
10+
11+
jobs:
12+
security:
13+
name: Security Vulnerability Scan
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v4
19+
20+
- name: Set up Python
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: '3.11'
24+
cache: 'pip'
25+
26+
- name: Install dependencies
27+
run: |
28+
python -m pip install --upgrade pip
29+
pip install safety bandit pip-audit
30+
31+
- name: Run Safety check
32+
run: |
33+
safety check --json || true
34+
continue-on-error: true
35+
36+
- name: Run Bandit security linter
37+
run: |
38+
bandit -r modbus_app/ -f json -o bandit-report.json || true
39+
continue-on-error: true
40+
41+
- name: Run pip-audit
42+
run: |
43+
pip-audit --requirement requirements.txt --format json || true
44+
continue-on-error: true
45+
46+
- name: Upload Bandit report
47+
uses: actions/upload-artifact@v4
48+
if: always()
49+
with:
50+
name: bandit-report
51+
path: bandit-report.json
52+
53+
codeql:
54+
name: CodeQL Analysis
55+
runs-on: ubuntu-latest
56+
permissions:
57+
security-events: write
58+
actions: read
59+
contents: read
60+
61+
steps:
62+
- name: Checkout code
63+
uses: actions/checkout@v4
64+
65+
- name: Initialize CodeQL
66+
uses: github/codeql-action/init@v3
67+
with:
68+
languages: python
69+
70+
- name: Perform CodeQL Analysis
71+
uses: github/codeql-action/analyze@v3

0 commit comments

Comments
 (0)