Files
rengine/api/pyproject.toml
T
Yogesh OjhaandClaude Opus 5 4b6ab5ecfd test: the invariants the product promises are now enforced by a suite
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
2026-09-10 20:46:15 +05:30

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",
]