Implement SSH identity authentication

This commit is contained in:
2026-08-25 19:52:47 +02:00
parent f636f3b551
commit 5dbda4bbd2
14 changed files with 1964 additions and 60 deletions

View File

@@ -701,7 +701,7 @@ url = "https://example.test/team/store.git"
}
#[test]
fn ssh_remote_configuration_round_trips_without_https_credentials() -> TestResult {
fn ssh_remote_configuration_round_trips_with_secret_free_authentication() -> TestResult {
let fixture = ConfigurationFixture::new()?;
fixture.write_explicit(
r#"
@@ -712,12 +712,27 @@ key_material = "keys"
[[git.remotes]]
name = "origin"
url = "git@example.test:team/store.git"
ssh_identity_file = "keys/id_ed25519"
ssh_known_hosts_file = "known_hosts"
"#,
)?;
let config = fixture.loader().load(Some(&fixture.explicit_path()))?;
let remote = &config.git_remotes()[0];
assert_eq!(remote.url(), "git@example.test:team/store.git");
assert!(remote.https_credentials().is_none());
let authentication = remote.ssh_authentication().expect("SSH authentication");
assert_eq!(
authentication.identity().key_file(),
Some(
fs::canonicalize(fixture.temporary.path())?
.join("cwd/config/keys/id_ed25519")
.as_path()
)
);
assert_eq!(
authentication.known_hosts_file(),
fs::canonicalize(fixture.temporary.path())?.join("cwd/config/known_hosts")
);
config.update_git_identity(&GitIdentity::new("Alice", "alice@example.test")?)?;
let reloaded = fixture.loader().load(Some(&fixture.explicit_path()))?;
@@ -725,6 +740,70 @@ url = "git@example.test:team/store.git"
let persisted = fs::read_to_string(fixture.explicit_path())?;
assert!(!persisted.contains("server_id"));
assert!(!persisted.contains("application_id"));
assert!(!persisted.contains("passphrase"));
assert!(persisted.contains("ssh_identity_file"));
assert!(persisted.contains("ssh_known_hosts_file"));
Ok(())
}
#[test]
fn ssh_authentication_requires_exactly_one_identity_source() -> TestResult {
let fixture = ConfigurationFixture::new()?;
fixture.write_explicit(
r#"
vault = "vault"
default_key = "alice"
key_material = "keys"
[[git.remotes]]
name = "origin"
url = "ssh://git@example.test/team/store.git"
"#,
)?;
assert_eq!(
fixture
.loader()
.load(Some(&fixture.explicit_path()))
.expect_err("SSH identity is required"),
ConfigError::InvalidField {
field: "git.remotes.ssh_authentication"
}
);
fixture.write_explicit(
r#"
vault = "vault"
default_key = "alice"
key_material = "keys"
[[git.remotes]]
name = "origin"
url = "ssh://git@example.test/team/store.git"
ssh_agent_fingerprint = "SHA256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
ssh_agent_socket = "agent.sock"
ssh_known_hosts_file = "known_hosts"
"#,
)?;
let config = fixture.loader().load(Some(&fixture.explicit_path()))?;
let authentication = config.git_remotes()[0]
.ssh_authentication()
.expect("SSH authentication");
assert_eq!(
authentication
.identity()
.agent_fingerprint()
.expect("agent fingerprint")
.as_str(),
"SHA256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
);
assert_eq!(
authentication.identity().agent_socket(),
Some(
fs::canonicalize(fixture.temporary.path())?
.join("cwd/config/agent.sock")
.as_path()
)
);
Ok(())
}