drone/gitrpc/check/branch.go

97 lines
2.9 KiB
Go

// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package check
import (
"errors"
"fmt"
"strings"
)
/* https://git-scm.com/docs/git-check-ref-format
* How to handle various characters in refnames:
* 0: An acceptable character for refs
* 1: End-of-component
* 2: ., look for a preceding . to reject .. in refs
* 3: {, look for a preceding @ to reject @{ in refs
* 4: A bad character: ASCII control characters, and
* ":", "?", "[", "\", "^", "~", SP, or TAB
* 5: *, reject unless REFNAME_REFSPEC_PATTERN is set
*/
var refnameDisposition = [256]byte{
1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 2, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 4, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4,
}
func BranchName(branch string) error {
const lock = ".lock"
last := byte('\x00')
for i := 0; i < len(branch); i++ {
ch := branch[i] & 255
disp := refnameDisposition[ch]
switch disp {
case 1:
if i == 0 {
goto out
}
if last == '/' { // Refname contains "//"
return fmt.Errorf("branch '%s' cannot have two consecutive slashes // ", branch)
}
case 2:
if last == '.' { // Refname contains ".."
return fmt.Errorf("branch '%s' cannot have two consecutive dots .. ", branch)
}
case 3:
if last == '@' { // Refname contains "@{".
return fmt.Errorf("branch '%s' cannot contain a sequence @{", branch)
}
case 4:
return fmt.Errorf("branch '%s' cannot have ASCII control characters "+
"(i.e. bytes whose values are lower than \040, or \177 DEL), space, tilde ~, caret ^, or colon : anywhere", branch)
case 5:
return fmt.Errorf("branch '%s' can't be a pattern", branch)
}
last = ch
}
out:
if last == '\x00' {
return errors.New("branch name is empty")
}
if last == '.' {
return fmt.Errorf("branch '%s' cannot have . at the end", branch)
}
if last == '@' {
return fmt.Errorf("branch '%s' cannot be the single character @", branch)
}
if last == '/' {
return fmt.Errorf("branch '%s' cannot have / at the end", branch)
}
if branch[0] == '.' {
return fmt.Errorf("branch '%s' cannot start with '.'", branch)
}
if strings.HasSuffix(branch, lock) {
return fmt.Errorf("branch '%s' cannot end with '%s'", branch, lock)
}
return nil
}