10000 tests: known_hosts manipulating ssh clone tests · libgit2/libgit2@0c68d75 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0c68d75

Browse files
committed
tests: known_hosts manipulating ssh clone tests
Teach the clone tests how to clone from github.com, when given a keypair with a passphrase and known_hosts data. This allows us to better exercise our known_hosts checking and ensure that the lifecycle of the certificate callback matches our expectations.
1 parent c84be77 commit 0c68d75

File tree

2 files changed

+143
-22
lines changed

2 files changed

+143
-22
lines changed

.github/workflows/main.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ jobs:
141141
BUILD_TEMP: D:\Temp
142142
SKIP_SSH_TESTS: true
143143
SKIP_NEGOTIATE_TESTS: true
144+
GITTEST_GITHUB_SSH_KEY: ${{ secrets.GITTEST_GITHUB_SSH_KEY }}
145+
GITTEST_GITHUB_SSH_PUBKEY: ${{ secrets.GITTEST_GITHUB_SSH_PUBKEY }}
146+
GITTEST_GITHUB_SSH_PASSPHRASE: ${{ secrets.GITTEST_GITHUB_SSH_PASSPHRASE }}
147+
GITTEST_GITHUB_SSH_REMOTE_HOSTKEY: ${{ secrets.GITTEST_GITHUB_SSH_REMOTE_HOSTKEY }}
144148
- name: "Windows (x86, Visual Studio)"
145149
id: windows-x86-vs
146150
os: windows-2019

tests/libgit2/online/clone.c

Lines changed: 139 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ static char *_remote_expectcontinue = NULL;
3636
static char *_remote_redirect_initial = NULL;
3737
static char *_remote_redirect_subsequent = NULL;
3838

39+
static char *_github_ssh_pubkey = NULL;
40+
static char *_github_ssh_privkey = NULL;
41+
static char *_github_ssh_passphrase = NULL;
42+
static char *_github_ssh_remotehostkey = NULL;
43+
3944
static int _orig_proxies_need_reset = 0;
4045
static char *_orig_http_proxy = NULL;
4146
static char *_orig_https_proxy = NULL;
@@ -85,6 +90,11 @@ void test_online_clone__initialize(void)
8590
_remote_redirect_initial = cl_getenv("GITTEST_REMOTE_REDIRECT_INITIAL");
8691
_remote_redirect_subsequent = cl_getenv("GITTEST_REMOTE_REDIRECT_SUBSEQUENT");
8792

93+
_github_ssh_pubkey = cl_getenv("GITTEST_GITHUB_SSH_PUBKEY");
94+
_github_ssh_privkey = cl_getenv("GITTEST_GITHUB_SSH_KEY");
95+
_github_ssh_passphrase = cl_getenv("GITTEST_GITHUB_SSH_PASSPHRASE");
96+
_github_ssh_remotehostkey = cl_getenv("GITTEST_GITHUB_SSH_REMOTE_HOSTKEY");
97+
8898
if (_remote_expectcontinue)
8999
git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, 1);
90100

@@ -119,6 +129,11 @@ void test_online_clone__cleanup(void)
119129
git__free(_remote_redirect_initial);
120130
git__free(_remote_redirect_subsequent);
121131

