Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ version = "1.5.0"
Git_LFS_jll = "020c3dae-16b3-5ae5-87b3-4cb189e250b2"
Git_jll = "f8c6e375-362e-5223-8a59-34ff63f689eb"
JLLWrappers = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
NetworkOptions = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
OpenSSH_jll = "9bd350c2-7e96-507f-8002-3f2e150b4e1b"

[compat]
Git_LFS_jll = "3.7"
Git_jll = "2.44"
JLLWrappers = "1.1"
NetworkOptions = "1"
OpenSSH_jll = "9, 10"
julia = "~1.6.6, 1.7.3"

Expand Down
1 change: 1 addition & 0 deletions src/Git.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ packages. This is implemented with the `git` function, which returns a
module Git

import Git_jll
import NetworkOptions

export git

Expand Down
33 changes: 30 additions & 3 deletions src/git_function.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,10 @@ function git(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true)
share_git_core = joinpath(share, "git-core")
share_git_core_templates = joinpath(share_git_core, "templates")

ssl_cert = joinpath(dirname(Sys.BINDIR), "share", "julia", "cert.pem")

env_mapping = Dict{String,String}()
env_mapping["GIT_EXEC_PATH"] = libexec_git_core
env_mapping["GIT_SSL_CAINFO"] = ssl_cert
env_mapping["GIT_TEMPLATE_DIR"] = share_git_core_templates
merge!(env_mapping, ssl_ca_env())

@static if Sys.isapple()
# This is needed to work around System Integrity Protection (SIP) restrictions
Expand Down Expand Up @@ -77,6 +75,35 @@ function git(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true)
return git_cmd
end

"""
ssl_ca_env() -> Dict{String,String}

Environment variables pointing Git at the certificate authority roots to use.

An explicit `GIT_SSL_CAINFO` or `GIT_SSL_CAPATH` set by the user is respected (nothing is
returned and Git's own handling applies). Otherwise the location is taken from
`NetworkOptions.ca_roots_path()`, which honours `JULIA_SSL_CA_ROOTS_PATH`, `SSL_CERT_FILE`
and `SSL_CERT_DIR`, then the system certificate bundle, and finally falls back to the
bundle shipped with Julia. A directory is passed as `GIT_SSL_CAPATH`, a file as
`GIT_SSL_CAINFO`.
"""
function ssl_ca_env()
env = Dict{String,String}()
if !isempty(get(ENV, "GIT_SSL_CAINFO", "")) || !isempty(get(ENV, "GIT_SSL_CAPATH", ""))
return env
end
ca_roots = NetworkOptions.ca_roots_path()
# Defensive: `ca_roots_path()` is documented to always return a path, but leave Git's
# defaults alone if no path is available.
(ca_roots === nothing || isempty(ca_roots)) && return env
if isdir(ca_roots)
env["GIT_SSL_CAPATH"] = ca_roots
else
env["GIT_SSL_CAINFO"] = ca_roots
end
return env
end

function git(args::AbstractVector{<:AbstractString}; kwargs...)
cmd = git(; kwargs...)
append!(cmd.exec, args)
Expand Down
16 changes: 16 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,22 @@ end
@test orig_templatedir == get_env("GIT_TEMPLATE_DIR")
end

# https://github.com/JuliaVersionControl/Git.jl/issues/41
@testset "CA roots" begin
cainfo(cmd) = only(e[length("GIT_SSL_CAINFO=")+1:end] for e in cmd.env
if startswith(e, "GIT_SSL_CAINFO="))
if Sys.iswindows()
@test_skip false
else
withenv("GIT_SSL_CAINFO" => nothing, "JULIA_SSL_CA_ROOTS_PATH" => "/my/ca.pem") do
@test cainfo(git()) == "/my/ca.pem"
end
withenv("GIT_SSL_CAINFO" => "/user/ca.pem", "JULIA_SSL_CA_ROOTS_PATH" => "/my/ca.pem") do
@test cainfo(git()) == "/user/ca.pem"
end
end
end

# This makes sure the work around for the SIP restrictions on macOS
# (<https://github.com/JuliaVersionControl/Git.jl/issues/40>) works correctly. While SIP is
# a macOS-specific issue, it's good to exercise this code path everywhere.
Expand Down
Loading