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
2 changes: 2 additions & 0 deletions ansible/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.vault_pass
hosts.ini
11 changes: 11 additions & 0 deletions ansible/ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[defaults]
inventory = inventory/hosts.ini
roles_path = roles
host_key_checking = False
remote_user = ubuntu
retry_files_enabled = False

[privilege_escalation]
become = True
become_method = sudo
become_user = root
Loading