Skip to content

Commit 71444e8

Browse files
committed
docs: add documentation for lab03
1 parent 93d863e commit 71444e8

4 files changed

Lines changed: 190 additions & 3 deletions

File tree

.github/workflows/python-ci.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@ name: Python CI/CD
33
on:
44
push:
55
branches: [ main, lab03 ]
6+
paths:
7+
- 'app_python/**'
8+
- '.github/workflows/python-ci.yml'
69
pull_request:
710
branches: [ main ]
11+
paths:
12+
- 'app_python/**'
13+
- '.github/workflows/python-ci.yml'
814

915
jobs:
1016
test:
@@ -26,7 +32,7 @@ jobs:
2632
cd app_python
2733
pip install -r requirements.txt
2834
29-
- name: Run a linter
35+
- name: Run linter
3036
run: |
3137
cd app_python
3238
flake8 app.py
@@ -63,5 +69,5 @@ jobs:
6369
context: ./app_python
6470
push: true
6571
tags: |
66-
${{ secrets.DOCKER_USERNAME }}/fastapi-app:latest
67-
${{ secrets.DOCKER_USERNAME }}/fastapi-app:$(date +%Y.%m.%d)
72+
${{ secrets.DOCKER_USERNAME }}/fastapi-lab-app:latest
73+
${{ secrets.DOCKER_USERNAME }}/fastapi-lab-app:$(date +%Y.%m.%d)

app_python/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ __pycache__/
33
*.py[cod]
44
venv/
55
*.log
6+
.pytest_cache
67

78
# IDE
89
.vscode/

