Transformation: Python
git clone https://github.com/AEEF-AI/aeef-transform.git
The Transformation tier extends the Quick Start Python setup with a full 7-stage CI pipeline, mutation testing via mutmut, strict type checking with mypy, and provenance generation. This guide covers every addition.
Full Pipeline Walkthrough
The CI pipeline runs seven stages:
ruff-check --> ruff-format --> mypy --> pytest-cov --> mutmut --> SAST --> SCA+license
Stage 1: Ruff Lint
- name: Lint
run: ruff check .
Ruff checks for code quality issues, import ordering, naming conventions, and security anti-patterns. Rules are configured in pyproject.toml under [tool.ruff].
Stage 2: Ruff Format
- name: Format Check
run: ruff format --check .
Verifies code formatting consistency. Fails if any file would be reformatted.
Stage 3: Type Check (mypy)
- name: Type Check
run: mypy app/
mypy enforces strict type checking. The configuration requires type annotations on all function signatures:
# mypy.ini
[mypy]
python_version = 3.12
strict = true
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
Stage 4: Test with Coverage
- name: Test
run: pytest
pytest runs with the pytest-cov plugin enforcing an 80% coverage floor. Coverage options are configured in pyproject.toml under [tool.pytest.ini_options].
Stage 5: Mutation Testing (mutmut)
- name: Mutation Testing
run: |
mutmut run --no-progress || true
mutmut results
mutmut introduces mutations to source code and checks that tests detect them. A custom script validates the mutation score meets the 70% threshold.
The check_mutation_score.py script:
import argparse
import subprocess
import json
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--threshold", type=float, default=70.0)
args = parser.parse_args()
result = subprocess.run(
["mutmut", "results", "--json"],
capture_output=True, text=True, check=True,
)
data = json.loads(result.stdout)
killed = data["killed"]
total = data["total"]
score = (killed / total) * 100 if total > 0 else 0
if score < args.threshold:
raise SystemExit(
f"Mutation score {score:.1f}% below threshold {args.threshold}%"
)
print(f"Mutation score: {score:.1f}% (threshold: {args.threshold}%)")
if __name__ == "__main__":
main()
Stage 6: SAST (Semgrep)
- name: SAST
run: |
semgrep --config .semgrep/ --config p/python app/
bandit -r app/ -c pyproject.toml
Runs Semgrep with AEEF custom rules and the community Python ruleset.
Stage 7: SCA and License Check
- name: SCA
run: |
pip-audit --strict --desc
Checks for known vulnerabilities and verifies dependency licenses.
Ruff Configuration
The Transformation tier Ruff config adds stricter rules:
# In pyproject.toml under [tool.ruff]
[tool.ruff]
target-version = "py312"
line-length = 100
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"N", # pep8-naming
"UP", # pyupgrade
"B", # flake8-bugbear
"S", # flake8-bandit
"A", # flake8-builtins
"C4", # flake8-comprehensions
"DTZ", # flake8-datetimez
"T20", # flake8-print
"SIM", # flake8-simplify
"TCH", # flake8-type-checking
"RUF", # ruff-specific
]
ignore = ["S101"] # allow assert in tests
[tool.ruff.lint.per-file-ignores]
"tests/**" = ["S101", "S106"]
pytest-cov Thresholds
Coverage thresholds are configured in pyproject.toml:
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "--cov=app --cov-report=term-missing --cov-report=html --cov-report=json --cov-fail-under=80"
[tool.coverage.run]
branch = true
source = ["app"]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"if __name__ == .__main__.:",
]
Provenance Generation
The CI pipeline generates a provenance record after all stages complete. A post-job step collects stage outcomes and writes a JSON provenance file validated against the AEEF schema:
- name: Generate Provenance
if: always()
run: python scripts/generate_provenance.py
Next Steps
- Need monitoring and sovereign compliance? Upgrade to Production: Python.
- Set up the agent SDLC? See Agent SDLC Setup.
- Configure metrics collection? See Metrics Pipeline Setup.