Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions .github/cache-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"cache": {
"pip": true,
"docker": true,
"node": false,
"actions": true
},
"optimizations": {
"parallel_jobs": true,
"skip_duplicate_actions": true,
"cancel_in_progress_on_new_commit": true
}
}
196 changes: 196 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
name: Python CI/CD Pipeline

on: [push, pull_request]

env:
DOCKER_REGISTRY: docker.io
IMAGE_NAME: ${{ github.repository_owner }}/devops-info-service
PYTHON_VERSION: '3.13'
DOCKER_BUILDKIT: 1

jobs:
lint-and-test:
name: Lint and Test
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: 'pip'
cache-dependency-path: 'app_python/requirements.txt'

- name: Install dependencies
working-directory: ./app_python
run: |
pip install -r requirements.txt
pip install pytest pytest-cov httpx

- name: Run unit tests with coverage
working-directory: ./app_python
run: |
echo "Running tests with coverage..."
python -m pytest tests/ -v --cov=app --cov-report=xml --cov-report=html

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./app_python/coverage.xml
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false

- name: Upload test artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: |
app_python/coverage.xml
app_python/htmlcov/
retention-days: 7

build-and-push:
name: Build and Push Docker Image
runs-on: ubuntu-latest
needs: lint-and-test
if: github.ref == 'refs/heads/lab03'

permissions:
contents: read
packages: write
security-events: write

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Generate version tag
id: version
run: |
echo "version=$(date +'%Y.%m.%d')-${GITHUB_SHA::7}" >> $GITHUB_OUTPUT

- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=raw,value=${{ steps.version.outputs.version }}
labels: |
maintainer=${{ github.actor }}
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.created=${{ steps.meta.outputs.created }}
org.opencontainers.image.revision=${{ github.sha }}

- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: ./app_python
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64

- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
image: ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest

- name: Scan image for vulnerabilities with Trivy
uses: aquasecurity/trivy-action@0.24.0
with:
image-ref: ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
format: 'sarif'
output: 'trivy-results.sarif'
exit-code: '0'

- name: Check if Trivy results exist
id: check_trivy
run: |
if [ -f trivy-results.sarif ]; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "Trivy results found"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "No Trivy results file found"
fi

- name: Upload Trivy scan results to GitHub Security tab
if: steps.check_trivy.outputs.exists == 'true'
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-results.sarif

security-scan:
name: Security Scan (Snyk)
runs-on: ubuntu-latest
needs: lint-and-test
continue-on-error: true

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Install dependencies
working-directory: ./app_python
run: |
pip install -r requirements.txt

- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/python@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high

- name: Run safety check
working-directory: ./app_python
run: |
pip install safety
safety check -r requirements.txt

notify:
name: Notify Status
runs-on: ubuntu-latest
needs: [lint-and-test, build-and-push, security-scan]
if: always()
steps:
- name: Check workflow status
run: |
echo "## Workflow Status" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Lint and Test | ${{ needs.lint-and-test.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Build and Push | ${{ needs.build-and-push.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Security Scan | ${{ needs.security-scan.result }} |" >> $GITHUB_STEP_SUMMARY
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test
.vscode
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Master **production-grade DevOps practices** through hands-on labs. Build, conta
| 16 | 16 | Cluster Monitoring | Kube-Prometheus, Init Containers |
| — | **Exam Alternative Labs** | | |
| 17 | 17 | Edge Deployment | Fly.io, Global Distribution |
| 18 | 18 | Decentralized Storage | 4EVERLAND, IPFS, Web3 |
| 18 | 18 | Reproducible Builds | Nix, Deterministic Builds, Flakes |

---

Expand All @@ -61,7 +61,7 @@ Don't want to take the exam? Complete **both** bonus labs:
| Lab | Topic | Points |
|-----|-------|--------|
| **Lab 17** | Fly.io Edge Deployment | 20 pts |
| **Lab 18** | 4EVERLAND & IPFS | 20 pts |
| **Lab 18** | Reproducible Builds with Nix | 20 pts |

**Requirements:**
- Complete both labs (17 + 18 = 40 pts, replaces exam)
Expand Down Expand Up @@ -142,7 +142,7 @@ Each lab is worth **10 points** (main tasks) + **2.5 points** (bonus).
- StatefulSets, Monitoring

**Exam Alternative (Labs 17-18)**
- Fly.io, 4EVERLAND/IPFS
- Fly.io, Nix Reproducible Builds

</details>

Expand Down
78 changes: 78 additions & 0 deletions app_python/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Python
__pycache__/
*.py[cod]
*.pyo
*.so
*.pyd
.Python

# Virtual environments
venv/
env/
ENV/
env.bak/
venv.bak/
.venv/

# Distribution / packaging
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
tests/

# Logs
*.log
logs/

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Git
.git/
.gitignore

# Docker
Dockerfile
docker-compose*.yml

# Documentation
docs/
*.md
LICENSE
12 changes: 12 additions & 0 deletions app_python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Python
__pycache__/
*.py[cod]
venv/
*.log

# IDE
.vscode/
.idea/

# OS
.DS_Store
18 changes: 18 additions & 0 deletions app_python/.pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
-v
--tb=short
--strict-markers
--disable-warnings
--cov=.
--cov-report=term-missing
--cov-report=xml
--cov-report=html
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
integration: integration tests
unit: unit tests
Loading