Skip to content

Commit 7e4d838

Browse files
Your Nameclaude
andcommitted
fix(scan_github): skip test files before temp-write to prevent _is_test_file bypass
scan_github writes each file to a random temp path (e.g. /tmp/tmpXXX.py), losing the original filename. The call-site checker's _is_test_file check on call.file then always sees a non-test name and never suppresses test-file violations. Corpus batch 25: celery/django-celery-beat had 50/54 save_without_update_fields violations in t/unit/test_*.py — all FPs. Fix: skip test-named files in the GitHub path loop before download+extraction, mirroring _is_test_file logic (basename test_ prefix, _test.py suffix, or test/tests/testing directory component). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent f935377 commit 7e4d838

2 files changed

Lines changed: 30 additions & 0 deletions

File tree

scan_github.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,16 @@ def scan_repo(
223223

224224
# Process up to max_files to avoid runaway on monorepos
225225
for path in py_files[:max_files]:
226+
# Skip test files: temp file loses original name so _is_test_file in the
227+
# call-site checker won't fire — skip here at the source instead.
228+
_basename = path.split("/")[-1]
229+
_parts = path.split("/")
230+
if (
231+
_basename.startswith("test_")
232+
or _basename.endswith("_test.py")
233+
or any(p in {"test", "tests", "testing"} for p in _parts)
234+
):
235+
continue
226236
source = fetch_file_content(owner, repo, path, default_branch, session)
227237
if not source:
228238
continue

test_checker.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,26 @@ def test_update(self):
635635
assert not v, f"save() in test files must not be flagged: {v}"
636636

637637

638+
def test_save_in_subdir_test_file_not_flagged(tmp_path):
639+
# Regression: celery/django-celery-beat t/unit/test_schedulers.py leaked through
640+
# scan_github because temp files lose the original name, making _is_test_file miss
641+
# basename-prefixed test files nested under non-test directories (t/unit/).
642+
# The fix: skip test-named files in scan_github *before* writing the temp file.
643+
# Locally, check_codebase detects test files correctly via basename.
644+
test_dir = tmp_path / "t" / "unit"
645+
test_dir.mkdir(parents=True)
646+
(test_dir / "test_schedulers.py").write_text(
647+
"import django.db.models\n"
648+
"def test_update():\n"
649+
" m = MyModel.objects.get(pk=1)\n"
650+
" m.enabled = True\n"
651+
" m.save()\n"
652+
)
653+
violations = check_codebase(tmp_path)
654+
v = [v for v in violations if v.context == "save_without_update_fields"]
655+
assert not v, f"save() in t/unit/test_*.py must not be flagged: {v}"
656+
657+
638658
def test_objects_get_not_flagged_as_optional(tmp_path):
639659
# Corpus: EvalAI — token = JwtToken.objects.get(user=user); token.refresh_token
640660
# Model.objects.get() raises DoesNotExist, never returns None.

0 commit comments

Comments
 (0)