GeezerVison is showing github.com — Make the rmtree callback Windows-only by EliahKagan · Pull Request #1739 · gitpython-developers/GitPython
Conversation
EliahKagan
commented
Nov 14, 2023
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Fixes #1738
Changes
In addition to failing before the fix and passing afterwards, the test also is run on Windows, where it always passed and continues to pass after the fix, providing further assurance that Windows was never affected.
The bug itself, as well as the high-level considerations in fixing it, why this approach is not a breaking change, and why I took this approach rather than doing something else, are presented in #1738, and I think need not be repeated here.
There are a few considerations pertaining to the specific code changes here that I think are worth calling attention to briefly:
- The entire callback is used only on Windows now, since there remains nothing in it that should ever be done on any other system. Because of this, setting
HIDE_WINDOWS_KNOWN_ERRORS to True on a non-Windows system, which should never be done (and has fortunately never happened as a result of the same-named environment variable being set), no longer affects the behavior of rmtree. I would consider this a benefit, and I've adjusted the tests for it accordingly.
- This is part of the gradual improvement and reduction of Windows-specific logic in
git.util.rmtree, and reduction in the effect of HIDE_WINDOWS_KNOWN_ERRORS. It is thus a small further step toward Remove unittest code from non-test code #790.
- The reasoning that this is not a breaking change is based on what the
os.chmod call does and does not do. But this also makes a failure not retry deletion (since there is nothing it would do to improve the situation for a retry). One can sometimes relinquish the rest of one's time slice with time.sleep(0) or similar to try to let another process release a resource, which making an ineffective system call and retrying might be a much less reliable way of sometimes doing. But for deleting files that should not be necessary or helpful outside Windows, which didn't have the bug and whose behavior is not changed. Thus I don't think an ineffective system call and a retry can help at all. So this is not a breaking change by that mechanism either. (Separately, and on a separate branch, I did try os.sleep(0) to see if it alleviated the PermissionError problem on Windows that is related to files being open by another process; it did not.)
- I've taken the opportunity to make some further improvements to other tests of
git.util.rmtree in test_util.py. I think they are now somewhat more readable and a bit easier to modify further. We are still testing somewhat more Windows-related behavior on non-Windows systems than I think will ultimately be necessary--due to some previous additions I had made there--but I'm reluctant to try and pare that down until there are Windows CI job.
- My original motivation for looking at that code, which led to discovering the bug, was to simplify the situation around
HIDE_WINDOWS_KNOWN_ERRORS so it would be easier for me to reason about its interaction with and significance to the near-future Windows CI jobs. So this may be considered a step toward that as well.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This adds a test in test_util that reveals the bug where
git.util.rmtree will change the permissions on files outside the
tree being removed, if the tree being removed contains a symlink to
a file outside the tree, and the symlink is in a (sub)directory
whose own permissions prevent the symlink itself from being
removed.
The new test failure shows how git.util.rmtree currently calls
os.chmod in a way that dereferences symlinks, including those that
point from inside the tree being deleted to outside it.
Another similar demonstration is temporarily included in the
perm.sh script. That script served as scratchwork for writing the
unit test, and it can be removed soon (while keeping the test).
This keeps the same approach, but expresses it better. This does
not update the tests (yet), so one test is still failing.
This changes tests in test_util to verify the opposite behavior
from what was enforced before, in the unusual case (that hopefully
never happens outside of monkey-patching in test_util.py itself)
where the system is not Windows but HIDE_WINDOWS_KNOWN_ERRORS is
set to True.
The same-named environment variable will not, and never has, set
HIDE_WINDOWS_KNOWN_ERRORS to True on non-Windows systems, but it is
possible to set it to True directly. Since it is named as a
constant and no documentation has ever suggested changing its value
directly, nor otherwise attempting to use it outside Windows, it
shouldn't matter what happens in this unusual case. But asserting
that wrapping never occurs in this combination of circumstances is
what makes the most sense in light of the recent change to pass no
callback to shutil.rmtree on non-Windows systems.
Because of how it is parameterized, but only in some of the test
cases that use it, making this a pytest fixture would be cumbersome
without further refactoring, so this is a helper method instead.
(It may be feasible to further refactor the test suite to improve
this more.)
This also removes a type annotation from a test method. It may
eventually be helpful to add annotations, in which case that would
come back along with others (if that test still exists in this
form), but it's the only test with such an annotation in this
test class, and the annotation had been added accidentally.
This removes the perm.sh script that demonstrated the cross-tree
permission change bug. Tests for test_util test for this (in case
of a regression) and the bug is fixed, so the script, which served
to inform the writing of the corresponding unit test, is no longer
needed.
Byron
left a comment
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is such a great find, with a simple fix that the implementation should have started with from the beginning.
Thanks again for all your work!
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
EliahKagan reacted with thumbs up emoji
This was referenced Nov 28, 2023
otc-zuul Bot
pushed a commit
to opentelekomcloud-infra/eyes_on_docs
that referenced
this pull request
Mar 6, 2024
JoeWang1127
referenced
this pull request
in googleapis/sdk-platform-java
Apr 6, 2024
[](https://renovatebot.com)
This PR contains the following updates:
| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [GitPython](https://togithub.com/gitpython-developers/GitPython) |
`==3.1.40` -> `==3.1.41` |
[](https://docs.renovatebot.com/merge-confidence/)
|
[](https://docs.renovatebot.com/merge-confidence/)
|
[](https://docs.renovatebot.com/merge-confidence/)
|
[](https://docs.renovatebot.com/merge-confidence/)
|
---
> [!WARNING]
> Some dependencies could not be looked up. Check the Dependency
Dashboard for more information.
### GitHub Vulnerability Alerts
####
[CVE-2024-22190](https://togithub.com/gitpython-developers/GitPython/security/advisories/GHSA-2mqj-m65w-jghx)
### Summary
This issue exists because of an incomplete fix for CVE-2023-40590. On
Windows, GitPython uses an untrusted search path if it uses a shell to
run `git`, as well as when it runs `bash.exe` to interpret hooks. If
either of those features are used on Windows, a malicious `git.exe` or
`bash.exe` may be run from an untrusted repository.
### Details
Although GitPython often avoids executing programs found in an untrusted
search path since 3.1.33, two situations remain where this still occurs.
Either can allow arbitrary code execution under some circumstances.
#### When a shell is used
GitPython can be told to run `git` commands through a shell rather than
as direct subprocesses, by passing `shell=True` to any method that
accepts it, or by both setting `Git.USE_SHELL = True` and not passing
`shell=False`. Then the Windows `cmd.exe` shell process performs the
path search, and GitPython does not prevent that shell from finding and
running `git` in the current directory.
When GitPython runs `git` directly rather than through a shell, the
GitPython process performs the path search, and currently omits the
current directory by setting `NoDefaultCurrentDirectoryInExePath` in its
own environment during the `Popen` call. Although the `cmd.exe` shell
will honor this environment variable when present, GitPython does not
currently pass it into the shell subprocess's environment.
Furthermore, because GitPython sets the subprocess CWD to the root of a
repository's working tree, using a shell will run a malicious `git.exe`
in an untrusted repository even if GitPython itself is run from a
trusted location.
This also applies if `Git.execute` is called directly with `shell=True`
(or after `Git.USE_SHELL = True`) to run any command.
#### When hook scripts are run
On Windows, GitPython uses `bash.exe` to run hooks that appear to be
scripts. However, unlike when running `git`, no steps are taken to avoid
finding and running `bash.exe` in the current directory.
This allows the author of an untrusted fork or branch to cause a
malicious `bash.exe` to be run in some otherwise safe workflows. An
example of such a scenario is if the user installs a trusted hook while
on a trusted branch, then switches to an untrusted feature branch
(possibly from a fork) to review proposed changes. If the untrusted
feature branch contains a malicious `bash.exe` and the user's current
working directory is the working tree, and the user performs an action
that runs the hook, then although the hook itself is uncorrupted, it
runs with the malicious `bash.exe`.
Note that, while `bash.exe` is a shell, this is a separate scenario from
when `git` is run using the unrelated Windows `cmd.exe` shell.
### PoC
On Windows, create a `git.exe` file in a repository. Then create a
`Repo` object, and call any method through it (directly or indirectly)
that supports the `shell` keyword argument with `shell=True`:
```powershell
mkdir testrepo
git init testrepo
cp ... testrepo git.exe # Replace "..." with any executable of choice.
python -c "import git; print(git.Repo('testrepo').git.version(shell=True))"
```
The `git.exe` executable in the repository directory will be run.
Or use no `Repo` object, but do it from the location with the `git.exe`:
```powershell
cd testrepo
python -c "import git; print(git.Git().version(shell=True))"
```
The `git.exe` executable in the current directory will be run.
For the scenario with hooks, install a hook in a repository, create a
`bash.exe` file in the current directory, and perform an operation that
causes GitPython to attempt to run the hook:
```powershell
mkdir testrepo
cd testrepo
git init
mv .git/hooks/pre-commit.sample .git/hooks/pre-commit
cp ... bash.exe # Replace "..." with any executable of choice.
echo "Some text" >file.txt
git add file.txt
python -c "import git; git.Repo().index.commit('Some message')"
```
The `bash.exe` executable in the current directory will be run.
### Impact
The greatest impact is probably in applications that set `Git.USE_SHELL
= True` for historical reasons. (Undesired console windows had, in the
past, been created in some kinds of applications, when it was not used.)
Such an application may be vulnerable to arbitrary code execution from a
malicious repository, even with no other exacerbating conditions. This
is to say that, if a shell is used to run `git`, the full effect of
CVE-2023-40590 is still present. Furthermore, as noted above, running
the application itself from a trusted directory is not a sufficient
mitigation.
An application that does not direct GitPython to use a shell to run
`git` subprocesses thus avoids most of the risk. However, there is no
such straightforward way to prevent GitPython from running `bash.exe` to
interpret hooks. So while the conditions needed for that to be exploited
are more involved, it may be harder to mitigate decisively prior to
patching.
### Possible solutions
A straightforward approach would be to address each bug directly:
- When a shell is used, pass `NoDefaultCurrentDirectoryInExePath` into
the subprocess environment, because in that scenario the subprocess is
the `cmd.exe` shell that itself performs the path search.
- Set `NoDefaultCurrentDirectoryInExePath` in the GitPython process
environment during the `Popen` call made to run hooks with a `bash.exe`
subprocess.
These need only be done on Windows.
---
### Release Notes
<details>
<summary>gitpython-developers/GitPython (GitPython)</summary>
###
[`v3.1.41`](https://togithub.com/gitpython-developers/GitPython/releases/tag/3.1.41):
- fix Windows security issue
[Compare
Source](https://togithub.com/gitpython-developers/GitPython/compare/3.1.40...3.1.41)
The details about the Windows security issue [can be found in this
advisory](https://togithub.com/gitpython-developers/GitPython/security/advisories/GHSA-2mqj-m65w-jghx).
Special thanks go to
[@​EliahKagan](https://togithub.com/EliahKagan) who reported the
issue and fixed it in a single stroke, while being responsible for an
incredible amount of improvements that he contributed over the last
couple of months ❤️.
#### What's Changed
- Add `__all__` in git.exc by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1719](https://togithub.com/gitpython-developers/GitPython/pull/1719)
- Set submodule update cadence to weekly by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1721](https://togithub.com/gitpython-developers/GitPython/pull/1721)
- Never modify sys.path by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1720](https://togithub.com/gitpython-developers/GitPython/pull/1720)
- Bump git/ext/gitdb from `8ec2390` to `ec58b7e` by
[@​dependabot](https://togithub.com/dependabot) in
[https://github.com/gitpython-developers/GitPython/pull/1722](https://togithub.com/gitpython-developers/GitPython/pull/1722)
- Revise comments, docstrings, some messages, and a bit of code by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1725](https://togithub.com/gitpython-developers/GitPython/pull/1725)
- Use zero-argument super() by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1726](https://togithub.com/gitpython-developers/GitPython/pull/1726)
- Remove obsolete note in \_iter_packed_refs by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1727](https://togithub.com/gitpython-developers/GitPython/pull/1727)
- Reorganize test_util and make xfail marks precise by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1729](https://togithub.com/gitpython-developers/GitPython/pull/1729)
- Clarify license and make module top comments more consistent by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1730](https://togithub.com/gitpython-developers/GitPython/pull/1730)
- Deprecate compat.is\_<platform>, rewriting all uses by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1732](https://togithub.com/gitpython-developers/GitPython/pull/1732)
- Revise and restore some module docstrings by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1735](https://togithub.com/gitpython-developers/GitPython/pull/1735)
- Make the rmtree callback Windows-only by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1739](https://togithub.com/gitpython-developers/GitPython/pull/1739)
- List all non-passing tests in test summaries by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1740](https://togithub.com/gitpython-developers/GitPython/pull/1740)
- Document some minor subtleties in test_util.py by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1749](https://togithub.com/gitpython-developers/GitPython/pull/1749)
- Always read metadata files as UTF-8 in setup.py by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1748](https://togithub.com/gitpython-developers/GitPython/pull/1748)
- Test native Windows on CI by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1745](https://togithub.com/gitpython-developers/GitPython/pull/1745)
- Test macOS on CI by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1752](https://togithub.com/gitpython-developers/GitPython/pull/1752)
- Let close_fds be True on all platforms by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1753](https://togithub.com/gitpython-developers/GitPython/pull/1753)
- Fix IndexFile.from_tree on Windows by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1751](https://togithub.com/gitpython-developers/GitPython/pull/1751)
- Remove unused TASKKILL fallback in AutoInterrupt by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1754](https://togithub.com/gitpython-developers/GitPython/pull/1754)
- Don't return with operand when conceptually void by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1755](https://togithub.com/gitpython-developers/GitPython/pull/1755)
- Group .gitignore entries by purpose by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1758](https://togithub.com/gitpython-developers/GitPython/pull/1758)
- Adding dubious ownership handling by
[@​marioaag](https://togithub.com/marioaag) in
[https://github.com/gitpython-developers/GitPython/pull/1746](https://togithub.com/gitpython-developers/GitPython/pull/1746)
- Avoid brittle assumptions about preexisting temporary files in tests
by [@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1759](https://togithub.com/gitpython-developers/GitPython/pull/1759)
- Overhaul noqa directives by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1760](https://togithub.com/gitpython-developers/GitPython/pull/1760)
- Clarify some Git.execute kill_after_timeout limitations by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1761](https://togithub.com/gitpython-developers/GitPython/pull/1761)
- Bump actions/setup-python from 4 to 5 by
[@​dependabot](https://togithub.com/dependabot) in
[https://github.com/gitpython-developers/GitPython/pull/1763](https://togithub.com/gitpython-developers/GitPython/pull/1763)
- Don't install black on Cygwin by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1766](https://togithub.com/gitpython-developers/GitPython/pull/1766)
- Extract all "import gc" to module level by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1765](https://togithub.com/gitpython-developers/GitPython/pull/1765)
- Extract remaining local "import gc" to module level by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1768](https://togithub.com/gitpython-developers/GitPython/pull/1768)
- Replace xfail with gc.collect in TestSubmodule.test_rename by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1767](https://togithub.com/gitpython-developers/GitPython/pull/1767)
- Enable CodeQL by [@​EliahKagan](https://togithub.com/EliahKagan)
in
[https://github.com/gitpython-developers/GitPython/pull/1769](https://togithub.com/gitpython-developers/GitPython/pull/1769)
- Replace some uses of the deprecated mktemp function by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1770](https://togithub.com/gitpython-developers/GitPython/pull/1770)
- Bump github/codeql-action from 2 to 3 by
[@​dependabot](https://togithub.com/dependabot) in
[https://github.com/gitpython-developers/GitPython/pull/1773](https://togithub.com/gitpython-developers/GitPython/pull/1773)
- Run some Windows environment variable tests only on Windows by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1774](https://togithub.com/gitpython-developers/GitPython/pull/1774)
- Fix TemporaryFileSwap regression where file_path could not be Path by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1776](https://togithub.com/gitpython-developers/GitPython/pull/1776)
- Improve hooks tests by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1777](https://togithub.com/gitpython-developers/GitPython/pull/1777)
- Fix if items of Index is of type PathLike by
[@​stegm](https://togithub.com/stegm) in
[https://github.com/gitpython-developers/GitPython/pull/1778](https://togithub.com/gitpython-developers/GitPython/pull/1778)
- Better document IterableObj.iter_items and improve some subclasses by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1780](https://togithub.com/gitpython-developers/GitPython/pull/1780)
- Revert "Don't install black on Cygwin" by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1783](https://togithub.com/gitpython-developers/GitPython/pull/1783)
- Add missing pip in $PATH on Cygwin CI by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1784](https://togithub.com/gitpython-developers/GitPython/pull/1784)
- Shorten Iterable docstrings and put IterableObj first by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1785](https://togithub.com/gitpython-developers/GitPython/pull/1785)
- Fix incompletely revised Iterable/IterableObj docstrings by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1786](https://togithub.com/gitpython-developers/GitPython/pull/1786)
- Pre-deprecate setting Git.USE_SHELL by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1782](https://togithub.com/gitpython-developers/GitPython/pull/1782)
- Deprecate Git.USE_SHELL by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1787](https://togithub.com/gitpython-developers/GitPython/pull/1787)
- In handle_process_output don't forward finalizer result by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1788](https://togithub.com/gitpython-developers/GitPython/pull/1788)
- Fix mypy warning "Missing return statement" by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1789](https://togithub.com/gitpython-developers/GitPython/pull/1789)
- Fix two remaining Windows untrusted search path cases by
[@​EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1792](https://togithub.com/gitpython-developers/GitPython/pull/1792)
#### New Contributors
- [@​marioaag](https://togithub.com/marioaag) made their first
contribution in
[https://github.com/gitpython-developers/GitPython/pull/1746](https://togithub.com/gitpython-developers/GitPython/pull/1746)
- [@​stegm](https://togithub.com/stegm) made their first
contribution in
[https://github.com/gitpython-developers/GitPython/pull/1778](https://togithub.com/gitpython-developers/GitPython/pull/1778)
**Full Changelog**:
gitpython-developers/GitPython@3.1.40...3.1.41
</details>
---
### Configuration
📅 **Schedule**: Branch creation - "" (UTC), Automerge - At any time (no
schedule defined).
🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.
♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.
---
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box
---
This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/googleapis/sdk-platform-java).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4yNjkuMiIsInVwZGF0ZWRJblZlciI6IjM3LjI2OS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiJ9-->
Reviewers
Byron
Byron approved these changes
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|