From 38beba655bf26e88a384deba1b1bf97c753bfccd Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Sun, 17 May 2026 00:42:20 -0600 Subject: [PATCH 1/6] fix(actions): wrong assumption that run id always >= job id (#37737) (#37742) Backport #37737 Fix #37734 Follow up #37008 The `jobNum >= runNum` check is useless. Removed it to support `job_id < run_id` --- routers/web/repo/actions/view.go | 3 +-- tests/integration/actions_route_test.go | 10 +++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 44b13213b4..7a1fcaee9e 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -138,8 +138,7 @@ func resolveCurrentRunForView(ctx *context_module.Context) *actions_model.Action var runByID, runByIndex *actions_model.ActionRun var targetJobByIndex *actions_model.ActionRunJob - // Each run must have at least one job, so a valid job ID in the same run cannot be smaller than the run ID. - if !byIndex && jobNum >= runNum { + if !byIndex { // Probe the repo-scoped job ID first and only accept it when the job exists and belongs to the same runNum. job, err := actions_model.GetRunJobByRepoAndID(ctx, ctx.Repo.Repository.ID, jobNum) if err != nil && !errors.Is(err, util.ErrNotExist) { diff --git a/tests/integration/actions_route_test.go b/tests/integration/actions_route_test.go index 1b585ef1d0..b73fc21d1b 100644 --- a/tests/integration/actions_route_test.go +++ b/tests/integration/actions_route_test.go @@ -160,6 +160,10 @@ func testActionsRouteForLegacyIndexBasedURL(t *testing.T) { collisionJobIdx0 := mkJob(2600, collisionRun.ID, "legacy-collision-job-1", collisionRun.CommitSHA) collisionJobIdx1 := mkJob(2601, collisionRun.ID, "legacy-collision-job-2", collisionRun.CommitSHA) + // A run whose job has a smaller ID than the run itself (job_id < run_id) + jobSmallerThanRunRun := mkRun(5000, 5500, "legacy route job before run", "aaa007") + jobSmallerThanRunJob := mkJob(4500, jobSmallerThanRunRun.ID, "legacy-job-before-run-job", jobSmallerThanRunRun.CommitSHA) + // A small ID-based run/job pair that collides with a different legacy run/job index pair. ambiguousIDRun := mkRun(3, 1, "legacy route ambiguous id", "aaa005") ambiguousIDJob := mkJob(4, ambiguousIDRun.ID, "legacy-ambiguous-id-job", ambiguousIDRun.CommitSHA) @@ -182,11 +186,12 @@ func testActionsRouteForLegacyIndexBasedURL(t *testing.T) { targetAmbiguousLegacyJob := ambiguousLegacyJobs[int(ambiguousIDJob.ID)] insertBeansWithExplicitIDs(t, "action_run", - smallIDRun, otherSmallRun, normalRun, ambiguousIDRun, ambiguousLegacyRun, collisionRun, + smallIDRun, otherSmallRun, normalRun, ambiguousIDRun, ambiguousLegacyRun, collisionRun, jobSmallerThanRunRun, ) insertBeansWithExplicitIDs(t, "action_run_job", smallIDJob, otherSmallJob, normalRunJob, ambiguousIDJob, collisionJobIdx0, collisionJobIdx1, ambiguousLegacyJobIdx0, ambiguousLegacyJobIdx1, ambiguousLegacyJobIdx2, ambiguousLegacyJobIdx3, ambiguousLegacyJobIdx4, ambiguousLegacyJobIdx5, + jobSmallerThanRunJob, ) t.Run("OnlyRunID", func(t *testing.T) { @@ -220,6 +225,9 @@ func testActionsRouteForLegacyIndexBasedURL(t *testing.T) { user2Session.MakeRequest(t, req, http.StatusOK) req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/actions/runs/%d/jobs/%d", user2.Name, repo.Name, normalRun.ID, normalRunJob.ID)) user2Session.MakeRequest(t, req, http.StatusOK) + // URL must resolve even when job_id < run_id. + req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/actions/runs/%d/jobs/%d", user2.Name, repo.Name, jobSmallerThanRunRun.ID, jobSmallerThanRunJob.ID)) + user2Session.MakeRequest(t, req, http.StatusOK) }) t.Run("RunIndexAndJobIndex", func(t *testing.T) { -- 2.52.0 From 233144e33e1c90fd799e76ea55236fda661e5ed2 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Sat, 16 May 2026 07:15:53 -0700 Subject: [PATCH 2/6] fix(auth): set User-Agent on avatar fetch and sync avatar on link-account register (#37564) (#37588) (#37726) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport #37588 by @pandareen ## Summary Fixes [go-gitea/gitea#37564](https://github.com/go-gitea/gitea/issues/37564): when an OIDC provider returns a `picture` claim, Gitea is supposed to download that image as the user's avatar (if `[oauth2_client] UPDATE_AVATAR = true`). Two latent bugs prevented this from working consistently: 1. **Default Go User-Agent rejected by some image hosts.** `oauth2UpdateAvatarIfNeed` used `http.Get`, which sends `User-Agent: Go-http-client/1.1`. Hosts like `upload.wikimedia.org` reject that UA with `403`, and every error path silently returned, so the user was left with an identicon and **no log line** to diagnose the issue. 2. **Link-account *register* path skipped avatar sync.** First-time OIDC sign-ins where auto-registration is disabled (or required a username/password retype) go through `LinkAccountPostRegister`, which created the user but never called `oauth2SignInSync`. So the avatar / full name / SSH keys from the IdP were dropped on the floor for those users, even though the existing-account-link path (`oauth2LinkAccount`) and the auto-register path (`handleOAuth2SignIn`) both already did the sync. ## Changes - `routers/web/auth/oauth.go` — `oauth2UpdateAvatarIfNeed` now uses `http.NewRequest` + `http.DefaultClient.Do`, sets `User-Agent: Gitea `, and logs every failure path at `Warn` (invalid URL, fetch error, non-200, body read error, oversize body, upload error). No silent failures. - `routers/web/auth/linkaccount.go` — `LinkAccountPostRegister` now calls `oauth2SignInSync` after a successful user creation, mirroring the auto-register and link-existing-account flows. - `tests/integration/oauth_avatar_test.go` — new `TestOAuth2AvatarFromPicture` integration test with five sub-cases: - `AutoRegister_FetchesAvatarFromPictureWithGiteaUA` — happy path, asserts `use_custom_avatar=true`, an avatar hash is set, exactly one HTTP request was made, and the request carried a `Gitea ` UA. The mock server enforces the UA prefix to mirror real-world hosts that reject Go's default UA. - `AutoRegister_NonOK_DoesNotUpdateAvatar` — server returns 403; user's avatar must remain unset. - `AutoRegister_EmptyPicture_NoFetch` — empty `picture` claim must not trigger any HTTP request. - `AutoRegister_UpdateAvatarFalse_NoFetch` — `UPDATE_AVATAR=false` must not trigger any HTTP request. - `LinkAccountRegister_FetchesAvatarFromPicture` — guards the `linkaccount.go` fix; without the new `oauth2SignInSync` call this assertion fails. ## Test plan - [x] `go test -tags 'sqlite sqlite_unlock_notify' -run '^TestOAuth2AvatarFromPicture$' ./tests/integration/ -v` — 5/5 sub-tests pass. - [x] Manual: log in as a Keycloak user with `picture` claim pointing at `https://avatars.githubusercontent.com/u/9919?v=4` — Gitea avatar is replaced with the GitHub picture. - [x] Manual: same flow with `https://upload.wikimedia.org/...` — request now succeeds (or returns a clearly logged `Warn` line if rate-limited with `429`); previously it silently 403'd. - [x] Manual: `UPDATE_AVATAR=false` — user keeps the identicon, no outbound request in container logs. - [ ] Reviewer: please double-check that no other call sites of `oauth2UpdateAvatarIfNeed` rely on the old `http.Get` behaviour. ## Related - Upstream issue: go-gitea/gitea#37564 -------------------------------------------- AI Editor was used in this PR --------- Signed-off-by: silverwind Co-authored-by: pandareen <7270563+pandareen@users.noreply.github.com> Co-authored-by: silverwind Co-authored-by: Claude (Opus 4.7) Co-authored-by: wxiaoguang Co-authored-by: Nicolas --- modules/log/logger_impl.go | 21 ++++++ modules/log/logger_test.go | 7 ++ routers/web/auth/linkaccount.go | 5 ++ routers/web/auth/oauth.go | 52 ++++++++++----- tests/integration/oauth_avatar_test.go | 92 ++++++++++++++++++++++++++ tests/integration/oauth_test.go | 15 ++++- 6 files changed, 174 insertions(+), 18 deletions(-) create mode 100644 tests/integration/oauth_avatar_test.go diff --git a/modules/log/logger_impl.go b/modules/log/logger_impl.go index 9ca5a7d00d..acff767633 100644 --- a/modules/log/logger_impl.go +++ b/modules/log/logger_impl.go @@ -5,6 +5,7 @@ package log import ( "context" + "net/url" "reflect" "runtime" "strings" @@ -226,6 +227,8 @@ func (l *LoggerImpl) Log(skip int, event *Event, format string, logArgs ...any) } } else if ls := asLogStringer(v); ls != nil { msgArgs[i] = logStringFormatter{v: ls} + } else if str, ok := v.(string); ok { + msgArgs[i] = protectSensitiveInfo(str) } } @@ -235,6 +238,24 @@ func (l *LoggerImpl) Log(skip int, event *Event, format string, logArgs ...any) l.SendLogEvent(event) } +func protectSensitiveInfo(s string) string { + u, err := url.Parse(s) + if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" { + return s + } + q := u.Query() + for _, vals := range q { + for i := range vals { + vals[i] = "_" + } + } + masked := &url.URL{Scheme: u.Scheme, Host: u.Host, Path: u.Path, RawQuery: q.Encode()} + if u.User != nil { + masked.User = url.User("_masked_") + } + return masked.String() +} + func (l *LoggerImpl) GetLevel() Level { return Level(l.level.Load()) } diff --git a/modules/log/logger_test.go b/modules/log/logger_test.go index a74139dc51..6e38610ddd 100644 --- a/modules/log/logger_test.go +++ b/modules/log/logger_test.go @@ -177,3 +177,10 @@ func TestLoggerExpressionFilter(t *testing.T) { assert.Equal(t, []string{"foo\n", "foo bar\n", "by filename\n"}, w1.FetchLogs()) } + +func TestProtectSensitiveInfo(t *testing.T) { + assert.Empty(t, protectSensitiveInfo("")) + assert.Equal(t, "mailto:user@example.com", protectSensitiveInfo("mailto:user@example.com")) + assert.Equal(t, "https://example.com", protectSensitiveInfo("https://example.com")) + assert.Equal(t, "https://_masked_@example.com/path?k=_", protectSensitiveInfo("https://u:p@example.com/path?k=v#hash")) +} diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index c070c50acf..9c0deb3ecd 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -253,6 +253,11 @@ func LinkAccountPostRegister(ctx *context.Context) { return } + oauth2SignInSync(ctx, linkAccountData.AuthSourceID, u, linkAccountData.GothUser) + if ctx.Written() { + return + } + authSource, err := auth.GetSourceByID(ctx, linkAccountData.AuthSourceID) if err != nil { ctx.ServerError("GetSourceByID", err) diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index d1e220ca69..37be3f5466 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -13,6 +13,7 @@ import ( "net/url" "sort" "strings" + "time" "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" user_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/user" @@ -301,21 +302,42 @@ func showLinkingLogin(ctx *context.Context, authSourceID int64, gothUser goth.Us ctx.Redirect(setting.AppSubURL + "/user/link_account") } -func oauth2UpdateAvatarIfNeed(ctx *context.Context, url string, u *user_model.User) { - if setting.OAuth2Client.UpdateAvatar && len(url) > 0 { - resp, err := http.Get(url) - if err == nil { - defer func() { - _ = resp.Body.Close() - }() - } - // ignore any error - if err == nil && resp.StatusCode == http.StatusOK { - data, err := io.ReadAll(io.LimitReader(resp.Body, setting.Avatar.MaxFileSize+1)) - if err == nil && int64(len(data)) <= setting.Avatar.MaxFileSize { - _ = user_service.UploadAvatar(ctx, u, data) - } - } +var oauth2AvatarHTTPClient = &http.Client{Timeout: 30 * time.Second} + +func oauth2UpdateAvatarIfNeed(ctx *context.Context, avatarURL string, u *user_model.User) { + if !setting.OAuth2Client.UpdateAvatar || len(avatarURL) == 0 { + return + } + req, err := http.NewRequestWithContext(ctx, http.MethodGet, avatarURL, nil) + if err != nil { + log.Warn("invalid avatar URL %q: %v", avatarURL, err) + return + } + // Some hosts (e.g. Wikimedia) reject Go's default User-Agent. + req.Header.Set("User-Agent", "Gitea "+setting.AppVer) + + resp, err := oauth2AvatarHTTPClient.Do(req) + if err != nil { + log.Warn("fetch %q failed: %v", avatarURL, err) + return + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusOK { + log.Warn("fetch %q returned status %d", avatarURL, resp.StatusCode) + return + } + data, err := io.ReadAll(io.LimitReader(resp.Body, setting.Avatar.MaxFileSize+1)) + if err != nil { + log.Warn("read body from %q failed: %v", avatarURL, err) + return + } + if int64(len(data)) > setting.Avatar.MaxFileSize { + log.Warn("avatar from %q exceeds max size %d", avatarURL, setting.Avatar.MaxFileSize) + return + } + if err := user_service.UploadAvatar(ctx, u, data); err != nil { + log.Warn("UploadAvatar for user %q failed: %v", u.Name, err) } } diff --git a/tests/integration/oauth_avatar_test.go b/tests/integration/oauth_avatar_test.go new file mode 100644 index 0000000000..d86f2f2cbe --- /dev/null +++ b/tests/integration/oauth_avatar_test.go @@ -0,0 +1,92 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "net/http" + "testing" + + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/routers/web/auth" + "code.gitea.io/gitea/services/auth/source/oauth2" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/tests" + + "github.com/markbates/goth" + "github.com/markbates/goth/gothic" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestOAuth2AvatarFromPicture(t *testing.T) { + defer tests.PrepareTestEnv(t)() + defer test.MockVariableValue(&setting.OAuth2Client.UpdateAvatar, true)() + + mockServer := createOAuth2MockProvider() + defer mockServer.Close() + addOAuth2Source(t, "test-oidc-avatar", oauth2.Source{ + Provider: "openidConnect", + ClientID: "test-client-id", + OpenIDConnectAutoDiscoveryURL: mockServer.URL + "/.well-known/openid-configuration", + }) + authSource, err := auth_model.GetActiveOAuth2SourceByAuthName(t.Context(), "test-oidc-avatar") + require.NoError(t, err) + providerName := authSource.Cfg.(*oauth2.Source).Provider + + t.Run("AutoRegister", func(t *testing.T) { + defer test.MockVariableValue(&setting.OAuth2Client.Username, "")() + defer test.MockVariableValue(&setting.OAuth2Client.EnableAutoRegistration, true)() + defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) { + return goth.User{ + Provider: providerName, + UserID: "oidc-user-ua-pic", + Email: "oidc-user-ua-pic@example.com", + Name: "OIDC UA Pic", + AvatarURL: mockServer.URL + "/avatar.png", + }, nil + })() + + req := NewRequest(t, "GET", "/user/oauth2/test-oidc-avatar/callback?code=XYZ&state=XYZ") + emptyTestSession(t).MakeRequest(t, req, http.StatusSeeOther) + + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "oidc-user-ua-pic"}) + assert.True(t, user.UseCustomAvatar, "avatar must sync (requires Gitea UA)") + assert.NotEmpty(t, user.Avatar) + }) + + t.Run("LinkAccountRegister", func(t *testing.T) { + const newUserName = "oidc-link-register" + defer web.RouteMockReset() + web.RouteMock(web.MockAfterMiddlewares, func(ctx *context.Context) { + require.NoError(t, auth.Oauth2SetLinkAccountData(ctx, auth.LinkAccountData{ + AuthSourceID: authSource.ID, + GothUser: goth.User{ + Provider: providerName, + UserID: "oidc-link-register-sub", + Email: "oidc-link-register-a@example.com", + Name: "OIDC Link Register", + AvatarURL: mockServer.URL + "/avatar.png", + }, + })) + }) + + req := NewRequestWithValues(t, "POST", "/user/link_account_signup", map[string]string{ + "user_name": newUserName, + "email": "oidc-link-register-b@example.com", + "password": "AVeryStrongPassword!1", + "retype": "AVeryStrongPassword!1", + }) + emptyTestSession(t).MakeRequest(t, req, http.StatusSeeOther) + + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: newUserName}) + require.Equal(t, auth_model.OAuth2, user.LoginType) + assert.True(t, user.UseCustomAvatar, "register-link flow must sync avatar from `picture` claim") + assert.NotEmpty(t, user.Avatar) + }) +} diff --git a/tests/integration/oauth_test.go b/tests/integration/oauth_test.go index 90f606656b..a55336c419 100644 --- a/tests/integration/oauth_test.go +++ b/tests/integration/oauth_test.go @@ -8,6 +8,8 @@ import ( "crypto/sha256" "encoding/base64" "fmt" + "image" + "image/png" "io" "net/http" "net/http/httptest" @@ -1131,10 +1133,17 @@ func addOAuth2Source(t *testing.T, authName string, cfg oauth2.Source) { require.NoError(t, err) } -func createMockServer() *httptest.Server { +func createOAuth2MockProvider() *httptest.Server { var mockServer *httptest.Server mockServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { + case "/avatar.png": + if !strings.HasPrefix(r.Header.Get("User-Agent"), "Gitea ") { + http.Error(w, "user agent doesn't match", http.StatusForbidden) + return + } + w.Header().Set("Content-Type", "image/png") + _ = png.Encode(w, image.NewRGBA(image.Rect(0, 0, 8, 8))) case "/.well-known/openid-configuration": _, _ = w.Write([]byte(`{ "issuer": "` + mockServer.URL + `", @@ -1153,7 +1162,7 @@ func createMockServer() *httptest.Server { func TestSignInOauthCallbackSyncSSHKeys(t *testing.T) { defer tests.PrepareTestEnv(t)() - mockServer := createMockServer() + mockServer := createOAuth2MockProvider() defer mockServer.Close() ctx := t.Context() @@ -1233,7 +1242,7 @@ func TestSignInOauthCallbackSyncSSHKeys(t *testing.T) { // Checks if an OAuth provider with spaces within the name does work, // with the encoding of its names in the URL (PR#37327) func testOAuthSourceSpecialChars(t *testing.T) { - mockServer := createMockServer() + mockServer := createOAuth2MockProvider() defer mockServer.Close() addOAuth2Source(t, "test space", oauth2.Source{ -- 2.52.0 From 00d862f737da7349d79a7c22f930b38f7901ea56 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Fri, 8 May 2026 14:04:04 -0700 Subject: [PATCH 3/6] fix: make clone URL respect public URL detection setting (#37615) (#37617) Backport #37615 by @wxiaoguang Fix #37614 Co-authored-by: wxiaoguang --- web_src/js/features/repo-common.ts | 6 +++--- web_src/js/utils/url.test.ts | 18 +----------------- web_src/js/utils/url.ts | 16 ---------------- 3 files changed, 4 insertions(+), 36 deletions(-) diff --git a/web_src/js/features/repo-common.ts b/web_src/js/features/repo-common.ts index 65b89cf261..50d0db3673 100644 --- a/web_src/js/features/repo-common.ts +++ b/web_src/js/features/repo-common.ts @@ -5,7 +5,6 @@ import {showErrorToast} from '../modules/toast.ts'; import {sleep} from '../utils.ts'; import RepoActivityTopAuthors from '../components/RepoActivityTopAuthors.vue'; import {createApp} from 'vue'; -import {toOriginUrl} from '../utils/url.ts'; import {createTippy} from '../modules/tippy.ts'; import {localUserSettings} from '../modules/user-settings.ts'; @@ -79,7 +78,8 @@ function initCloneSchemeUrlSelection(parent: Element) { const isTea = scheme === 'tea'; if (tabHttps) { - tabHttps.textContent = window.origin.split(':')[0].toUpperCase(); // show "HTTP" or "HTTPS" + const link = tabHttps.getAttribute('data-link')!; + tabHttps.textContent = link.split(':')[0].toUpperCase(); // show "HTTP" or "HTTPS" tabHttps.classList.toggle('active', isHttps); } if (tabSsh) { @@ -99,7 +99,7 @@ function initCloneSchemeUrlSelection(parent: Element) { } if (!tab) return; - const link = toOriginUrl(tab.getAttribute('data-link')!); + const link = tab.getAttribute('data-link')!; for (const el of document.querySelectorAll('.js-clone-url')) { if (el.nodeName === 'INPUT') { diff --git a/web_src/js/utils/url.test.ts b/web_src/js/utils/url.test.ts index a2e7339375..0a7e27ca61 100644 --- a/web_src/js/utils/url.test.ts +++ b/web_src/js/utils/url.test.ts @@ -1,4 +1,4 @@ -import {linkifyURLs, pathEscape, pathEscapeSegments, toOriginUrl, urlQueryEscape} from './url.ts'; +import {linkifyURLs, pathEscape, pathEscapeSegments, urlQueryEscape} from './url.ts'; describe('escape', () => { const queryNonAscii = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; @@ -45,19 +45,3 @@ test('linkifyURLs', () => { expect(linkifyURLs('https://evil.com/\nonclick=alert(1)')).toEqual(`${link('https://evil.com/')}\nonclick=alert(1)`); expect(linkifyURLs('https://evil.com/"onmouseover=alert(1)')).toEqual(`${link('https://evil.com/"onmouseover=alert')}(1)`); }); - -test('toOriginUrl', () => { - const oldLocation = String(window.location); - for (const origin of ['https://example.com', 'https://example.com:3000']) { - window.location.assign(`${origin}/`); - expect(toOriginUrl('/')).toEqual(`${origin}/`); - expect(toOriginUrl('/org/repo.git')).toEqual(`${origin}/org/repo.git`); - expect(toOriginUrl('https://another.com')).toEqual(`${origin}/`); - expect(toOriginUrl('https://another.com/')).toEqual(`${origin}/`); - expect(toOriginUrl('https://another.com/org/repo.git')).toEqual(`${origin}/org/repo.git`); - expect(toOriginUrl('https://another.com:4000')).toEqual(`${origin}/`); - expect(toOriginUrl('https://another.com:4000/')).toEqual(`${origin}/`); - expect(toOriginUrl('https://another.com:4000/org/repo.git')).toEqual(`${origin}/org/repo.git`); - } - window.location.assign(oldLocation); -}); diff --git a/web_src/js/utils/url.ts b/web_src/js/utils/url.ts index 927f0937a4..84328faf24 100644 --- a/web_src/js/utils/url.ts +++ b/web_src/js/utils/url.ts @@ -57,19 +57,3 @@ export function linkifyURLs(html: string): string { return `${cleanUrl}${trailing}`; // eslint-disable-line github/unescaped-html-literal }); } - -/** Convert an absolute or relative URL to an absolute URL with the current origin. It only - * processes absolute HTTP/HTTPS URLs or relative URLs like '/xxx' or '//host/xxx'. */ -export function toOriginUrl(urlStr: string) { - try { - if (urlStr.startsWith('http://') || urlStr.startsWith('https://') || urlStr.startsWith('/')) { - const {origin, protocol, hostname, port} = window.location; - const url = new URL(urlStr, origin); - url.protocol = protocol; - url.hostname = hostname; - url.port = port || (protocol === 'https:' ? '443' : '80'); - return url.toString(); - } - } catch {} - return urlStr; -} -- 2.52.0 From 6d9f0d97272b980a8af876558e4799b5bb6c5c2b Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sat, 2 May 2026 12:58:40 +0200 Subject: [PATCH 4/6] Fix basic auth bug (#37503) Backport for #37486 --- services/auth/basic.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/auth/basic.go b/services/auth/basic.go index caf47af4f6..75a6345876 100644 --- a/services/auth/basic.go +++ b/services/auth/basic.go @@ -68,7 +68,7 @@ func (b *Basic) parseAuthBasic(req *http.Request) (ret struct{ authToken, uname, // VerifyAuthToken only the access token provided as parameter, used by other auth methods that want to reuse access token verification logic func (b *Basic) VerifyAuthToken(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore, authToken string) (*user_model.User, error) { - // get oauth2 token's user's ID + // get oauth2 token's user's ID and access scope accessTokenScope, uid := GetOAuthAccessTokenScopeAndUserID(req.Context(), authToken) if uid != 0 { log.Trace("Basic Authorization: Valid OAuthAccessToken for user[%d]", uid) -- 2.52.0 From cc61032697e324cc92d8b015c75bb18f888eaa92 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Fri, 8 May 2026 09:14:41 -0700 Subject: [PATCH 5/6] fix(git): Fix smart http request scope bug (#37583) (#37605) Backport #37583 by @lunny Co-authored-by: Lunny Xiao Co-authored-by: Nicolas Co-authored-by: Claude Opus 4.7 Co-authored-by: silverwind --- tests/integration/git_smart_http_test.go | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/integration/git_smart_http_test.go b/tests/integration/git_smart_http_test.go index 33e90c7dfa..b07e047091 100644 --- a/tests/integration/git_smart_http_test.go +++ b/tests/integration/git_smart_http_test.go @@ -9,6 +9,9 @@ import ( "net/url" "testing" + auth_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" + repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" + "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest" "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/test" "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" @@ -20,6 +23,7 @@ import ( func TestGitSmartHTTP(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { testGitSmartHTTP(t, u) + testGitSmartHTTPTokenScopes(t) testRenamedRepoRedirect(t) testGitArchiveRemote(t, u) }) @@ -80,6 +84,42 @@ func testGitSmartHTTP(t *testing.T, u *url.URL) { } } +func testGitSmartHTTPTokenScopes(t *testing.T) { + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerName: "user2", Name: "repo2"}) + require.True(t, repo.IsPrivate) + + session := loginUser(t, "user2") + badToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadNotification) + readToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository) + writeToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + publicOnlyToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopePublicOnly, auth_model.AccessTokenScopeReadRepository) + + t.Run("upload-pack requires read repository scope", func(t *testing.T) { + path := "/user2/repo2/info/refs?service=git-upload-pack" + + MakeRequest(t, NewRequest(t, "GET", path).AddBasicAuth(badToken, "x-oauth-basic"), http.StatusForbidden) + MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(badToken), http.StatusForbidden) + + resp := MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(readToken), http.StatusOK) + assert.Contains(t, resp.Body.String(), "refs/heads/master") + }) + + t.Run("receive-pack requires write repository scope", func(t *testing.T) { + path := "/user2/repo2/info/refs?service=git-receive-pack" + + MakeRequest(t, NewRequest(t, "GET", path).AddBasicAuth(readToken, "x-oauth-basic"), http.StatusForbidden) + MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(readToken), http.StatusForbidden) + + resp := MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(writeToken), http.StatusOK) + assert.Contains(t, resp.Body.String(), "refs/heads/master") + }) + + t.Run("public-only scope rejects private repo", func(t *testing.T) { + path := "/user2/repo2/info/refs?service=git-upload-pack" + MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(publicOnlyToken), http.StatusForbidden) + }) +} + func testRenamedRepoRedirect(t *testing.T) { defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)() -- 2.52.0 From 775766bc649243eb159ff03456754fe0eb6cf06f Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Tue, 26 May 2026 16:49:33 -0500 Subject: [PATCH 6/6] chore(deps): bump go-git/go-git/v5 to 5.19.0 (security) Addresses security fixes in the go-git library. Upstream backport of go-gitea/gitea#37608. Co-Authored-By: Claude Opus 4.6 (1M context) --- go.mod | 15 +++++++-------- go.sum | 52 ++++++++++++++-------------------------------------- 2 files changed, 21 insertions(+), 46 deletions(-) diff --git a/go.mod b/go.mod index 6c415897bf..5dc8bf4261 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module git.mokoconsulting.tech/MokoConsulting/MokoGitea -go 1.26.2 +go 1.26.3 // rfc5280 said: "The serial number is an integer assigned by the CA to each certificate." // But some CAs use negative serial number, just relax the check. related: @@ -9,6 +9,7 @@ godebug x509negativeserial=1 require ( code.gitea.io/actions-proto-go v0.4.1 + code.gitea.io/gitea v1.26.2 code.gitea.io/sdk/gitea v0.24.1 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 connectrpc.com/connect v1.19.1 @@ -52,8 +53,8 @@ require ( github.com/go-chi/cors v1.2.2 github.com/go-co-op/gocron/v2 v2.19.1 github.com/go-enry/go-enry/v2 v2.9.5 - github.com/go-git/go-billy/v5 v5.8.0 - github.com/go-git/go-git/v5 v5.18.0 + github.com/go-git/go-billy/v5 v5.9.0 + github.com/go-git/go-git/v5 v5.19.0 github.com/go-ldap/ldap/v3 v3.4.13 github.com/go-redsync/redsync/v4 v4.16.0 github.com/go-sql-driver/mysql v1.9.3 @@ -242,17 +243,18 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/nwaples/rardecode/v2 v2.2.2 // indirect + github.com/nxadm/tail v1.4.8 // indirect github.com/oasdiff/yaml v0.0.9 // indirect github.com/oasdiff/yaml3 v0.0.12 // indirect github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect github.com/olekukonko/errors v1.2.0 // indirect github.com/olekukonko/ll v0.1.8 // indirect github.com/olekukonko/tablewriter v1.1.4 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect + github.com/olivere/elastic/v7 v7.0.32 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/philhofer/fwd v1.2.0 // indirect github.com/pierrec/lz4/v4 v4.1.26 // indirect - github.com/pjbgf/sha1cd v0.5.0 // indirect + github.com/pjbgf/sha1cd v0.6.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.2 // indirect @@ -265,7 +267,6 @@ require ( github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.4 // indirect github.com/skeema/knownhosts v1.3.2 // indirect - github.com/smartystreets/assertions v1.1.1 // indirect github.com/sorairolake/lzip-go v0.3.8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect @@ -277,7 +278,6 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect - github.com/zeebo/assert v1.3.0 // indirect github.com/zeebo/blake3 v0.2.4 // indirect go.etcd.io/bbolt v1.4.3 // indirect go.uber.org/atomic v1.11.0 // indirect @@ -287,7 +287,6 @@ require ( go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect go4.org v0.0.0-20260112195520-a5071408f32f // indirect - golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect golang.org/x/mod v0.35.0 // indirect golang.org/x/time v0.15.0 // indirect golang.org/x/tools v0.44.0 // indirect diff --git a/go.sum b/go.sum index cbca6c940f..38d76a2b40 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdB cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= code.gitea.io/actions-proto-go v0.4.1 h1:l0EYhjsgpUe/1VABo2eK7zcoNX2W44WOnb0MSLrKfls= code.gitea.io/actions-proto-go v0.4.1/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas= +code.gitea.io/gitea v1.26.2 h1:i0oTSOGXnB3WLILa0lRzwi4KFIkKIEZnoyCtYiajtYY= +code.gitea.io/gitea v1.26.2/go.mod h1:K2pVuCKcxMzEl/KBD3b4GsWIOu6ZH74g8lJYiACcnsM= code.gitea.io/gitea-vet v0.2.3 h1:gdFmm6WOTM65rE8FUBTRzeQZYzXePKSSB1+r574hWwI= code.gitea.io/gitea-vet v0.2.3/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= code.gitea.io/sdk/gitea v0.24.1 h1:hpaqcdGcBmfMpV7JSbBJVwE99qo+WqGreJYKrDKEyW8= @@ -269,6 +271,8 @@ github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY= github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= @@ -300,12 +304,12 @@ github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e h1:oRq/fiirun5Hql github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDzZG0= -github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY= +github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA= +github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.18.0 h1:O831KI+0PR51hM2kep6T8k+w0/LIAD490gvqMCvL5hM= -github.com/go-git/go-git/v5 v5.18.0/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo= +github.com/go-git/go-git/v5 v5.19.0 h1:+WkVUQZSy/F1Gb13udrMKjIM2PrzsNfDKFSfo5tkMtc= +github.com/go-git/go-git/v5 v5.19.0/go.mod h1:Pb1v0c7/g8aGQJwx9Us09W85yGoyvSwuhEGMH7zjDKQ= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= @@ -326,7 +330,6 @@ github.com/go-redsync/redsync/v4 v4.16.0 h1:bNcOzeHH9d3s6pghU9NJFMPrQa41f5Nx3L4Y github.com/go-redsync/redsync/v4 v4.16.0/go.mod h1:V4gagqgyASWBZuwx4xGzu72aZNb/6Mo05byUa3mVmKQ= github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= @@ -354,12 +357,6 @@ github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8J github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -373,9 +370,6 @@ github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl76 github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v25.12.19+incompatible h1:haMV2JRRJCe1998HeW/p0X9UaMTK6SDo0ffLn2+DbLs= github.com/google/flatbuffers v25.12.19+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -570,7 +564,6 @@ github.com/niklasfasching/go-org v1.9.1 h1:/3s4uTPOF06pImGa2Yvlp24yKXZoTYM+nsIlM github.com/niklasfasching/go-org v1.9.1/go.mod h1:ZAGFFkWvUQcpazmi/8nHqwvARpr1xpb+Es67oUGX/48= github.com/nwaples/rardecode/v2 v2.2.2 h1:/5oL8dzYivRM/tqX9VcTSWfbpwcbwKG1QtSJr3b3KcU= github.com/nwaples/rardecode/v2 v2.2.2/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= @@ -585,14 +578,13 @@ github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8= github.com/olekukonko/ll v0.1.8/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw= github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= +github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E= +github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -608,8 +600,8 @@ github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pierrec/lz4/v4 v4.1.26 h1:GrpZw1gZttORinvzBdXPUXATeqlJjqUG/D87TKMnhjY= github.com/pierrec/lz4/v4 v4.1.26/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4= -github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0= -github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= +github.com/pjbgf/sha1cd v0.6.0 h1:3WJ8Wz8gvDz29quX1OcEmkAlUg9diU4GxJHqs0/XiwU= +github.com/pjbgf/sha1cd v0.6.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -693,7 +685,6 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -801,8 +792,8 @@ golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ss golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= -golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0= -golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= golang.org/x/image v0.40.0 h1:Tw4GyDXMo+daZN1znreBRC3VayR1aLFUyUEOLUdW1a8= golang.org/x/image v0.40.0/go.mod h1:uIc348UZMSvS5Z65CVZ7iDPaNobNFEPeJ4kbqTOszmA= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -820,9 +811,7 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -841,7 +830,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -857,16 +845,12 @@ golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -915,7 +899,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200928182047-19e03678916f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= @@ -930,12 +913,6 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20260401020348-3a24fdc17823 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20260401020348-3a24fdc17823/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -953,7 +930,6 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -- 2.52.0