-
Couldn't load subscription status.
- Fork 7.3k
Add support for ssh_config Include directives #2230
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
Conversation
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.
Thank you! This looks great. But I fear it introduces a regression.
git/ssh_config.go
Outdated
| for _, file := range files { | ||
| wg.Add(1) | ||
| go func(fileName string) { | ||
| _ = p.read(fileName) | ||
| wg.Done() |
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.
Ordinarily, this kind of concurrency in Go is great.
In this case, though, parallelism could lead to indeterministic results when multiple files are scanned. We distinctly want the files to be scanned in the order given so that later files (e.g. the user's personal config file) have precedence over earlier files (e.g. system config).
Please either 1) remove the parallelism or 2) ensure that aliases scanned in later files always have precedence over those scanned in earlier files, regardless of the order that the results came back in.
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.
I've removed the concurrency. I tried making each config file has its own SSHAliasMap and in the end I could merge them in the right precedence, but for now I believe it okay have it sequentially. π€
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.
Thanks for this!
git/ssh_config.go
Outdated
| match := sshHostRE.FindStringSubmatch(line) | ||
| match := sshIncludeDirectiveRE.FindStringSubmatch(line) | ||
| if match != nil { | ||
| fileNames, err := filepath.Glob(match[2]) |
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.
Interested in how relative paths are supposed to be resolved, I've just looked up the documentation for the Include directive and it says:
Include the specified configuration file(s). Multiple pathnames may be specified and each pathname may contain glob(7) wildcards and, for user configurations, shell-like
~references to user home directories. Files without absolute paths are assumed to be in~/.sshif included in a user configuration file or/etc/sshif included from the system configuration file. Include directive may appear inside aMatchorHostblock to perform conditional inclusion.
So for this Include implementation to work properly, I think that is missing is:
- relative path support;
- multiple paths support (I'm guessing paths are split by spaces?);
- the contents of an
Includefollowing aMatchorHostblock should only ever apply to thatMatch/Hostblock, unless the included file also containsMatch/Hostdirectives.
For illustrative purposes:
Host example.com
Include file1 file2 # the directives in file1 & file2 only apply to `example.com`
Do you think it would be possible to add these features? I realize this blows up the scope a little bit, but I feel that if we add Include support, we should make it work as Include is supposed to work.
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.
@mislav I agree with you, if we want to add support for the Include directive, we should fully support it. I'll take a look at the ssh_config spec and implement a solution for it.
git/ssh_config_test.go
Outdated
| includedTempFile := createTempFile(t, "included") | ||
| includedConfigFile := ` | ||
| Host webapp | ||
| HostName webapp.example.com | ||
| ` | ||
| fmt.Fprint(includedTempFile, includedConfigFile) |
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.
I am not very happy with this test, but I need to created a temp file under ~/.ssh/ dir in order to test inclusion logic.. Any suggestions on how to improve this will be welcome. π
cc @mislav
Edited: I don't even thing it will work for all builds π
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.
I've pushed changes to avoid reading files in tests from either /etc/ssh or ~/.ssh locations, and instead reads files from test stubs. It also adds support for =-delimited keyword-argument pairs as supported by the config format.
Thank you for all your work! π
- Per ssh_config(5), keywords and arguments may be separated by an `=` sign as well as whitespace. - When following the `Include` directive, skip directories that were returned as the result of globbing. - Respect the `Host` context when recursing into `Include`s - Avoid having tests read from the actual filesystem. - Avoid repeatedly looking up the home directory.
Fixes #2179