@@ -15,24 +15,27 @@ import (
1515// RepoAccessCache caches repository metadata related to lockdown checks so that
1616// multiple tools can reuse the same access information safely across goroutines.
1717type RepoAccessCache struct {
18- client * githubv4.Client
19- mu sync.Mutex
20- cache * cache2go.CacheTable
21- ttl time.Duration
22- logger * slog.Logger
18+ client * githubv4.Client
19+ mu sync.Mutex
20+ cache * cache2go.CacheTable
21+ ttl time.Duration
22+ logger * slog.Logger
23+ trustedBotLogins map [string ]struct {}
2324}
2425
2526type repoAccessCacheEntry struct {
2627 isPrivate bool
2728 knownUsers map [string ]bool // normalized login -> has push access
2829 viewerLogin string
30+ viewerType string
2931}
3032
3133// RepoAccessInfo captures repository metadata needed for lockdown decisions.
3234type RepoAccessInfo struct {
3335 IsPrivate bool
3436 HasPushAccess bool
3537 ViewerLogin string
38+ ViewerType string
3639}
3740
3841const (
@@ -85,6 +88,12 @@ func GetInstance(client *githubv4.Client, opts ...RepoAccessOption) *RepoAccessC
8588 client : client ,
8689 cache : cache2go .Cache (defaultRepoAccessCacheKey ),
8790 ttl : defaultRepoAccessTTL ,
91+ trustedBotLogins : map [string ]struct {}{
92+ "dependabot[bot]" : {},
93+ "dependabot-preview[bot]" : {},
94+ "github-actions[bot]" : {},
95+ "github-copilot[bot]" : {},
96+ },
8897 }
8998 for _ , opt := range opts {
9099 if opt != nil {
@@ -115,7 +124,8 @@ func (c *RepoAccessCache) IsSafeContent(ctx context.Context, username, owner, re
115124 c .logDebug ("error checking repo access info for content filtering" , "owner" , owner , "repo" , repo , "user" , username , "error" , err )
116125 return false , err
117126 }
118- if repoInfo .IsPrivate || repoInfo .ViewerLogin == username {
127+
128+ if c .isTrustedBot (username , repoInfo .ViewerType ) || repoInfo .IsPrivate || repoInfo .ViewerLogin == username {
119129 return true , nil
120130 }
121131 return repoInfo .HasPushAccess , nil
@@ -150,12 +160,14 @@ func (c *RepoAccessCache) getRepoAccessInfo(ctx context.Context, username, owner
150160 }
151161 entry .knownUsers [userKey ] = info .HasPushAccess
152162 entry .viewerLogin = info .ViewerLogin
163+ entry .viewerType = info .ViewerType
153164 entry .isPrivate = info .IsPrivate
154165 c .cache .Add (key , c .ttl , entry )
155166 return RepoAccessInfo {
156167 IsPrivate : entry .isPrivate ,
157168 HasPushAccess : entry .knownUsers [userKey ],
158169 ViewerLogin : entry .viewerLogin ,
170+ ViewerType : entry .viewerType ,
159171 }, nil
160172 }
161173
@@ -171,13 +183,15 @@ func (c *RepoAccessCache) getRepoAccessInfo(ctx context.Context, username, owner
171183 knownUsers : map [string ]bool {userKey : info .HasPushAccess },
172184 isPrivate : info .IsPrivate ,
173185 viewerLogin : info .ViewerLogin ,
186+ viewerType : info .ViewerType ,
174187 }
175188 c .cache .Add (key , c .ttl , entry )
176189
177190 return RepoAccessInfo {
178191 IsPrivate : entry .isPrivate ,
179192 HasPushAccess : entry .knownUsers [userKey ],
180193 ViewerLogin : entry .viewerLogin ,
194+ ViewerType : entry .viewerType ,
181195 }, nil
182196}
183197
@@ -188,7 +202,8 @@ func (c *RepoAccessCache) queryRepoAccessInfo(ctx context.Context, username, own
188202
189203 var query struct {
190204 Viewer struct {
191- Login githubv4.String
205+ Typename string `graphql:"__typename"`
206+ Login githubv4.String
192207 }
193208 Repository struct {
194209 IsPrivate githubv4.Boolean
@@ -227,15 +242,24 @@ func (c *RepoAccessCache) queryRepoAccessInfo(ctx context.Context, username, own
227242 IsPrivate : bool (query .Repository .IsPrivate ),
228243 HasPushAccess : hasPush ,
229244 ViewerLogin : string (query .Viewer .Login ),
245+ ViewerType : query .Viewer .Typename ,
230246 }, nil
231247}
232248
233- func cacheKey (owner , repo string ) string {
234- return fmt .Sprintf ("%s/%s" , strings .ToLower (owner ), strings .ToLower (repo ))
235- }
236-
237249func (c * RepoAccessCache ) logDebug (msg string , args ... any ) {
238250 if c != nil && c .logger != nil {
239251 c .logger .Debug (msg , args ... )
240252 }
241253}
254+
255+ func (c * RepoAccessCache ) isTrustedBot (username string , viewerType string ) bool {
256+ if viewerType != "Bot" {
257+ return false
258+ }
259+ _ , ok := c .trustedBotLogins [strings .ToLower (username )]
260+ return ok
261+ }
262+
263+ func cacheKey (owner , repo string ) string {
264+ return fmt .Sprintf ("%s/%s" , strings .ToLower (owner ), strings .ToLower (repo ))
265+ }
0 commit comments