I'm having an issue using SPM on Windows 11. I have two private Swift Package repositories on GitHub. It has been working fine for one Package to depend on the other, and I've only had some occational SSH issues that have been quickly resolved.
Now however, I've been trying to set up my development environment on Windows 11 and can't get 'swift build' to fetch private dependencies. I constantly get "Permission denied" errors, even though the SSH key works (which is evident since I can clone the repository just fine).
I have tried setting up multiple virtual machines with Windows 11 and yet always run into the same issue. I thought it might be a VM issue but today I tried on a physical Windows 11 PC and get the same issue.
Are there any known issues with SPM on Windows 11? I'm aware that Swift on Windows is still in development but I've managed to get it working on Windows 10 multiple times so I thought I'd best reach out for help.
I would suggest that you check what URL is being used. Most likely, it is using the
https transport, which would require the authentication to have the bearer token which requires that you login with the prompt that shows up first. This is due to the repository being private and not a Windows specific thing I believe.
CC: @Max_Desiatov @NeoNacho
Thanks for the quick reply @compnerd, and let me also say I much appreciate your work to bring Swift to Windows!
Regarding the URL; do you mean I should check the URL in the Package.swift manifest? It is using firstname.lastname@example.org, not https://github.com so it should be using SSH, right?
Or do you mean I can check somewhere else what URL it's actually using? I don't imagine the swift command transforms the URL from Package manifest at all?
You're welcome, I'm glad that you find it useful!
Okay, good, so using
email@example.com:... would imply it should use SSH, which now makes me wonder why is that failing. If
git clone with the URL works from the command line, SPM should be able to do that (it does the same exact thing).
If git clone with the URL works from the command line, SPM should be able to do that (it does the same exact thing).
That's my thinking as well, however I've seen
git clone work without
swift build working. In those cases I have had to run
ssh-agent -s followed by
ssh-add path/to/key to get
swift build to find the dependencies successfully. I believe that
git in that case finds the
.ssh/config file, but I'm not sure why the
swift command wouldn't be able to.
On macOS the
ssh-agent command has to run with
eval and I have previously also had to run
start-ssh-agent on Windows 10 to get it working (I think that's a script included by Git for Windows but I don't know what it does). Needless to say I've tried those on my Windows 11 setups and nothing worked there. I hope that adds some context.
This seems entirely reasonable. Setting up the SSH Agent to get the ssh key to be used is required. One possible thing could be happening is that we are blowing away the configuration for the ssh agent from the environment when invoking the child process. It might be possible to observe this using procmon while
swift resolve executes.
I haven't used procmon in a long time, so that'll be fun. I'm not familiar with
swift resolve though, is that a subcommand of the driver? Can you tell me how I filter for it? And can you tell me more about what I'm looking for in terms of the ssh-agent?
I guess the reference was to
swift package resolve? If so, that's a SwiftPM subcommand of the
swift-package executable binary called when you invoke
I see, so should I run
swift-package resolve while monitoring using procmon? Or is that called by
I'm still not sure exactly what I'm looking for. Can you explain what would indicate that the ssh-agent configuration changes for a child process? Am I looking for a specific event?
I appreciate that you take the time to help me troubleshoot. In the meantime I'm using a workaround and cloning the dependencies manually so I'm not blocked by this. But I hope to be able to get this running correctly.
When you run
swift package resolve, SPM should try to compute the version information for all the packages, which will require cloning them. By using procmon, you should be able to find the invocation of
git that it runs, and hopefully identify the environment variables at the time of execution. Hopefully that will help recreate the command and identify what is going on.
I can see that when
git.exe is launched by the
swift-package.exe it's given the environment variable
If I add this to my command line (I'm using x64 Native Tools Command Prompt) I get the same
permission denied (publickey) error on a
git clone firstname.lastname@example.org:... command.
And removing it using
set GIT_SSH_COMMAND= fixes it and the same
git clone email@example.com:... command succeeds again.
I'm guessing this is the issue, though I'm not sure what to do about it.
It sounds like a configuration issue. The issue is that the way that
ssh is currently configured, it does not have access to the credentials required.
ssh -vvv might be helpful to see where the configuration is and allow you to configure this.
Figuring out how to configure this might require @NeoNacho or @Max_Desiatov to identify how to wire this up properly.
Alright, I managed to get it working, and I feel like I'm close to understanding what's going on.
ssh -T firstname.lastname@example.org worked fine, and doesn't ask for a password, which shows the ssh agent seems to be accessible and working. And
ssh-add -l showed my key as expected. However
git clone email@example.com:... always asked me for a password to my ssh key, which seemed odd and I realized a bit late how significant this was.
So I went searching a bit and found this answer on SO. I tried a modified version of the proposed solution:
git config --global core.sshCommand (get-command ssh).Source.Replace('\','/') and found that now
git clone firstname.lastname@example.org:... no longer asked for a password but worked seamlessly. Trying
swift build again I found it still didn't work, but I thought I must be close so I went back to the SO answer.
Reading it again I think I finally understand, the answer says:
When you install git, it comes with ssh. But if you have a newer version of Windows 10, Windows has an install of SSH that comes with it. Installed in C:\Windows\System32\OpenSSH. That gets put into the environment PATH
Assuming this is correct I think it makes sense that perhaps I have only set up the projects on older Windows 10 versions, hence why I have not encountered this issue before.
When I realized there were 2 separate ssh-agents running I found the one
git is using instead of the one I have given my key. I had some trouble before I realized that the
start-ssh-agent script I mentioned earlier is actually used to start the ssh-agent
git uses instead of the Windows built-in one (if I understand correctly). So having run that script and also
ssh-add /path/to/key with the
ssh-add explicitly in
C:\Program Files\Git\usr\bin I got it working. So now both
git clone email@example.com:... and
swift build run successfully, without asking for password!
Thanks a lot for helping me guys! I'm curious if there's some documentation I've missed about this. Is there some recommended way of setting up ssh on Windows when there's this double implementation?
I’m not certain, but I’d check the git book. This is part of why the recommendation is to never use swift from git bash - the environment is different and I’ve seen weird behavioral differences.
I understand, like I said before I almost always use the x64 Native Command Prompt
but in recent Swift versions I've found that CMD also works fine.
Yes, it should as there was effort put into trying to make that work properly as well If there are corner cases with that still, please to report them.