Thank you for considering contributing to Veritas! This document provides guidelines and instructions for contributing.
- Code of Conduct
- Getting Started
- Development Setup
- Development Workflow
- Testing Guidelines
- Code Style
- Commit Messages
- Pull Request Process
- Adding New Features
- Reporting Bugs
This project follows a standard code of conduct:
- Be respectful: Treat all contributors with respect
- Be collaborative: Work together to improve the project
- Be open: Accept constructive feedback
- Be professional: Keep discussions focused and productive
- Python 3.10 (see
.python-version) - Git
- GitHub account
-
Fork the repository on GitHub
-
Clone your fork:
git clone https://github.com/YOUR_USERNAME/Forensic-Image-Analysis-Toolkit.git cd Forensic-Image-Analysis-Toolkit -
Add upstream remote:
git remote add upstream https://github.com/CodeRafay/Forensic-Image-Analysis-Toolkit.git
python -m venv .venv
# Activate
# Windows:
.venv\Scripts\activate
# macOS/Linux:
source .venv/bin/activate# Runtime dependencies (enough to run the app and the full test suite)
pip install -r requirements.txt
# Optional: linters/formatters
pip install -r requirements-dev.txtpre-commit installThis ensures code quality checks run automatically before each commit.
git checkout -b feature/your-feature-nameBranch naming conventions:
feature/- New featuresbugfix/- Bug fixesdocs/- Documentation updatesrefactor/- Code refactoringtest/- Adding tests
- Write clean, readable code
- Follow existing code style
- Add comments for complex logic
- Update documentation as needed
The suite uses the standard-library unittest runner; pytest is not needed.
# All 142 tests (a few minutes)
python -m unittest discover -s tests -t .
# One module
python -m unittest tests.test_ela
# One test
python -m unittest tests.test_contract.TestResultContract.test_all_entry_points_all_inputspytest.ini is kept for anyone who prefers pytest, but its addopts require
pytest-cov; install requirements-dev.txt first or run pytest -o addopts="".
# Auto-format with black
black .
# Sort imports
isort .
# Check with flake8
flake8 analysis/ tests/git add .
git commit -m "feat: add new forensic technique"See Commit Messages for guidelines.
git push origin feature/your-feature-nameThen create a Pull Request on GitHub.
Every public analysis function takes an image path (plus keyword options) and
returns analysis.util.make_result(...):
{
"status": "ok" | "insufficient_data" | "not_applicable" | "error",
"summary": str, # one neutral sentence: what was measured
"findings": [{"level": "info" | "notice" | "warning", "text": str}],
"metrics": {label: number | str}, # headline numbers shown in the UI
"images": {caption: uint8 ndarray}, # (H, W) or (H, W, 3), in memory
"tables": {title: list[dict] | dict},
"limitations": [str], # always shown
"details": {...}, # raw JSON-serialisable values for tests
}Rules (the first four are checked by tests/test_contract.py):
- Never raise. Wrap the body and return
util.error_result(e, LIMITATIONS). - Too little data (tiny or flat image) must be
insufficient_dataornot_applicable, never anokthat looks clean. - Float metrics must be finite; images must be uint8 arrays.
- Never claim authenticity. Summaries and findings must not say "authentic", "admissible", "no manipulation" or "proves"; say "no inconsistency found at this sensitivity" instead.
- Write nothing to disk; return images as arrays.
- Decode with
util.load_array(no re-encode, EXIF orientation not applied). Only analyses that do not depend on compression traces may use its in-memorymax_pxdownscale.
The app renders every result with one function (render in app.py), so a
module can add metrics, images or tables without touching the UI.
- Each module has
tests/test_<module>.py(unittest.TestCase). - Add every new entry point to
ENTRY_POINTSintests/test_contract.py. It is then run on JPEG, PNG, grayscale, RGBA, palette, 16×16, 1×1 and flat inputs. - Calibrate thresholds on a seeded benchmark. Generate positives and
negatives synthetically with
np.random.default_rng(<seed>)(no downloads): e.g. splices at several JPEG qualities, clean JPEGs q20–100, crops, PNGs. Measure the detection rate and the false-alarm rate, set the module constant to a stated false-alarm rate, cite the measurement in a comment next to the constant and inDescriptions/<Technique>.md, and add a test asserting both rates (seetest_splice_benchmarkintests/test_ela.py). - A metric must vary with what it measures: check it on a clean image, a manipulated one and a synthetic extreme before relying on it.
Follow PEP 8 with these specifics:
- Line length: 100 characters
- Indentation: 4 spaces
- Quotes: Single quotes for strings (unless avoiding escapes)
- Naming:
- Functions:
snake_case - Classes:
PascalCase - Constants:
UPPER_SNAKE_CASE
- Functions:
Use Google-style docstrings:
def analyze_thing(image_path, window=16):
"""
One-line description of what is measured, then the published method:
Author, "Title", Venue Year.
Args:
image_path: image file (read as stored, never re-encoded)
window: smoothing window in px
Returns:
util.make_result(...). Metrics: <labels>. Images: <captions>.
details: <raw keys used by tests>.
"""Use type hints for function signatures:
from typing import List, Tuple, Optional
def process_images(
paths: List[str],
quality: int = 90
) -> Tuple[List[str], Optional[str]]:
pass<type>(<scope>): <subject>
<body>
<footer>
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringtest: Adding or updating testschore: Maintenance tasks
feat(ela): report error relative to the image median
The high-error mask and percentage now use K x the image's own median
error, so they no longer depend on brightness or resave quality.
Calibrated on a seeded splice benchmark (see ela.py).
Closes #42
fix(metadata): handle images without EXIF data
Previously crashed when processing images without EXIF metadata.
Now returns an info finding ("No EXIF") in the result contract.
Fixes #58
- All tests pass (
python -m unittest discover -s tests -t .) - Code formatted (
black .) - Imports sorted (
isort .) - No linting errors (
flake8) - Documentation updated
- CHANGELOG.md updated (if applicable)
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Documentation update
- [ ] Refactoring
## Testing
How was this tested?
## Screenshots (if applicable)
Add screenshots for UI changes
## Checklist
- [ ] Tests pass
- [ ] Documentation updated
- [ ] Code follows style guidelines- Automated checks must pass (CI/CD)
- At least one maintainer approval required
- Address review feedback
- Squash commits if needed
- Maintainer will merge
- Module
analysis/<technique>.pywith an entry point returning the result contract. Cite the published method in the module docstring and keep calibrated thresholds as module constants with their measurement. Add the module name to_MODULE_NAMESinanalysis/__init__.py. - Tests:
tests/test_<technique>.pywith a seeded benchmark, and anENTRY_POINTSrow intests/test_contract.py. - App: add a tab in
app.pythat callsrun_panel(key, label, analysis.<module>.<fn>, file_path, ...)anddescribe("<Technique>"). - Docs:
Descriptions/<Technique>.md(method, what the output means, measured benchmark numbers, limitations), a row in the README technique table, an entry indocs/API.md, and a CHANGELOG entry. - Dependencies: pin any new package in
requirements.txt.
- Entry point returns
make_result, never raises - Added to
tests/test_contract.pyENTRY_POINTS - Thresholds calibrated on a seeded benchmark; rates asserted in a test
- Tab added in
app.py -
Descriptions/<Technique>.md, README,docs/API.md, CHANGELOG updated - No wording that claims an image is authentic
**Describe the bug**
Clear description of the bug
**To Reproduce**
Steps to reproduce:
1. Go to '...'
2. Click on '...'
3. See error
**Expected behavior**
What should happen
**Screenshots**
If applicable
**Environment**
- OS: [e.g., Windows 11]
- Python version: [e.g., 3.10.11]
- Veritas version: [e.g., 3.0.0]
**Additional context**
Any other relevant information- GitHub Issues: https://github.com/CodeRafay/Forensic-Image-Analysis-Toolkit/issues
- Security Issues: Email [rafayadeel1999@gmail.com] (do not post publicly)
Forensic-Image-Analysis-Toolkit/
├── analysis/ # One module per technique + util.py (result contract)
├── tests/ # test_<module>.py per module + test_contract.py
├── Descriptions/ # Per-technique guides shown in the app
├── docs/ # API, deployment, project report
├── .streamlit/ # Streamlit configuration
├── app.py # Streamlit app (13 tabs, one renderer)
├── requirements.txt # Pinned runtime dependencies
├── requirements-dev.txt # Optional dev tools
└── README.md
See the README for the full tree.
- Documentation: Read docs/ folder
- GitHub Discussions: Ask questions
- Issues: Search existing issues
- Email: [rafayadeel1999@gmail.com]
Contributors will be:
- Listed in CONTRIBUTORS.md
- Credited in release notes
- Acknowledged in README.md (for significant contributions)
By contributing, you agree that your contributions will be licensed under the same license as the project (BSD License).
Thank you for contributing to Veritas! 🎉