uselesskey-ssh 0.6.0

Deterministic OpenSSH key and certificate fixtures for infra and deployment tests.
Documentation
use ssh_key::{Certificate, PrivateKey, PublicKey, certificate::CertType};
use uselesskey_core::Factory;
use uselesskey_ssh::{
    SshCertFactoryExt, SshCertSpec, SshCertType, SshFactoryExt, SshSpec, SshValidity,
};

#[test]
fn round_trip_parse_openssh_keys() {
    let fx = Factory::deterministic_from_str("ssh-roundtrip-seed");

    for spec in [SshSpec::ed25519(), SshSpec::rsa()] {
        let key = fx.ssh_key("deploy", spec);

        let parsed_private = PrivateKey::from_openssh(key.private_key_openssh())
            .expect("private key fixture must parse");
        let parsed_public = PublicKey::from_openssh(key.authorized_key_line())
            .expect("authorized_keys line must parse");

        assert_eq!(
            parsed_private
                .public_key()
                .to_openssh()
                .expect("public key encoding must succeed"),
            parsed_public
                .to_openssh()
                .expect("public key encoding must succeed")
        );
    }
}

#[test]
fn authorized_keys_lines_are_deterministic() {
    let fx_a = Factory::deterministic_from_str("ssh-authz-seed");
    let fx_b = Factory::deterministic_from_str("ssh-authz-seed");

    let a = fx_a.ssh_key("host-a", SshSpec::ed25519());
    let b = fx_b.ssh_key("host-a", SshSpec::ed25519());
    let c = fx_a.ssh_key("host-b", SshSpec::ed25519());

    assert_eq!(a.authorized_key_line(), b.authorized_key_line());
    assert_ne!(a.authorized_key_line(), c.authorized_key_line());
}

#[test]
fn cert_principals_and_validity_match_spec() {
    let fx = Factory::deterministic_from_str("ssh-cert-seed");

    let spec = SshCertSpec {
        principals: vec!["deploy".to_string(), "ci".to_string()],
        validity: SshValidity::new(1_700_000_000, 1_800_000_000),
        cert_type: SshCertType::User,
        critical_options: vec![("force-command".to_string(), "/usr/bin/deploy".to_string())],
        extensions: vec![("permit-pty".to_string(), "".to_string())],
    };

    let cert_fx = fx.ssh_cert("deploy-cert", spec.clone());
    let parsed = Certificate::from_openssh(cert_fx.certificate_openssh())
        .expect("certificate fixture must parse");

    assert_eq!(parsed.valid_principals(), spec.principals.as_slice());
    assert_eq!(parsed.valid_after(), spec.validity.valid_after);
    assert_eq!(parsed.valid_before(), spec.validity.valid_before);
    assert_eq!(parsed.cert_type(), CertType::User);

    let force_command = parsed
        .critical_options()
        .get("force-command")
        .map(String::as_str);
    assert_eq!(force_command, Some("/usr/bin/deploy"));

    let permit_pty = parsed.extensions().get("permit-pty").map(String::as_str);
    assert_eq!(permit_pty, Some(""));
}