Thank you for considering contributing to Confy Addons! This project was developed with dedication by Brazilian students 🇧🇷 and we value all contributions, whether they are bug fixes, new features, documentation improvements, or tests.
To ensure an organized workflow and a good experience for everyone, please follow the guidelines below.
- Code of Conduct
- Getting Started
- Development Environment Setup
- Project Structure
- Contribution Workflow
- Code Standards
- Quality Tools
- Testing
- Running the Project Locally
- Creating a Pull Request
- Review Process
- Reporting Security Issues
We are committed to maintaining a welcoming, safe, and collaborative environment. Everyone should be treated with respect, regardless of age, gender identity, sexual orientation, ethnicity, religion, or experience level.
Unacceptable behaviors include:
- Harassment, discrimination, or insults
- Sexualized language or content
- Threats or personal attacks
- Unauthorized disclosure of private information
To report violations, contact: confy@henriquesebastiao.com
Before you begin, make sure you have:
- Git installed and configured
- Python 3.9.2 or higher (we support up to Python 3.14)
- Poetry for dependency management (recommended)
- A GitHub account
python --version
poetry --version
git --version- Go to github.com/confy-security/confy-addons
- Click the "Fork" button in the top right corner
- This will create a copy of the repository in your account
git clone https://github.com/YOUR-USERNAME/confy-addons.git
cd confy-addonsgit remote add upstream https://github.com/confy-security/confy-addons.git
git remote -v # Verify you have 'origin' and 'upstream'poetry installThis command will:
- Create a virtual environment (if it doesn't exist)
- Install all main and development dependencies
- Automatically activate the virtual environment
If the environment was not activated automatically:
poetry shellOr execute commands within the environment with:
poetry run <command>confy-addons/
├── .github/
│ ├── CODEOWNERS # Code owners
│ ├── dependabot.yml # Dependabot configuration
│ └── workflows/
│ ├── test.yml # Test pipeline
│ ├── publish.yml # Publishing pipeline
│ └── smokeshow.yml # Test coverage
├── confy_addons/
│ ├── __init__.py # Main exports
│ ├── core/
│ │ ├── abstract.py # Abstract classes
│ │ ├── constants.py # Project constants
│ │ ├── exceptions.py # Custom exceptions
│ │ └── mixins.py # Reusable mixins
│ ├── encryption/
│ │ ├── __init__.py
│ │ ├── aes.py # AES implementation
│ │ └── rsa.py # RSA implementation
│ └── prefixes.py # Message prefixes
├── tests/
│ ├── __init__.py
│ ├── test_abstract.py
│ ├── test_aes.py
│ ├── test_encryption_mixin.py
│ ├── test_prefizes.py
│ └── test_rsa.py
├── pyproject.toml # Poetry and project config
├── CONTRIBUTING.md # This file
├── CODE_OF_CONDUCT.md
├── SECURITY.md
├── README.md
└── LICENSEAlways create a separate branch for each contribution:
# Update from the main branch
git checkout main
git pull upstream main
# Create and switch to a new branch
git checkout -b type/short-description
# Example branch names:
# - feature/add-aes-validation
# - bugfix/fix-decryption-error
# - docs/improve-readme
# - test/increase-rsa-coverageBranch naming conventions:
feature/- For new featuresbugfix/- For bug fixesdocs/- For documentation improvementstest/- For adding/improving testsrefactor/- For code refactoring
Make changes to the code following the project standards (see Code Standards section).
# Edit files as needed
vim confy_addons/encryption/aes.py
# See the status of changes
git status
# Stage changes
git add .Write descriptive commit messages:
git commit -m "Add AES key size validation"Best practices for commit messages:
- Use the imperative mood ("add" instead of "added")
- Start with a capital letter
- Don't use a period at the end
- Limit the first line to 50 characters
- Add a more detailed description after a blank line if needed
Complete example:
Fix decryption error in CFB mode
- Validate minimum IV size
- Improve error messages
- Add edge case testThe Confy Addons project follows rigorous quality and style standards. Understanding these standards is essential.
The project uses Ruff for static analysis and code formatting.
Active rules:
I- Import sortingF- Pyflakes errorsE- PEP 8 style errorsW- PEP 8 style warningsPL- PylintPT- PytestD- Docstrings (Pydocstyle)UP- Syntax updatesPERF- Performance optimizations
Main configurations:
- Maximum line length: 99 characters
- Quote style: Single quotes (
') - Preview: Enabled (uses experimental Ruff features)
✅ Correct:
"""Module docstring explaining the module."""
from confy_addons.core.constants import AES_KEY_SIZE
from confy_addons.core.exceptions import EncryptionError
class MyEncryption:
"""Docstring for the class."""
def __init__(self, key: bytes) -> None:
"""Initialize encryption handler.
Args:
key: The encryption key.
Raises:
TypeError: If key is not bytes.
"""
if not isinstance(key, bytes):
raise TypeError('key must be bytes')
self._key = key
def encrypt(self, plaintext: str) -> str:
"""Encrypt plaintext string.
Args:
plaintext: The text to encrypt.
Returns:
str: The encrypted text.
"""
try:
# implementation
return encrypted_text
except Exception as e:
raise EncryptionError('Encryption failed') from e❌ Incorrect:
# Missing module docstring
from confy_addons.core.exceptions import EncryptionError
from confy_addons.core.constants import AES_KEY_SIZE # Wrong order
class MyEncryption:
# Missing class docstring
def __init__(self, key: bytes) -> None: # Missing method docstring
if not isinstance(key, bytes):
raise TypeError("key must be bytes") # Double quotes instead of single
self._key = key
def encrypt(self, plaintext: str) -> str: # Missing docstring
try:
return encrypted_text
except Exception as e:
raise EncryptionError("Encryption failed") from e # Double quotesUse type hints in all public methods:
def encrypt(self, plaintext: str) -> str:
"""Encrypt plaintext."""
...
def decrypt(self, b64_ciphertext: str) -> str:
"""Decrypt ciphertext."""
...
@property
def key(self) -> bytes:
"""Return the encryption key."""
return self._keyFollow the Google Style standard for docstrings:
def method(self, arg1: str, arg2: int) -> bool:
"""Brief description of what the method does.
Longer description if needed, explaining the behavior
and any important details.
Args:
arg1: Description of arg1.
arg2: Description of arg2.
Returns:
bool: Description of return value.
Raises:
ValueError: When X condition happens.
TypeError: When Y type is invalid.
"""Use constants for magic values (already defined in confy_addons/core/constants.py):
from confy_addons.core.constants import AES_KEY_SIZE, AES_IV_SIZE
# ✅ Correct
key_size = AES_KEY_SIZE
# ❌ Incorrect
key_size = 32 # Magic number!Use the logging module for messages:
import logging
logger = logging.getLogger(__name__)
# Log at appropriate levels
logger.debug('Debug information')
logger.info('Important information')
logger.warning('Important warning')
logger.error('An error occurred')The project uses several tools to ensure quality. All are automatically executed by Taskipy commands.
Check code:
task lint
# or manually:
poetry run ruff check .Format code automatically:
task format
# or manually:
poetry run ruff format .
poetry run ruff check . --fixChecks the correctness of type hints:
task mypy
# or manually:
poetry run mypy -p confy_addons -p testsExample of detected error:
# MyPy will complain about this:
x: int = "string" # Invalid typeAnalyzes cyclomatic complexity:
task radon
# or manually:
poetry run radon cc ./confy_addons -a -naA = average | NA = non-aggregated (shows details per function)
Checks for security issues:
task bandit
# or manually:
poetry run bandit -r ./confy_addonsTests are fundamental. All pull requests should maintain or increase test coverage.
The project uses Pytest with coverage plugin.
Test structure:
- Tests are in
tests/ - File names:
test_*.py - Function names:
test_* - One test per aspect/functionality
Run all tests:
task test
# or manually:
poetry run pytest -s -x --cov=confy_addons -vvRun tests from a specific file:
poetry run pytest tests/test_aes.py -vRun a specific test:
poetry run pytest tests/test_aes.py::test_aes_key_generation_length -vRun with HTML coverage report:
task test
# Coverage HTML will be in: htmlcov/index.htmlUseful flags:
-vor--verbose- Verbose mode (shows each test)-s- Show prints (without capturing stdout)-x- Stop at first failure--cov=confy_addons- Measure module coverage--cov-report=html- Generate HTML report
Example of a good test:
import pytest
from confy_addons import AESEncryption
from confy_addons.core.exceptions import EncryptionError
def test_aes_encrypt_decrypt_roundtrip():
"""Test that encrypt followed by decrypt returns original text."""
aes = AESEncryption()
original = 'Hello, World!'
encrypted = aes.encrypt(original)
decrypted = aes.decrypt(encrypted)
assert decrypted == original
def test_aes_encrypt_invalid_type_raises_error():
"""Test that encrypt raises TypeError with non-string input."""
aes = AESEncryption()
with pytest.raises(TypeError, match='plaintext must be a str'):
aes.encrypt(b'bytes-not-allowed')
def test_aes_init_invalid_key_length_raises_error():
"""Test that initializing with wrong key length raises ValueError."""
with pytest.raises(ValueError, match='AES key must be 32 bytes'):
AESEncryption(key=b'short-key')Best practices for tests:
- One behavior per test
- Descriptive names that explain the test
- Use docstrings to explain the test
- Arrange → Act → Assert
- Test both normal and edge cases
- Test exceptions
Run all checks before committing:
task pre_testThis executes:
- Ruff (linting)
- Ruff (format check)
- MyPy (type checking)
# 1. Make changes to the code
vim confy_addons/encryption/aes.py
# 2. Check style (will be auto-corrected)
task format
# 3. Run tests locally
task test
# 4. Check types
task mypy
# 5. Check security
task bandit
# 6. If all passes, commit
git add .
git commit -m "Your commit message"
# 7. Push to your fork
git push origin feature/your-featureError: Poetry not found
pip install poetry
poetry --versionError: Virtual environment not activated
poetry shell
# or use 'poetry run' before each commandBefore pushing, synchronize with the main branch:
git fetch upstream
git rebase upstream/mainIf there are conflicts, resolve them and continue:
git add .
git rebase --continuegit push origin feature/your-feature- Go to your fork on GitHub
- You will see a "Compare & pull request" suggestion
- Click and fill in the PR template
PR Template:
## 📝 Description
Brief and clear description of what was changed.
## 🎯 Type of Change
- [ ] Bug fix (fix that doesn't break existing functionality)
- [ ] New feature (adds functionality that doesn't break existing features)
- [ ] Breaking change (alters existing functionality)
- [ ] Documentation
- [ ] Test
## 🔍 Checklist
- [ ] I ran `task format` and the code is formatted
- [ ] I ran `task lint` and there are no errors
- [ ] I ran `task mypy` and there are no type errors
- [ ] I ran `task test` and all tests pass
- [ ] I added tests for new functionality
- [ ] I updated documentation if necessary
- [ ] My PR has no conflicts with the main branch
## 🖼️ Screenshots (if applicable)
If relevant, add screenshots or usage examples.
## 📚 References
Links to related issues or relevant documentation.
Closes #123Keep the conversation professional and constructive:
- Answer all questions from reviewers
- Make requested changes with new commits
- If you disagree, explain your viewpoint educatedly
- Ask for clarification if you don't understand
- Code follows standards - Ruff, MyPy, Bandit, Radon
- Tests with good coverage - Minimum 85% coverage
- Documentation updated - Docstrings, README if necessary
- Well-structured commits - Clear and atomic messages
- No breaking changes - Unless intentional
- Submit the PR
- Automated tests run in CI/CD
- Team members review the code
- Changes are requested (if necessary)
- You make adjustments
- After approval, the PR is merged
- Receive feedback as a learning opportunity
- Review others' code constructively
- Use professional and courteous tone
- Focus on the code, not the person
To report a security vulnerability:
- Send an email to: confy@henriquesebastiao.com
- Include:
- Detailed description of the issue
- Steps to reproduce
- Code example if possible
- Affected version
The team will respond within 48 hours.
- Fork the repository
- Clone your fork
- Create a branch (
git checkout -b feature/my-feature) - Make changes and commits
- Push to your fork
- Create a Pull Request
Use Python 3.9.2 or higher for development. The project supports up to Python 3.14.
Write tests for:
- New functionality (normal and edge cases)
- Bug fixes (reproduce the bug before fixing)
- Changes to existing code
Try to maintain coverage above 85%.
Run Radon to check complexity:
task radonRefactor if necessary. PRs with very high complexity may be rejected.
Check the Ruff documentation.
Your contribution makes this project better. If you have questions, open an issue or contact us through the email above.
Built with ❤️ by Brazilian students