Skip to content

Commit 91d29c3

Browse files
committed
fix: prohibit full names with a trailing ..
Just like in Git, it's considered invalid.
1 parent 9d5d8a6 commit 91d29c3

File tree

4 files changed

+26
-10
lines changed

4 files changed

+26
-10
lines changed

gix-validate/src/reference.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ pub mod name {
1515
StartsWithSlash,
1616
#[error("Multiple slashes in a row are not allowed as they may change the reference's meaning")]
1717
RepeatedSlash,
18-
#[error("Names must not be a single '.', but may contain it.")]
19-
SingleDot,
18+
#[error("Path components must not start with '.'")]
19+
StartsWithDot,
2020
}
2121

2222
impl From<Infallible> for Error {
@@ -28,8 +28,8 @@ pub mod name {
2828

2929
use bstr::BStr;
3030

31-
/// Validate a reference name running all the tests in the book. This disallows lower-case references, but allows
32-
/// ones like `HEAD`.
31+
/// Validate a reference name running all the tests in the book. This disallows lower-case references like `lower`, but also allows
32+
/// ones like `HEAD`, and `refs/lower`.
3333
pub fn name(path: &BStr) -> Result<&BStr, name::Error> {
3434
validate(path, Mode::Complete)
3535
}
@@ -51,19 +51,17 @@ fn validate(path: &BStr, mode: Mode) -> Result<&BStr, name::Error> {
5151
return Err(name::Error::StartsWithSlash);
5252
}
5353
let mut previous = 0;
54-
let mut one_before_previous = 0;
5554
let mut saw_slash = false;
5655
for byte in path.iter() {
5756
match *byte {
58-
b'/' if previous == b'.' && one_before_previous == b'/' => return Err(name::Error::SingleDot),
5957
b'/' if previous == b'/' => return Err(name::Error::RepeatedSlash),
58+
b'.' if previous == b'/' => return Err(name::Error::StartsWithDot),
6059
_ => {}
6160
}
6261

6362
if *byte == b'/' {
6463
saw_slash = true;
6564
}
66-
one_before_previous = previous;
6765
previous = *byte;
6866
}
6967

gix-validate/src/tag.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ pub mod name {
2121
Asterisk,
2222
#[error("A ref must not start with a '.'")]
2323
StartsWithDot,
24+
#[error("A ref must not end with a '.'")]
25+
EndsWithDot,
2426
#[error("A ref must not end with a '/'")]
2527
EndsWithSlash,
2628
#[error("A ref must not be empty")]
@@ -29,6 +31,7 @@ pub mod name {
2931
}
3032

3133
/// Assure the given `input` resemble a valid git tag name, which is returned unchanged on success.
34+
/// Tag names are provided as names, lik` v1.0` or `alpha-1`, without paths.
3235
pub fn name(input: &BStr) -> Result<&BStr, name::Error> {
3336
if input.is_empty() {
3437
return Err(name::Error::Empty);
@@ -55,6 +58,9 @@ pub fn name(input: &BStr) -> Result<&BStr, name::Error> {
5558
if input[0] == b'.' {
5659
return Err(name::Error::StartsWithDot);
5760
}
61+
if input[input.len() - 1] == b'.' {
62+
return Err(name::Error::EndsWithDot);
63+
}
5864
if input.ends_with(b".lock") {
5965
return Err(name::Error::LockFileSuffix);
6066
}

gix-validate/tests/reference/mod.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ mod name_partial {
5555
mktest!(
5656
refs_path_component_is_singular_dot,
5757
b"refs/./still-inside-but-not-cool",
58-
RefError::SingleDot
58+
RefError::StartsWithDot
5959
);
6060
mktest!(any_path_starts_with_slash, b"/etc/foo", RefError::StartsWithSlash);
6161
mktest!(empty_path, b"", RefError::Tag(TagError::Empty));
@@ -107,6 +107,7 @@ mod name {
107107
mktest!(all_uppercase, b"MAIN");
108108
mktest!(all_uppercase_with_underscore, b"NEW_HEAD");
109109
mktest!(chinese_utf8, "refs/heads/你好吗".as_bytes());
110+
mktest!(dot_in_directory_component, b"this./totally./works");
110111
}
111112

112113
mod invalid {
@@ -136,10 +137,21 @@ mod name {
136137
b".refs/somewhere",
137138
RefError::Tag(TagError::StartsWithDot)
138139
);
140+
141+
mktest!(
142+
refs_path_name_starts_with_dot_in_name,
143+
b"refs/.somewhere",
144+
RefError::StartsWithDot
145+
);
146+
mktest!(
147+
refs_path_name_ends_with_dot_in_name,
148+
b"refs/somewhere.",
149+
RefError::Tag(TagError::EndsWithDot)
150+
);
139151
mktest!(
140152
refs_path_component_is_singular_dot,
141153
b"refs/./still-inside-but-not-cool",
142-
RefError::SingleDot
154+
RefError::StartsWithDot
143155
);
144156
mktest!(capitalized_name_without_path, b"Main", RefError::SomeLowercase);
145157
mktest!(lowercase_name_without_path, b"main", RefError::SomeLowercase);

gix-validate/tests/tag/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ mod name {
1919
mktest!(contains_brackets, b"this_{is-fine}_too");
2020
mktest!(contains_brackets_and_at, b"this_{@is-fine@}_too");
2121
mktest!(dot_in_the_middle, b"token.other");
22-
mktest!(dot_at_the_end, b"hello.");
2322
mktest!(slash_inbetween, b"hello/world");
2423
}
2524

@@ -76,6 +75,7 @@ mod name {
7675
mktestb!(contains_newline, b"prefix\nsuffix");
7776
mktestb!(contains_carriage_return, b"prefix\rsuffix");
7877
mktest!(starts_with_dot, b".with-dot", StartsWithDot);
78+
mktest!(ends_with_dot, b"with-dot.", EndsWithDot);
7979
mktest!(empty, b"", Empty);
8080
}
8181
}

0 commit comments

Comments
 (0)