PyPI / filelock / 4.1.1

filelock 4.1.1

Source
https://github.com/tox-dev/py-filelock
Tag scanned
4.1.1
Compared with
4.1.0 (1 signals introduced since)
Files
92 scanned, 9 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 2 warn · 14 info
Scan time
15.4 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 16 of 16 warn and critical signals; 14 demoted to info.
Disclude version
4.0.0
Scanned (UTC)
2026-10-14 18:16

Signals

Ordered by severity, then signals introduced in this release. Hidden characters are shown as ⟨U+…⟩.

  1. warn dynamic-execution compose.yaml:18:30 new in this release

    [embedded bash] command name is a variable (`$$`) not set in this file — the caller or environment decides what runs (ast pass, confidence 0.70)

    "cp -a /repo \"$$HOME/work\" && cd \"$$HOME/work\" && pip install -q . && exec tox run -e py -x env.py.base_python=3.14 -x env_pkg_base.default_base_python=3.14"
    likely benign LLM, confidence 0.60 Embedded bash in a compose file that copies the repo to HOME and runs tox.
    Reasoning

    The snippet is a CI-style bash block in a compose file: cp a repo, pip install, then exec tox. The flagged variable is an escaped $$HOME, which compose renders as a plain $HOME, and the command names shown are literal. The flag looks like a scanner artifact, though a variable command name is worth a glance.

  2. warn frame-introspection tasks/capabilities.py:229:13

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

                nested.append(True)
                sys.setprofile(sys.getprofile())
    
        sys.addaudithook(setprofile_again)
    suspicious LLM, confidence 0.70 An audit hook re-applies the current profile function, keeping the probe hook installed.
    Reasoning

    Inside an audit hook, setprofile is re-applied to the current profile. This is unusual and worth reviewing because it keeps a profile hook alive. In context it reads as a capability probe checking whether profile hooks persist, but the re-arming via addaudithook is the odd part.

  3. info warn → info by review frame-introspection src/filelock/_api.py:1248:31

    `inspect.currentframe` — call-stack frame introspection (ast pass, confidence 0.70)

                    return
                state.releasing = inspect.currentframe()
                try:
                    _LOGGER.debug("Attempting to release lock %s on %s", id(self), self.lock_file)
    likely benign LLM, confidence 0.95 Records the caller frame when a lock is being released.
    Reasoning

    inspect.currentframe is stored on the lock state to record the releasing caller for logging and reentrancy tracking. This is a standard debugging aid in a file-locking library.

  4. info warn → info by review frame-introspection src/filelock/_api.py:1390:35

    `inspect.currentframe` — call-stack frame introspection (ast pass, confidence 0.70)

            attempt = 0
            self._context.acquiring = inspect.currentframe()
            try:
                while True:
    likely benign LLM, confidence 0.95 Records the caller frame when a lock acquisition begins.
    Reasoning

    The acquiring caller frame is stored on the context for diagnostics during lock acquisition. This is routine in a locking library and has no network, exec, or exfiltration behavior.

  5. info warn → info by review frame-introspection src/filelock/_api.py:1644:14

    `inspect.currentframe` — call-stack frame introspection (ast pass, confidence 0.70)

            return False
        caller = inspect.currentframe()
        while caller is not None and caller is not frame:
            caller = caller.f_back
    likely benign LLM, confidence 0.95 Walks the call stack to find a specific caller frame.
    Reasoning

    The code walks the f_back chain to locate an enclosing frame, which is a normal way to find a caller in library code. Nothing in the snippet is harmful.

  6. info warn → info by review frame-introspection tasks/capabilities.py:181:5

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        previous: Final = sys.getprofile()
        sys.setprofile(interrupt)
        try:
            with suppress(KeyboardInterrupt), contextmanager(probe)():
    likely benign LLM, confidence 0.80 Installs a temporary profile hook that injects an interrupt, then restores the previous profile.
    Reasoning

    In a tasks/ helper, sys.setprofile installs an interrupt-injecting profile function around a context, restoring the previous profile afterwards. This fits a test harness for interrupt safety. The try/finally restore is consistent with test tooling, not persistence.

  7. info warn → info by review frame-introspection tasks/capabilities.py:186:9

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        finally:
            sys.setprofile(previous)
        return bool(finished)
    likely benign LLM, confidence 0.80 Restores the previous profile function after the interrupt probe.
    Reasoning

    This is the finally block restoring the previous profile function after the probe. It is cleanup for the temporary interrupt hook and carries no malicious signal.

  8. info warn → info by review frame-introspection tasks/capabilities.py:233:9

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        try:
            sys.setprofile(sys.getprofile())
        except RuntimeError:
            return False
    likely benign LLM, confidence 0.75 Probe that tests whether setting the profile function raises RuntimeError.
    Reasoning

    This is a probe that checks whether setprofile can be set and returns False on RuntimeError. It appears to test whether the interpreter supports the hook in the current context. Like the neighbouring finding, it's test tooling, but the audit-hook interplay merits a look.

  9. info warn → info by review frame-introspection tests/test_filelock.py:1481:5

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        entered: Final[set[FrameType]] = set()
        sys.setprofile(interrupt)
        try:
            lock.release()
    likely benign LLM, confidence 0.85 Test installs a profile hook to inject an interrupt during lock release.
    Reasoning

    In a test, a profile function is installed to interrupt at a chosen point during lock release, then removed in a finally block. This is a standard way to test interrupt-safety in a locking library.

  10. info warn → info by review frame-introspection tests/test_filelock.py:1487:9

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        finally:
            sys.setprofile(None)
        return False
    likely benign LLM, confidence 0.90 Clears the test's profile hook in a finally block.
    Reasoning

    This finally block clears the profile function after the test. It is test cleanup with no malicious intent.

  11. info warn → info by review frame-introspection tests/test_soft_lease.py:401:9

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

        def read_compromise() -> None:
            sys.setprofile(pause_in_claim_creation)
            try:
                assert lease.compromise is None
    likely benign LLM, confidence 0.90 Test installs a profile hook to pause claim creation for a race-condition check.
    Reasoning

    A test installs a profile hook to pause during claim creation so a concurrent reader can observe state. This is a deterministic concurrency test and does not indicate malicious behaviour.

  12. info warn → info by review frame-introspection tests/test_soft_lease.py:405:13

    `sys.setprofile` — call-stack frame introspection (ast pass, confidence 0.70)

            finally:
                sys.setprofile(None)
    
        reader: Final = Thread(target=read_compromise)
    likely benign LLM, confidence 0.90 Removes the test's profile hook after the race check.
    Reasoning

    This finally block removes the test's profile hook. It is cleanup in a concurrency test.

  13. info warn → info by review frame-introspection tests/test_soft_lifetime_warning.py:47:28

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

            if entry_point == "constructor":
                warning_line = sys._getframe().f_lineno + 1
                lock_type(tmp_path / "test.lock", lifetime=10)
            else:
    likely benign LLM, confidence 0.95 Test reads the current line number via sys._getframe to assert a warning location.
    Reasoning

    sys._getframe().f_lineno is used in a test to capture the expected warning line number. This is a common testing technique with no security relevance.

  14. info warn → info by review frame-introspection tests/test_soft_lifetime_warning.py:51:28

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

                lock = lock_type(tmp_path / "test.lock")
                warning_line = sys._getframe().f_lineno + 1
                lock.lifetime = 10
    likely benign LLM, confidence 0.93 Test code uses sys._getframe().f_lineno to record the line where a lifetime warning is expected to be emitted.
    Reasoning

    sys._getframe() is used in a test to capture the current line number so the test can assert that a deprecation/soft lifetime warning points at the correct source line. This is a legitimate testing technique for verifying warning locations, not obfuscation or malicious behavior.

  15. info warn → info by review frame-introspection tests/test_soft_lifetime_warning.py:139:28

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

            if entry_point == "constructor":
                warning_line = sys._getframe().f_lineno + 1
                lock_type(tmp_path / "test.lock", lifetime=10)
            else:
    likely benign LLM, confidence 0.93 Test captures the expected warning line number via sys._getframe() before a constructor call that triggers a lifetime warning.
    Reasoning

    Same pattern as the other finding: a test records the expected warning line via sys._getframe().f_lineno before calling the constructor with lifetime=10, to verify warnings.warn stacklevel behavior. Benign test scaffolding.

  16. info warn → info by review frame-introspection tests/test_soft_lifetime_warning.py:143:28

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

                lock = lock_type(tmp_path / "test.lock")
                warning_line = sys._getframe().f_lineno + 1
                lock.lifetime = 10
    likely benign LLM, confidence 0.93 Test records the expected line of a lock.lifetime assignment via sys._getframe() to validate the emitted warning location.
    Reasoning

    Identical pattern in the attribute-assignment branch: sys._getframe() records the line of the upcoming lock.lifetime assignment so the test can check the warning location. Legitimate test technique with no malicious indicators.

Reproduce This Scan

Run disclude locally to verify. Add --format sarif for SARIF output. Add --llm (with an API key in the environment) to include the LLM review.

cargo install disclude --version 4.0.0
git clone https://github.com/tox-dev/py-filelock py-filelock && cd py-filelock
git checkout 4.1.1
disclude scan --severity info --diff 4.1.0 .