diff --git a/services/auth/auth.go b/services/auth/auth.go index 90e2115bc5f60..305746eaf8533 100644 --- a/services/auth/auth.go +++ b/services/auth/auth.go @@ -28,6 +28,7 @@ type globalVarsStruct struct { archivePathRe *regexp.Regexp feedPathRe *regexp.Regexp feedRefPathRe *regexp.Regexp + actionsBadgePathRe *regexp.Regexp } var globalVars = sync.OnceValue(func() *globalVarsStruct { @@ -35,8 +36,12 @@ var globalVars = sync.OnceValue(func() *globalVarsStruct { gitRawOrAttachPathRe: regexp.MustCompile(`^/[-.\w]+/[-.\w]+/(?:(?:git-(?:(?:upload)|(?:receive))-pack$)|(?:info/refs$)|(?:HEAD$)|(?:objects/)|(?:raw/)|(?:releases/download/)|(?:attachments/))`), lfsPathRe: regexp.MustCompile(`^/[-.\w]+/[-.\w]+/info/lfs/`), archivePathRe: regexp.MustCompile(`^/[-.\w]+/[-.\w]+/archive/`), - feedPathRe: regexp.MustCompile(`^/[-.\w]+(/[-.\w]+)?\.(rss|atom)$`), // "/owner.rss" or "/owner/repo.atom" - feedRefPathRe: regexp.MustCompile(`^/[-.\w]+/[-.\w]+/(rss|atom)/`), // "/owner/repo/rss/branch/..." + // "/owner.rss" or "/owner/repo.atom" + feedPathRe: regexp.MustCompile(`^/[-.\w]+(/[-.\w]+)?\.(rss|atom)$`), + // "/owner/repo/rss/branch/..." + feedRefPathRe: regexp.MustCompile(`^/[-.\w]+/[-.\w]+/(rss|atom)/`), + // "/owner/repo/actions/workflows/foo/badge.svg" + actionsBadgePathRe: regexp.MustCompile(`^/[-.\w]+/[-.\w]+/actions/workflows/[-.\w]+/badge\.svg$`), } }) @@ -112,6 +117,10 @@ func (a *authPathDetector) isArchivePath() bool { return a.vars.archivePathRe.MatchString(a.req.URL.Path) } +func (a *authPathDetector) isActionsBadgeRequest() bool { + return a.req.Method == http.MethodGet && a.vars.actionsBadgePathRe.MatchString(a.req.URL.Path) +} + func (a *authPathDetector) isAuthenticatedTokenRequest() bool { switch a.req.URL.Path { case "/login/oauth/userinfo", "/login/oauth/introspect": diff --git a/services/auth/auth_test.go b/services/auth/auth_test.go index c45f312c90f8b..9035fd5d5f466 100644 --- a/services/auth/auth_test.go +++ b/services/auth/auth_test.go @@ -131,6 +131,11 @@ func Test_isGitRawOrLFSPath(t *testing.T) { } } +func Test_isActionsBadgeRequest(t *testing.T) { + req, _ := http.NewRequest(http.MethodGet, "http://localhost/owner/repo/actions/workflows/build.yml/badge.svg", nil) + assert.True(t, newAuthPathDetector(req).isActionsBadgeRequest()) +} + func Test_isFeedRequest(t *testing.T) { tests := []struct { want bool diff --git a/services/auth/basic.go b/services/auth/basic.go index 3161d7f33d4c2..0c7bacc7e0531 100644 --- a/services/auth/basic.go +++ b/services/auth/basic.go @@ -44,7 +44,7 @@ func (b *Basic) parseAuthBasic(req *http.Request) (ret struct{ authToken, uname, // Basic authentication should only fire on API, Feed, Download, Archives or on Git or LFSPaths // Not all feed (rss/atom) clients feature the ability to add cookies or headers, so we need to allow basic auth for feeds detector := newAuthPathDetector(req) - if !detector.isAPIPath() && !detector.isFeedRequest(req) && !detector.isContainerPath() && !detector.isAttachmentDownload() && !detector.isArchivePath() && !detector.isGitRawOrAttachOrLFSPath() { + if !detector.isAPIPath() && !detector.isFeedRequest(req) && !detector.isContainerPath() && !detector.isAttachmentDownload() && !detector.isArchivePath() && !detector.isGitRawOrAttachOrLFSPath() && !detector.isActionsBadgeRequest() { return ret } diff --git a/services/auth/oauth2.go b/services/auth/oauth2.go index 86903b0ce1715..17fd8745e3bd4 100644 --- a/services/auth/oauth2.go +++ b/services/auth/oauth2.go @@ -155,7 +155,7 @@ func (o *OAuth2) Verify(req *http.Request, w http.ResponseWriter, store DataStor // These paths are not API paths, but we still want to check for tokens because they maybe in the API returned URLs detector := newAuthPathDetector(req) if !detector.isAPIPath() && !detector.isAttachmentDownload() && !detector.isAuthenticatedTokenRequest() && - !detector.isGitRawOrAttachPath() && !detector.isArchivePath() { + !detector.isGitRawOrAttachPath() && !detector.isArchivePath() && !detector.isActionsBadgeRequest() { return nil, nil //nolint:nilnil // the auth method is not applicable }