Skip to content

Commit 42b7091

Browse files
committed
Implement Lab03 CI/CD pipeline
1 parent ea2fbd1 commit 42b7091

6 files changed

Lines changed: 205 additions & 0 deletions

File tree

.github/workflows/python-ci.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: Python CI
2+
3+
on:
4+
push:
5+
branches: [ master, lab03 ]
6+
paths:
7+
- 'app_python/**'
8+
- '.github/workflows/python-ci.yml'
9+
pull_request:
10+
paths:
11+
- 'app_python/**'
12+
13+
jobs:
14+
test-build:
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Setup Python
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: "3.13"
24+
cache: "pip"
25+
26+
- name: Install dependencies
27+
run: |
28+
pip install -r app_python/requirements.txt
29+
pip install -r app_python/requirements-dev.txt
30+
31+
- name: Lint
32+
run: ruff app_python
33+
34+
- name: Run tests
35+
run: pytest app_python/tests
36+
37+
- name: Generate version
38+
run: echo "VERSION=$(date +%Y.%m.%d)" >> $GITHUB_ENV
39+
40+
- name: Login Docker
41+
uses: docker/login-action@v3
42+
with:
43+
username: ${{ secrets.DOCKERHUB_USERNAME }}
44+
password: ${{ secrets.DOCKERHUB_TOKEN }}
45+
46+
- name: Snyk Scan
47+
uses: snyk/actions/python@master
48+
env:
49+
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
50+
with:
51+
command: test
52+
53+
54+
- name: Build and Push
55+
uses: docker/build-push-action@v6
56+
with:
57+
context: ./app_python
58+
push: true
59+
tags: |
60+
maksimmenshikh/devops-info-service:${{ env.VERSION }}
61+
maksimmenshikh/devops-info-service:latest

app_python/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,11 @@ docker run -p 5000:5000 maksimmenshikh/devops-info-service
123123
### Pull from Docker Hub
124124

125125
docker pull maksimmenshikh/devops-info-service
126+
127+
## Running Tests
128+
129+
cd app_python
130+
pip install -r requirements-dev.txt
131+
pytest -v
132+
133+
![CI](https://github.com/MMenshikh/DevOps-Core-Course/actions/workflows/python-ci.yml/badge.svg)

app_python/docs/LAB03.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# LAB03 --- CI/CD Pipeline with GitHub Actions
2+
3+
## CI/CD Practices Applied
4+
5+
### Automated Builds
6+
7+
Docker image is automatically built on push and pull requests using
8+
GitHub Actions.
9+
10+
### Secure Secrets Management
11+
12+
Sensitive data stored in GitHub Repository Secrets instead of hardcoding
13+
credentials.
14+
15+
### Container Security Scanning
16+
17+
Snyk integrated into pipeline to scan Docker image for vulnerabilities.
18+
19+
### Continuous Delivery
20+
21+
Docker image automatically pushed to DockerHub after successful pipeline
22+
execution.
23+
24+
------------------------------------------------------------------------
25+
26+
## Pipeline Information & Decisions
27+
28+
CI Platform: GitHub Actions\
29+
Container Registry: DockerHub\
30+
Security Scanner: Snyk
31+
32+
Triggers: - push to main - pull requests
33+
34+
Pipeline Stages: 1. Repository checkout 2. Docker image build 3.
35+
Security scan with Snyk 4. DockerHub login 5. Image push to registry
36+
37+
------------------------------------------------------------------------
38+
39+
## Workflow Execution Process
40+
41+
### Automatic Trigger
42+
43+
Pipeline runs when:
44+
45+
- code is pushed
46+
- pull request is created
47+
48+
### Build Stage
49+
50+
Docker image built using:
51+
52+
docker build -t devops-info-service .
53+
54+
### Security Scan
55+
56+
Snyk scans Docker image for known vulnerabilities before publishing.
57+
58+
### Push Stage
59+
60+
Image pushed to:
61+
62+
maksimmenshikh/devops-info-service
63+
64+
------------------------------------------------------------------------
65+
66+
## Technical Analysis
67+
68+
Automated CI reduces manual deployment steps and human error.
69+
70+
Secrets stored in GitHub prevent credential exposure in repository code.
71+
72+
Security scanning ensures vulnerabilities are detected early in
73+
development.
74+
75+
Automated publishing guarantees consistent container versions.
76+
77+
------------------------------------------------------------------------
78+
79+
## Challenges & Solutions
80+
81+
### Missing Secrets
82+
83+
Pipeline failed due to missing repository secrets.\
84+
Solved by adding DOCKERHUB_TOKEN, DOCKERHUB_USERNAME and SNYK_TOKEN.
85+
86+
### Docker Authentication Failure
87+
88+
Fixed by generating DockerHub access token and configuring
89+
docker/login-action.
90+
91+
### Failed Security Scan
92+
93+
Resolved by rebuilding image and ensuring dependencies were up to date.
84.5 KB
Loading

app_python/requirements-dev.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pytest==8.3.5
2+
pytest-cov==5.0.0
3+
ruff==0.9.0

app_python/tests/test_app.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import pytest
2+
from app import app
3+
4+
5+
@pytest.fixture
6+
def client():
7+
app.config["TESTING"] = True
8+
with app.test_client() as client:
9+
yield client
10+
11+
12+
def test_index_ok(client):
13+
response = client.get("/")
14+
assert response.status_code == 200
15+
16+
data = response.get_json()
17+
18+
assert "service" in data
19+
assert "system" in data
20+
assert "runtime" in data
21+
assert "request" in data
22+
assert "endpoints" in data
23+
24+
25+
def test_health_ok(client):
26+
response = client.get("/health")
27+
assert response.status_code == 200
28+
29+
data = response.get_json()
30+
assert data["status"] == "healthy"
31+
assert "timestamp" in data
32+
assert "uptime_seconds" in data
33+
34+
35+
def test_404(client):
36+
response = client.get("/unknown")
37+
assert response.status_code == 404
38+
39+
data = response.get_json()
40+
assert data["error"] == "Not Found"

0 commit comments

Comments
 (0)