Description
Current behavior 😯
When invoking a credential helper, gix correctly calls get
, but it then discards at least any password_expiry_utc
before passing the result to the subsequent store
invocation it correctly attempts in response to the successful use of the credential.
Expected behavior 🤔
gix should pass all details from the get
stage of credential helper invocation into the store
stage.
Git behavior
https://github.com/git/git/blob/6f84262c44a89851c3ae5a6e4c1a9d06b2068d75/credential.h#L187 is where Git expresses its ability to do this; it's documented at https://git-scm.com/docs/git-credential/2.41.0#Documentation/git-credential.txt-codepasswordexpiryutccode . See the "Steps to reproduce" section to see empirically what Git does.
Steps to reproduce 🕹
Preamble
Create the following script, as cred-helper.sh
:
#!/bin/sh
set -e
log_request() {
printf "Command: %s\n" "$*" >&2
printf "Request details:\n" >&2
while IFS= read -r line; do
printf "%s\n" "$line" >&2
done
}
case "$1" in
"get")
log_request "$@"
printf "\nReading credentials... " >&2
cred=$(cat ./creds.txt)
printf "%s\n" "$cred"
now=$(date +%s)
printf 'password_expiry_utc=%s\n' "$((now + 10))"
printf "quit=true\n"
;;
"store")
log_request "$@"
;;
*)
log_request "$@"
exit 1
;;
esac
Make it your cred helper in some repository:
chmod u+x cred-helper.sh
git config --local credential.helper ""
git config --local credential.helper "$(pwd)/cred-helper.sh"
git config --local http.proactiveAuth basic
git remote add smaug123 https://github.com/Smaug123/test-repo.git
Generate a PAT in GitHub, and put it in creds.txt
:
username=Smaug123
password=github_pat_REDACTED
Observe that git fetch smaug123
passes through the password expiry to the store
command:
git fetch
Command: get
Request details:
capability[]=authtype
capability[]=state
protocol=https
host=github.com
wwwauth[]=Basic
Reading credentials... Command: store
Request details:
protocol=https
host=github.com
username=Smaug123
password=github_pat_REDACTED
password_expiry_utc=1746654451
Observe that gix does not
This is a bit harder: gix doesn't appear to respect http.proactiveAuth
(though my testing wasn't super rigorous, so I might be wrong about that), so you'll have to be trying to access a private repo in here so that gix tries to use a cred helper at all (so, if you're using GitHub as the server, you'll have to make sure the GitHub PAT you generated has permission to read that repo's contents). Nor does gix seem to read the local .git/config
as git does, so this has to go into your ~/.gitconfig instead:
[credential]
helper =
helper = "/path/to/cred-helper.sh"
Then Cargo.toml:
[package]
name = "git-clone"
version = "0.1.0"
edition = "2024"
[dependencies]
gix = { version = "0.72.1", features = ["worktree-mutation", "blocking-network-client", "blocking-http-transport-reqwest-rust-tls"] }
src/main.rs:
use std::path::Path;
use gix::bstr::BString;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let local_path = Path::new("/tmp/gix-smaug123");
let url = gix::Url::from_parts(
gix::url::Scheme::Https,
None,
None,
Some("github.com".to_string()),
None,
BString::from("/MyOrg/MyPrivateRepo/"),
false,
)?;
let mut prepared_clone = gix::prepare_clone(url, local_path)?;
let (mut prepare_checkout, _outcome) = prepared_clone
.fetch_then_checkout(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)?;
let (_, _) = prepare_checkout.main_worktree(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)?;
Ok(())
}
And cargo run
, observing the output:
Command: get
Request details:
protocol=https
host=github.com
Reading credentials... Command: store
Request details:
url=https://github.com/REDACTED
protocol=https
host=github.com
username=Smaug123
password=REDACTED
Observe that gix has not passed through password_expiry_utc
as git
did.