Contributing to CredProxy¶
Thank you for your interest in contributing to CredProxy! This guide will help you get started with development, testing, and submitting contributions.
Quick Start for Development
Prerequisites
Python 3.11+ - Required for development
Docker - For container-based testing
Poetry - Dependency management
Git - Version control
Development Setup
1. Clone the repository
git clone <repository-url>
cd credproxy
2. Set up virtual environment and install tools
python3 -m venv venv
source venv/bin/activate
pip install pip poetry -U --user
3. Install dependencies with Poetry
poetry install
4. Activate the virtual environment
poetry shell
5. Run initial validation
make validate
6. Run the example to verify setup
docker compose -f docker-compose.example.yaml up --build
Running CredProxy for Development
For development and testing, you can run CredProxy using multiple entry points:
Primary Method (Recommended)
Development mode with Flask server
poetry run credproxy --dev --config config.yaml
Production mode
poetry run credproxy --config config.yaml
Validate configuration
poetry run credproxy --validate-only --config config.yaml
Alternative Method (Development)
Using Python module execution
python -m credproxy --config config.yaml
With Poetry
poetry run python -m credproxy --config config.yaml
Entry Points Summary:
``credproxy`` command - Primary entry point (defined in pyproject.toml)
``python -m credproxy`` - Alternative entry point for development
Both provide identical functionality and accept the same arguments
Use
credproxycommand for testing deploymentsUse either method for development and testing
Note: Development mode requires existing AWS infrastructure (IAM roles/profiles). For actual usage, see the main README.rst for Docker-based deployment.
Project Structure
credproxy/
├── credproxy/ # Main source code
│ ├── __init__.py # Version and metadata
│ ├── __main__.py # Alternative entry point for python -m credproxy
│ ├── cli.py # Command-line interface (primary entry point)
│ ├── config.py # Configuration management
│ ├── credentials_handler.py # AWS credential handling
│ ├── main.py # Flask application
│ ├── substitutions.py # Variable substitution logic
│ ├── logging.py # Logging configuration
│ └── config-schema.json # JSON Schema for validation
Testing
Running Tests
Run all tests with coverage
make test-cov
Run tests without coverage
make test
Run specific test file
poetry run pytest tests/test_config.py -v
Run with specific pattern
poetry run pytest tests/ -k "test_config" -v
Test Coverage
View coverage report
make test-cov-view
Generate coverage summary
make test-cov-summary
Writing Tests
Follow these guidelines when writing tests:
Use descriptive test names that explain what is being tested
Follow AAA pattern: Arrange, Act, Assert
Mock external dependencies (AWS calls, file I/O)
Test both success and failure cases
Include edge cases and error conditions
Testing New Features
Prometheus Metrics
When testing metrics functionality:
def test_metrics_endpoint_returns_prometheus_format():
"""Test that /metrics endpoint returns Prometheus-compatible format."""
# Arrange
client = app.test_client()
# Act
response = client.get("/metrics")
# Assert
assert response.status_code == 200
assert "text/plain" in response.content_type
assert "credential_requests_total" in response.data.decode()
def test_metrics_configuration_validation():
"""Test metrics configuration validation."""
# Test valid configuration
config = {"metrics": {"prometheus": {"enabled": True}}}
assert validate_metrics_config(config) is True
# Test invalid configuration
config = {"metrics": {"prometheus": {"invalid_field": True}}}
assert validate_metrics_config(config) is False
Dynamic Services
When testing dynamic services functionality:
def test_dynamic_services_file_watching():
"""Test that file watcher detects configuration changes."""
# Arrange
config_file = create_temp_config_file({"services": {}})
watcher = FileWatcher(config_file)
# Act
update_config_file(config_file, {"services": {"new_service": {}}})
watcher.check_for_changes()
# Assert
assert watcher.has_changes() is True
def test_dynamic_services_validation():
"""Test dynamic service configuration validation."""
# Test valid service addition
new_service = {
"auth_token": "token123",
"assumed_role": {"RoleArn": "arn:aws:iam::123456789012:role/TestRole"},
}
assert validate_dynamic_service(new_service) is True
# Test invalid service (missing required fields)
invalid_service = {"auth_token": "token123"}
assert validate_dynamic_service(invalid_service) is False
Health Check Logging
When testing health check logging:
def test_health_check_logging_configuration():
"""Test health check logging configuration."""
# Test with logging enabled
config = {"health_check": {"log_requests": True}}
assert validate_health_check_config(config) is True
# Test with logging disabled
config = {"health_check": {"log_requests": False}}
assert validate_health_check_config(config) is True
def test_health_check_logging_output():
"""Test that health check requests are logged when enabled."""
# Arrange
with patch("credproxy.logger.LOG") as mock_log:
config = {"health_check": {"log_requests": True}}
# Act
perform_health_check(config)
# Assert
mock_log.info.assert_called_with("Health check requested")
def test_config_validation_with_valid_iam_keys():
"""Test that valid IAM keys configuration passes validation."""
# Arrange
config = {
"aws_defaults": {
"region": "us-west-2",
"auth_method": "iam_keys",
"iam_keys": {
"access_key_id": "AKIAIOSFODNN7EXAMPLE",
"secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
},
},
"services": {
"test": {
"auth_token": "token",
"assumed_role": {"RoleArn": "arn:aws:iam::123456789012:role/TestRole"},
}
},
}
# Act
result = validate_config(config)
# Assert
assert result is True
Code Style
Formatting
We use automated formatting tools:
# Format code (ruff formatter with import sorting)
make format
# Check formatting without making changes
make lint
Style Guidelines
Ruff formatter with 88-character line length and built-in import sorting
Type hints required for all functions
Docstrings for all public functions and classes
No emojis in code or comments (professional tone)
Import Style
from __future__ import annotations
# Standard library
import json
import logging
from typing import TYPE_CHECKING
# Third-party
import boto3
from flask import Flask, request
Local
from credproxy.config import Config
from credproxy.credentials_handler import CredentialsHandler
if TYPE_CHECKING:
from credproxy.types import ConfigType
Development Workflow
Create a Feature Branch
git checkout -b feature/your-feature-name
or
git checkout -b fix/issue-description
Make Changes
Write code following the style guidelines
Add tests for new functionality
Update documentation if needed
Ensure all tests pass
Run Validation
Run full validation suite
make validate
This includes:
- Code formatting checks
- Linting
- Type checking
- Tests with coverage
Commit Changes
Use conventional commit messages:
feat: add support for AWS session tokens
fix: resolve credential refresh timing issue
docs: update installation instructions
test: add integration tests for IAM profiles
refactor: simplify configuration validation
Submit Pull Request
Push your branch to the repository
Create a pull request with a clear description
Link any relevant issues
Ensure CI checks pass
Bug Reports
When reporting bugs, please include:
Environment information: - Python version - Docker version (if applicable) - Operating system
Configuration: - Redacted configuration file - Environment variables (without secrets)
Steps to reproduce: - Clear, reproducible steps - Expected vs actual behavior
Logs: - Relevant log output - Error messages and stack traces
Feature Requests
Feature requests are welcome! Please:
Check existing issues for similar requests
Describe the use case clearly
Explain the proposed solution
Consider implementation complexity
Documentation
Updating Documentation
README.rst - Project overview and quick start
USAGE.md - Detailed usage examples
SECURITY.md - Security considerations
Documentation Style
Use clear, concise language
Include code examples for all features
Add diagrams where helpful
Keep examples up-to-date with code changes
Release Process
Releases are managed using semantic versioning:
MAJOR: Breaking changes
MINOR: New features (backward compatible)
PATCH: Bug fixes (backward compatible)
Version Bumping
Bump version (uses tbump)
tbump patch # or minor, major
This updates:
- pyproject.toml
- credproxy/__init__.py
- Creates git tag
Community Guidelines
Code of Conduct
Be respectful and inclusive
Welcome newcomers and help them learn
Focus on constructive feedback
Assume good intentions
Getting Help
GitHub Issues - Bug reports and feature requests
Discussions - General questions and ideas
Documentation - Check existing docs first
Development Tools
Make Commands
make help # Show all available commands
make validate # Run all checks (lint + test)
make test # Run tests
make test-cov # Run tests with coverage
make lint # Run linting checks (ruff)
make format # Format code (ruff formatter)
make conform # Format and lint code (ruff)
make clean # Clean build artifacts
Poetry Commands
poetry install # Install dependencies
poetry shell # Activate virtual environment
poetry run <command> # Run command in virtual environment
poetry add <package> # Add new dependency
poetry update # Update dependencies
Pre-commit Hooks
Pre-commit hooks are automatically configured:
ruff - Code formatting, linting, and import sorting
pyupgrade - Python syntax upgrades
These run automatically on commit and help maintain code quality.
Contributing Areas
We welcome contributions in these areas:
Core functionality - Credential handling, configuration
Authentication methods - New AWS auth approaches
Performance - Optimization and caching
Documentation - Examples, guides, API docs
Testing - Unit tests, integration tests
Docker - Multi-arch builds, optimization
CI/CD - GitHub Actions, workflows
Docker images build
Custom Docker Images
Build custom CredProxy images with specific configurations:
FROM public.ecr.aws/compose-x/aws/credproxy:latest
COPY config.yaml /credproxy/config.yaml
Multi-Stage Builds
Use multi-stage builds for production deployments:
FROM python:3.11-slim as builder
WORKDIR /app
COPY . .
RUN poetry install --only=main
FROM python:3.11-slim
COPY --from=builder /app /app
WORKDIR /app
CMD ["python", "-m", "credproxy.main"]
Questions?
If you have questions about contributing:
Check existing Issues
Start a Discussion
Read the Documentation
Thank you for contributing to CredProxy!