Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .bestpractices.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
"build_floss_tools_justification": "pip, uv, hatchling, pytest, ruff and pyright are all FLOSS, and the build runs on ubuntu-latest and windows-latest GitHub runners.",

"test_status": "Met",
"test_justification": "An automated test suite of 6376 tests lives under tests_py/ (measured 2026-07-28 with 'pytest --collect-only -q'), covering core, handlers, infrastructure, integration, invariants and architecture: https://github.com/cdeust/Cortex/tree/main/tests_py",
"test_justification": "An automated test suite of 6426 tests lives under tests_py/ (measured 2026-07-29 with 'pytest --collect-only -q'), covering core, handlers, infrastructure, integration, invariants and architecture: https://github.com/cdeust/Cortex/tree/main/tests_py",

"test_invocation_status": "Met",
"test_invocation_justification": "The whole suite runs with a single 'pytest' command, documented in CONTRIBUTING.md under Testing along with per-layer subsets: https://github.com/cdeust/Cortex/blob/main/CONTRIBUTING.md",
Expand All @@ -114,7 +114,7 @@
"test_policy_justification": "CONTRIBUTING.md carries an explicit, mandatory testing policy: new functionality ships with tests in the automated suite, a bug fix carries a regression test that fails on the pre-fix code, and each failure path asserts its observable effect including the signal it emits \u2014 https://github.com/cdeust/Cortex/blob/main/CONTRIBUTING.md#the-testing-policy-mandatory. The per-tool checklist ('Add a unit test', 'Add an integration test if the tool touches the database') and the five-element mechanism checklist restate it per change type.",

"tests_are_added_status": "Met",
"tests_are_added_justification": "New functionality ships with its tests; the suite has grown to 6376 tests alongside the v4.x feature series, and CI runs it on every pull request.",
"tests_are_added_justification": "New functionality ships with its tests; the suite has grown to 6426 tests alongside the v4.x feature series, and CI runs it on every pull request.",

"tests_documented_added_status": "Met",
"tests_documented_added_justification": "The requirement is written into the documented instructions for change proposals: https://github.com/cdeust/Cortex/blob/main/CONTRIBUTING.md#the-testing-policy-mandatory states that every change adding or altering observable behaviour must arrive with tests in the same PR, the per-tool and per-mechanism checklists repeat it as a concrete step, and .github/PULL_REQUEST_TEMPLATE.md requires a Test plan section in every pull request.",
Expand Down Expand Up @@ -189,7 +189,7 @@
"static_analysis_often_justification": "CodeQL default setup analyses each push and pull request and additionally runs on a weekly schedule, so analysis happens per change rather than per release.",

"dynamic_analysis_status": "Unmet",
"dynamic_analysis_justification": "No dynamic analysis tool in the badge's sense (fuzzer, sanitizer, or scanner) is applied. The project runs a 6376-test suite with coverage on every change, but a test suite is not a dynamic analysis tool and is not claimed as one here.",
"dynamic_analysis_justification": "No dynamic analysis tool in the badge's sense (fuzzer, sanitizer, or scanner) is applied. The project runs a 6426-test suite with coverage on every change, but a test suite is not a dynamic analysis tool and is not claimed as one here.",

"dynamic_analysis_unsafe_status": "N/A",
"dynamic_analysis_unsafe_justification": "Cortex is written in Python, a memory-safe language, so the memory-safety tooling this criterion asks about (ASan, Valgrind) does not apply.",
Expand Down Expand Up @@ -297,7 +297,7 @@
"interfaces_current_justification": "The stack targets currently supported runtimes and APIs: Python 3.10 through 3.13, all four in the CI matrix, with pgvector 0.3+/PostgreSQL 17 and current major versions of FastMCP, Pydantic v2, numpy and sentence-transformers. Deprecated interfaces are removed rather than wrapped \u2014 the standing rule is one-shot migrations with no back-compat shims (CLAUDE.md), and CI runs on the newest released Python so a deprecation surfaces as a warning in the build rather than as a surprise at end of life.",

"automated_integration_testing_status": "Met",
"automated_integration_testing_justification": "The full suite runs on every push and pull request to main via .github/workflows/ci.yml and reports success or failure per job: 6376 tests on Python 3.10-3.13 against PostgreSQL + pgvector, the same suite against the SQLite backend, the suite on Windows, and a Docker smoke job that boots the bare container and exercises the DB-less contract. tests_py/integration/ holds the database-backed integration tests specifically.",
"automated_integration_testing_justification": "The full suite runs on every push and pull request to main via .github/workflows/ci.yml and reports success or failure per job: 6426 tests on Python 3.10-3.13 against PostgreSQL + pgvector, the same suite against the SQLite backend, the suite on Windows, and a Docker smoke job that boots the bare container and exercises the DB-less contract. tests_py/integration/ holds the database-backed integration tests specifically.",

