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
File name extension requirement broke Git hooks #16480
Comments
I was so upset about this change that I forgot to add repro steps. Sorry for that. I have now added the missing details to the original message. |
Why cannot you add .ps1 extension? |
As stated in the description, it's required by Git:
|
@SteveL-MSFT Was the change required due to security reason? Can you please take a look? |
That's weird at least on Linux it works for me echo -e '#!/usr/bin/env pwsh\necho "test"' > /tmp/test_script
chmod +x /tmp/test_script
# All 3 below work on 7.2.0
/tmp/test_script
pwsh /tmp/test_script
pwsh -File /tmp/test_script Maybe it's a problem specific for Windows where shebangs don't usually work and it relies on the file extension to have an associated executable. Still if tools like Mingw/Cygwin/WSL can work with the shebang and still pick up Windows executables then I don't think checking the extension is really ideal. |
This issue originated from #15859 which was for Windows only. |
From the linked PR:
Personally I think pwsh should be consistent everywhere and we can ignore what WinPS did. Especially since WinPS was a bit more restrictive. I don't see a real reason why this would really be beneficial to security. |
I wonder on Windows if it might work to allow for Would be good for Security WG to take a look at such a proposal. |
Why not check the signature all the time and not just with the extension? If PowerShell knows it is going to execute a file as a script then it should do the check regardless of whether an extension is present. |
Not sure about performance impact of that kind of workaround, but in reality it might actually fix this one as well: #9887. Only on Windows, though. I haven't tested that one recently but I'd guess that empty automatic variables is still an issue. |
@WG-Security
Windows signature checking is based on file extension, and this is something we cannot control. The idea of copying a non-extension file to a file with an extension, has a number of problems. We may not have permissions to write to the current location. Writing the file to a different location may break the scripts behavior if it is intended to run in a specific location. |
Upgrading PowerShell broke all our githooks. I'd reiterate that the change from #15859 is breaking and even though I've read the release notes I did not comprehend that this would be a side effect. |
I'll note too, we actually symlinked to our Powershell script:
Which ironically does have a Our work around is to create a shim bash script which then invokes the PowerShell script: $shim = @"
#!/usr/bin/env sh
pwsh -noprofile -F ./bin/pre-commit.ps1
"@
$shim -replace "`r`n", "`n" | Out-File ".git/hooks/pre-commit" -Encoding utf8NoBOM -NoNewline |
Hmm, sheband is Unix alternative to Windows file extension , so to speak. Interesting, could we port signature checking to Unix with supporting sheband? |
Windows has many file types that can be, from the user's point-of-view, executed without extension. For example, Preliminary tests show that Git seem to work fine with an exe as a hook file, so I might try to convert my scripts to executables. I'm by no means a prorgrammer and my first results with ps2exe module were buggy. Converting every hook is ugly and clumsy workaroud, but I'm running out of options. Our company IT keeps updating my PowerShell to the latest version automatically so downgrading won't help for long. |
Just ran into this problem ,too. On Windows 10, and just upgraded to PowerShell 7.2 -- this broke my pre-commit hooks. Not good. |
As a compromise, how about allowing non-extension files to execute when a signature check is not required? I'm trying to think of ways a user could indicate that yeah, I get it's a security risk but I don't care. I want to allow extensionless scripts to execute. IMO this is kind of a big deal. You should be able to write Git commit hooks in PowerShell. |
Why don't Git like file extensions? |
In Unix-like systems the piece of information that tells the operating system that file is executable is an attribute of the underlying file system – the execute permission. It has no relation what so ever with the actual file name. In case the file that should be executed happens to be script, like Bash, Python, PowerShell, Perl, etc., etc. , then a special notation starting with I have no actual knowledge about how Git was ported to Windows but just based on their web site and my experience, there is some kind of emulation layer that allows for Git developers to do things Unix-way, e.g without the need to care about extensions, and the emulation layer then does its best to implement those operations in the Windows world. This is clearly visible in the hooks as, even in Windows, they need to have that shebang notation but with Adding support for extensions would require curated and parametrized list of allowed extensions, and well defined search order for those in case there is multiple extensions with the same file name. It's a can of worms from the Unix perspective. [1] Actually, the executable in the example is Git provided Windows port of |
That doesn't really help explain why the hook can't just have the While I agree that requiring the extension is wrong there's not much that can be done about that at this time without adding even more complexity and logic to the signature verification stage. If your git hooks can have the extension then that's definitely the easier of 2 options. |
If I have files |
Ah ok that's the part I was missing, the git hooks have to be under that name rather than it be configurable. Thanks for clarifying! |
Git allows changing the hook's path using config |
List of supported hooks is indeed hard-coded. It's defined here: https://git-scm.com/docs/githooks. Abstracting the steps in the work flow from the actual file names would definitely make things easier on the Windows side. |
Hmm, so if the hook file name is |
Btw, @atruskie's workaround works well for me. The code he posted looked a bit weird to me, at first, until I realized that was meant to be ran from the command line to create the shim. The resulting code that ends up in, say, the pre-commit hook would look like this: #!/usr/bin/env sh
pwsh -noprofile -F ./path/to/pre-commit.ps1 |
Those kind of shims might work in limited set of cases where input is not needed, but some of the hooks get their input from I would like to see this getting fixed in PowerShell as nothing has changed in Git and hooks did work with |
@SteveL-MSFT @PaulHigin I've recently gone through this code and it seems like the While yes pwsh uses an API which takes in the filename there is also an API that is already implemented where you can supply the contents of a file and specify the extension yourself. In the case where This is even possible through the $psd1Content = Get-Module -Name Pester -ListAvailable |
Sort-Object -Property Version -Descending |
Select-Object -First 1 -Property @{N='PSPath'; E={$_.Path}} |
Get-Content -Raw -AsByteStream
Get-AuthenticodeSignature -SourcePathOrExtension '.psd1' -Content $psd1Content No need for temp file and pwsh has to read the contents anyway so it's not like it's doing extra work. |
@jborean93 that's great news! So if we can ensure that on Windows the script is still validated, then we just need someone to submit a PR :) |
@TravisEz13 I seem to remember that there is an issue with this. Maybe Travis can recall what it is (if any). |
Perhaps it is how SRP/AppLocker and Defender APIs work. |
@WG-Security |
@WG-Engine from a security perspective, this can be done (enable for PowerShell execution policy, disable for other policies), but it seems wrong to have different behaviors. |
If PowerShell script really needs to pass AppLocker and WDAC (understandable) and it works with extensions only, and Git is not going to change how hooks are called (which seems to be the case), then there is not too many options left. And the remaining ones are not pretty either. One possible solution is to take advantage of the fact that in Windows an executable can be called without extension. So, my suggestion is to make For example, if a diretory
then a command There is some pros and cons to this. Pros
Cons
|
WG-Engine reviewed this issue yesterday. We agree with the premise of the issue: there doesn't appear to be a compelling reason to prevent PowerShell from executing files without a We acknowledge that there are however security concerns here, especially with regard to how the initial implementation bypassed the safeguards initially present with usage of
Our impression is that there shouldn't be a security issue with invoking extension-less scripts; if the script contains an embedded signature, it should be verified as per normal, and if it is catalog-signed (or using AppLocker etc), unless the signing/identification method somehow can indicate the script should be extensionless, the signature verification should fail as it would for any other unknown scripts. It is likely there is work needed here to fully determine the scope of the underlying issue and more properly rework |
Bump. Any progress on this? |
Please make it extensionless, automation is needed 🥹🥹, any progress? |
Prerequisites
Description
Now that script files must have
.ps1
file name extension in Windows, because of #15859, it's no longer possible to have Git hooks written in PowerShell. This is a breaking change!From Git documentation at https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks (emphasis by me)
Git hooks in written in PowerShell have worked flawlessly since the file name exetension requirement was removed in PowerShell 6.x. After the 7.2 release, trying execute a git command that has hooks associated with it results in an error message and commit fails.
Steps to reproduce
Make sure Git is installed with full support for all commands. Meaning that paths
C:\Program Files\Git\cmd
C:\Program Files\Git\mingw64\bin
C:\Program Files\Git\usr\bin
are present in user or system
PATH
environment variable. Git for Windows installer will do this for you.Then create a file named
pre-commit
with content:Note that shebang line is required here because of how Git was ported to Windows.
Make sure the file name does not have any extension and place the file into
.git\hooks
directory of a local git repository.Make some changes in the repo and try to commit them. For example:
git commit -m "Testing"
or use VS Code's version control tab.Expected behavior
pre-commit hook gets executed:
Actual behavior
Commit fails with error message:
Git: Processing -File '.git/hooks/pre-commit' failed because the file does not have a '.ps1' extension. Specify a valid PowerShell script file name, and then try again.
Error details
No response
Environment data
Visuals
No response
The text was updated successfully, but these errors were encountered: