sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/github/helpers.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package github 18 19 import ( 20 "fmt" 21 "net/http" 22 "regexp" 23 "strconv" 24 "strings" 25 ) 26 27 // SecurityForkNameRE is a regexp matching repos that are temporary security forks. 28 // https://help.github.com/en/github/managing-security-vulnerabilities/collaborating-in-a-temporary-private-fork-to-resolve-a-security-vulnerability 29 var SecurityForkNameRE = regexp.MustCompile(`^[\w-]+-ghsa-[\w-]+$`) 30 31 // ImageSizeLimit is the maximum image size GitHub allows in bytes (5MB). 32 const ImageSizeLimit = 5242880 33 34 // HasLabel checks if label is in the label set "issueLabels". 35 func HasLabel(label string, issueLabels []Label) bool { 36 for _, l := range issueLabels { 37 if strings.EqualFold(l.Name, label) { 38 return true 39 } 40 } 41 return false 42 } 43 44 // HasLabels checks if all labels are in the github.label set "issueLabels". 45 func HasLabels(labels []string, issueLabels []Label) bool { 46 for _, label := range labels { 47 if !HasLabel(label, issueLabels) { 48 return false 49 } 50 } 51 return true 52 } 53 54 // ImageTooBig checks if image is bigger than github limits. 55 func ImageTooBig(url string) (bool, error) { 56 // try to get the image size from Content-Length header 57 resp, err := http.Head(url) 58 if err != nil { 59 return true, fmt.Errorf("HEAD error: %w", err) 60 } 61 defer resp.Body.Close() 62 if sc := resp.StatusCode; sc != http.StatusOK { 63 return true, fmt.Errorf("failing %d response", sc) 64 } 65 size, _ := strconv.Atoi(resp.Header.Get("Content-Length")) 66 if size > ImageSizeLimit { 67 return true, nil 68 } 69 return false, nil 70 } 71 72 // LevelFromPermissions adapts a repo permissions struct to the 73 // appropriate permission level used elsewhere. 74 func LevelFromPermissions(permissions RepoPermissions) RepoPermissionLevel { 75 if permissions.Admin { 76 return Admin 77 } else if permissions.Maintain { 78 return Maintain 79 } else if permissions.Push { 80 return Write 81 } else if permissions.Triage { 82 return Triage 83 } else if permissions.Pull { 84 return Read 85 } else { 86 return None 87 } 88 } 89 90 // PermissionsFromTeamPermissions 91 func PermissionsFromTeamPermission(permission TeamPermission) RepoPermissions { 92 switch permission { 93 case RepoPull: 94 return RepoPermissions{Pull: true} 95 case RepoTriage: 96 return RepoPermissions{Pull: true, Triage: true} 97 case RepoPush: 98 return RepoPermissions{Pull: true, Triage: true, Push: true} 99 case RepoMaintain: 100 return RepoPermissions{Pull: true, Triage: true, Push: true, Maintain: true} 101 case RepoAdmin: 102 return RepoPermissions{Pull: true, Triage: true, Push: true, Maintain: true, Admin: true} 103 default: 104 // Should never happen unless the type gets new value 105 return RepoPermissions{} 106 } 107 } 108 109 // CommentLikeEventTypes are various event types that can be coerced into 110 // a GenericCommentEvent. 111 type CommentLikeEventTypes interface { 112 IssueEvent | IssueCommentEvent | PullRequestEvent | ReviewEvent | ReviewCommentEvent 113 } 114 115 // GeneralizeComment takes an event that can be coerced into a GenericCommentEvent 116 // and returns a populated GenericCommentEvent. 117 func GeneralizeComment[E CommentLikeEventTypes](event E) (*GenericCommentEvent, error) { 118 switch t := any(event).(type) { 119 120 case IssueEvent: 121 action := GeneralizeCommentAction(string(t.Action)) 122 if action == "" { 123 return nil, fmt.Errorf("failed to determine events action [%v]", string(t.Action)) 124 } 125 126 return &GenericCommentEvent{ 127 ID: t.Issue.ID, 128 NodeID: t.Issue.NodeID, 129 GUID: t.GUID, 130 IsPR: t.Issue.IsPullRequest(), 131 Action: action, 132 Body: t.Issue.Body, 133 HTMLURL: t.Issue.HTMLURL, 134 Number: t.Issue.Number, 135 Repo: t.Repo, 136 User: t.Issue.User, 137 IssueAuthor: t.Issue.User, 138 Assignees: t.Issue.Assignees, 139 IssueState: t.Issue.State, 140 IssueTitle: t.Issue.Title, 141 IssueBody: t.Issue.Body, 142 IssueHTMLURL: t.Issue.HTMLURL, 143 }, nil 144 case IssueCommentEvent: 145 action := GeneralizeCommentAction(string(t.Action)) 146 if action == "" { 147 return nil, fmt.Errorf("failed to determine events action [%v]", string(t.Action)) 148 } 149 150 return &GenericCommentEvent{ 151 ID: t.Issue.ID, 152 NodeID: t.Issue.NodeID, 153 CommentID: &t.Comment.ID, 154 GUID: t.GUID, 155 IsPR: t.Issue.IsPullRequest(), 156 Action: action, 157 Body: t.Comment.Body, 158 HTMLURL: t.Comment.HTMLURL, 159 Number: t.Issue.Number, 160 Repo: t.Repo, 161 User: t.Comment.User, 162 IssueAuthor: t.Issue.User, 163 Assignees: t.Issue.Assignees, 164 IssueState: t.Issue.State, 165 IssueTitle: t.Issue.Title, 166 IssueBody: t.Issue.Body, 167 IssueHTMLURL: t.Issue.HTMLURL, 168 }, nil 169 case PullRequestEvent: 170 action := GeneralizeCommentAction(string(t.Action)) 171 if action == "" { 172 return nil, fmt.Errorf("failed to determine events action [%v]", string(t.Action)) 173 } 174 175 return &GenericCommentEvent{ 176 ID: t.PullRequest.ID, 177 NodeID: t.PullRequest.NodeID, 178 GUID: t.GUID, 179 IsPR: true, 180 Action: action, 181 Body: t.PullRequest.Body, 182 HTMLURL: t.PullRequest.HTMLURL, 183 Number: t.PullRequest.Number, 184 Repo: t.Repo, 185 User: t.PullRequest.User, 186 IssueAuthor: t.PullRequest.User, 187 Assignees: t.PullRequest.Assignees, 188 IssueState: t.PullRequest.State, 189 IssueTitle: t.PullRequest.Title, 190 IssueBody: t.PullRequest.Body, 191 IssueHTMLURL: t.PullRequest.HTMLURL, 192 }, nil 193 case ReviewEvent: 194 action := GeneralizeCommentAction(string(t.Action)) 195 if action == "" { 196 return nil, fmt.Errorf("failed to determine events action [%v]", string(t.Action)) 197 } 198 199 return &GenericCommentEvent{ 200 GUID: t.GUID, 201 NodeID: t.Review.NodeID, 202 IsPR: true, 203 Action: action, 204 Body: t.Review.Body, 205 HTMLURL: t.Review.HTMLURL, 206 Number: t.PullRequest.Number, 207 Repo: t.Repo, 208 User: t.Review.User, 209 IssueAuthor: t.PullRequest.User, 210 Assignees: t.PullRequest.Assignees, 211 IssueState: t.PullRequest.State, 212 IssueTitle: t.PullRequest.Title, 213 IssueBody: t.PullRequest.Body, 214 IssueHTMLURL: t.PullRequest.HTMLURL, 215 }, nil 216 case ReviewCommentEvent: 217 action := GeneralizeCommentAction(string(t.Action)) 218 if action == "" { 219 return nil, fmt.Errorf("failed to determine events action [%v]", string(t.Action)) 220 } 221 222 return &GenericCommentEvent{ 223 GUID: t.GUID, 224 NodeID: t.Comment.NodeID, 225 IsPR: true, 226 CommentID: &t.Comment.ID, 227 Action: action, 228 Body: t.Comment.Body, 229 HTMLURL: t.Comment.HTMLURL, 230 Number: t.PullRequest.Number, 231 Repo: t.Repo, 232 User: t.Comment.User, 233 IssueAuthor: t.PullRequest.User, 234 Assignees: t.PullRequest.Assignees, 235 IssueState: t.PullRequest.State, 236 IssueTitle: t.PullRequest.Title, 237 IssueBody: t.PullRequest.Body, 238 IssueHTMLURL: t.PullRequest.HTMLURL, 239 }, nil 240 } 241 242 return nil, fmt.Errorf("we were unable to generalize comment, unknown type encountered") 243 }