-
Student Name: Cathal Flood
-
Student Number: C22312211
-
Course: DevOps - Continuous Integration and Deployment
-
Assessment: CA3 Complete CI/CD Pipeline Implementation
-
Submission Date 14/12/2025
- GitHub Repository: 'https://github.com/floodcathal/devops-cicd-pipeline'
- Azure DevOps Project: 'https://dev.azure.com/C22312211/C22312211_CA3'
- Azure DevOps Pipeline: 'https://dev.azure.com/C22312211/C22312211_CA3/_build?definitionId=1'
- Azure Test Environment URL: 'https://c22312211-ca3-test-heead9ecemdydtdh.francecentral-01.azurewebsites.net/'
- Azure Production Environment URL: 'https://c22312211-ca3-prod-cte7gfdcgvhwa4gm.francecentral-01.azurewebsites.net/'
- Project Overview
- Repository Information
- Application Architecture
- CI/CD Pipeline
- Branch Protection Rules
- Testing Strategy
- Deployment Environments
- Setup and Installation
- Pipeline Execution
- Security and Performance
- Learning Outcomes
- Troubleshooting Guide
- References
This project implements a complete CI/CD pipeline for a Flask based calculator web application The pipeline automates the entire software delivery process from code commit to production deployment, incorporating comprehensive testing, security scanning, and approval gates.
- Multi-stage CI/CD pipeline with 7 distinct stages
- Automated testing including unit tests, security scans, performance tests, and UAT
- Multi-environment deployment (Test and Production)
- Approval gates for controlled production releases
- 100% code coverage with comprehensive test suite
- Security scanning using Bandit and Safety
- Browser automation testing using Selenium
- Zero-downtime deployments using Azure ZipDeploy API
- Application: Python 3.11, Flask 3.0.0, Gunicorn
- Testing: Pytest, Pylint, Bandit, Safety, Selenium
- CI/CD: Azure DevOps Pipelines
- Deployment: Azure App Services (Linux)
- Version Control: Git, GitHub
- Containerization: Docker (via Azure App Services)
- URL:
https://github.com/floodcathal/devops-cicd-pipeline - Branch:
main
- URL:
https://dev.azure.com/C22312211/C22312211_CA3 - Pipeline:
C22312211_CA3
- Test:
c22312211-ca3-test-heead9ecemdydtdh.francecentral-01.azurewebsites.net - Production:
c22312211-ca3-prod-cte7gfdcgvhwa4gm.francecentral-01.azurewebsites.net
C22312211_CA3/
├── app.py # Flask web application
├── calculator.py # Calculator business
logic
├── requirements.txt # Python dependencies
├── azure-pipelines.yml # CI/CD pipeline
definition
├── test_calculator.py # Unit tests
├── test_security.py # Security tests
├── test_performance.py # Performance tests
├── test_selenium_uat.py # User acceptance tests
├── .coveragerc # Coverage configuration
├── .gitignore # Git ignore rules
├── README.md # This file
└── screenshots/ # Documentation screenshots
The pipeline consists of 7 sequential stages that ensure code quality, security, and reliable deployment:
1. Pipeline Overview
Purpose: Compile code, run unit tests, perform static analysis, and create deployment artifact.
Steps:
- Set up Python 3.11 environment
- Install project dependencies
- Run Pylint static code analysis
- Execute unit tests with pytest
- Measure code coverage (target: 100%)
- Publish test results and coverage reports
- Create deployment artifact (ZIP file)
Success Criteria:
- All 8 unit tests pass
- Code coverage ≥ 100%
- Pylint score acceptable
- Artifact created successfully
Duration: ~3 minutes
Purpose: Scan code for security vulnerabilities and dependency issues.
Tools Used:
- Bandit: Scans Python code for security issues
- Safety: Checks dependencies for known vulnerabilities
Checks Performed:
- SQL injection vulnerabilities
- Use of insecure functions
- Hard-coded credentials
- Weak cryptography
- Known CVEs in dependencies
Success Criteria:
- No high-severity security issues
- Security reports published
Duration: ~2 minutes
Tests:
- Calculator operation speed (< 1ms per operation)
- Web application response time (< 2 seconds)
- Load testing with multiple iterations
Success Criteria:
- All performance benchmarks met
- No degradation from previous builds
Duration: ~1 minute
Purpose: Deploy application to Test environment for validation.
Process:
- Download build artifact from Stage 1
- Extract deployment files
- Deploy to Azure Web App (Test) using ZipDeploy API
- Wait for application startup (30 seconds)
- Perform health check verification
Technology:
- Azure App Services (Linux)
- Python 3.11 runtime
- Gunicorn WSGI server
Success Criteria:
- Deployment completes without errors
- Health endpoint returns 200 OK
- Application is accessible
Duration: ~3 minutes
Purpose: Automated browser testing on deployed Test environment.
Technology:
- Selenium WebDriver
- Chrome browser (headless mode)
Test Scenarios:
- Page loads successfully
- Environment badge displays "TEST"
- Calculator performs addition (10 + 5 = 15)
- User interface is responsive
- Error handling works correctly
Success Criteria:
- All Selenium tests pass
- Calculator functions correctly in browser
- No JavaScript errors
Duration: ~4 minutes
Purpose: Manual approval required before production deployment.
Process:
- Pipeline pauses after UAT completion
- Designated approver reviews:
- Test environment functionality
- Test results
- Security scan reports
- UAT test outcomes
- Approver grants/denies production deployment
Timeout: 3 days (auto-reject if not approved)
Success Criteria:
- Manual approval granted
Duration: Variable (depends on approver)
Purpose: Deploy approved application to Production environment.
Process:
- Download same build artifact used in Test
- Extract deployment files
- Deploy to Azure Web App (Production)
- Wait for application startup
- Perform health check
- Mark deployment as complete
Success Criteria:
- Deployment completes successfully
- Health endpoint returns 200 OK
- Production environment accessible
- Calculator functions correctly
Duration: ~3 minutes
To ensure code quality and prevent accidental changes to the main branch, the following branch protection rules are enforced:
Protected Branch: main
Required Settings:
-
Require pull request before merging
- At least 1 approval required
- Dismiss stale pull request approvals when new commits are pushed
-
Require status checks to pass before merging
- Azure Pipelines CI build must succeed
- All tests must pass
-
Require conversation resolution before merging
- All review comments must be resolved
-
Include administrators
- Rules apply to repository administrators as well
2. Branch Protection
Protected Branch: main
Policies Enabled:
- Require a minimum number of reviewers: 1
- Check for linked work items: Optional
- Check for comment resolution: Required
- Build validation: Azure Pipelines CI must succeed
Configuration:
- Azure DevOps → Repos → Branches
- Click "..." on
mainbranch → Branch policies - Configure policies as above
- Save changes
Framework: Pytest with pytest-cov
Coverage:
- 8 test cases covering all calculator operations
- 100% code coverage of calculator.py
- Edge cases and error handling included
Test Cases:
- Addition of positive numbers
- Subtraction with negative results
- Multiplication including zero
- Division with decimal results
- Division by zero (error handling)
- Power operation
- Square root of positive number
- Square root of negative number (error handling)
Execution:
pytest test_calculator.py --cov=calculator --cov-report=html -vTools:
-
Bandit - Python Security Scanner
- Scans for common security issues
- Identifies insecure code patterns
- Checks for hardcoded secrets
-
Safety - Dependency Vulnerability Scanner
- Checks dependencies against CVE database
- Identifies outdated packages with known vulnerabilities
- Recommends security updates
Execution:
bandit -r calculator.py app.py -f txt
safety checkMetrics Measured:
- Operation Speed: < 1 millisecond per calculation
- Response Time: < 2 seconds for web requests
- Throughput: 1000+ operations per second
Execution:
python test_performance.pyTechnology: Selenium WebDriver with Chrome
Test Flow:
- Launch headless Chrome browser
- Navigate to deployed application
- Locate input elements by ID
- Enter test data (10, 5)
- Click "Add" button
- Verify result displays "15"
- Check environment badge
Execution:
export TEST_URL=https://[test-url]
python test_selenium_uat.pyPurpose: Pre-production validation and testing
Configuration:
- URL:
c22312211-ca3-test-heead9ecemdydtdh.francecentral-01.azurewebsites.net - Runtime: Python 3.11 on Linux
- Server: Gunicorn WSGI
- Environment Variables:
ENVIRONMENT=TESTDEBUG=TrueSCM_DO_BUILD_DURING_DEPLOYMENT=true
Features:
- Orange environment badge
- Verbose logging enabled
- Automated deployments from pipeline
Purpose: Live production system
Configuration:
- URL:
c22312211-ca3-prod-cte7gfdcgvhwa4gm.francecentral-01.azurewebsites.net - Runtime: Python 3.11 on Linux
- Server: Gunicorn WSGI
- Environment Variables:
ENVIRONMENT=PRODUCTIONDEBUG=FalseSCM_DO_BUILD_DURING_DEPLOYMENT=true
Features:
- Blue environment badge
- Minimal logging (errors only)
- Manual approval required for deployment
- Git
- Python 3.11+
- Azure DevOps account
- Azure subscription
- GitHub account
-
Clone the repository:
git clone [https://github.com/floodcathal/devops-ci-calculator] cd C22312211_CA3 -
Create virtual environment:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Run tests:
pytest test_calculator.py --cov=calculator -v
-
Run application locally:
python app.py
Open browser to
http://localhost:5000
-
Create Azure DevOps project:
- Name:
C22312211_CA3 - Visibility: Private
- Name:
-
Create Variable Group:
- Name:
CA3-Deployment - Variables:
AZURE_WEBAPP_NAME_TESTAZURE_WEBAPP_NAME_PRODAZURE_WEBAPP_PUBLISH_PROFILE_TEST(secret)AZURE_WEBAPP_PUBLISH_PROFILE_PROD(secret) 3. Variable Groups
- Name:
-
Create Environments:
- Test (no approvals)
- Production (optional additional approvals)
-
Create Pipeline:
- Connect to GitHub repository
- Use existing
azure-pipelines.yml
-
Create Resource Group:
az group create --name CA3-Resources --location francecentral
-
Create Test App Service:
az webapp create \ --resource-group CA3-Resources \ --name c22312211-ca3-test \ --runtime "PYTHON:3.11" \ --os-type Linux -
Create Production App Service:
az webapp create \ --resource-group CA3-Resources \ --name c22312211-ca3-prod \ --runtime "PYTHON:3.11" \ --os-type Linux -
Configure both apps:
- Set startup command:
gunicorn --bind=0.0.0.0 --timeout 600 app:app - Enable SCM Basic Auth
- Download publish profiles
- Add to variable group
- Set startup command:
Automatic Triggers:
- Push to
mainbranch - Pull request to
mainbranch
Manual Trigger:
- Navigate to Azure DevOps → Pipelines
- Select pipeline
- Click "Run pipeline"
- Select branch (main)
- Click "Run"
-
View real-time logs:
- Click on running pipeline
- Select stage to view
- Click on job to see detailed logs
-
Review test results:
- Navigate to "Tests" tab
- View pass/fail status
- Examine failed test details
-
Check code coverage:
- Navigate to "Code Coverage" tab
- View coverage percentage
- Drill down to file level
- Receive notification
- Navigate to pipeline run
- Click "Review" button on Approval Gate stage
- Review checklist:
- All tests passed
- UAT completed successfully
- security reports reviewed
- test environment verified
- Add comment
- Production deployment begins automatically
-
Code Scanning:
- Bandit for Python security issues
- No high-severity vulnerabilities allowed
-
Dependency Management:
- Safety checks for CVEs in dependencies
- Regular updates of packages
-
Secure Configuration:
- Debug mode disabled in production
- Environment variables for sensitive data
- Secrets stored in Azure DevOps Library
-
Deployment Security:
- Publish profiles as secrets
- HTTPS enforcement
- Basic auth for deployment endpoints
-
Application Level:
- Efficient Python code (< 1ms per operation)
- Gunicorn for production WSGI server
- Proper timeout configurations
-
Deployment Process:
- Artifact caching
- ZipDeploy for fast deployments
- Parallel test execution where possible
-
Infrastructure:
- Azure App Services scaling
- CDN for static assets (if needed)
- Health check monitoring
1. Pipeline Overview - All 7 stages completed
Complete pipeline with all green checkmarks
2. Build Stage - Unit tests and coverage
Test results showing 8/8 passed and 100% code coverage
3. Security Testing - Bandit and Safety results
No high-severity security issues found
4. Performance Testing - Benchmark results
All performance metrics met
5. Test Deployment - Successful deployment
Deployment logs and health check verification
6. UAT Testing - Selenium test results
Browser automation tests successful
7. Approval Gate - Manual approval step
Manual approval interface and checklist
8. Production Deployment - Final deployment
Production deployment completed successfully
9. Test Environment - Calculator interface
Calculator with TEST environment badge
10. Test Calculation - Working calculator
Calculation result: 10 + 5 = 15
11. Production Environment - Live application
Calculator with PRODUCTION environment badge
12. Production Calculation - Verified functionality
Calculator working correctly in production
13. Resource Group - Azure resources
All Azure resources for the project
14. App Services - Web apps configuration
Test and Production app services configuration
15. Variable Group - Secure configuration
Pipeline variables with secrets hidden
16. GitHub Overview - Repository structure
Complete repository file structure
-
Pipeline Design:
- Multi-stage pipeline successfully implements all required components
- Clear separation of concerns between stages
- Efficient use of artifacts to avoid rebuilding
-
Testing Implementation:
- Achieved 100% code coverage
- Comprehensive test suite covering all scenarios
- Successful integration of Selenium for UAT
-
Deployment Strategy:
- ZipDeploy API provides fast, reliable deployments
- Health checks ensure application availability
- Environment variables enable proper configuration
-
DevOps Practices:
- Automated entire delivery pipeline
- Manual approval gates provide control
- Clear visibility into all stages
-
Service Connection Authentication:
- Initial attempts to use service principal failed due to insufficient permissions
- Solution: Used publish profile authentication with ZipDeploy API
- Learning: Multiple authentication methods available; choose based on permissions
-
JavaScript Syntax Error:
- Multi-line comment syntax broke JavaScript execution
- Solution: Used single-line comments (//) instead of multi-line (/* */)
- Learning: Careful attention to embedded code syntax in templates
-
DNS Resolution for Health Checks:
- Generic Azure URLs didn't resolve immediately
- Solution: Made health checks non-blocking with fallback
- Learning: Azure DNS can take time to propagate
-
YAML Syntax Issues:
- YAML anchors not supported in Azure Pipelines
- Solution: Removed anchors, used explicit step definitions
- Learning: Azure Pipelines YAML has specific limitations
Symptoms:
- Build stage shows red X
- Error: "ModuleNotFoundError: No module named 'flask'"
Solution:
# Check requirements.txt includes all dependencies
pip freeze > requirements.txt
git add requirements.txt
git commit -m "fix: Update requirements.txt"
git pushSymptoms:
- Tests pass locally but fail in pipeline
- Error: "AssertionError" or test failures
Solution:
-
Run tests locally with same Python version:
python --version # Should be 3.11.x pytest test_calculator.py -v -
Check test file encoding (should be UTF-8)
-
Verify calculator.py logic matches test expectations
Symptoms:
- Deploy stage fails
- Error: "Input required: PublishProfilePassword"
Solution:
-
Verify variable group has correct publish profiles:
Azure DevOps → Pipelines → Library → CA3-Deployment -
Re-download publish profiles from Azure Portal:
- App Services → Your app → Get publish profile
- Copy ENTIRE XML content
- Update variable in variable group
- Lock the variable (make it secret)
-
Verify variable names match YAML:
AZURE_WEBAPP_PUBLISH_PROFILE_TESTAZURE_WEBAPP_PUBLISH_PROFILE_PROD
Symptoms:
- Deployment succeeds but health check fails
- Error: "curl: (6) Could not resolve host"
Solution:
-
Check app is actually running:
# Open in browser https://your-app-name.azurewebsites.net -
Verify app name in variable group matches Azure app name
-
If DNS issue persists, health checks are non-blocking (won't fail pipeline)
Symptoms:
- UAT stage fails
- Error: "ChromeDriver version mismatch" or "WebDriver not found"
Solution: Pipeline installs Chrome automatically. If fails locally:
# Install Chrome
sudo apt-get install google-chrome-stable
# Install ChromeDriver
wget https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/120.0.6099.109/linux64/chromedriver-linux64.zip
unzip chromedriver-linux64.zip
sudo mv chromedriver-linux64/chromedriver /usr/local/bin/
sudo chmod +x /usr/local/bin/chromedriverSymptoms:
- Page loads but buttons don't work
- Console error: "calc is not defined"
Solution:
-
Check browser console for errors (F12)
-
Verify JavaScript is properly closed:
<script> // JavaScript code here </script>
-
Check for syntax errors:
- Use
//for single-line comments - NOT
/* */without closing
- Use
-
Hard refresh browser:
Ctrl + Shift + R
Symptoms:
- Bandit reports high-severity issues
- Pipeline continues (doesn't fail)
Solution:
-
Review Bandit report in pipeline logs
-
Common issues:
debug=True→ Use environment variable- Hardcoded secrets → Use environment variables
- Insecure functions → Replace or suppress with
# nosec
-
Suppress false positives:
app.run(host='0.0.0.0') # nosec B104
Symptoms:
- Pipeline shows "Informational run"
- Error: "YAML error preventing Azure Pipelines from determining if pipeline should run"
Solution:
-
Validate YAML online: https://www.yamllint.com/
-
Common issues:
- Incorrect indentation (use 2 spaces, not tabs)
- Missing quotes around strings with special characters
- Duplicate keys
-
Use provided YAML file from repository (tested and working)
-
Python Testing: -pytest documentation. pytest: helps you write better programs. Available at: https://docs.pytest.org/en/stable/ [Accessed: November 2025]
- pytest-cov Documentation. pytest-cov documentation. Available at: https://pytest-cov.readthedocs.io/en/latest/readme.html [Accessed: November 2025]
-
Azure DevOps:
- Microsoft. Azure Pipelines Documentation. Available at: https://learn.microsoft.com/en-us/azure/devops/pipelines/?view=azure-devops [Accessed: November 2025]
- Microsoft. YAML schema reference Available at: https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/?view=azure-pipelines [Accessed: November 2025]
-
Code Quality:
- Pylint Documentation: Pylint user manual. Available at: https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/?view=azure-pipelines [Accessed: November 2025]
- Python Software Foundation: PEP 8 - style guide for python code. Available at: https://peps.python.org/pep-0008/ [Accessed: November 2025]
- Flask (n.d.). Welcome to Flask — Flask Documentation (1.1.x). [online] flask.palletsprojects.com. Available at: https://flask.palletsprojects.com/.
- docs.pytest.org. (n.d.). pytest: helps you write better programs — pytest documentation. [online] Available at: https://docs.pytest.org/.
- Selenium. (n.d.). The Selenium Browser Automation Project. [online] Available at: https://www.selenium.dev/documentation/.
- SyntaxC4 (2025). Azure App Service documentation - Azure App Service. [online] Microsoft.com. Available at: https://docs.microsoft.com/azure/app-service/.
- Python 3.11: PYTHON (2025). Python. [online] Python.org. Available at: https://www.python.org/.
- Flask 3.0.0: Flask (n.d.). Welcome to Flask — Flask Documentation (1.1.x). [online] flask.palletsprojects.com. Available at: https://flask.palletsprojects.com/.
- Gunicorn: gunicorn.org. (n.d.). Gunicorn - Python WSGI HTTP Server for UNIX. [online] Available at: https://gunicorn.org/.
- Bandit: Readthedocs.io. (2025). Welcome to Bandit — Bandit documentation. [online] Available at: https://bandit.readthedocs.io/ .
- Safety: pyupio. (2025, November 6). GitHub - pyupio/safety: Safety checks Python dependencies for known security vulnerabilities and suggests the proper remediations for vulnerabilities detected. GitHub. https://github.com/pyupio/safety
- Selenium: Selenium (2023). SeleniumHQ Browser Automation. [online] www.selenium.dev. Available at: https://www.selenium.dev/.
Last Updated: 14th of December 2025
End of README






















