You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SAFE601 missing_assertions now recognises Python assertion method calls, not just the assert keyword. unittest / Django TestCase bodies assert via self.assertEqual(...) / self.assertRaises(...) and pytest via pytest.raises(...) / pytest.warns(...), none of which the rule could previously see - so every unittest-style test read as assertion-less and forced a file-wide SAFE601 ignore (which also hid genuinely under-asserted production code). Python gains a configurable assertion_calls list (bare key, per the Python convention), counted in addition to the assert keyword; call_name strips the receiver so self.assertEqual / pytest.raises match on the bareword. The default set covers the unittest assert* surface plus pytest's raises / warns; extend it with project-specific assertion helpers. This closes the systemic false-positive class surfaced by the optimus-secure-fdn Django review. A mistyped scalar (assertion_calls = "assertEqual") fails loud rather than silently matching characters, matching the other per-language lists.
SAFE601 can now be scoped to test functions only via test_functions_only = true (default false, so Holzmann rule 5's production-assertion intent is unchanged for existing configs). When on, the rule fires only for functions named for a test_function_prefixes entry (default ["test"]) that live in a file safelint recognises as a test file (under test_dirs, or matching the language's test-filename convention - the same definition SAFE701/702 use). This lets teams run SAFE601 as a "test must actually assert something" guard: production code that validates by raising, and fixtures / setUp / helper methods that legitimately have no assertions, are skipped, while a test_* function that asserts nothing still fires. The shared test-file identification used by SAFE601/701/702 now lives in one place (rules/_test_files.py).
SAFE907 unvalidated_request_input gains a configurable validator allowlist. The rule previously recognised only a hardcoded set of validating calls (Python is_valid / full_clean / validate / model_validate / parse_obj; PHP $request->validate), so a project that validates request input through its own helper (validate_export_request(), an allowlist filter builder) could only silence the rule with a file-level ignore - which then hid any genuinely-unvalidated read elsewhere in that file. New request_validators (Python, bare key) / request_validators_php (PHP) lists are unioned with the built-in set; a read guarded by a listed helper no longer fires. Exact call-name match (receiver stripped), validated via the shared string-list guard so a mistyped scalar fails loud. Also surfaced by the optimus-secure-fdn Django review.
Fixed
test_coupling (SAFE702): an explicit file target's changed-files context is now the repo-wide diff, and the rule only fires for a source that actually changed. Two coupled corrections. (1) safelint check foo.py gave foo.py a changed set of just [foo.py], so an overlapping run safelint check pkg/ pkg/foo.py (which dedups to the file target) could false-positive: a sibling test updated in the same commit was dropped from that single-file set, so check pkg/foo.py fired while check pkg/ stayed clean. A file target now carries the full repo-wide diff (falling back to the named file only when git is unavailable), so the verdict is identical however the file is named. (2) test_coupling now gates on the source file being in the changed set, so a named-but-unmodified file (check foo.py on a file you did not touch) no longer trips coupling - it did not change, so there is nothing to couple. Directory and pre-commit (safelint <file> ...) invocations are unaffected: every file they lint is already in the changed set. This supersedes the 2.11.0 "the named file is its own changed set" behaviour for check, which is git-aware (the positional pre-commit hook contract is unchanged).