diff --git a/src/refspec.c b/src/refspec.c index 77c58c84e..9f0df35a7 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -223,7 +223,13 @@ static int refspec_transform( int git_refspec_transform(git_buf *out, const git_refspec *spec, const char *name) { - git_buf_sanitize(out); + assert(out && spec && name); + git_buf_sanitize(out); + + if (!git_refspec_src_matches(spec, name)) { + giterr_set(GITERR_INVALID, "ref '%s' doesn't match the source", name); + return -1; + } if (!spec->pattern) return git_buf_puts(out, spec->dst); @@ -233,7 +239,13 @@ int git_refspec_transform(git_buf *out, const git_refspec *spec, const char *nam int git_refspec_rtransform(git_buf *out, const git_refspec *spec, const char *name) { - git_buf_sanitize(out); + assert(out && spec && name); + git_buf_sanitize(out); + + if (!git_refspec_dst_matches(spec, name)) { + giterr_set(GITERR_INVALID, "ref '%s' doesn't match the destination", name); + return -1; + } if (!spec->pattern) return git_buf_puts(out, spec->src); diff --git a/tests/network/refspecs.c b/tests/network/refspecs.c index aa9b36e58..c6bcb10e8 100644 --- a/tests/network/refspecs.c +++ b/tests/network/refspecs.c @@ -88,7 +88,7 @@ void test_network_refspecs__parsing(void) assert_refspec(GIT_DIRECTION_FETCH, "refs/pull/*/head:refs/remotes/origin/pr/*", true); } -void assert_transform(const char *refspec, const char *name, const char *result) +static void assert_valid_transform(const char *refspec, const char *name, const char *result) { git_refspec spec; git_buf buf = GIT_BUF_INIT; @@ -103,8 +103,46 @@ void assert_transform(const char *refspec, const char *name, const char *result) void test_network_refspecs__transform_mid_star(void) { - assert_transform("refs/pull/*/head:refs/remotes/origin/pr/*", "refs/pull/23/head", "refs/remotes/origin/pr/23"); - assert_transform("refs/heads/*:refs/remotes/origin/*", "refs/heads/master", "refs/remotes/origin/master"); - assert_transform("refs/heads/*:refs/heads/*", "refs/heads/master", "refs/heads/master"); - assert_transform("refs/*:refs/*", "refs/heads/master", "refs/heads/master"); + assert_valid_transform("refs/pull/*/head:refs/remotes/origin/pr/*", "refs/pull/23/head", "refs/remotes/origin/pr/23"); + assert_valid_transform("refs/heads/*:refs/remotes/origin/*", "refs/heads/master", "refs/remotes/origin/master"); + assert_valid_transform("refs/heads/*:refs/remotes/origin/*", "refs/heads/user/feature", "refs/remotes/origin/user/feature"); + assert_valid_transform("refs/heads/*:refs/heads/*", "refs/heads/master", "refs/heads/master"); + assert_valid_transform("refs/heads/*:refs/heads/*", "refs/heads/user/feature", "refs/heads/user/feature"); + assert_valid_transform("refs/*:refs/*", "refs/heads/master", "refs/heads/master"); +} + +static void assert_invalid_transform(const char *refspec, const char *name) +{ + git_refspec spec; + git_buf buf = GIT_BUF_INIT; + + git_refspec__parse(&spec, refspec, true); + cl_git_fail(git_refspec_transform(&buf, &spec, name)); + + git_buf_free(&buf); + git_refspec__free(&spec); +} + +void test_network_refspecs__invalid(void) +{ + assert_invalid_transform("refs/heads/*:refs/remotes/origin/*", "master"); + assert_invalid_transform("refs/heads/*:refs/remotes/origin/*", "refs/headz/master"); +} + +static void assert_invalid_rtransform(const char *refspec, const char *name) +{ + git_refspec spec; + git_buf buf = GIT_BUF_INIT; + + git_refspec__parse(&spec, refspec, true); + cl_git_fail(git_refspec_rtransform(&buf, &spec, name)); + + git_buf_free(&buf); + git_refspec__free(&spec); +} + +void test_network_refspecs__invalid_reverse(void) +{ + assert_invalid_rtransform("refs/heads/*:refs/remotes/origin/*", "master"); + assert_invalid_rtransform("refs/heads/*:refs/remotes/origin/*", "refs/remotes/o/master"); }