Skip to content

Commit

Permalink
fix: prohibit full names with a trailing ..
Browse files Browse the repository at this point in the history
Just like in Git, it's considered invalid.
  • Loading branch information
Byron committed Aug 1, 2024
1 parent 9d5d8a6 commit 91d29c3
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 10 deletions.
12 changes: 5 additions & 7 deletions gix-validate/src/reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ pub mod name {
StartsWithSlash,
#[error("Multiple slashes in a row are not allowed as they may change the reference's meaning")]
RepeatedSlash,
#[error("Names must not be a single '.', but may contain it.")]
SingleDot,
#[error("Path components must not start with '.'")]
StartsWithDot,
}

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

use bstr::BStr;

/// Validate a reference name running all the tests in the book. This disallows lower-case references, but allows
/// ones like `HEAD`.
/// Validate a reference name running all the tests in the book. This disallows lower-case references like `lower`, but also allows
/// ones like `HEAD`, and `refs/lower`.
pub fn name(path: &BStr) -> Result<&BStr, name::Error> {
validate(path, Mode::Complete)
}
Expand All @@ -51,19 +51,17 @@ fn validate(path: &BStr, mode: Mode) -> Result<&BStr, name::Error> {
return Err(name::Error::StartsWithSlash);
}
let mut previous = 0;
let mut one_before_previous = 0;
let mut saw_slash = false;
for byte in path.iter() {
match *byte {
b'/' if previous == b'.' && one_before_previous == b'/' => return Err(name::Error::SingleDot),
b'/' if previous == b'/' => return Err(name::Error::RepeatedSlash),
b'.' if previous == b'/' => return Err(name::Error::StartsWithDot),
_ => {}
}

if *byte == b'/' {
saw_slash = true;
}
one_before_previous = previous;
previous = *byte;
}

Expand Down
6 changes: 6 additions & 0 deletions gix-validate/src/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub mod name {
Asterisk,
#[error("A ref must not start with a '.'")]
StartsWithDot,
#[error("A ref must not end with a '.'")]
EndsWithDot,
#[error("A ref must not end with a '/'")]
EndsWithSlash,
#[error("A ref must not be empty")]
Expand All @@ -29,6 +31,7 @@ pub mod name {
}

/// Assure the given `input` resemble a valid git tag name, which is returned unchanged on success.
/// Tag names are provided as names, lik` v1.0` or `alpha-1`, without paths.
pub fn name(input: &BStr) -> Result<&BStr, name::Error> {
if input.is_empty() {
return Err(name::Error::Empty);
Expand All @@ -55,6 +58,9 @@ pub fn name(input: &BStr) -> Result<&BStr, name::Error> {
if input[0] == b'.' {
return Err(name::Error::StartsWithDot);
}
if input[input.len() - 1] == b'.' {
return Err(name::Error::EndsWithDot);
}
if input.ends_with(b".lock") {
return Err(name::Error::LockFileSuffix);
}
Expand Down
16 changes: 14 additions & 2 deletions gix-validate/tests/reference/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ mod name_partial {
mktest!(
refs_path_component_is_singular_dot,
b"refs/./still-inside-but-not-cool",
RefError::SingleDot
RefError::StartsWithDot
);
mktest!(any_path_starts_with_slash, b"/etc/foo", RefError::StartsWithSlash);
mktest!(empty_path, b"", RefError::Tag(TagError::Empty));
Expand Down Expand Up @@ -107,6 +107,7 @@ mod name {
mktest!(all_uppercase, b"MAIN");
mktest!(all_uppercase_with_underscore, b"NEW_HEAD");
mktest!(chinese_utf8, "refs/heads/你好吗".as_bytes());
mktest!(dot_in_directory_component, b"this./totally./works");
}

mod invalid {
Expand Down Expand Up @@ -136,10 +137,21 @@ mod name {
b".refs/somewhere",
RefError::Tag(TagError::StartsWithDot)
);

mktest!(
refs_path_name_starts_with_dot_in_name,
b"refs/.somewhere",
RefError::StartsWithDot
);
mktest!(
refs_path_name_ends_with_dot_in_name,
b"refs/somewhere.",
RefError::Tag(TagError::EndsWithDot)
);
mktest!(
refs_path_component_is_singular_dot,
b"refs/./still-inside-but-not-cool",
RefError::SingleDot
RefError::StartsWithDot
);
mktest!(capitalized_name_without_path, b"Main", RefError::SomeLowercase);
mktest!(lowercase_name_without_path, b"main", RefError::SomeLowercase);
Expand Down
2 changes: 1 addition & 1 deletion gix-validate/tests/tag/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ mod name {
mktest!(contains_brackets, b"this_{is-fine}_too");
mktest!(contains_brackets_and_at, b"this_{@is-fine@}_too");
mktest!(dot_in_the_middle, b"token.other");
mktest!(dot_at_the_end, b"hello.");
mktest!(slash_inbetween, b"hello/world");
}

Expand Down Expand Up @@ -76,6 +75,7 @@ mod name {
mktestb!(contains_newline, b"prefix\nsuffix");
mktestb!(contains_carriage_return, b"prefix\rsuffix");
mktest!(starts_with_dot, b".with-dot", StartsWithDot);
mktest!(ends_with_dot, b"with-dot.", EndsWithDot);
mktest!(empty, b"", Empty);
}
}

0 comments on commit 91d29c3

Please sign in to comment.