app_python/docs/LAB03.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# Lab 3 — Continuous Integration (CI/CD)
2+
3+
## 1. Unit Testing
4+
5+
### Framework chosen
6+
7+
I chose `pytest` because of using plain `assert` statement instead of complex assertion methods. The framework has clear output with `-v` flag showing exactly what passed/failed. `pytest` is well-documented with many tutorials and examples.
8+
9+
### Test Structure
10+
11+
**Test Coverage:**
12+
13+
1. `test_root_endpoint()` - Tests `GET /` endpoint
14+
15+
2. `test_health_endpoint()` - Tests `GET /health` endpoint
16+
17+
3. `test_404_error` - Tests error handling
18+
19+
Each test is independent. Tests use FastAPI's `TestClient` (no live server needed).
20+
21+
### How to Run Tests Locally
22+
23+
```bash
24+
cd app_python
25+
pip install -r requirements.txt
26+
pytest tests/test_app.py -v
27+
```
28+
29+
### Terminal Output Showing All Tests Passing
30+
31+
```bash
32+
=================================================================== test session starts ====================================================================
33+
platform linux -- Python 3.14.2, pytest-8.0.0, pluggy-1.6.0
34+
rootdir: /home/flowelx/DevOps-Core-Course/app_python
35+
plugins: anyio-4.12.1
36+
collected 3 items
37+
38+
tests/test_app.py ... [100%]
39+
40+
===================================================================== warnings summary =====================================================================
41+
venv/lib/python3.14/site-packages/starlette/_utils.py:40
42+
venv/lib/python3.14/site-packages/starlette/_utils.py:40
43+
venv/lib/python3.14/site-packages/starlette/_utils.py:40
44+
venv/lib/python3.14/site-packages/starlette/_utils.py:40
45+
venv/lib/python3.14/site-packages/starlette/_utils.py:40
46+
venv/lib/python3.14/site-packages/starlette/_utils.py:40
47+
venv/lib/python3.14/site-packages/starlette/_utils.py:40
48+
venv/lib/python3.14/site-packages/starlette/_utils.py:40
49+
tests/test_app.py::test_404_error
50+
/home/flowelx/DevOps-Core-Course/app_python/venv/lib/python3.14/site-packages/starlette/_utils.py:40: DeprecationWarning: 'asyncio.iscoroutinefunction' is deprecated and slated for removal in Python 3.16; use inspect.iscoroutinefunction() instead
51+
return asyncio.iscoroutinefunction(obj) or (callable(obj) and asyncio.iscoroutinefunction(obj.__call__))
52+
53+
venv/lib/python3.14/site-packages/fastapi/routing.py:233
54+
venv/lib/python3.14/site-packages/fastapi/routing.py:233
55+
/home/flowelx/DevOps-Core-Course/app_python/venv/lib/python3.14/site-packages/fastapi/routing.py:233: DeprecationWarning: 'asyncio.iscoroutinefunction' is deprecated and slated for removal in Python 3.16; use inspect.iscoroutinefunction() instead
56+
is_coroutine = asyncio.iscoroutinefunction(dependant.call)
57+
58+
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
59+
============================================================== 3 passed, 11 warnings in 0.27s ==============================================================
60+
```
61+
62+
## 2. GitHub Actions CI Workflow
63+
64+
### Workflow Trigger Strategy
65+
66+
**Configuration:**
67+
68+
```yaml
69+
on:
70+
push:
71+
branches: [ main, lab03 ]
72+
pull_request:
73+
branches: [ main ]
74+
```
75+
76+
CI runs on feature branch and main. It saves GitHub Actions minutes, focused on importnant branches.
77+
Docker build only runs on push to `main`. This prevents unnecessary Docker builds for every commit.
78+
79+
### Marketplace Actions Chosen
80+
81+
1. `actions/checkout@v4` - Official GitHub action, reliable, well-maintained
82+
83+
2. `actions/setup-python@v5` - Handles multiple Python versions, caching built-in
84+
85+
3. `docker/login-action@v3` - Secure token-based login, handles credentials properly
86+
87+
4. `docker/build-push-action@v5` - Single action for both operations, supports caching
88+
89+
### Docker Tagging Strategy
90+
91+
**Strategy:** Calendar Versioning
92+
93+
**Format:** `YYYY.NN.DD`
94+
95+
It is convinient for frequent updates. There is no need to track breaking changes.
96+
97+
### Successful Workflow Run
98+
99+
**Link to Workflow Run:** https://github.com/flowelx/DevOps-Core-Course/actions/runs/21786077651/job/62857660802
100+
101+
**Screenshot of Green Checkmark:**
102+
103+
![successfull ci](screenshots/successful-ci.jpg)
104+
105+
## CI Best Practices & Security
106+
107+
### Caching Implementation
108+
109+
**Python Package Caching:**
110+
111+
```yaml
112+
- uses: actions/setup-python@v5
113+
with:
114+
cache: 'pip'
115+
cache-dependency-path: 'app_python/requirements.txt'
116+
```
117+
118+
### CI Best Practices Applied
119+
120+
1. Path-based Triggers
121+
122+
```yaml
123+
paths:
124+
- 'app_python/**'
125+
- '.github/workflows/python-ci.yml'
126+
```
127+
128+
2. **Job Dependencies**
129+
130+
```yaml
131+
build:
132+
needs: test
133+
```
134+
135+
3. **Conditional Execution**
136+
137+
```yaml
138+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
139+
```
140+
141+
4. **Security Scanning**
142+
143+
```yaml
144+
- name: Security scan with pip-audit
145+
run: |
146+
cd app_python
147+
pip install pip-audit
148+
pip-audit -r requirements.txt || echo "Security scan completed"
149+
```
150+
151+
5. **Linting**
152+
153+
```yaml
154+
- name: Run linter
155+
run: |
156+
cd app_python
157+
flake8 app.py
158+
```
159+
160+
6. **Test Reporting**
161+
162+
```yaml
163+
pytest tests/test_app.py
164+
```
165+
166+
### Security Scanning Results
167+
168+
**Tool Used:** `pip-audit`
169+
170+
I couldn't use Snyk because the site did not open with or without vpn. So I applied `pip-audit`.
171+
172+
**Scan Results:**
173+
174+
```
175+
Found 2 known vulnerabilities in 1 package
176+
Name Version ID Fix Versions
177+
--------- ------- -------------- ------------
178+
starlette 0.38.6 CVE-2024-47874 0.40.0
179+
starlette 0.38.6 CVE-2025-54121 0.47.2
180+
```
30.8 KB
Loading

0 commit comments

Comments
 (0)