132+
git__free(_github_ssh_pubkey);
133+
git__free(_github_ssh_privkey);
134+
git__free(_github_ssh_passphrase);
135+
git__free(_github_ssh_remotehostkey);
136+
122137
if (_orig_proxies_need_reset) {
123138
cl_setenv("HTTP_PROXY", _orig_http_proxy);
124139
cl_setenv("HTTPS_PROXY", _orig_https_proxy);
@@ -554,6 +569,68 @@ static int check_ssh_auth_methods(git_credential **cred, const char *url, const
554569
return GIT_EUSER;
555570
}
556571

572+
static int succeed_certificate_check(git_cert *cert, int valid, const char *host, void *payload)
573+
{
574+
GIT_UNUSED(cert);
575+
GIT_UNUSED(valid);
576+
GIT_UNUSED(payload);
577+
578+
cl_assert_equal_s("github.com", host);
579+
< EDBE /td>580+
return 0;
581+
}
582+
583+
static int fail_certificate_check(git_cert *cert, int valid, const char *host, void *payload)
584+
{
585+
GIT_UNUSED(cert);
586+
GIT_UNUSED(valid);
587+
GIT_UNUSED(host);
588+
GIT_UNUSED(payload);
589+
590+
return GIT_ECERTIFICATE;
591+
}
592+
593+
static int github_credentials(
594+
git_credential **cred,
595+
const char *url,
596+
const char *username_from_url,
597+
unsigned int allowed_types,
598+
void *data)
599+
{
600+
GIT_UNUSED(url);
601+
GIT_UNUSED(username_from_url);
602+
GIT_UNUSED(data);
603+
604+
if ((allowed_types & GIT_CREDENTIAL_USERNAME) != 0) {
605+
return git_credential_username_new(cred, "git");
606+
}
607+
608+
cl_assert((allowed_types & GIT_CREDENTIAL_SSH_KEY) != 0);
609+
610+
return git_credential_ssh_key_memory_new(cred,
611+
"git",
612+
_github_ssh_pubkey,
613+
_github_ssh_privkey,
614+
_github_ssh_passphrase);
615+
}
616+
617+
void test_online_clone__ssh_github(void)
618+
{
619+
#if !defined(GIT_SSH) || !defined(GIT_SSH_MEMORY_CREDENTIALS)
620+
clar__skip();
621+
#endif
622+
623+
if (!_github_ssh_pubkey || !_github_ssh_privkey)
624+
clar__skip();
625+
626+
cl_fake_homedir(NULL);
627+
628+
g_options.fetch_opts.callbacks.credentials = github_credentials;
629+
g_options.fetch_opts.callbacks.certificate_check = succeed_certificate_check;
630+
631+
cl_git_pass(git_clone(&g_repo, SSH_REPO_URL, "./foo", &g_options));
632+
}
633+
557634
void test_online_clone__ssh_auth_methods(void)
558635
{
559636
int with_user;
@@ -563,7 +640,7 @@ void test_online_clone__ssh_auth_methods(void)
563640
#endif
564641
g_options.fetch_opts.callbacks.credentials = check_ssh_auth_methods;
565642
g_options.fetch_opts.callbacks.payload = &with_user;
566-
g_options.fetch_opts.callbacks.certificate_check = NULL;
643+
g_options.fetch_opts.callbacks.certificate_check = succeed_certificate_check;
567644

568645
with_user = 0;
569646
cl_git_fail_with(GIT_EUSER,
@@ -574,6 +651,67 @@ void test_online_clone__ssh_auth_methods(void)
574651
git_clone(&g_repo, "ssh://git@github.com/libgit2/TestGitRepository", "./foo", &g_options));
575652
}
576653

654+
/*
655+
* Ensure that the certificate check callback is still called, and
656+
* can accept a host key that is not in the known hosts file.
657+
*/
658+
void test_online_clone__ssh_certcheck_accepts_unknown(void)
659+
{
660+
#if !defined(GIT_SSH) || !defined(GIT_SSH_MEMORY_CREDENTIALS)
661+
clar__skip();
662+
#endif
663+
664+
if (!_github_ssh_pubkey || !_github_ssh_privkey)
665+
clar__skip();
666+
667+
cl_fake_homedir(NULL);
668+
669+
g_options.fetch_opts.callbacks.credentials = github_credentials;
670+
671+
/* Ensure we fail without the certificate check */
672+
cl_git_fail_with(GIT_ECERTIFICATE,
673+
git_clone(&g_repo, SSH_REPO_URL, "./foo", NULL));
674+
675+
/* Set the callback to accept the certificate */
676+
g_options.fetch_opts.callbacks.certificate_check = succeed_certificate_check;
677+
678+
cl_git_pass(git_clone(&g_repo, SSH_REPO_URL, "./foo", &g_options));
679+
}
680+
681+
/*
682+
* Ensure that the known hosts file is read and the certificate check
683+
* callback is still called after that.
684+
*/
685+
void test_online_clone__ssh_certcheck_override_knownhosts(void)
686+
{
687+
git_str knownhostsfile = GIT_STR_INIT;
688+
689+
#if !defined(GIT_SSH) || !defined(GIT_SSH_MEMORY_CREDENTIALS)
690+
clar__skip();
691+
#endif
692+
693+
if (!_github_ssh_pubkey || !_github_ssh_privkey || !_github_ssh_remotehostkey)
694+
clar__skip();
695+
696+
g_options.fetch_opts.callbacks.credentials = github_credentials;
697+
698+
cl_fake_homedir(&knownhostsfile);
699+
cl_git_pass(git_str_joinpath(&knownhostsfile, knownhostsfile.ptr, ".ssh"));
700+
cl_git_pass(p_mkdir(knownhostsfile.ptr, 0777));
701+
702+
cl_git_pass(git_str_joinpath(&knownhostsfile, knownhostsfile.ptr, "known_hosts"));
703+
cl_git_rewritefile(knownhostsfile.ptr, _github_ssh_remotehostkey);
704+
705+
/* Ensure we succeed without the certificate check */
706+
cl_git_pass(git_clone(&g_repo, SSH_REPO_URL, "./foo", &g_options));
707+
708+
/* Set the callback to accept the certificate */
709+
g_options.fetch_opts.callbacks.certificate_check = fail_certificate_check;
710+
cl_git_fail_with(GIT_ECERTIFICATE, git_clone(&g_repo, SSH_REPO_URL, "./bar", &g_options));
711+
712+
git_str_dispose(&knownhostsfile);
713+
}
714+
577715
static int custom_remote_ssh_with_paths(
578716
git_remote **out,
579717
git_repository *repo,
@@ -746,16 +884,6 @@ void test_online_clone__ssh_memory_auth(void)
746884
cl_git_pass(git_clone(&g_repo, _remote_url, "./foo", &g_options));
747885
}
748886

749-
static int fail_certificate_check(git_cert *cert, int valid, const char *host, void *payload)
750-
{
751-
GIT_UNUSED(cert);
752-
GIT_UNUSED(valid);
753-
GIT_UNUSED(host);
754-
GIT_UNUSED(payload);
755-
756-
return GIT_ECERTIFICATE;
757-
}
758-
759887
void test_online_clone__certificate_invalid(void)
760888
{
761889
g_options.fetch_opts.callbacks.certificate_check = fail_certificate_check;
@@ -769,17 +897,6 @@ void test_online_clone__certificate_invalid(void)
769897
#endif
770898
}
771899

772-
static int succeed_certificate_check(git_cert *cert, int valid, const char *host, void *payload)
773-
{
774-
GIT_UNUSED(cert);
775-
GIT_UNUSED(valid);
776-
GIT_UNUSED(payload);
777-
778-
cl_assert_equal_s("github.com", host);
779-
780-
return 0;
781-
}
782-
783900
void test_online_clone__certificate_valid(void)
784901
{
785902
g_options.fetch_opts.callbacks.certificate_check = succeed_certificate_check;

0 commit comments

Comments
 (0)
0