History

fix: prohibit full names with a trailing `.`.

Just like in Git, it's considered invalid.

Sebastian Thiel committed 2 years ago

Commit 91d29c31 parent 9d5d8a64 files · +26 −10Browse files

Unified · Split

4 files
  1. gix-validate/src/reference.rs +5 −7
  2. gix-validate/src/tag.rs +6 −0
  3. gix-validate/tests/reference/mod.rs +14 −2
  4. gix-validate/tests/tag/mod.rs +1 −1
gix-validate/src/reference.rs+5−7
@@ -15,8 +15,8 @@ pub mod name { · 14 unmodified lines
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 { · 5 unmodified lines
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> { · 15 unmodified lines
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+6−0
@@ -21,6 +21,8 @@ pub mod name { · 20 unmodified lines
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 { · 2 unmodified lines
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> { · 20 unmodified lines
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+14−2
@@ -55,7 +55,7 @@ mod name_partial { · 54 unmodified lines
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 { · 45 unmodified lines
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 { · 23 unmodified lines
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+1−1
@@ -19,7 +19,6 @@ mod name { · 18 unmodified lines
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 { · 50 unmodified lines
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 }