"regression_tests_added50_status": "Met",
"regression_tests_added50_justification": "Measured on 2026-07-27 over the merged pull requests titled as fixes in the preceding six months (2026-01-27 onward): 23 of 30 \u2014 76.7% \u2014 changed the test tree in the same PR, against the 50% this criterion asks for. (The measure counts a PR as carrying tests when it touches tests_py/ or tests_js/, which is a proxy for 'added a regression test'; the policy behind it is written down at https://github.com/cdeust/Cortex/blob/main/CONTRIBUTING.md#the-testing-policy-mandatory \u2014 a bug fix carries a regression test that fails on the pre-fix code.)",
Expand Down
19 changes: 19 additions & 0 deletions .clusterfuzzlite/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# ClusterFuzzLite build environment for the fuzz/ harnesses.
#
# ClusterFuzzLite is the per-repository form of OSS-Fuzz: it builds the
# harnesses in fuzz/ against libFuzzer via atheris and runs them on pull
# requests (a short batch) and on a schedule (a longer one). See
# .github/workflows/fuzz.yml for the two cadences.
#
# Base image pinned by digest, exactly as the other four Dockerfiles in this
# repository are: an unpinned base makes the build non-reproducible and is
# itself an OpenSSF Scorecard Pinned-Dependencies finding, so adding fuzzing
# with a floating base would trade one finding for another.
# source: gcr.io/v2/oss-fuzz-base/base-builder-python/manifests/latest,
# docker-content-digest header, fetched 2026-07-28.
FROM gcr.io/oss-fuzz-base/base-builder-python@sha256:093721649cdd0d15c1e97eb905ed94079c09ffc8b3341c5dc42957b92f1b388f

# $SRC is the OSS-Fuzz convention for the checkout root.
COPY . $SRC/cortex
WORKDIR $SRC/cortex
COPY .clusterfuzzlite/build.sh $SRC/build.sh
29 changes: 29 additions & 0 deletions .clusterfuzzlite/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash -eu
# Build every fuzz/ harness into a libFuzzer binary.
#
# -e so a failed dependency install fails the build instead of producing a
# fuzzer that cannot import the code it is meant to exercise — a silently
# useless fuzzer is worse than none, because the dashboard turns green.

# Runtime dependencies of the modules under test, hash-pinned from uv.lock
# (scripts/generate_pip_constraints.py). The harnesses import mcp_server
# modules, so their imports must resolve.
pip3 install --require-hashes -r "$SRC/cortex/requirements/ci-sqlite-min.txt"
pip3 install --no-deps -e "$SRC/cortex"

# compile_python_fuzzer is provided by the base image. It wraps each harness
# with atheris's instrumentation and emits $OUT/<name>.
for harness in "$SRC"/cortex/fuzz/fuzz_*.py; do
compile_python_fuzzer "$harness"
done

# Ship each harness's committed corpus as its seed corpus. These are the
# reproducers of bugs already found (see fuzz/corpus/*/repro-*) plus shape
# seeds; starting from them keeps the fuzzer from rediscovering the shallow
# surface on every run.
for corpus in "$SRC"/cortex/fuzz/corpus/*/; do
name="$(basename "$corpus")"
if [ -d "$corpus" ]; then
zip -j "$OUT/${name}_seed_corpus.zip" "$corpus"* >/dev/null
fi
done
32 changes: 18 additions & 14 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,24 @@ WORKDIR /workspace
COPY pyproject.toml README.md ./
COPY mcp_server ./mcp_server

# CPU-only torch wheel: sentence-transformers pulls torch transitively as a
# mandatory base dependency (pyproject.toml); pip's default index resolves
# the full CUDA build (~2GB across torch/cudnn/cusparselt/cublas/etc.) even
# though this container never uses a GPU — identical rationale to
# ../Dockerfile:38-45 and benchmarks/reproduce.sh's own CPU-only builds.
# Versions pinned exactly to this repo's lockfile so the devcontainer
# never silently drifts from what CI/production actually run.
# source: uv.lock (this repo, checked 2026-07-14) — torch==2.11.0,
# sentence-transformers==5.4.1, flashrank==0.2.10.
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir torch==2.11.0 --index-url https://download.pytorch.org/whl/cpu && \
pip install --no-cache-dir ".[postgresql,codebase]" \
"sentence-transformers==5.4.1" \
"flashrank==0.2.10"
# Dependencies, hash-pinned from uv.lock via
# scripts/generate_pip_constraints.py — the same lock CI and production
# resolve from, so the devcontainer cannot silently drift from them.
#
# This replaces three hand-copied version pins (torch==2.11.0,
# sentence-transformers==5.4.1, flashrank==0.2.10) that had already drifted:
# the lock had moved to torch 2.13.0 while this file still said 2.11.0. An
# exact version is also not a hash — it names a release, not the bytes the
# index serves for it. The CPU-only torch build is carried by the file (see
# [[tool.uv.index]] in pyproject.toml) rather than by an --index-url flag
# here; the rationale for CPU-only is unchanged and lives in ../Dockerfile.
COPY requirements/devcontainer.txt /tmp/requirements.txt
RUN pip install --no-cache-dir --require-hashes -r /tmp/requirements.txt

# The project itself, editable so a contributor's edits take effect without
# a rebuild. --no-deps because the hashed file above is the complete
# dependency graph; without it pip would re-resolve, unpinned.
RUN pip install --no-cache-dir --no-deps -e .

# ── Model prewarming AT BUILD TIME ─────────────────────────────────────────
# HF_HOME / XDG_CACHE_HOME point at a durable image path baked into a layer
Expand Down
7 changes: 7 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,10 @@
*.dylib binary
*.dll binary
*.exe binary

# Fuzz corpus inputs are opaque byte sequences, not text. Git's end-of-line
# normalisation would rewrite CRLF seeds to LF on checkout and silently
# change what the harness is fed — fuzz/corpus/fuzz_yaml_frontmatter/seed-crlf
# exists precisely to exercise CRLF handling, so normalising it deletes the
# case. -text disables that; -diff keeps binary junk out of diffs.
fuzz/corpus/** -text -diff
Loading