mirror of
https://github.com/yogeshojha/rengine.git
synced 2026-10-19 23:01:29 +02:00
reNgine had no tests. All 102 test_*.py in the tree were inside .venv, and CI
built images and ran CodeQL without ever running a line of the code. Nothing
would have caught the is:new rewrite in a8b9304d being wrong: every target on
the dev box has exactly one scan, so is:new returns zero everywhere and a
counts-unchanged check compares zero to zero. is:new is precisely the predicate
that only wakes up on a target's SECOND scan.
The suite starts with the three laws CLAUDE.md states and the code has no way
to enforce:
- is:new needs a baseline. A first scan reports nothing new; a second reports
only what the first missed; another target's history is not this target's
baseline; a LATER scan is not a baseline; a project scope judges newness per
target; and the facet filter, a second code path onto the same predicate,
agrees with the query.
- The count is a promise. Every non-zero lead equals the search it opens, and
every group in all twelve host dimensions equals the rows its drill-down token
lands on.
- NOT is null-safe. For six flags, the flag and its negation partition the scan
exactly — three-valued logic must not silently drop rows whose column is NULL.
Mutation-tested rather than assumed: reducing is_new to not_(seen_earlier()) —
the 2.x behaviour where a first scan marks every host new — fails four of the
seven baseline tests, including `assert 5 == 0`. A suite that cannot fail is
worth nothing.
The harness builds a database of its own (rengine_test, dropped and migrated
per session) so a run can never touch real scans, and each test writes inside a
transaction it never commits. The Estate fixture builds a project, its targets,
their scans and their rows the way a scan does, addressed by name rather than by
uuid, and seeds every one of the twelve group dimensions.
CI runs it: a lint job over the ten python packages, and a pytest job that
builds the api image and runs the suite against real postgres and redis, so what
is tested is the artifact that ships. Two files that had drifted out of ruff
format are formatted, because a gate that is red on the day it lands teaches
people to ignore it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013dKUV96WkQQETZBMoAG98C
41 lines
916 B
TOML
41 lines
916 B
TOML
[project]
|
|
name = "rengine-api"
|
|
version = "3.0.0"
|
|
description = "reNgine: FastAPI backend"
|
|
requires-python = ">=3.13"
|
|
dependencies = [
|
|
"alembic>=1.18.3",
|
|
"anthropic>=0.69.0",
|
|
"apprise>=1.9.0",
|
|
"argon2-cffi>=25.1.0",
|
|
"asyncpg>=0.31.0",
|
|
"brotli>=1.1.0",
|
|
"fonttools>=4.59.2",
|
|
"celery>=5.6.2",
|
|
"cryptography>=42",
|
|
"fastapi>=0.128.0",
|
|
"fastapi-pagination>=0.15.8",
|
|
"passlib[bcrypt]>=1.7.4",
|
|
"pydantic-settings>=2.12.0",
|
|
"pyotp>=2.9.0",
|
|
"python-jose>=3.5.0",
|
|
"python-multipart>=0.0.22",
|
|
"qrcode[pil]>=7.4.2",
|
|
"redis>=7.1.0",
|
|
"sqlmodel>=0.0.31",
|
|
"uvicorn>=0.40.0",
|
|
"validators>=0.35.0",
|
|
"pyyaml>=6.0",
|
|
"zxcvbn>=4.5.0",
|
|
"rengine-shared @ file:///app/shared",
|
|
"rengine-tools @ file:///app/tools",
|
|
]
|
|
|
|
[dependency-groups]
|
|
dev = [
|
|
"pytest>=8.4.2",
|
|
"pytest-asyncio>=1.2.0",
|
|
"pytest-cov>=7.0.0",
|
|
"anyio>=4.11.0",
|
|
]
|