Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace some uses of the deprecated mktemp function #1770

Merged
merged 2 commits into from
Dec 13, 2023

Commits on Dec 13, 2023

  1. Avoid mktemp in tests, in straightforward cases

    The tempfile.mktemp function is deprecated, because of a race
    condition where the file may be concurrently created between when
    its name is generated and when it is opened. Other faciliies in the
    tempfile module overcome this by generating a name, attempting to
    create the file or directory in a way that guarantees failure if it
    already existed, and, in the occasional case that it did already
    exist, generating another name and trying again (stopping after a
    predefined limit). For further information on mktemp deprecation:
    
    - https://docs.python.org/3/library/tempfile.html#tempfile.mktemp
    - gitpython-developers/smmap#41
    
    The security risk of calls to mktemp in this project's test suite
    is low. However, it is still best to avoid using it, because it is
    deprecated, because it is (at least slightly) brittle, and because
    any use of mktemp looks like a potential security risk and thereby
    imposes a burden on working with the code (which could potentially
    be addressed with detailed comments analyzing why it is believed
    safe in particular cases, but this would typically be more verbose,
    and at least as challenging to add, as replacing mktemp with a
    better alternative).
    
    This commit replaces *some* uses of mktemp in the test suite: those
    where it is readily clear how to do so in a way that preserves the
    code's intent:
    
    - Where a name for a temporary directory is generated with mktemp
      and os.mkdir is called immediately, mkdtemp is now used.
    
    - Where a name for a temporary file that is not customized (such as
      with a prefix) is generated with mktemp, such that the code under
      test never uses the filename but only the already-open file-like
      object, TemporaryFile is now used. As the name isn't customized,
      the test code in these cases does not express an intent to allow
      the developer to inspect the file after a test failure, so even
      if the file wasn't guaranteed to be deleted with a finally block
      or context manager, it is fine to do so. TemporaryFile supports
      this use case well on all systems including Windows, and
      automatically deletes the file.
    
    - Where a name for a temporary file that *is* customized (such as
      with a prefix) to reflect the way the test uses it is generated
      with mktemp, and the test code does not attempt deterministic
      deletion of the file when an exception would make the test fail,
      NamedTemporaryFile with delete=False is now used. The original
      code to remove the file when the test succeeds is modified
      accordingly to do the same job, and also commented to explain
      that it is being handled this way to allow the file to be kept
      and examined when a test failure occurs.
    
    Other cases in the test suite should also be feasible to replace,
    but are left alone for now. Some of them are ambiguous in their
    intent, with respect to whether the file should be retained after a
    test failure. Others appear deliberately to avoid creating a file
    or directory where the code under test should do so, possibly to
    check that this is done properly. (One way to preserve that latter
    behavior, while avoiding the weakness of using mktemp and also
    avoiding inadverently reproducing that weakness by other means,
    could be to use a path in a temporary directory made for the test.)
    
    This commit also doesn't address the one use of mktemp in the code
    under test (i.e., outside the test suite, inside the git module).
    EliahKagan committed Dec 13, 2023
    Configuration menu
    Copy the full SHA
    41fac85 View commit details
    Browse the repository at this point in the history
  2. Replace the one use of mktemp in the git module

    This makes two related changes to git.index.util.TemporaryFileSwap:
    
    - Replace mktemp with mkstemp and then immediately closing the file.
      This avoids two possible name clashes: the usual name clash where
      the file may be created by another process between when mktemp
      generates the name and when the file is created, and the problem
      that mktemp does not check for files that contain the generated
      name as a part. The latter is specific to the use here, where
      a string generated by mktemp was manually concatenated to the
      base filename. This addresses that by passing the filename as the
      prefix for mkstemp to use.
    
    - Replace os.remove with os.replace and simplify. This is made
      necessary on Windows by the file already existing, due to mkstemp
      creating it. Deleting the file and allowing it to be recreated
      would reproduce the mktemp race condition in full (obscured and
      with extra steps). But os.replace supports an existing target
      file on all platforms. It is now also used in __exit__, where it
      allows the Windows check for the file to be removed, and (in any
      OS) better expresses the intent of the code to human readers.
      Furthermore, because one of the "look before you leap" checks in
      __exit__ is removed, the minor race condition in cleaning up the
      file is somewhat decreased.
    
    A small amount of related refactoring is included. The interface is
    not changed, even where it could be simplified (by letting __exit__
    return None), and resource acquisition remains done on construction
    rather than in __enter__, because changing those aspects of the
    design could break some existing uses.
    
    Although the use of mktemp replaced here was in the git module and
    not the test suite, its use was to generate filenames for use in a
    directory that would ordinarily be under the user's control, such
    that the ability to carry out typical mktemp-related attacks would
    already require the ability to achieve the same goals more easily
    and reliably. Although TemporaryFileSwap is a public class that may
    be used directly by applications, it is only useful for making a
    temporary file in the same directory as an existing file. Thus the
    intended benefits of this change are mainly to code quality and
    a slight improvement in robustness.
    EliahKagan committed Dec 13, 2023
    Configuration menu
    Copy the full SHA
    9e86053 View commit details
    Browse the repository at this point in the history