From f39ca5ba72d73a433e64e096081d8a175e11b833 Mon Sep 17 00:00:00 2001 From: Frank Bria <136862992+frankbria@users.noreply.github.com> Date: Fri, 19 Jun 2026 15:20:25 -0700 Subject: [PATCH 1/3] fix(ci): run full non-e2e suite in CI, drop -m v2 blind spot (#669) The backend CI gate ran `pytest -m v2`, but the root conftest never auto-marked v2, so ~514 legit tests (40% of files) were silently deselected and never gated a PR. The v1->v2 refactor that the filter existed for is done. Categorized the 514 deselected tests: 497 pass, 16 skip, 1 is a real-LLM `lifecycle` test (correctly excluded). No dead tests remain (the v1 /api/projects pair was removed in #667). Changes: - CI: `-m v2` -> `-m "not lifecycle"` so every non-e2e test gates PRs; only real-LLM lifecycle tests (run locally via scripts/lifecycle) are excluded. Timeout 15->20m for the ~500 extra tests under coverage. - pytest.ini: document the new two-tier gate; v2 marker kept for back-compat but no longer gates. - tests/auth/test_query_param_token.py: sign JWTs with the LIVE manager.SECRET instead of the import-time binding. Un-hiding the suite surfaced this order-dependent flake: any test that starts the app via TestClient refreshes SECRET from .env (lifespan), which made import-bound tokens unverifiable. Full non-e2e run: 3830 passed, 11 skipped, 6 deselected (lifecycle), 0 failed. --- .github/workflows/test.yml | 9 +++++---- pytest.ini | 10 +++++++--- tests/auth/test_query_param_token.py | 11 +++++++++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2693b0bd..70043663 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -236,12 +236,12 @@ jobs: uv pip install -e . echo "✅ Package installed in editable mode" - - name: Run pytest (v2 suite) with coverage - timeout-minutes: 15 + - name: Run pytest (full non-e2e suite) with coverage + timeout-minutes: 20 run: | uv run pytest tests/ \ --ignore=tests/e2e \ - -m v2 \ + -m "not lifecycle" \ -q \ --tb=short \ --cov=codeframe \ @@ -249,7 +249,8 @@ jobs: --cov-report=xml \ --cov-report=html echo "Coverage measured for reporting purposes." - echo "Note: -m v2 covers v2 code paths only; legacy v1 modules are excluded." + echo "Note: gate runs every non-e2e test except 'lifecycle' (real-LLM," + echo " run locally via scripts/lifecycle before opening a PR)." - name: Upload coverage reports uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4 diff --git a/pytest.ini b/pytest.ini index 668452e7..6f6cbb83 100644 --- a/pytest.ini +++ b/pytest.ini @@ -45,6 +45,13 @@ markers = edge_case: marks edge case tests for boundary conditions and error handling lifecycle: full end-to-end lifecycle tests (real LLM calls — run via scripts/lifecycle) +# CI gate (the backend job in .github/workflows/test.yml) runs the full non-e2e +# suite EXCEPT real-LLM lifecycle tests: +# pytest tests/ --ignore=tests/e2e -m "not lifecycle" +# The `v2` marker is no longer a CI gate (the v1->v2 refactor is done); it stays +# registered for back-compat / ad-hoc selection. Don't rely on it to gate a +# test — anything non-e2e and non-lifecycle runs in CI by default (#669). +# # To run only unit tests (fast): # pytest -m "not integration and not slow and not e2e" # @@ -54,9 +61,6 @@ markers = # To run all tests except slow ones: # pytest -m "not slow" # -# To run only v2 tests: -# pytest -m v2 -# # To run lifecycle tests (real LLM — use scripts/lifecycle instead): # ANTHROPIC_API_KEY=sk-ant-... pytest -m lifecycle diff --git a/tests/auth/test_query_param_token.py b/tests/auth/test_query_param_token.py index 527e6a39..2b6c014f 100644 --- a/tests/auth/test_query_param_token.py +++ b/tests/auth/test_query_param_token.py @@ -15,8 +15,9 @@ from fastapi import FastAPI, Depends, Request from fastapi.testclient import TestClient +from codeframe.auth import manager from codeframe.auth.dependencies import get_current_user, get_current_user_optional -from codeframe.auth.manager import SECRET, JWT_ALGORITHM, reset_auth_engine +from codeframe.auth.manager import JWT_ALGORITHM, reset_auth_engine from codeframe.platform_store.database import Database pytestmark = pytest.mark.v2 @@ -27,7 +28,13 @@ PLAIN_PATH = "/whoami" -def _make_token(user_id: int = 1, secret: str = SECRET) -> str: +def _make_token(user_id: int = 1, secret: str = None) -> str: + # Read manager.SECRET live, not at import. get_current_user verifies against + # the live global, and any test that starts the app via TestClient refreshes + # it from .env (lifespan -> refresh_secret). Binding at import would make + # these tokens unverifiable once that happens — an order-dependent flake. + if secret is None: + secret = manager.SECRET payload = { "sub": str(user_id), "aud": ["fastapi-users:auth"], From 6ee3c56ea50d8209b78d2a4f5f3b1c300e719113 Mon Sep 17 00:00:00 2001 From: Frank Bria <136862992+frankbria@users.noreply.github.com> Date: Fri, 19 Jun 2026 15:27:18 -0700 Subject: [PATCH 2/3] docs: point CLAUDE.md test commands at the new CI gate (#669) --- CLAUDE.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 1a04bd22..82c712cc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -152,10 +152,10 @@ tests/ ### Python / CLI ```bash -uv run pytest # All tests -uv run pytest -m v2 # v2 tests only -uv run pytest tests/core/ # Core module tests -uv run pytest tests/lifecycle/ # Lifecycle tests (no live API calls — uses MockProvider) +uv run pytest # All tests +uv run pytest --ignore=tests/e2e -m "not lifecycle" # The CI gate (every non-e2e, non-real-LLM test) +uv run pytest tests/core/ # Core module tests +scripts/lifecycle --mode cli|api|web|all # Real-LLM lifecycle tests (run locally before a PR) uv run ruff check . # Web UI From 683cae9d6ddb75fb40acfc92a948aaa51aee2df8 Mon Sep 17 00:00:00 2001 From: Frank Bria <136862992+frankbria@users.noreply.github.com> Date: Fri, 19 Jun 2026 15:37:36 -0700 Subject: [PATCH 3/3] docs: match CI gate command to workflow (explicit tests/) (#669) --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 82c712cc..6c96cedc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -153,7 +153,7 @@ tests/ ### Python / CLI ```bash uv run pytest # All tests -uv run pytest --ignore=tests/e2e -m "not lifecycle" # The CI gate (every non-e2e, non-real-LLM test) +uv run pytest tests/ --ignore=tests/e2e -m "not lifecycle" # The CI gate (every non-e2e, non-real-LLM test) uv run pytest tests/core/ # Core module tests scripts/lifecycle --mode cli|api|web|all # Real-LLM lifecycle tests (run locally before a PR) uv run ruff check .