Contributing
How to contribute to Cloud Cost Guard
Contributing to OpsCurb
Thank you for your interest in contributing to OpsCurb! This document provides guidelines for contributing to our open-source components and community.
๐ค Ways to Contribute
1. Report Bugs
Found a bug? Help us fix it!
Where: GitHub Issues
Include:
- Clear description of the bug
- Steps to reproduce
- Expected vs. actual behavior
- Screenshots (if applicable)
- Environment (OS, browser, AWS region)
- Error messages or logs
Template:
**Bug Description**
A clear description of what the bug is.
**Steps to Reproduce**
1. Go to '...'
2. Click on '...'
3. See error
**Expected Behavior**
What you expected to happen.
**Actual Behavior**
What actually happened.
**Environment**
- OS: [e.g., macOS 13.0]
- Browser: [e.g., Chrome 120]
- OpsCurb Version: [e.g., 1.2.0]
2. Suggest Features
Have an idea? We'd love to hear it!
Where: Feature Requests
Include:
- Feature description
- Use case / problem it solves
- Proposed solution
- Alternatives considered
- Priority (nice-to-have vs. critical)
3. Improve Documentation
Documentation improvements are always welcome!
What to Improve:
- Fix typos or grammar
- Clarify confusing sections
- Add examples
- Update outdated information
- Translate to other languages
How:
- Fork the repository
- Make your changes
- Submit a pull request
4. Contribute Code
We welcome code contributions!
What We Accept:
- Bug fixes
- New scanner types
- Performance improvements
- Test coverage improvements
- Refactoring
What We Don't Accept (without prior discussion):
- Major architectural changes
- New dependencies
- Breaking changes
๐ ๏ธ Development Setup
Prerequisites
- Python 3.11+
- Node.js 18+
- PostgreSQL 15+
- AWS Account (for testing)
- Git
Local Setup
1. Clone the repository:
git clone https://github.com/opscurb/cloud-cost-guard.git
cd cloud-cost-guard
2. Set up backend:
cd api
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env
# Edit .env with your configuration
3. Set up frontend:
cd frontend
npm install
cp .env.local.example .env.local
# Edit .env.local with your configuration
4. Set up database:
# Create database
createdb opscurb
# Run migrations
cd database
psql opscurb < migrations/001_initial_schema.sql
5. Run locally:
# Terminal 1: Backend
cd api
uvicorn main:app --reload
# Terminal 2: Frontend
cd frontend
npm run dev
6. Access:
- Frontend: http://localhost:3000
- API: http://localhost:8000
- API Docs: http://localhost:8000/docs
๐ Coding Standards
Python (Backend)
Style: PEP 8
Tools:
blackfor formattingflake8for lintingmypyfor type checking
Run:
black .
flake8 .
mypy .
Example:
from typing import List, Optional
from pydantic import BaseModel
class Finding(BaseModel):
"""Represents a cost optimization finding."""
id: str
resource_id: str
severity: str
estimated_monthly_cost: float
def get_annual_cost(self) -> float:
"""Calculate annual cost."""
return self.estimated_monthly_cost * 12
TypeScript (Frontend)
Style: Airbnb TypeScript Style Guide
Tools:
prettierfor formattingeslintfor linting
Run:
npm run format
npm run lint
Example:
interface Finding {
id: string;
resourceId: string;
severity: 'high' | 'medium' | 'low';
estimatedMonthlyCost: number;
}
export function getAnnualCost(finding: Finding): number {
return finding.estimatedMonthlyCost * 12;
}
๐งช Testing
Backend Tests
Framework: pytest
Run:
cd api
pytest
pytest --cov # With coverage
Example:
def test_calculate_ebs_cost():
"""Test EBS cost calculation."""
volume = {
"VolumeId": "vol-123",
"Size": 100,
"VolumeType": "gp3"
}
cost = calculate_ebs_cost(volume, "us-east-1")
assert cost == 8.0 # $0.08/GB * 100GB
Frontend Tests
Framework: Jest + React Testing Library
Run:
cd frontend
npm test
npm test -- --coverage # With coverage
Example:
import { render, screen } from '@testing-library/react';
import FindingCard from './FindingCard';
test('renders finding card', () => {
const finding = {
id: '1',
resourceId: 'vol-123',
severity: 'high',
estimatedMonthlyCost: 80
};
render(<FindingCard finding={finding} />);
expect(screen.getByText('vol-123')).toBeInTheDocument();
});
๐ Pull Request Process
Before Submitting
- Create an issue (if one doesn't exist)
- Fork the repository
- Create a branch:
git checkout -b feature/your-feature-name - Make your changes
- Write tests
- Run tests: Ensure all tests pass
- Run linters: Fix any linting errors
- Update documentation: If needed
- Commit: Use clear commit messages
Commit Messages
Format:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting)refactor: Code refactoringtest: Test changeschore: Build/tooling changes
Example:
feat(scanners): add CloudWatch Logs scanner
Add new scanner to detect unused CloudWatch Log Groups.
Identifies log groups with no recent activity and estimates
cost savings from deletion.
Closes #123
Submitting PR
- Push to your fork:
git push origin feature/your-feature-name - Create pull request on GitHub
- Fill out PR template
- Wait for review
- Address feedback
- Get approval
- Merge!
PR Template
## Description
Brief description of changes.
## Related Issue
Closes #123
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Tests added/updated
- [ ] All tests passing
- [ ] Manual testing completed
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] No new warnings
๐ฏ Adding a New Scanner
Want to add a new AWS scanner? Here's how:
1. Create scanner file:
# scanners/cloudwatch_logs_scanner.py
from typing import List, Dict
from .base_scanner import BaseScanner
class CloudWatchLogsScanner(BaseScanner):
"""Scanner for unused CloudWatch Log Groups."""
def scan(self, session) -> List[Dict]:
"""Scan for unused log groups."""
client = session.client('logs')
findings = []
# Implementation here
return findings
2. Add tests:
# tests/test_cloudwatch_logs_scanner.py
def test_cloudwatch_logs_scanner():
"""Test CloudWatch Logs scanner."""
# Test implementation
3. Register scanner:
# scanners/__init__.py
from .cloudwatch_logs_scanner import CloudWatchLogsScanner
SCANNERS = [
# ... existing scanners
CloudWatchLogsScanner,
]
4. Update documentation:
- Add to README.md
- Add to API_DOCUMENTATION.md
๐ Code of Conduct
Our Pledge
We pledge to make participation in our community a harassment-free experience for everyone.
Our Standards
Positive behavior:
- Using welcoming language
- Being respectful
- Accepting constructive criticism
- Focusing on what's best for the community
Unacceptable behavior:
- Harassment or discrimination
- Trolling or insulting comments
- Personal or political attacks
- Publishing others' private information
Enforcement
Violations may result in:
- Warning
- Temporary ban
- Permanent ban
Report: conduct@opscurb.com
๐ Getting Help
Questions: community@opscurb.com
Discord: Join our Discord
Forum: community.opscurb.com
๐ Recognition
Contributors are recognized in:
- README.md contributors section
- Release notes
- Annual contributor awards
Top contributors may receive:
- Free Pro plan
- Exclusive swag
- Early access to features
Thank you for contributing! ๐
Last Updated: 2026-02-24
Version: 1.0