Fix nested runtime panic during SSH key authentication
Dependency security audit / rustsec (push) Successful in 23s

This commit is contained in:
Georg Bauer committed 2026-09-12 18:08:23 +02:00
1 parent aec3f237a9
commit 71a4f289cf
2 files changed
+36 -14

No files matched your search

+14 -1
View File
@@ -755,8 +755,21 @@ fn non_fast_forward_and_cancellation_fail_without_blind_replay() {
local.add_remote("origin", remote.url()).expect("remote");
let control = GitOperationControl::default();
let cancel = control.clone();
let observed = server.observed.clone();
let cancellation = thread::spawn(move || {
thread::sleep(Duration::from_millis(100));
let deadline = std::time::Instant::now() + Duration::from_secs(5);
while observed
.lock()
.expect("observed")
.receive_requests
.is_empty()
{
assert!(
std::time::Instant::now() < deadline,
"push request not received"
);
thread::sleep(Duration::from_millis(1));
}
cancel.cancel();
});
assert!(matches!(
+22 -13
View File
@@ -162,13 +162,11 @@ impl SshSession {
control.report(GitProgressPhase::Authenticating)?;
let user = connection.user.as_deref().unwrap_or("git");
let authenticated = match &connection.identity {
SshIdentitySource::KeyFile(path) => runtime.block_on(authenticate_key_file(
&mut handle,
user,
path,
passphrases,
control,
))?,
SshIdentitySource::KeyFile(path) => {
// Synchronous secret stores may drive their own runtime.
let key = load_identity(path, passphrases)?;
runtime.block_on(authenticate_key_file(&mut handle, user, key, control))?
}
SshIdentitySource::Agent {
fingerprint,
socket,
@@ -770,13 +768,10 @@ impl client::Handler for HostVerifier {
}
}
async fn authenticate_key_file(
handle: &mut client::Handle<HostVerifier>,
user: &str,
fn load_identity(
path: &Path,
passphrases: &dyn SshPassphraseProvider,
control: &GitOperationControl,
) -> Result<bool, GitError> {
) -> Result<PrivateKey, GitError> {
let metadata = fs::symlink_metadata(path).map_err(|_| GitError::SshIdentityMissing {
path: path.to_owned(),
})?;
@@ -802,6 +797,15 @@ async fn authenticate_key_file(
fingerprint: fingerprint.clone(),
})?;
}
Ok(key)
}
async fn authenticate_key_file(
handle: &mut client::Handle<HostVerifier>,
user: &str,
key: PrivateKey,
control: &GitOperationControl,
) -> Result<bool, GitError> {
let hash = rsa_hash(handle, key.public_key(), control).await?;
let result = controlled(
handle.authenticate_publickey(user, PrivateKeyWithHashAlg::new(Arc::new(key), hash)),
@@ -1230,7 +1234,12 @@ mod tests {
&self,
fingerprint: &SshFingerprint,
) -> Result<SecretBytes, GitError> {
self.0
// Model a synchronous secret store that drives its own async backend.
static RUNTIME: std::sync::OnceLock<tokio::runtime::Runtime> =
std::sync::OnceLock::new();
RUNTIME
.get_or_init(|| tokio::runtime::Runtime::new().expect("secret store runtime"))
.block_on(async { self.0 })
.map(|value| SecretBytes::new(value.to_vec()))
.ok_or_else(|| GitError::SshKeyPassphraseUnavailable {
fingerprint: fingerprint.clone(),