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
15 StartsWithSlash,15 StartsWithSlash,
16 #[error("Multiple slashes in a row are not allowed as they may change the reference's meaning")]16 #[error("Multiple slashes in a row are not allowed as they may change the reference's meaning")]
17 RepeatedSlash,17 RepeatedSlash,
18 #[error("Names must not be a single '.', but may contain it.")]18 #[error("Path components must not start with '.'")]
19 SingleDot,19 StartsWithDot,
20 }20 }
21 21
22 impl From<Infallible> for Error {22 impl From<Infallible> for Error {
@@ -28,8 +28,8 @@ pub mod name { · 5 unmodified lines
28 28
29use bstr::BStr;29use bstr::BStr;
30 30
31/// Validate a reference name running all the tests in the book. This disallows lower-case references, but allows31/// 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`.32/// ones like `HEAD`, and `refs/lower`.
33pub fn name(path: &BStr) -> Result<&BStr, name::Error> {33pub fn name(path: &BStr) -> Result<&BStr, name::Error> {
34 validate(path, Mode::Complete)34 validate(path, Mode::Complete)
35}35}
@@ -51,19 +51,17 @@ fn validate(path: &BStr, mode: Mode) -> Result<&BStr, name::Error> { · 15 unmodified lines
51 return Err(name::Error::StartsWithSlash);51 return Err(name::Error::StartsWithSlash);
52 }52 }
53 let mut previous = 0;53 let mut previous = 0;
54 let mut one_before_previous = 0;
55 let mut saw_slash = false;54 let mut saw_slash = false;
56 for byte in path.iter() {55 for byte in path.iter() {
57 match *byte {56 match *byte {
58 b'/' if previous == b'.' && one_before_previous == b'/' => return Err(name::Error::SingleDot),
59 b'/' if previous == b'/' => return Err(name::Error::RepeatedSlash),57 b'/' if previous == b'/' => return Err(name::Error::RepeatedSlash),
58 b'.' if previous == b'/' => return Err(name::Error::StartsWithDot),
60 _ => {}59 _ => {}
61 }60 }
62 61
63 if *byte == b'/' {62 if *byte == b'/' {
64 saw_slash = true;63 saw_slash = true;
65 }64 }
66 one_before_previous = previous;
67 previous = *byte;65 previous = *byte;
68 }66 }
69 67
gix-validate/src/tag.rs+6−0
@@ -21,6 +21,8 @@ pub mod name { · 20 unmodified lines
21 Asterisk,21 Asterisk,
22 #[error("A ref must not start with a '.'")]22 #[error("A ref must not start with a '.'")]
23 StartsWithDot,23 StartsWithDot,
24 #[error("A ref must not end with a '.'")]
25 EndsWithDot,
24 #[error("A ref must not end with a '/'")]26 #[error("A ref must not end with a '/'")]
25 EndsWithSlash,27 EndsWithSlash,
26 #[error("A ref must not be empty")]28 #[error("A ref must not be empty")]
@@ -29,6 +31,7 @@ pub mod name { · 2 unmodified lines
29}31}
30 32
31/// Assure the given `input` resemble a valid git tag name, which is returned unchanged on success.33/// 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.
32pub fn name(input: &BStr) -> Result<&BStr, name::Error> {35pub fn name(input: &BStr) -> Result<&BStr, name::Error> {
33 if input.is_empty() {36 if input.is_empty() {
34 return Err(name::Error::Empty);37 return Err(name::Error::Empty);
@@ -55,6 +58,9 @@ pub fn name(input: &BStr) -> Result<&BStr, name::Error> { · 20 unmodified lines
55 if input[0] == b'.' {58 if input[0] == b'.' {
56 return Err(name::Error::StartsWithDot);59 return Err(name::Error::StartsWithDot);
57 }60 }
61 if input[input.len() - 1] == b'.' {
62 return Err(name::Error::EndsWithDot);
63 }
58 if input.ends_with(b".lock") {64 if input.ends_with(b".lock") {
59 return Err(name::Error::LockFileSuffix);65 return Err(name::Error::LockFileSuffix);
60 }66 }
gix-validate/tests/reference/mod.rs+14−2
@@ -55,7 +55,7 @@ mod name_partial { · 54 unmodified lines
55 mktest!(55 mktest!(
56 refs_path_component_is_singular_dot,56 refs_path_component_is_singular_dot,
57 b"refs/./still-inside-but-not-cool",57 b"refs/./still-inside-but-not-cool",
58 RefError::SingleDot58 RefError::StartsWithDot
59 );59 );
60 mktest!(any_path_starts_with_slash, b"/etc/foo", RefError::StartsWithSlash);60 mktest!(any_path_starts_with_slash, b"/etc/foo", RefError::StartsWithSlash);
61 mktest!(empty_path, b"", RefError::Tag(TagError::Empty));61 mktest!(empty_path, b"", RefError::Tag(TagError::Empty));
@@ -107,6 +107,7 @@ mod name { · 45 unmodified lines
107 mktest!(all_uppercase, b"MAIN");107 mktest!(all_uppercase, b"MAIN");
108 mktest!(all_uppercase_with_underscore, b"NEW_HEAD");108 mktest!(all_uppercase_with_underscore, b"NEW_HEAD");
109 mktest!(chinese_utf8, "refs/heads/你好吗".as_bytes());109 mktest!(chinese_utf8, "refs/heads/你好吗".as_bytes());
110 mktest!(dot_in_directory_component, b"this./totally./works");
110 }111 }
111 112
112 mod invalid {113 mod invalid {
@@ -136,10 +137,21 @@ mod name { · 23 unmodified lines
136 b".refs/somewhere",137 b".refs/somewhere",
137 RefError::Tag(TagError::StartsWithDot)138 RefError::Tag(TagError::StartsWithDot)
138 );139 );
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 );
139 mktest!(151 mktest!(
140 refs_path_component_is_singular_dot,152 refs_path_component_is_singular_dot,
141 b"refs/./still-inside-but-not-cool",153 b"refs/./still-inside-but-not-cool",
142 RefError::SingleDot154 RefError::StartsWithDot
143 );155 );
144 mktest!(capitalized_name_without_path, b"Main", RefError::SomeLowercase);156 mktest!(capitalized_name_without_path, b"Main", RefError::SomeLowercase);
145 mktest!(lowercase_name_without_path, b"main", RefError::SomeLowercase);157 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
19 mktest!(contains_brackets, b"this_{is-fine}_too");19 mktest!(contains_brackets, b"this_{is-fine}_too");
20 mktest!(contains_brackets_and_at, b"this_{@is-fine@}_too");20 mktest!(contains_brackets_and_at, b"this_{@is-fine@}_too");
21 mktest!(dot_in_the_middle, b"token.other");21 mktest!(dot_in_the_middle, b"token.other");
22 mktest!(dot_at_the_end, b"hello.");
23 mktest!(slash_inbetween, b"hello/world");22 mktest!(slash_inbetween, b"hello/world");
24 }23 }
25 24
@@ -76,6 +75,7 @@ mod name { · 50 unmodified lines
76 mktestb!(contains_newline, b"prefix\nsuffix");75 mktestb!(contains_newline, b"prefix\nsuffix");
77 mktestb!(contains_carriage_return, b"prefix\rsuffix");76 mktestb!(contains_carriage_return, b"prefix\rsuffix");
78 mktest!(starts_with_dot, b".with-dot", StartsWithDot);77 mktest!(starts_with_dot, b".with-dot", StartsWithDot);
78 mktest!(ends_with_dot, b"with-dot.", EndsWithDot);
79 mktest!(empty, b"", Empty);79 mktest!(empty, b"", Empty);
80 }80 }
81}81}