Skip to content

Commit 29b3c04

Browse files
authored
Add access checker (#40)
1 parent 3c7ba68 commit 29b3c04

19 files changed

Lines changed: 862 additions & 4 deletions

File tree

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"go.testTags": "unit"
3+
}

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ Simply calling `codeownerslint` will kick off the cli on the current directory.
2929
| ------------- | ------------- | ------------------------------------------------------------------------------ |
3030
| d | . | Directory: specifies the directory you want to use to lint the CODEOWNERS file |
3131
| f | | Format: specifies the format you want to return lint results |
32-
32+
| t | | Token: specifies the Github's token you want to use |
33+
| tt | bearer | Token Type: specifies the Github's token type you want to use |
34+
3335
##### Exit Codes
3436

3537
| Exit Code | Description |

checker.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ func RegisterChecker(name string, checker Checker) error {
3939
type ValidatorOptions struct {
4040
Directory string
4141
CodeownersFileLocation string
42+
GithubTokenType string
43+
GithubToken string
4244
}
4345

4446
// Checker provides tools for validating CODEOWNER file contents
@@ -132,6 +134,8 @@ func Check(options CheckOptions) ([]CheckResult, error) {
132134
validators[checker] = c.NewValidator(ValidatorOptions{
133135
Directory: options.Directory,
134136
CodeownersFileLocation: fileLocation,
137+
GithubToken: options.GithubToken,
138+
GithubTokenType: options.GithubTokenType,
135139
})
136140
}
137141

checkers/access.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package checkers
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/fmenezes/codeowners"
8+
)
9+
10+
const accessCheckerName string = "Access"
11+
12+
func init() {
13+
codeowners.RegisterChecker(accessCheckerName, Access{})
14+
}
15+
16+
// Access represents checker to validate if an owner has access to repo
17+
type Access struct{}
18+
19+
// NewValidator returns validating capabilities for this checker
20+
func (c Access) NewValidator(options codeowners.ValidatorOptions) codeowners.Validator {
21+
return accessValidator{
22+
options: options,
23+
accessMemo: make(map[string]bool),
24+
}
25+
}
26+
27+
type accessValidator struct {
28+
options codeowners.ValidatorOptions
29+
accessMemo map[string]bool
30+
}
31+
32+
// ValidateLine runs this NoOwner's check against each line
33+
func (v accessValidator) ValidateLine(lineNo int, line string) []codeowners.CheckResult {
34+
results := []codeowners.CheckResult{}
35+
36+
_, owners := codeowners.ParseLine(line)
37+
38+
if len(owners) == 0 {
39+
return nil
40+
}
41+
42+
for _, owner := range owners {
43+
if !ownerValid(owner) {
44+
continue
45+
}
46+
writeAccess, found := v.accessMemo[owner]
47+
if !found {
48+
writeAccess, _ = ownerHasWriteAccess(v.options, owner)
49+
v.accessMemo[owner] = writeAccess
50+
}
51+
if !writeAccess {
52+
result := codeowners.CheckResult{
53+
Position: codeowners.Position{
54+
FilePath: v.options.CodeownersFileLocation,
55+
StartLine: lineNo,
56+
EndLine: lineNo,
57+
StartColumn: strings.Index(line, owner) + 1,
58+
},
59+
Message: fmt.Sprintf("Owner '%s' has no write access", owner),
60+
Severity: codeowners.Error,
61+
CheckName: accessCheckerName,
62+
}
63+
result.Position.EndColumn = result.Position.StartColumn + len(owner)
64+
65+
results = append(results, result)
66+
}
67+
}
68+
69+
if len(results) > 0 {
70+
return results
71+
}
72+
73+
return nil
74+
}

0 commit comments

Comments
 (0)