From d547bea24a75391eaf14e45c0faa56089c12ba81 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 14:07:02 -0700 Subject: [PATCH 01/10] fix(coderd): reject workspace proxy hostname prefixes (#27544) (#27616) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of https://github.com/coder/coder/pull/27544 Original PR: #27544 — fix(coderd): reject workspace proxy hostname prefixes Merge commit: 8cc7f2bb0e0b33199393cc3773c7d691bd2fbf6b Requested by: @geokat Co-authored-by: George K Co-authored-by: Bobby Ho --- coderd/database/querier_test.go | 52 +++++++++++++++++++++++++++++ coderd/database/queries.sql.go | 2 +- coderd/database/queries/proxies.sql | 2 +- coderd/workspaceapps_test.go | 9 +++++ 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/coderd/database/querier_test.go b/coderd/database/querier_test.go index 5e8571e93b22c..9a453bc2f2f6c 100644 --- a/coderd/database/querier_test.go +++ b/coderd/database/querier_test.go @@ -1841,6 +1841,16 @@ func TestProxyByHostname(t *testing.T) { accessURL: "https://two.coder.com", wildcardHostname: "*--suffix.two.coder.com", }, + { + name: "three", + accessURL: "https://three.coder.com:8443", + wildcardHostname: "*.wildcard.three.coder.com", + }, + { + name: "four", + accessURL: "https://four.coder.com/", + wildcardHostname: "*.wildcard.four.coder.com", + }, } for _, p := range proxies { dbgen.WorkspaceProxy(t, db, database.WorkspaceProxy{ @@ -1871,6 +1881,34 @@ func TestProxyByHostname(t *testing.T) { allowWildcardHost: true, matchProxyName: "one", }, + { + name: "MatchAccessURLWithPort", + testHostname: "three.coder.com", + allowAccessURL: true, + allowWildcardHost: false, + matchProxyName: "three", + }, + { + name: "MatchAccessURLWithTrailingSlash", + testHostname: "four.coder.com", + allowAccessURL: true, + allowWildcardHost: false, + matchProxyName: "four", + }, + { + name: "RejectAccessURLPrefix", + testHostname: "one.coder", + allowAccessURL: true, + allowWildcardHost: false, + matchProxyName: "", + }, + { + name: "RejectAccessURLTLDPrefix", + testHostname: "one.coder.co", + allowAccessURL: true, + allowWildcardHost: false, + matchProxyName: "", + }, { name: "MatchWildcard", testHostname: "something.wildcard.one.coder.com", @@ -1878,6 +1916,13 @@ func TestProxyByHostname(t *testing.T) { allowWildcardHost: true, matchProxyName: "one", }, + { + name: "RejectWildcardHostnamePrefix", + testHostname: "something.wildcard.one.coder", + allowAccessURL: false, + allowWildcardHost: true, + matchProxyName: "", + }, { name: "MatchSuffix", testHostname: "something--suffix.two.coder.com", @@ -1885,6 +1930,13 @@ func TestProxyByHostname(t *testing.T) { allowWildcardHost: true, matchProxyName: "two", }, + { + name: "RejectSuffixHostnamePrefix", + testHostname: "something--suffix.two.coder", + allowAccessURL: false, + allowWildcardHost: true, + matchProxyName: "", + }, { name: "ValidateHostname/1", testHostname: ".*ne.coder.com", diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 2e2e8a919b4c2..f6fe41c028732 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -21702,7 +21702,7 @@ WHERE ( ( $2 :: bool = true AND - url SIMILAR TO '[^:]*://' || $1 :: text || '([:/]?%)*' + url SIMILAR TO '[^:]*://' || $1 :: text || '([:/]%)*' ) OR ( $3 :: bool = true AND diff --git a/coderd/database/queries/proxies.sql b/coderd/database/queries/proxies.sql index df59d3baf107f..cac44de84d4c8 100644 --- a/coderd/database/queries/proxies.sql +++ b/coderd/database/queries/proxies.sql @@ -120,7 +120,7 @@ WHERE ( ( @allow_access_url :: bool = true AND - url SIMILAR TO '[^:]*://' || @hostname :: text || '([:/]?%)*' + url SIMILAR TO '[^:]*://' || @hostname :: text || '([:/]%)*' ) OR ( @allow_wildcard_hostname :: bool = true AND diff --git a/coderd/workspaceapps_test.go b/coderd/workspaceapps_test.go index 8db2858e01e32..db6f77ab95142 100644 --- a/coderd/workspaceapps_test.go +++ b/coderd/workspaceapps_test.go @@ -115,6 +115,15 @@ func TestWorkspaceApplicationAuth(t *testing.T) { redirectURI: "https://proxy.test.coder.com/path", expectRedirect: "https://proxy.test.coder.com/path", }, + { + name: "RejectProxyAccessURLPrefix", + accessURL: "https://test.coder.com", + appHostname: "*.test.coder.com", + proxyURL: "https://proxy.test.coder.com", + proxyAppHostname: "*.proxy.test.coder.com", + redirectURI: "https://proxy.test.coder/path", + expectRedirect: "", + }, { name: "ProxySubdomainOK", accessURL: "https://test.coder.com", From b080be4461d0bae9bf1f1578a08ff7eac4fbebca Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Wed, 5 Aug 2026 21:35:02 +0200 Subject: [PATCH 02/10] fix(coderd): show correct deletion time in dormancy notification (backport #26488) (#27895) Code-only backport of #26488 to `release/2.34`. The dormancy notification's "will be automatically deleted in X" sentence rendered the dormancy threshold (`time_til_dormant`) instead of the auto-delete duration (`time_til_dormant_autodelete`). A 30-day threshold rendered as "4 weeks" even when auto-delete was configured to fire much sooner or later, so users were told the wrong deletion date. Unlike #26488, this backport contains **no migration**. Adding migration 000527 to the 2.34 line would break the migration ordering for deployments that later upgrade. Instead, the stored notification body is left untouched and the existing `timeTilDormant` label is populated with the correct value: - When the template has auto-delete configured, the label carries the countdown derived from the workspace's `deleting_at`, which `UpdateWorkspaceDormantDeletingAt` already computes atomically from `time_til_dormant_autodelete`. - When auto-delete is disabled, `deleting_at` is unset and the sentence cannot be omitted without a body change, so the label falls back to generic wording: "...will be automatically deleted in line with your template's auto-deletion policy if it remains inactive." Upgrading to >= 2.35.1 later applies migration 000527 and the `timeTilDelete` rename as usual; this patch is fully superseded at that point.
Implementation notes - `coderd/autobuild/lifecycle_executor.go`: propagate `wsNew.DeletingAt` onto `ws` after the dormancy UPDATE and humanize it into the `timeTilDormant` label. - `coderd/workspaces.go` (`putWorkspaceDormant`): use `newWorkspace.DeletingAt` for the label; the template fetch that fed the wrong duration is removed. - The label key intentionally stays `timeTilDormant` because the 2.34 notification body (migration 000311) references it; renaming would require a data migration, which this backport deliberately avoids. - No feature flag: the change is a pure correctness fix with no schema or API surface. - Tests adapted from #26488: `TestNotifications/DormancyAutoDelete` (lifecycle executor) and `TestWorkspaceNotifications/Dormant/InitiatorNotOwnerWithAutoDelete` (API path), plus fallback-wording assertions in the existing no-auto-delete tests. Both use a 35-day auto-delete so `humanize.Time` deterministically renders "1 month from now".
--- *This PR was generated by Coder Agents on behalf of @ibetitsmike.* --- coderd/autobuild/lifecycle_executor.go | 8 +-- coderd/autobuild/lifecycle_executor_test.go | 77 +++++++++++++++++++++ coderd/notifications/dormancy.go | 16 +++++ coderd/workspaces.go | 17 +---- coderd/workspaces_test.go | 62 +++++++++++++++++ 5 files changed, 161 insertions(+), 19 deletions(-) create mode 100644 coderd/notifications/dormancy.go diff --git a/coderd/autobuild/lifecycle_executor.go b/coderd/autobuild/lifecycle_executor.go index 60954373c470f..9e7e5dd071f4e 100644 --- a/coderd/autobuild/lifecycle_executor.go +++ b/coderd/autobuild/lifecycle_executor.go @@ -11,7 +11,6 @@ import ( "sync/atomic" "time" - "github.com/dustin/go-humanize" "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -382,8 +381,10 @@ func (e *Executor) runOnce(t time.Time) Stats { Old: wsOld.WorkspaceTable(), New: wsNew, } - // To keep the `ws` accurate without doing a sql fetch + // Keep `ws` accurate without a sql fetch. The UPDATE derives + // deleting_at from the template's time_til_dormant_autodelete. ws.DormantAt = wsNew.DormantAt + ws.DeletingAt = wsNew.DeletingAt shouldNotifyDormancy = true @@ -467,7 +468,6 @@ func (e *Executor) runOnce(t time.Time) Stats { } } if shouldNotifyDormancy { - dormantTime := dbtime.Now().Add(time.Duration(tmpl.TimeTilDormant)) _, err = e.notificationsEnqueuer.Enqueue( e.ctx, ws.OwnerID, @@ -475,7 +475,7 @@ func (e *Executor) runOnce(t time.Time) Stats { map[string]string{ "name": ws.Name, "reason": "inactivity exceeded the dormancy threshold", - "timeTilDormant": humanize.Time(dormantTime), + "timeTilDormant": notifications.DormantDeletionText(ws.DeletingAt), }, "lifecycle_executor", ws.ID, diff --git a/coderd/autobuild/lifecycle_executor_test.go b/coderd/autobuild/lifecycle_executor_test.go index 345647977d663..f3126dc2f712a 100644 --- a/coderd/autobuild/lifecycle_executor_test.go +++ b/coderd/autobuild/lifecycle_executor_test.go @@ -1336,6 +1336,83 @@ func TestNotifications(t *testing.T) { require.Contains(t, sent[0].Targets, workspace.ID) require.Contains(t, sent[0].Targets, workspace.OrganizationID) require.Contains(t, sent[0].Targets, workspace.OwnerID) + + require.Equal(t, "line with your template's auto-deletion policy", sent[0].Labels["timeTilDormant"]) + require.Equal(t, workspace.Name, sent[0].Labels["name"]) + require.Equal(t, "inactivity exceeded the dormancy threshold", sent[0].Labels["reason"]) + }) + + t.Run("DormancyAutoDelete", func(t *testing.T) { + t.Parallel() + + var ( + ticker = make(chan time.Time) + statCh = make(chan autobuild.Stats) + notifyEnq = notificationstest.FakeEnqueuer{} + // 35 days keeps humanize.Time deterministically in its "1 month" bucket. + timeTilDormant = time.Minute + timeTilDormantAutoDelete = 35 * 24 * time.Hour + client, db = coderdtest.NewWithDatabase(t, &coderdtest.Options{ + AutobuildTicker: ticker, + AutobuildStats: statCh, + IncludeProvisionerDaemon: true, + NotificationsEnqueuer: ¬ifyEnq, + TemplateScheduleStore: schedule.MockTemplateScheduleStore{ + SetFn: func(ctx context.Context, db database.Store, template database.Template, options schedule.TemplateScheduleOptions) (database.Template, error) { + template.TimeTilDormant = int64(options.TimeTilDormant) + template.TimeTilDormantAutoDelete = int64(options.TimeTilDormantAutoDelete) + return schedule.NewAGPLTemplateScheduleStore().Set(ctx, db, template, options) + }, + GetFn: func(_ context.Context, _ database.Store, _ uuid.UUID) (schedule.TemplateScheduleOptions, error) { + return schedule.TemplateScheduleOptions{ + UserAutostartEnabled: false, + UserAutostopEnabled: true, + DefaultTTL: 0, + AutostopRequirement: schedule.TemplateAutostopRequirement{}, + TimeTilDormant: timeTilDormant, + TimeTilDormantAutoDelete: timeTilDormantAutoDelete, + }, nil + }, + }, + }) + admin = coderdtest.CreateFirstUser(t, client) + version = coderdtest.CreateTemplateVersion(t, client, admin.OrganizationID, nil) + ) + + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, admin.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { + ctr.TimeTilDormantMillis = ptr.Ref(timeTilDormant.Milliseconds()) + ctr.TimeTilDormantAutoDeleteMillis = ptr.Ref(timeTilDormantAutoDelete.Milliseconds()) + }) + userClient, _ := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID) + workspace := coderdtest.CreateWorkspace(t, userClient, template.ID) + coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, workspace.LatestBuild.ID) + + workspace = coderdtest.MustTransitionWorkspace(t, client, workspace.ID, codersdk.WorkspaceTransitionStart, codersdk.WorkspaceTransitionStop) + _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, workspace.LatestBuild.ID) + + p, err := coderdtest.GetProvisionerForTags(db, time.Now(), workspace.OrganizationID, nil) + require.NoError(t, err) + + notifyEnq.Clear() + tickTime := workspace.LastUsedAt.Add(timeTilDormant * 3) + coderdtest.UpdateProvisionerLastSeenAt(t, db, p.ID, tickTime) + ticker <- tickTime + _ = testutil.TryReceive(testutil.Context(t, testutil.WaitShort), t, statCh) + + workspace = coderdtest.MustWorkspace(t, client, workspace.ID) + require.NotNil(t, workspace.DormantAt) + + sent := notifyEnq.Sent() + require.Len(t, sent, 1) + require.Equal(t, sent[0].TemplateID, notifications.TemplateWorkspaceDormant) + require.Contains(t, sent[0].Labels, "timeTilDormant") + require.Contains(t, sent[0].Labels["timeTilDormant"], "1 month", + "timeTilDormant must humanize TimeTilDormantAutoDelete, got %q", + sent[0].Labels["timeTilDormant"]) + require.NotContains(t, sent[0].Labels["timeTilDormant"], "ago", + "timeTilDormant must be a future timestamp, got %q", + sent[0].Labels["timeTilDormant"]) }) } diff --git a/coderd/notifications/dormancy.go b/coderd/notifications/dormancy.go new file mode 100644 index 0000000000000..236bcd130e996 --- /dev/null +++ b/coderd/notifications/dormancy.go @@ -0,0 +1,16 @@ +package notifications + +import ( + "database/sql" + + "github.com/dustin/go-humanize" +) + +// DormantDeletionText supplies the timeTilDormant label embedded in the stored +// TemplateWorkspaceDormant "will be automatically deleted in ..." sentence. +func DormantDeletionText(deletingAt sql.NullTime) string { + if deletingAt.Valid { + return humanize.Time(deletingAt.Time) + } + return "line with your template's auto-deletion policy" +} diff --git a/coderd/workspaces.go b/coderd/workspaces.go index b812011edca75..2bbaaf5e65b5f 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -12,7 +12,6 @@ import ( "strings" "time" - "github.com/dustin/go-humanize" "github.com/go-chi/chi/v5" "github.com/google/uuid" "golang.org/x/sync/errgroup" @@ -1514,19 +1513,7 @@ func (api *API) putWorkspaceDormant(rw http.ResponseWriter, r *http.Request) { ) } - tmpl, tmplErr := api.Database.GetTemplateByID(ctx, newWorkspace.TemplateID) - if tmplErr != nil { - api.Logger.Warn( - ctx, - "failed to fetch the template of the workspace marked as dormant", - slog.Error(err), - slog.F("workspace_id", newWorkspace.ID), - slog.F("template_id", newWorkspace.TemplateID), - ) - } - - if initiatorErr == nil && tmplErr == nil { - dormantTime := dbtime.Time(now).Add(time.Duration(tmpl.TimeTilDormant)) + if initiatorErr == nil { _, err = api.NotificationsEnqueuer.Enqueue( // nolint:gocritic // Need notifier actor to enqueue notifications dbauthz.AsNotifier(ctx), @@ -1535,7 +1522,7 @@ func (api *API) putWorkspaceDormant(rw http.ResponseWriter, r *http.Request) { map[string]string{ "name": newWorkspace.Name, "reason": "a " + initiator.Username + " request", - "timeTilDormant": humanize.Time(dormantTime), + "timeTilDormant": notifications.DormantDeletionText(newWorkspace.DeletingAt), }, "api", newWorkspace.ID, diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index de7ae93ccf6fa..b2fdbd705081a 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -5156,6 +5156,68 @@ func TestWorkspaceNotifications(t *testing.T) { require.Contains(t, sent[0].Targets, workspace.ID) require.Contains(t, sent[0].Targets, workspace.OrganizationID) require.Contains(t, sent[0].Targets, workspace.OwnerID) + require.Equal(t, "line with your template's auto-deletion policy", sent[0].Labels["timeTilDormant"]) + }) + + t.Run("InitiatorNotOwnerWithAutoDelete", func(t *testing.T) { + t.Parallel() + + // Given + var ( + notifyEnq = ¬ificationstest.FakeEnqueuer{} + // 35 days keeps humanize.Time deterministically in its "1 month" bucket. + timeTilDormantAutoDelete = 35 * 24 * time.Hour + client = coderdtest.New(t, &coderdtest.Options{ + IncludeProvisionerDaemon: true, + NotificationsEnqueuer: notifyEnq, + // The AGPL store ignores TimeTilDormantAutoDelete, so the mock + // writes it to the template row for deleting_at computation. + TemplateScheduleStore: schedule.MockTemplateScheduleStore{ + SetFn: func(ctx context.Context, db database.Store, template database.Template, options schedule.TemplateScheduleOptions) (database.Template, error) { + template.TimeTilDormantAutoDelete = int64(options.TimeTilDormantAutoDelete) + return schedule.NewAGPLTemplateScheduleStore().Set(ctx, db, template, options) + }, + GetFn: func(_ context.Context, _ database.Store, _ uuid.UUID) (schedule.TemplateScheduleOptions, error) { + return schedule.TemplateScheduleOptions{ + UserAutostartEnabled: false, + UserAutostopEnabled: true, + DefaultTTL: 0, + AutostopRequirement: schedule.TemplateAutostopRequirement{}, + TimeTilDormantAutoDelete: timeTilDormantAutoDelete, + }, nil + }, + }, + }) + user = coderdtest.CreateFirstUser(t, client) + memberClient, _ = coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.RoleOwner()) + version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { + ctr.TimeTilDormantAutoDeleteMillis = ptr.Ref[int64](timeTilDormantAutoDelete.Milliseconds()) + }) + workspace = coderdtest.CreateWorkspace(t, client, template.ID) + _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) + ) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + t.Cleanup(cancel) + + // When + err := memberClient.UpdateWorkspaceDormancy(ctx, workspace.ID, codersdk.UpdateWorkspaceDormancy{ + Dormant: true, + }) + + // Then + require.NoError(t, err, "mark workspace as dormant") + sent := notifyEnq.Sent(notificationstest.WithTemplateID(notifications.TemplateWorkspaceDormant)) + require.Len(t, sent, 1) + require.Contains(t, sent[0].Labels, "timeTilDormant") + require.Contains(t, sent[0].Labels["timeTilDormant"], "1 month", + "timeTilDormant must humanize the workspace's deleting_at, got %q", + sent[0].Labels["timeTilDormant"]) + require.NotContains(t, sent[0].Labels["timeTilDormant"], "ago", + "timeTilDormant must be a future timestamp, got %q", + sent[0].Labels["timeTilDormant"]) }) t.Run("InitiatorIsOwner", func(t *testing.T) { From 350070e97dbc252d2cdb62d85e80667f94888ff5 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 6 Aug 2026 02:01:48 +0500 Subject: [PATCH 03/10] fix(site): backport admin settings dropdown visibility fix to release/2.34 (#27851) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of #27481 to `release/2.34`. ## Problem `canViewAnyOrganization` included `viewAnyMembers`, a permission every user now has because of workspace sharing. This meant the Admin settings dropdown (and the Organizations entry within it) showed up for every user, not just admins. ## Fix - Removed `permissions.viewAnyMembers` from `canViewAnyOrganization` in `site/src/modules/permissions/index.ts`. - Updated `site/e2e/tests/roles.spec.ts` to match, including a new regression test for org members with no roles. ## Note on scope Upstream #27481 also refactored `DeploymentDropdown`/`MobileMenu` into a shared `AdminSettings.tsx` component driven by a single permissions object. That refactor doesn't apply to `release/2.34`: this branch's `DeploymentDropdown` and `MobileMenu` already gate the Admin settings menu with equivalent per-permission checks, so only the actual permission fix and its test coverage are backported here. ## Validation - `pnpm exec biome check` on the two changed files: clean. - Confirmed pre-existing `tsc` errors in this branch are unrelated environment/dependency issues (reproduced identically on a clean `release/2.34` checkout). > 🤖 This PR was created with the help of Coder Agents, and needs a human review. 🧑💻 --------- Co-authored-by: Jeremy Ruppel --- site/e2e/tests/roles.spec.ts | 28 +++++++++++++------ .../dashboard/Navbar/DeploymentDropdown.tsx | 9 ++++-- .../modules/dashboard/Navbar/MobileMenu.tsx | 15 ++++++---- site/src/modules/permissions/index.ts | 3 +- 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/site/e2e/tests/roles.spec.ts b/site/e2e/tests/roles.spec.ts index a1d39c7c42a11..973b815991d17 100644 --- a/site/e2e/tests/roles.spec.ts +++ b/site/e2e/tests/roles.spec.ts @@ -61,25 +61,21 @@ test.describe("roles admin settings access", () => { await login(page, users.templateAdmin); await page.goto("/", { waitUntil: "domcontentloaded" }); - await hasAccessToAdminSettings(page, ["Deployment", "Organizations"]); + await hasAccessToAdminSettings(page, ["Deployment"]); }); test("user admin can see admin settings", async ({ page }) => { await login(page, users.userAdmin); await page.goto("/", { waitUntil: "domcontentloaded" }); - await hasAccessToAdminSettings(page, ["Deployment", "Organizations"]); + await hasAccessToAdminSettings(page, ["Deployment"]); }); test("auditor can see admin settings", async ({ page }) => { await login(page, users.auditor); await page.goto("/", { waitUntil: "domcontentloaded" }); - await hasAccessToAdminSettings(page, [ - "Deployment", - "Organizations", - "Audit Logs", - ]); + await hasAccessToAdminSettings(page, ["Deployment", "Audit Logs"]); }); test("owner can see admin settings", async ({ page }) => { @@ -88,7 +84,6 @@ test.describe("roles admin settings access", () => { await hasAccessToAdminSettings(page, [ "Deployment", - "Organizations", "Healthcheck", "Audit Logs", ]); @@ -103,6 +98,23 @@ test.describe("org-scoped roles admin settings access", () => { await setupApiCalls(page); }); + test("member cannot see admin settings", async ({ page }) => { + // The unlicensed member test above cannot catch all regressions here. + // Many admin settings are locked behind a license and wouldn't be shown. + const org = await createOrganization(); + const member = await createOrganizationMember({ + orgRoles: { + [org.id]: [], + }, + }); + + await login(page, member); + await page.goto("/", { waitUntil: "domcontentloaded" }); + + // None, "Admin settings" button should not be visible + await hasAccessToAdminSettings(page, []); + }); + test("org template admin can see admin settings", async ({ page }) => { const org = await createOrganization(); const orgTemplateAdmin = await createOrganizationMember({ diff --git a/site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx b/site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx index 6517feca268ef..fcda1e15a3213 100644 --- a/site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx +++ b/site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx @@ -67,6 +67,7 @@ export const DeploymentDropdown: FC = ({ const DeploymentDropdownContent: FC = ({ canViewDeployment, + canViewOrganizations, canViewAuditLog, canViewConnectionLog, canViewAIBridge, @@ -80,9 +81,11 @@ const DeploymentDropdownContent: FC = ({ Deployment )} - - Organizations - + {canViewOrganizations && ( + + Organizations + + )} {canViewAISettings && ( AI diff --git a/site/src/modules/dashboard/Navbar/MobileMenu.tsx b/site/src/modules/dashboard/Navbar/MobileMenu.tsx index ff498e1ac2a7c..8a8877dba59f8 100644 --- a/site/src/modules/dashboard/Navbar/MobileMenu.tsx +++ b/site/src/modules/dashboard/Navbar/MobileMenu.tsx @@ -208,6 +208,7 @@ const ProxySettingsSub: FC = ({ proxyContextValue }) => { const AdminSettingsSub: FC = ({ canViewDeployment, + canViewOrganizations, canViewAuditLog, canViewConnectionLog, canViewHealth, @@ -239,12 +240,14 @@ const AdminSettingsSub: FC = ({ Deployment )} - - Organizations - + {canViewOrganizations && ( + + Organizations + + )} {canViewAuditLog && ( { return ( permissions !== undefined && - (permissions.viewAnyMembers || - permissions.editAnyGroups || + (permissions.editAnyGroups || permissions.assignAnyRoles || permissions.viewAnyIdpSyncSettings || permissions.editAnySettings) From 85bcd5d3a3d71d2e60be8aa83abee2596850c819 Mon Sep 17 00:00:00 2001 From: Jakub Domeracki Date: Thu, 6 Aug 2026 14:45:00 +0200 Subject: [PATCH 04/10] fix!: require org membership for user ACLs (#26852) (#27884) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of https://github.com/coder/coder/pull/26852 Original PR: #26852 — fix!: require org membership for user ACLs Merge commit: 6b3341aad326cd23e9dfc473aa6592975620aa2d Requested by: @jdomeracki-coder Clean cherry-pick, no conflicts. --- _Opened by Coder Agents on behalf of @jdomeracki-coder._ Co-authored-by: Jon Ayers --- coderd/rbac/authz_internal_test.go | 107 ++++++++++++++++++++++++++++- coderd/rbac/policy.rego | 4 +- 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/coderd/rbac/authz_internal_test.go b/coderd/rbac/authz_internal_test.go index 3d93306017756..163e5d01e09dd 100644 --- a/coderd/rbac/authz_internal_test.go +++ b/coderd/rbac/authz_internal_test.go @@ -312,19 +312,35 @@ func TestAuthorizeDomain(t *testing.T) { testAuthorize(t, "UserACLList", user, []authTestCase{ { - resource: ResourceWorkspace.WithOwner(unusedID.String()).InOrg(unusedID).WithACLUserList(map[string][]policy.Action{ + resource: ResourceWorkspace.WithOwner(unusedID.String()).InOrg(defOrg).WithACLUserList(map[string][]policy.Action{ user.ID: ResourceWorkspace.AvailableActions(), }), actions: ResourceWorkspace.AvailableActions(), allow: true, }, { - resource: ResourceWorkspace.WithOwner(unusedID.String()).InOrg(unusedID).WithACLUserList(map[string][]policy.Action{ + resource: ResourceWorkspace.WithOwner(unusedID.String()).InOrg(defOrg).WithACLUserList(map[string][]policy.Action{ user.ID: {policy.WildcardSymbol}, }), actions: ResourceWorkspace.AvailableActions(), allow: true, }, + { + // User ACLs only grant permissions in organizations where the + // subject is currently a member. + resource: ResourceWorkspace.WithOwner(unusedID.String()).InOrg(unusedID).WithACLUserList(map[string][]policy.Action{ + user.ID: ResourceWorkspace.AvailableActions(), + }), + actions: ResourceWorkspace.AvailableActions(), + allow: false, + }, + { + resource: ResourceWorkspace.WithOwner(unusedID.String()).InOrg(unusedID).WithACLUserList(map[string][]policy.Action{ + user.ID: {policy.WildcardSymbol}, + }), + actions: ResourceWorkspace.AvailableActions(), + allow: false, + }, { resource: ResourceWorkspace.WithOwner(unusedID.String()).InOrg(unusedID).WithACLUserList(map[string][]policy.Action{ user.ID: {policy.ActionRead, policy.ActionUpdate}, @@ -714,6 +730,93 @@ func TestAuthorizeDomain(t *testing.T) { })) } +// TestAuthorizeUserACLOrgMembership verifies that user ACL grants require org +// membership, while site-wide roles still authorize independent of ACLs. +func TestAuthorizeUserACLOrgMembership(t *testing.T) { + t.Parallel() + + orgID := uuid.New() + + // Site template-admin, not a member of orgID. + siteTemplateAdmin := Subject{ + ID: "site-template-admin", + Scope: must(ExpandScope(ScopeAll)), + Roles: Roles{ + must(RoleByName(RoleMember())), + must(RoleByName(RoleTemplateAdmin())), + }, + } + testAuthorize(t, "SiteTemplateAdminNotInOrg", siteTemplateAdmin, []authTestCase{ + { + // Authorized by the site role, no ACL needed. + resource: ResourceTemplate.InOrg(orgID), + actions: []policy.Action{policy.ActionUpdate}, + allow: true, + }, + { + // Redundant ACL entry; still authorized by the site role. + resource: ResourceTemplate.InOrg(orgID).WithACLUserList(map[string][]policy.Action{ + siteTemplateAdmin.ID: {policy.ActionUpdate}, + }), + actions: []policy.Action{policy.ActionUpdate}, + allow: true, + }, + }) + + // Site user-admin (no template perms), not a member of orgID. + siteUserAdmin := Subject{ + ID: "site-user-admin", + Scope: must(ExpandScope(ScopeAll)), + Roles: Roles{ + must(RoleByName(RoleMember())), + must(RoleByName(RoleUserAdmin())), + }, + } + testAuthorize(t, "SiteUserAdminNotInOrg", siteUserAdmin, []authTestCase{ + { + // No template role and no ACL entry: denied. + resource: ResourceTemplate.InOrg(orgID), + actions: []policy.Action{policy.ActionUpdate}, + allow: false, + }, + { + // An ACL grant must not authorize a non-member. + resource: ResourceTemplate.InOrg(orgID).WithACLUserList(map[string][]policy.Action{ + siteUserAdmin.ID: {policy.ActionUpdate}, + }), + actions: []policy.Action{policy.ActionUpdate}, + allow: false, + }, + }) + + // Same site user-admin, now also a member of orgID. + siteUserAdminOrgMember := Subject{ + ID: "site-user-admin-org-member", + Scope: must(ExpandScope(ScopeAll)), + Roles: Roles{ + must(RoleByName(RoleMember())), + must(RoleByName(RoleUserAdmin())), + orgMemberRole(orgID), + }, + } + testAuthorize(t, "SiteUserAdminOrgMember", siteUserAdminOrgMember, []authTestCase{ + { + // Org membership alone does not grant template update. + resource: ResourceTemplate.InOrg(orgID), + actions: []policy.Action{policy.ActionUpdate}, + allow: false, + }, + { + // As an org member, the ACL grant takes effect. + resource: ResourceTemplate.InOrg(orgID).WithACLUserList(map[string][]policy.Action{ + siteUserAdminOrgMember.ID: {policy.ActionUpdate}, + }), + actions: []policy.Action{policy.ActionUpdate}, + allow: true, + }, + }) +} + // TestAuthorizeLevels ensures level overrides are acting appropriately func TestAuthorizeLevels(t *testing.T) { t.Parallel() diff --git a/coderd/rbac/policy.rego b/coderd/rbac/policy.rego index e8844a22bdbd8..0a15955badd0f 100644 --- a/coderd/rbac/policy.rego +++ b/coderd/rbac/policy.rego @@ -330,7 +330,9 @@ object_is_included_in_scope_allow_list if { # ACL for users acl_allow if { - # TODO: Should you have to be a member of the org too? + # The subject must be a member of the object's organization for a + # user ACL grant to apply. + is_org_member perms := input.object.acl_user_list[input.subject.id] # Check if either the action or * is allowed From c15ae01435c4cdf1c4df9140d555874e5c681651 Mon Sep 17 00:00:00 2001 From: Jakub Domeracki Date: Thu, 6 Aug 2026 14:45:24 +0200 Subject: [PATCH 05/10] fix: redact env var values in agent debug manifest endpoint (#26904) (#27880) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of https://github.com/coder/coder/pull/26904 Original PR: #26904 — fix: redact env var values in agent debug manifest endpoint Merge commit: b33ff2d8514fd798a4e1610e1ca86a7aa448a266 Requested by: @jdomeracki-coder
Conflict resolution notes The cherry-pick conflicted in `agent/agent.go` because the new `redactedManifestEnvValue` constant landed where `release/2.34` has the `HandleHTTPDebugLogs` handler. Resolved by keeping both: the existing handler and the new constant. The manifest env-redaction block applied cleanly. The `./agent/...` package builds successfully.
--- _Opened by Coder Agents on behalf of @jdomeracki-coder._ Co-authored-by: Jon Ayers --- agent/agent.go | 24 +++++++++++++++++++++++- agent/agent_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/agent/agent.go b/agent/agent.go index 33ad83c804d8b..c598de819e7bd 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -2148,8 +2148,26 @@ func (a *agent) HandleHTTPDebugManifest(w http.ResponseWriter, r *http.Request) return } + // Redact env values. This endpoint is unauthenticated on loopback, + // reachable by any process regardless of Unix user. Keys are preserved + // so operators can still see which variables are configured. + debugManifest := *sdkManifest + if len(sdkManifest.EnvironmentVariables) > 0 { + envs := make(map[string]string, len(sdkManifest.EnvironmentVariables)) + for k, v := range sdkManifest.EnvironmentVariables { + // Preserve empty values, which carry no secret, matching + // sanitizeEnv in support/support.go. + if v == "" { + envs[k] = v + continue + } + envs[k] = redactedManifestEnvValue + } + debugManifest.EnvironmentVariables = envs + } + w.WriteHeader(http.StatusOK) - if err := json.NewEncoder(w).Encode(sdkManifest); err != nil { + if err := json.NewEncoder(w).Encode(debugManifest); err != nil { a.logger.Error(a.hardCtx, "write debug manifest", slog.Error(err)) } } @@ -2174,6 +2192,10 @@ func (a *agent) HandleHTTPDebugLogs(w http.ResponseWriter, r *http.Request) { } } +// redactedManifestEnvValue matches the marker used by sanitizeEnv in +// support/support.go so a support bundle and this endpoint agree. +const redactedManifestEnvValue = "***REDACTED***" + func (a *agent) HTTPDebug() http.Handler { r := chi.NewRouter() diff --git a/agent/agent_test.go b/agent/agent_test.go index 1fe8ad2725b22..7412338404f91 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -3519,6 +3519,10 @@ func TestAgent_DebugServer(t *testing.T) { //nolint:dogsled conn, _, _, _, agnt := setupAgentWithSecrets(t, agentsdk.Manifest{ DERPMap: derpMap, + EnvironmentVariables: map[string]string{ + "AWS_SECRET_ACCESS_KEY": "env-value-should-be-redacted-67890", + "EMPTY_VAR": "", + }, }, []agentsdk.WorkspaceSecret{ {EnvName: "DEBUG_SECRET", Value: []byte("super-secret-value-12345")}, }, 0, func(c *agenttest.Client, o *agent.Options) { @@ -3647,6 +3651,34 @@ func TestAgent_DebugServer(t *testing.T) { require.NoError(t, json.Unmarshal(body, &v)) }) + t.Run("ManifestEnvVarValuesRedacted", func(t *testing.T) { + t.Parallel() + + ctx := testutil.Context(t, testutil.WaitLong) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL+"/debug/manifest", nil) + require.NoError(t, err) + + res, err := srv.Client().Do(req) + require.NoError(t, err) + defer res.Body.Close() + require.Equal(t, http.StatusOK, res.StatusCode) + + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + + require.NotContains(t, string(body), "env-value-should-be-redacted-67890") + + var v agentsdk.Manifest + require.NoError(t, json.Unmarshal(body, &v)) + + require.Contains(t, v.EnvironmentVariables, "AWS_SECRET_ACCESS_KEY") + require.Equal(t, "***REDACTED***", v.EnvironmentVariables["AWS_SECRET_ACCESS_KEY"]) + + // Empty values carry no secret and are preserved as empty. + require.Contains(t, v.EnvironmentVariables, "EMPTY_VAR") + require.Equal(t, "", v.EnvironmentVariables["EMPTY_VAR"]) + }) + t.Run("Logs", func(t *testing.T) { t.Parallel() From 5c059ba989eacaaa5301ab53c946f245d0cfd1b8 Mon Sep 17 00:00:00 2001 From: Jakub Domeracki Date: Thu, 6 Aug 2026 14:45:27 +0200 Subject: [PATCH 06/10] fix: prevent open redirect in proxy authentication flow (#26647) (#27881) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of https://github.com/coder/coder/pull/26647 Original PR: #26647 — fix: prevent open redirect in proxy authentication flow Merge commit: 7e7a6b4f189532e9802270eb8286f94680e64403 Requested by: @jdomeracki-coder Clean cherry-pick, no conflicts. --- _Opened by Coder Agents on behalf of @jdomeracki-coder._ Co-authored-by: Jon Ayers --- coderd/workspaceapps/proxy.go | 48 +++-- coderd/workspaceapps/proxy_internal_test.go | 117 ++++++++++++ coderd/workspaceapps/proxy_test.go | 190 +++++++++++++++----- 3 files changed, 294 insertions(+), 61 deletions(-) create mode 100644 coderd/workspaceapps/proxy_internal_test.go diff --git a/coderd/workspaceapps/proxy.go b/coderd/workspaceapps/proxy.go index c90d4833fe97f..dfd8bff0b787d 100644 --- a/coderd/workspaceapps/proxy.go +++ b/coderd/workspaceapps/proxy.go @@ -165,6 +165,18 @@ func (s *Server) Attach(r chi.Router) { r.Get("/api/v2/workspaceagents/{workspaceagent}/pty", s.workspaceAgentPTY) } +// originLocalURL returns p as a relative URL rooted at the current origin, +// safe to use as a redirect Location. p (typically r.URL.Path) is +// attacker-controlled and already percent-decoded, so a leading "//" or "/\" +// run would otherwise be parsed by http.Redirect or a browser as a +// scheme-relative URL pointing at another host, turning a redirect back to the +// same path into an open redirect. Collapsing the leading slash and backslash +// run to a single "/" keeps the result same-origin, and url.URL.String() +// percent-encodes any control characters in the path. +func originLocalURL(p string) *url.URL { + return &url.URL{Path: "/" + strings.TrimLeft(p, `/\`)} +} + // handleAPIKeySmuggling is called by the proxy path and subdomain handlers to // process any "smuggled" API keys in the query parameters. // @@ -265,19 +277,17 @@ func (s *Server) handleAPIKeySmuggling(rw http.ResponseWriter, r *http.Request, HttpOnly: true, })) - // Strip the query parameter. - path := r.URL.Path - if path == "" { - path = "/" - } + // Strip the smuggled API key query parameter and redirect back to the same + // path. r.URL.Path is attacker-controlled and can smuggle a separate host + // (e.g. "//evil.com"); originLocalURL keeps the redirect on the current + // origin. + redirectURL := originLocalURL(r.URL.Path) + q := r.URL.Query() q.Del(SubdomainProxyAPIKeyParam) - rawQuery := q.Encode() - if rawQuery != "" { - path += "?" + q.Encode() - } + redirectURL.RawQuery = q.Encode() - http.Redirect(rw, r, path, http.StatusSeeOther) + http.Redirect(rw, r, redirectURL.String(), http.StatusSeeOther) return false } @@ -615,7 +625,14 @@ func (s *Server) proxyWorkspaceApp(rw http.ResponseWriter, r *http.Request, appT // Web applications typically request paths relative to the // root URL. This allows for routing behind a proxy or subpath. // See https://github.com/coder/code-server/issues/241 for examples. - http.Redirect(rw, r, r.URL.Path+"/", http.StatusTemporaryRedirect) + // + // r.URL.Path is attacker-controlled, so sanitize it before redirecting + // to avoid an off-origin "//host" Location (see originLocalURL). + redirectURL := originLocalURL(r.URL.Path) + if !strings.HasSuffix(redirectURL.Path, "/") { + redirectURL.Path += "/" + } + http.Redirect(rw, r, redirectURL.String(), http.StatusTemporaryRedirect) return } if path == "/" && r.URL.RawQuery == "" && appURL.RawQuery != "" { @@ -624,8 +641,13 @@ func (s *Server) proxyWorkspaceApp(rw http.ResponseWriter, r *http.Request, appT // query parameters for server-side requests, but sometimes // client-side applications require the query parameters to render // properly. With code-server, this is the "folder" param. - r.URL.RawQuery = appURL.RawQuery - http.Redirect(rw, r, r.URL.String(), http.StatusTemporaryRedirect) + // + // r.URL.Path is attacker-controlled, so build the Location from a + // sanitized same-origin path instead of r.URL directly (see + // originLocalURL). + redirectURL := originLocalURL(r.URL.Path) + redirectURL.RawQuery = appURL.RawQuery + http.Redirect(rw, r, redirectURL.String(), http.StatusTemporaryRedirect) return } diff --git a/coderd/workspaceapps/proxy_internal_test.go b/coderd/workspaceapps/proxy_internal_test.go new file mode 100644 index 0000000000000..cde66026f3f4d --- /dev/null +++ b/coderd/workspaceapps/proxy_internal_test.go @@ -0,0 +1,117 @@ +package workspaceapps + +import ( + "net/url" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +// Test_originLocalURL checks that originLocalURL produces a redirect target that +// stays on the current origin. +func Test_originLocalURL(t *testing.T) { + t.Parallel() + + t.Run("RejectsOffOrigin", func(t *testing.T) { + t.Parallel() + + // Each path models an already-percent-decoded r.URL.Path that tries to + // smuggle a separate host into the redirect. + cases := []struct { + name string + path string + }{ + {name: "DoubleSlash", path: "//evil.com/phish"}, + {name: "TripleSlash", path: "///evil.com/phish"}, + {name: "SlashBackslash", path: "/\\evil.com/phish"}, + {name: "SlashBackslashSlash", path: "/\\/evil.com/phish"}, + {name: "DoubleBackslash", path: "\\\\evil.com/phish"}, + {name: "SlashTab", path: "/\t/evil.com/phish"}, + {name: "SlashTabBackslash", path: "/\t\\evil.com/phish"}, + {name: "SlashNewline", path: "/\n/evil.com/phish"}, + {name: "SlashCarriageReturn", path: "/\r/evil.com/phish"}, + {name: "SlashTabDoubleSlash", path: "/\t//evil.com/phish"}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + loc := originLocalURL(tc.path).String() + + // The Location must parse as a relative, same-origin reference. + require.Falsef(t, strings.HasPrefix(loc, "//"), + "path %q produced scheme-relative Location %q", tc.path, loc) + parsed, err := url.Parse(loc) + require.NoErrorf(t, err, "path %q produced unparseable Location %q", tc.path, loc) + require.Emptyf(t, parsed.Scheme, "path %q produced Location %q with a scheme", tc.path, loc) + require.Emptyf(t, parsed.Host, "path %q produced Location %q with a host", tc.path, loc) + + // It must also be free of raw bytes a browser would normalize back + // into an authority before resolving (a backslash becomes "/", and + // tab/newline/CR are stripped, either of which could re-form + // "//host"). url.URL.String() guarantees this by percent-encoding + // them; we assert it here rather than reproducing browser + // normalization in the code. + for _, raw := range []string{`\`, "\t", "\n", "\r"} { + require.NotContainsf(t, loc, raw, + "path %q produced Location %q containing a raw %q", tc.path, loc, raw) + } + }) + } + }) + + t.Run("EscapesControlCharacters", func(t *testing.T) { + t.Parallel() + + // A redirect built from a path containing a raw control character is an + // open redirect: http.Redirect emits it verbatim (url.Parse rejects the + // control byte and skips cleaning) and browsers strip tab/newline/CR + // before resolving, re-forming "//evil.com". originLocalURL percent-encodes + // each one. Assert every class is escaped so a future change that breaks + // encoding for only one class is caught. + cases := []struct { + name string + in string + want string + }{ + {name: "Tab", in: "/\t/evil.com", want: "/%09/evil.com"}, + {name: "Newline", in: "/\n/evil.com", want: "/%0A/evil.com"}, + {name: "CarriageReturn", in: "/\r/evil.com", want: "/%0D/evil.com"}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + require.Equalf(t, tc.want, originLocalURL(tc.in).String(), + "originLocalURL(%q) must percent-encode the control character", tc.in) + }) + } + }) + + t.Run("PreservesLegitPaths", func(t *testing.T) { + t.Parallel() + + cases := []struct { + name string + in string + want string + }{ + {name: "Empty", in: "", want: "/"}, + {name: "Root", in: "/", want: "/"}, + {name: "Simple", in: "/test", want: "/test"}, + {name: "Nested", in: "/app/sub/page", want: "/app/sub/page"}, + {name: "PathApp", in: "/@user/ws/apps/app", want: "/@user/ws/apps/app"}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + require.Equalf(t, tc.want, originLocalURL(tc.in).String(), "originLocalURL(%q)", tc.in) + }) + } + }) +} diff --git a/coderd/workspaceapps/proxy_test.go b/coderd/workspaceapps/proxy_test.go index 8678614243c3d..cd180b328970c 100644 --- a/coderd/workspaceapps/proxy_test.go +++ b/coderd/workspaceapps/proxy_test.go @@ -8,12 +8,15 @@ import ( "net/http" "net/http/httptest" "net/url" + "strings" "testing" + "time" "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" + "github.com/coder/coder/v2/coderd/jwtutils" "github.com/coder/coder/v2/coderd/workspaceapps" "github.com/coder/coder/v2/coderd/workspaceapps/appurl" "github.com/coder/coder/v2/testutil" @@ -34,57 +37,148 @@ func (s *fakeSignedTokenProvider) Issue(_ context.Context, _ http.ResponseWriter return nil, "", false } -func TestHandleSubdomain_IgnoresUntrustedForwardedHost(t *testing.T) { +func TestHandleSubdomain(t *testing.T) { t.Parallel() - hostnamePattern := "*--apps.test.coder.com" - hostnameRegex, err := appurl.CompileHostnamePattern(hostnamePattern) - require.NoError(t, err) - - dashboardURL, err := url.Parse("https://dashboard.test.coder.com") - require.NoError(t, err) - - provider := &fakeSignedTokenProvider{} - srv := workspaceapps.NewServer(workspaceapps.ServerOptions{ - Logger: testutil.Logger(t), - DashboardURL: dashboardURL, - AccessURL: dashboardURL, - Hostname: hostnamePattern, - HostnameRegex: hostnameRegex, - RealIPConfig: &httpmw.RealIPConfig{ - TrustedOrigins: []*net.IPNet{{ - IP: net.ParseIP("10.0.0.1"), - Mask: net.CIDRMask(32, 32), - }}, - }, - SignedTokenProvider: provider, + t.Run("IgnoresUntrustedForwardedHost", func(t *testing.T) { + t.Parallel() + + hostnamePattern := "*--apps.test.coder.com" + hostnameRegex, err := appurl.CompileHostnamePattern(hostnamePattern) + require.NoError(t, err) + + dashboardURL, err := url.Parse("https://dashboard.test.coder.com") + require.NoError(t, err) + + provider := &fakeSignedTokenProvider{} + srv := workspaceapps.NewServer(workspaceapps.ServerOptions{ + Logger: testutil.Logger(t), + DashboardURL: dashboardURL, + AccessURL: dashboardURL, + Hostname: hostnamePattern, + HostnameRegex: hostnameRegex, + RealIPConfig: &httpmw.RealIPConfig{ + TrustedOrigins: []*net.IPNet{{ + IP: net.ParseIP("10.0.0.1"), + Mask: net.CIDRMask(32, 32), + }}, + }, + SignedTokenProvider: provider, + }) + + forgedHost := appurl.ApplicationURL{ + AppSlugOrPort: "app", + WorkspaceName: "workspace", + Username: "victim", + }.String() + "--apps.test.coder.com" + + nextCalled := false + next := http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { + nextCalled = true + }) + + // Given: a request with a forged X-Forwarded-Host set to a valid + // app hostname, and an immediate peer outside the trusted proxy + // config. + req := httptest.NewRequest(http.MethodGet, "https://dashboard.test.coder.com/", nil) + req.Header.Set(httpapi.XForwardedHostHeader, forgedHost) + req.RemoteAddr = "17.18.19.20:1234" + + // When: HandleSubdomain runs. + srv.HandleSubdomain()(next).ServeHTTP(httptest.NewRecorder(), req) + + // Then: it ignores untrusted X-Forwarded-Host, so the received + // dashboard host is used, the request falls through to the next + // handler, and the signed app token provider is never called. + require.True(t, nextCalled) + require.Zero(t, provider.fromRequestCalls) + require.Zero(t, provider.issueCalls) }) - forgedHost := appurl.ApplicationURL{ - AppSlugOrPort: "app", - WorkspaceName: "workspace", - Username: "victim", - }.String() + "--apps.test.coder.com" - - nextCalled := false - next := http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { - nextCalled = true + // After consuming a smuggled API key, the handler redirects to strip the key. + // A path that smuggles a separate host (e.g. "//evil.com") must redirect back + // to the current origin, not off-site. The full path-sanitization matrix lives + // in Test_originLocalURL. + t.Run("APIKeySmugglingStaysOnOrigin", func(t *testing.T) { + t.Parallel() + + ctx := testutil.Context(t, testutil.WaitShort) + + hostnamePattern := "*--apps.test.coder.com" + hostnameRegex, err := appurl.CompileHostnamePattern(hostnamePattern) + require.NoError(t, err) + + dashboardURL, err := url.Parse("https://dashboard.test.coder.com") + require.NoError(t, err) + + // StaticKey lets us mint a smuggled key the handler can decrypt. + // A256GCMKW needs a 32-byte key. + keycache := jwtutils.StaticKey{ID: "test", Key: generateSecret(t, 32)} + payload := workspaceapps.EncryptedAPIKeyPayload{APIKey: "fake-api-key"} + payload.Fill(time.Now()) + encryptedAPIKey, err := jwtutils.Encrypt(ctx, keycache, payload) + require.NoError(t, err) + + srv := workspaceapps.NewServer(workspaceapps.ServerOptions{ + Logger: testutil.Logger(t), + DashboardURL: dashboardURL, + AccessURL: dashboardURL, + Hostname: hostnamePattern, + HostnameRegex: hostnameRegex, + RealIPConfig: &httpmw.RealIPConfig{ + TrustedOrigins: []*net.IPNet{{ + IP: net.ParseIP("10.0.0.1"), + Mask: net.CIDRMask(32, 32), + }}, + }, + SignedTokenProvider: &fakeSignedTokenProvider{}, + APIKeyEncryptionKeycache: keycache, + }) + + host := appurl.ApplicationURL{ + AppSlugOrPort: "app", + WorkspaceName: "workspace", + Username: "user", + }.String() + "--apps.test.coder.com" + + // Set r.URL.Path directly: the slash-collapsing middleware writes to chi's + // RoutePath, not r.URL.Path, so the raw "//evil.com" survives to the handler. + // "x=1" rides along to confirm unrelated params are preserved. + req := httptest.NewRequest(http.MethodGet, "https://"+host+"/", nil) + req.Host = host + req.RemoteAddr = "10.0.0.1:1234" + req.URL.Path = "//evil.com/phish" + req.URL.RawQuery = url.Values{ + workspaceapps.SubdomainProxyAPIKeyParam: {encryptedAPIKey}, + "x": {"1"}, + }.Encode() + + rec := httptest.NewRecorder() + nextCalled := false + next := http.HandlerFunc(func(http.ResponseWriter, *http.Request) { + nextCalled = true + }) + + srv.HandleSubdomain()(next).ServeHTTP(rec, req) + + res := rec.Result() + defer res.Body.Close() + + // The key is consumed and a redirect is issued instead of proxying. + require.Equal(t, http.StatusSeeOther, res.StatusCode) + require.False(t, nextCalled) + + loc := res.Header.Get("Location") + require.NotEmpty(t, loc) + require.False(t, strings.HasPrefix(loc, "//"), "redirect %q must stay same-origin", loc) + + parsed, err := url.Parse(loc) + require.NoError(t, err) + require.Empty(t, parsed.Scheme, "redirect %q must not carry a scheme", loc) + require.Empty(t, parsed.Host, "redirect %q must not carry a host", loc) + + // The smuggled key is stripped and unrelated query params survive. + require.Empty(t, parsed.Query().Get(workspaceapps.SubdomainProxyAPIKeyParam)) + require.Equal(t, "1", parsed.Query().Get("x")) }) - - // Given: a request with a forged X-Forwarded-Host set to a valid - // app hostname, and an immediate peer outside the trusted proxy - // config. - req := httptest.NewRequest(http.MethodGet, "https://dashboard.test.coder.com/", nil) - req.Header.Set(httpapi.XForwardedHostHeader, forgedHost) - req.RemoteAddr = "17.18.19.20:1234" - - // When: HandleSubdomain runs. - srv.HandleSubdomain()(next).ServeHTTP(httptest.NewRecorder(), req) - - // Then: it ignores untrusted X-Forwarded-Host, so the received - // dashboard host is used, the request falls through to the next - // handler, and the signed app token provider is never called. - require.True(t, nextCalled) - require.Zero(t, provider.fromRequestCalls) - require.Zero(t, provider.issueCalls) } From d70055a0fa9c2dbea85229b533a8533f6aafc44c Mon Sep 17 00:00:00 2001 From: Jakub Domeracki Date: Thu, 6 Aug 2026 14:45:33 +0200 Subject: [PATCH 07/10] fix: only return group member count for workspace acl (#26206) (#27882) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of https://github.com/coder/coder/pull/26206 Original PR: #26206 — fix: only return group member count for workspace acl Merge commit: c7ddcce62c80a3128bed6728cf29dc6a29d1a105 Requested by: @jdomeracki-coder Clean cherry-pick, no conflicts. --- _Opened by Coder Agents on behalf of @jdomeracki-coder._ Co-authored-by: Jon Ayers --- cli/sharing.go | 15 +++---- cli/sharing_test.go | 42 +++++++++++++++++++ coderd/workspaces.go | 58 +++++++++++++------------ enterprise/cli/sharing_test.go | 7 +++- enterprise/coderd/workspaces_test.go | 63 ++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 35 deletions(-) diff --git a/cli/sharing.go b/cli/sharing.go index 61428d3b37243..61c0f75dd3089 100644 --- a/cli/sharing.go +++ b/cli/sharing.go @@ -312,13 +312,14 @@ func workspaceACLToTable(ctx context.Context, acl *codersdk.WorkspaceACL) (strin continue } - for _, user := range group.Members { - outputRows = append(outputRows, workspaceShareRow{ - User: user.Username, - Group: group.Name, - Role: group.Role, - }) - } + // The ACL endpoint intentionally omits the group's member roster to + // avoid leaking member PII, so we display one row per group rather + // than one row per member. + outputRows = append(outputRows, workspaceShareRow{ + User: defaultGroupDisplay, + Group: group.Name, + Role: group.Role, + }) } out, err := formatter.Format(ctx, outputRows) if err != nil { diff --git a/cli/sharing_test.go b/cli/sharing_test.go index 26ad858d09ff0..fa8026554dfed 100644 --- a/cli/sharing_test.go +++ b/cli/sharing_test.go @@ -205,6 +205,48 @@ func TestSharingStatus(t *testing.T) { } assert.True(t, found, "expected to find username %s with role %s in the output: %s", toShareWithUser.Username, codersdk.WorkspaceRoleUse, out.String()) }) + + t.Run("ListSharedGroups", func(t *testing.T) { + t.Parallel() + + var ( + client, db = coderdtest.NewWithDatabase(t, nil) + orgOwner = coderdtest.CreateFirstUser(t, client) + workspaceOwnerClient, workspaceOwner = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID, rbac.ScopedRoleOrgAuditor(orgOwner.OrganizationID)) + workspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ + OwnerID: workspaceOwner.ID, + OrganizationID: orgOwner.OrganizationID, + }).Do().Workspace + ctx = testutil.Context(t, testutil.WaitMedium) + ) + + // The Everyone group always exists for an organization and shares the + // organization's ID. The workspace ACL endpoint no longer returns the + // group's member roster, so the CLI must still list the group itself. + err := client.UpdateWorkspaceACL(ctx, workspace.ID, codersdk.UpdateWorkspaceACL{ + GroupRoles: map[string]codersdk.WorkspaceRole{ + orgOwner.OrganizationID.String(): codersdk.WorkspaceRoleUse, + }, + }) + require.NoError(t, err) + + inv, root := clitest.New(t, "sharing", "status", workspace.Name) + clitest.SetupConfig(t, workspaceOwnerClient, root) + + out := new(bytes.Buffer) + inv.Stdout = out + err = inv.WithContext(ctx).Run() + require.NoError(t, err) + + found := false + for _, line := range strings.Split(out.String(), "\n") { + if strings.Contains(line, database.EveryoneGroup) && strings.Contains(line, string(codersdk.WorkspaceRoleUse)) { + found = true + break + } + } + assert.True(t, found, "expected to find group %s with role %s in the output: %s", database.EveryoneGroup, codersdk.WorkspaceRoleUse, out.String()) + }) } func TestSharingRemove(t *testing.T) { diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 2bbaaf5e65b5f..337c0aa9447d8 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -2372,13 +2372,13 @@ func (api *API) workspaceACL(rw http.ResponseWriter, r *http.Request) { return } - // This is largely based on the template ACL implementation, and is far from - // ideal. Usually, when we use the System context it's because we need to - // run some query that won't actually be exposed to the user. That is not - // the case here. This data goes directly to an unauthorized user. We are - // just straight up breaking security promises. - // - // TODO: This needs to be fixed before GA. Currently in beta. + // Callers are authorized to read this workspace, not necessarily the + // users and groups on its ACL. We deliberately use the System context to + // look up that data, but only return minimal identity information that is + // safe to expose to anyone who can read the ACL: MinimalUser for ACL users + // (no email or other PII) and group identity plus a member count for ACL + // groups (no member roster). This mirrors the chat ACL and template + // available-ACL endpoints. // Fetch all of the users and their organization memberships userIDs := make([]uuid.UUID, 0, len(workspaceACL.Users)) @@ -2390,7 +2390,8 @@ func (api *API) workspaceACL(rw http.ResponseWriter, r *http.Request) { } userIDs = append(userIDs, id) } - // For context see https://github.com/coder/coder/pull/19375 + // ACL users are returned as MinimalUser, which contains no PII, so it is + // safe to fetch them under the System context. // nolint:gocritic dbUsers, err := api.Database.GetUsersByIDs(dbauthz.AsSystemRestricted(ctx), userIDs) if err != nil && !xerrors.Is(err, sql.ErrNoRows) { @@ -2422,7 +2423,8 @@ func (api *API) workspaceACL(rw http.ResponseWriter, r *http.Request) { // before making the DB call. dbGroups := make([]database.GetGroupsRow, 0) if len(groupIDs) > 0 { - // For context see https://github.com/coder/coder/pull/19375 + // Group identity must be visible to anyone who can read the ACL so + // that owners and shared users can see and manage entries. // nolint:gocritic dbGroups, err = api.Database.GetGroups(dbauthz.AsSystemRestricted(ctx), database.GetGroupsParams{GroupIds: groupIDs}) if err != nil && !xerrors.Is(err, sql.ErrNoRows) { @@ -2431,26 +2433,30 @@ func (api *API) workspaceACL(rw http.ResponseWriter, r *http.Request) { } } + // Fetch member counts for all groups in a single query to avoid an N+1 + // lookup. We intentionally do not populate the per-group member rosters: + // callers authorized to read the ACL are not necessarily authorized to + // read group membership, and the roster includes member PII. Only the + // total member count is returned (see Group.TotalMemberCount). + // nolint:gocritic + countRows, err := api.Database.GetGroupMembersCountByGroupIDs(dbauthz.AsSystemRestricted(ctx), database.GetGroupMembersCountByGroupIDsParams{ + GroupIds: groupIDs, + IncludeSystem: false, + }) + if err != nil && !xerrors.Is(err, sql.ErrNoRows) { + httpapi.InternalServerError(rw, err) + return + } + countByGroup := make(map[uuid.UUID]int64, len(countRows)) + for _, row := range countRows { + countByGroup[row.GroupID] = row.MemberCount + } + groups := make([]codersdk.WorkspaceGroup, 0, len(dbGroups)) for _, it := range dbGroups { - var members []database.GroupMember - // For context see https://github.com/coder/coder/pull/19375 - // nolint:gocritic - members, err = api.Database.GetGroupMembersByGroupID(dbauthz.AsSystemRestricted(ctx), database.GetGroupMembersByGroupIDParams{ - GroupID: it.Group.ID, - IncludeSystem: false, - }) - if err != nil { - httpapi.InternalServerError(rw, err) - return - } groups = append(groups, codersdk.WorkspaceGroup{ - Group: db2sdk.Group(database.GetGroupsRow{ - Group: it.Group, - OrganizationName: it.OrganizationName, - OrganizationDisplayName: it.OrganizationDisplayName, - }, members, len(members)), - Role: convertToWorkspaceRole(workspaceACL.Groups[it.Group.ID.String()].Permissions), + Group: db2sdk.Group(it, nil, int(countByGroup[it.Group.ID])), + Role: convertToWorkspaceRole(workspaceACL.Groups[it.Group.ID.String()].Permissions), }) } diff --git a/enterprise/cli/sharing_test.go b/enterprise/cli/sharing_test.go index 6e1e3c8dd4ff8..c972cd6cd9e10 100644 --- a/enterprise/cli/sharing_test.go +++ b/enterprise/cli/sharing_test.go @@ -216,14 +216,17 @@ func TestSharingStatus(t *testing.T) { err = inv.WithContext(ctx).Run() require.NoError(t, err) + // The ACL endpoint omits group member rosters to avoid leaking member + // PII, so the output lists the group itself rather than its members. found := false for _, line := range strings.Split(out.String(), "\n") { - if strings.Contains(line, orgMember.Username) && strings.Contains(line, string(codersdk.WorkspaceRoleUse)) && strings.Contains(line, group.Name) { + if strings.Contains(line, group.Name) && strings.Contains(line, string(codersdk.WorkspaceRoleUse)) { found = true break } } - assert.True(t, found, "expected to find username %s with role %s in the output: %s", orgMember.Username, codersdk.WorkspaceRoleUse, out.String()) + assert.True(t, found, "expected to find group %s with role %s in the output: %s", group.Name, codersdk.WorkspaceRoleUse, out.String()) + assert.NotContains(t, out.String(), orgMember.Username, "group member roster must not be exposed in sharing status output") }) } diff --git a/enterprise/coderd/workspaces_test.go b/enterprise/coderd/workspaces_test.go index 84dcc41f81ce6..0d0c97bdf3072 100644 --- a/enterprise/coderd/workspaces_test.go +++ b/enterprise/coderd/workspaces_test.go @@ -4477,6 +4477,69 @@ func TestUpdateWorkspaceACL(t *testing.T) { require.Equal(t, workspaceACL.Groups[0].Role, codersdk.WorkspaceRoleAdmin) }) + // A user who has merely been shared a workspace must not be able to + // enumerate the full roster and PII of groups on that workspace's ACL. + // The endpoint returns the group identity and total member count only. + t.Run("GroupMembersNotReturned", func(t *testing.T) { + t.Parallel() + + dv := coderdtest.DeploymentValues(t) + + adminClient, adminUser := coderdenttest.New(t, &coderdenttest.Options{ + Options: &coderdtest.Options{ + IncludeProvisionerDaemon: true, + DeploymentValues: dv, + }, + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{ + codersdk.FeatureTemplateRBAC: 1, + }, + }, + }) + orgID := adminUser.OrganizationID + client, _ := coderdtest.CreateAnotherUser(t, adminClient, orgID) + sharedClient, sharedUser := coderdtest.CreateAnotherUser(t, adminClient, orgID) + _, member := coderdtest.CreateAnotherUser(t, adminClient, orgID) + group := coderdtest.CreateGroup(t, adminClient, orgID, "bloob", member) + + tv := coderdtest.CreateTemplateVersion(t, adminClient, orgID, nil) + coderdtest.AwaitTemplateVersionJobCompleted(t, adminClient, tv.ID) + template := coderdtest.CreateTemplate(t, adminClient, orgID, tv.ID) + + ws := coderdtest.CreateWorkspace(t, client, template.ID) + coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) + + ctx := testutil.Context(t, testutil.WaitMedium) + err := client.UpdateWorkspaceACL(ctx, ws.ID, codersdk.UpdateWorkspaceACL{ + UserRoles: map[string]codersdk.WorkspaceRole{ + sharedUser.ID.String(): codersdk.WorkspaceRoleUse, + }, + GroupRoles: map[string]codersdk.WorkspaceRole{ + group.ID.String(): codersdk.WorkspaceRoleUse, + }, + }) + require.NoError(t, err) + + // The low-privilege shared user can read the ACL, but must not see + // the group's member roster (which would expose member emails and + // other PII). Only the total member count is returned. + workspaceACL, err := sharedClient.WorkspaceACL(ctx, ws.ID) + require.NoError(t, err) + require.Len(t, workspaceACL.Groups, 1) + require.Equal(t, group.ID, workspaceACL.Groups[0].ID) + require.Equal(t, codersdk.WorkspaceRoleUse, workspaceACL.Groups[0].Role) + require.Equal(t, 1, workspaceACL.Groups[0].TotalMemberCount) + require.Empty(t, workspaceACL.Groups[0].Members) + + // The workspace owner sees the same count-only shape; the roster is + // omitted for all callers. + workspaceACL, err = client.WorkspaceACL(ctx, ws.ID) + require.NoError(t, err) + require.Len(t, workspaceACL.Groups, 1) + require.Equal(t, 1, workspaceACL.Groups[0].TotalMemberCount) + require.Empty(t, workspaceACL.Groups[0].Members) + }) + t.Run("UnknownIDs", func(t *testing.T) { t.Parallel() From d6ea2bd16e66c2b6c0b90be9002a617c991c943b Mon Sep 17 00:00:00 2001 From: Jakub Domeracki Date: Thu, 6 Aug 2026 14:45:43 +0200 Subject: [PATCH 08/10] fix(coderd): scope provisioner module file downloads to the daemon's org (#26635) (#27883) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of https://github.com/coder/coder/pull/26635 Original PR: #26635 — fix(coderd): scope provisioner module file downloads to the daemon's org Merge commit: 1961908ca786be534f2cbe5a089149ec04f72a19 Requested by: @jdomeracki-coder
Conflict resolution notes The cherry-pick conflicted in generated database files because the new `HasTemplateVersionsUsingCachedModuleFileInOrg` query sits adjacent to chatd methods (`HydrateAgentChatsContext`, `IncrementChatGenerationAttempt`) that do not exist on `release/2.34`. Resolved by keeping only the new query and its generated bindings in `querier.go`, `dbmetrics/querymetrics.go`, `dbmock/dbmock.go`, and `dbauthz/dbauthz.go`, then running `gofmt`. Affected packages (`./coderd/database/...`, `./coderd/provisionerdserver/...`) build successfully.
--- _Opened by Coder Agents on behalf of @jdomeracki-coder._ --------- Co-authored-by: Jon Ayers --- coderd/database/dbauthz/dbauthz.go | 10 ++ coderd/database/dbauthz/dbauthz_test.go | 5 + coderd/database/dbmetrics/querymetrics.go | 8 + coderd/database/dbmock/dbmock.go | 15 ++ coderd/database/querier.go | 5 + coderd/database/queries.sql.go | 27 ++++ .../templateversionterraformvalues.sql | 14 ++ .../provisionerdserver/provisionerdserver.go | 20 +++ .../provisionerdserver_test.go | 142 ++++++++++++++++++ 9 files changed, 246 insertions(+) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index a92b2231c561d..eb1a1a634ceaa 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -5386,6 +5386,16 @@ func (q *querier) GetWorkspacesForWorkspaceMetrics(ctx context.Context) ([]datab return q.db.GetWorkspacesForWorkspaceMetrics(ctx) } +func (q *querier) HasTemplateVersionsUsingCachedModuleFileInOrg(ctx context.Context, arg database.HasTemplateVersionsUsingCachedModuleFileInOrgParams) (bool, error) { + // This query authorizes provisioner module-file downloads. The caller + // must be able to read files in the target organization; the actual + // tenant isolation comes from the organization_id filter in the query. + if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceFile.InOrg(arg.OrganizationID)); err != nil { + return false, err + } + return q.db.HasTemplateVersionsUsingCachedModuleFileInOrg(ctx, arg) +} + func (q *querier) InsertAIBridgeInterception(ctx context.Context, arg database.InsertAIBridgeInterceptionParams) (database.AIBridgeInterception, error) { return insert(q.log, q.auth, rbac.ResourceAibridgeInterception.WithOwner(arg.InitiatorID.String()), q.db.InsertAIBridgeInterception)(ctx, arg) } diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 489ffd7459c98..6e4f8c841dda9 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -2442,6 +2442,11 @@ func (s *MethodTestSuite) TestTemplate() { dbm.EXPECT().GetTemplateVersionTerraformValues(gomock.Any(), tv.ID).Return(val, nil).AnyTimes() check.Args(tv.ID).Asserts(t, policy.ActionRead) })) + s.Run("HasTemplateVersionsUsingCachedModuleFileInOrg", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) { + arg := database.HasTemplateVersionsUsingCachedModuleFileInOrgParams{FileID: uuid.New(), OrganizationID: uuid.New()} + dbm.EXPECT().HasTemplateVersionsUsingCachedModuleFileInOrg(gomock.Any(), arg).Return(true, nil).AnyTimes() + check.Args(arg).Asserts(rbac.ResourceFile.InOrg(arg.OrganizationID), policy.ActionRead).Returns(true) + })) s.Run("GetTemplateVersionVariables", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { t1 := testutil.Fake(s.T(), faker, database.Template{}) tv := testutil.Fake(s.T(), faker, database.TemplateVersion{TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}}) diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index 6613ece7f0c50..ba4cbb220c1c3 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -3682,6 +3682,14 @@ func (m queryMetricsStore) GetWorkspacesForWorkspaceMetrics(ctx context.Context) return r0, r1 } +func (m queryMetricsStore) HasTemplateVersionsUsingCachedModuleFileInOrg(ctx context.Context, arg database.HasTemplateVersionsUsingCachedModuleFileInOrgParams) (bool, error) { + start := time.Now() + r0, r1 := m.s.HasTemplateVersionsUsingCachedModuleFileInOrg(ctx, arg) + m.queryLatencies.WithLabelValues("HasTemplateVersionsUsingCachedModuleFileInOrg").Observe(time.Since(start).Seconds()) + m.queryCounts.WithLabelValues(httpmw.ExtractHTTPRoute(ctx), httpmw.ExtractHTTPMethod(ctx), "HasTemplateVersionsUsingCachedModuleFileInOrg").Inc() + return r0, r1 +} + func (m queryMetricsStore) InsertAIBridgeInterception(ctx context.Context, arg database.InsertAIBridgeInterceptionParams) (database.AIBridgeInterception, error) { start := time.Now() r0, r1 := m.s.InsertAIBridgeInterception(ctx, arg) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 7a4c5da40dc04..72340abacf6a8 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -6901,6 +6901,21 @@ func (mr *MockStoreMockRecorder) GetWorkspacesForWorkspaceMetrics(ctx any) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspacesForWorkspaceMetrics", reflect.TypeOf((*MockStore)(nil).GetWorkspacesForWorkspaceMetrics), ctx) } +// HasTemplateVersionsUsingCachedModuleFileInOrg mocks base method. +func (m *MockStore) HasTemplateVersionsUsingCachedModuleFileInOrg(ctx context.Context, arg database.HasTemplateVersionsUsingCachedModuleFileInOrgParams) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasTemplateVersionsUsingCachedModuleFileInOrg", ctx, arg) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// HasTemplateVersionsUsingCachedModuleFileInOrg indicates an expected call of HasTemplateVersionsUsingCachedModuleFileInOrg. +func (mr *MockStoreMockRecorder) HasTemplateVersionsUsingCachedModuleFileInOrg(ctx, arg any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasTemplateVersionsUsingCachedModuleFileInOrg", reflect.TypeOf((*MockStore)(nil).HasTemplateVersionsUsingCachedModuleFileInOrg), ctx, arg) +} + // InTx mocks base method. func (m *MockStore) InTx(arg0 func(database.Store) error, arg1 *database.TxOptions) error { m.ctrl.T.Helper() diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 5cffdb76bda8b..3235daa91dbe1 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -918,6 +918,11 @@ type sqlcQuerier interface { GetWorkspacesByTemplateID(ctx context.Context, templateID uuid.UUID) ([]WorkspaceTable, error) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]GetWorkspacesEligibleForTransitionRow, error) GetWorkspacesForWorkspaceMetrics(ctx context.Context) ([]GetWorkspacesForWorkspaceMetricsRow, error) + // Reports whether the given file is referenced as cached module files by any + // template version in the given organization. Used to authorize provisioner + // module-file downloads so a daemon cannot read another organization's cached + // Terraform module source. + HasTemplateVersionsUsingCachedModuleFileInOrg(ctx context.Context, arg HasTemplateVersionsUsingCachedModuleFileInOrgParams) (bool, error) InsertAIBridgeInterception(ctx context.Context, arg InsertAIBridgeInterceptionParams) (AIBridgeInterception, error) InsertAIBridgeModelThought(ctx context.Context, arg InsertAIBridgeModelThoughtParams) (AIBridgeModelThought, error) InsertAIBridgeTokenUsage(ctx context.Context, arg InsertAIBridgeTokenUsageParams) (AIBridgeTokenUsage, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index f6fe41c028732..c9103e4880d0a 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -26040,6 +26040,33 @@ func (q *sqlQuerier) GetTemplateVersionTerraformValues(ctx context.Context, temp return i, err } +const hasTemplateVersionsUsingCachedModuleFileInOrg = `-- name: HasTemplateVersionsUsingCachedModuleFileInOrg :one +SELECT EXISTS ( + SELECT 1 + FROM template_version_terraform_values tvtv + JOIN template_versions tv + ON tv.id = tvtv.template_version_id + WHERE tvtv.cached_module_files = $1::uuid + AND tv.organization_id = $2::uuid +) +` + +type HasTemplateVersionsUsingCachedModuleFileInOrgParams struct { + FileID uuid.UUID `db:"file_id" json:"file_id"` + OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` +} + +// Reports whether the given file is referenced as cached module files by any +// template version in the given organization. Used to authorize provisioner +// module-file downloads so a daemon cannot read another organization's cached +// Terraform module source. +func (q *sqlQuerier) HasTemplateVersionsUsingCachedModuleFileInOrg(ctx context.Context, arg HasTemplateVersionsUsingCachedModuleFileInOrgParams) (bool, error) { + row := q.db.QueryRowContext(ctx, hasTemplateVersionsUsingCachedModuleFileInOrg, arg.FileID, arg.OrganizationID) + var exists bool + err := row.Scan(&exists) + return exists, err +} + const insertTemplateVersionTerraformValuesByJobID = `-- name: InsertTemplateVersionTerraformValuesByJobID :exec INSERT INTO template_version_terraform_values ( diff --git a/coderd/database/queries/templateversionterraformvalues.sql b/coderd/database/queries/templateversionterraformvalues.sql index 2ded4a2675375..97b20a5103c45 100644 --- a/coderd/database/queries/templateversionterraformvalues.sql +++ b/coderd/database/queries/templateversionterraformvalues.sql @@ -23,3 +23,17 @@ VALUES @updated_at, @provisionerd_version ); + +-- name: HasTemplateVersionsUsingCachedModuleFileInOrg :one +-- Reports whether the given file is referenced as cached module files by any +-- template version in the given organization. Used to authorize provisioner +-- module-file downloads so a daemon cannot read another organization's cached +-- Terraform module source. +SELECT EXISTS ( + SELECT 1 + FROM template_version_terraform_values tvtv + JOIN template_versions tv + ON tv.id = tvtv.template_version_id + WHERE tvtv.cached_module_files = @file_id::uuid + AND tv.organization_id = @organization_id::uuid +); diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index d233cb41dd9be..9fb25812600b4 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -1584,6 +1584,26 @@ func (s *server) DownloadFile(request *proto.FileRequest, stream proto.DRPCProvi if file.CreatedBy != uuid.Nil || file.Mimetype != tarMimeType { return fail(xerrors.Errorf("file %s is not a modules file", fid)) } + // Ensure the requested module file belongs to a template version in + // this provisioner daemon's organization. Without this, any + // authenticated provisioner could download cached module archives + // (Terraform source) belonging to other organizations (ANT-2026-22440). + ok, err := s.Database.HasTemplateVersionsUsingCachedModuleFileInOrg(ctx, database.HasTemplateVersionsUsingCachedModuleFileInOrgParams{ + FileID: fid, + OrganizationID: s.OrganizationID, + }) + if err != nil { + return fail(xerrors.Errorf("authorize module file: %w", err)) + } + if !ok { + s.Logger.Warn(ctx, "module file download rejected: file not referenced by any template version in daemon org", + slog.F("file_id", fid), + slog.F("organization_id", s.OrganizationID), + ) + // Use the same error as the metadata check above so the handler + // does not confirm the existence of files in other organizations. + return fail(xerrors.Errorf("file %s is not a modules file", fid)) + } default: return fail(xerrors.Errorf("unsupported file upload type: %s", request.UploadType)) } diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index 0e7f175c67d46..7b59c46a54a72 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -2,6 +2,7 @@ package provisionerdserver_test import ( "context" + crand "crypto/rand" "database/sql" "encoding/json" "io" @@ -25,6 +26,8 @@ import ( "golang.org/x/xerrors" "google.golang.org/protobuf/types/known/timestamppb" "storj.io/drpc" + "storj.io/drpc/drpcmux" + "storj.io/drpc/drpcserver" "cdr.dev/slog/v3" "cdr.dev/slog/v3/sloggers/slogtest" @@ -52,6 +55,7 @@ import ( "github.com/coder/coder/v2/coderd/usage/usagetypes" "github.com/coder/coder/v2/coderd/wspubsub" "github.com/coder/coder/v2/codersdk" + "github.com/coder/coder/v2/codersdk/drpcsdk" "github.com/coder/coder/v2/provisionerd/proto" "github.com/coder/coder/v2/provisionersdk" sdkproto "github.com/coder/coder/v2/provisionersdk/proto" @@ -5420,3 +5424,141 @@ func newFakeUsageInserter() (*coderdtest.UsageInserter, *atomic.Pointer[usage.In poitr.Store(&inserter) return fake, poitr } + +// serveProvisionerDaemon serves the provisioner daemon server over an +// in-memory pipe and returns a connected client, mirroring how coderd serves +// in-memory provisioner daemons. This exercises the real DRPC streaming path +// instead of a hand-rolled mock stream. +func serveProvisionerDaemon(t *testing.T, srv proto.DRPCProvisionerDaemonServer) proto.DRPCProvisionerDaemonClient { + t.Helper() + clientPipe, serverPipe := drpcsdk.MemTransportPipe() + t.Cleanup(func() { + _ = clientPipe.Close() + _ = serverPipe.Close() + }) + mux := drpcmux.New() + require.NoError(t, proto.DRPCRegisterProvisionerDaemon(mux, srv)) + server := drpcserver.NewWithOptions(mux, drpcserver.Options{ + Manager: drpcsdk.DefaultDRPCOptions(nil), + }) + ctx, cancel := context.WithCancel(context.Background()) + closed := make(chan struct{}) + go func() { + defer close(closed) + _ = server.Serve(ctx, serverPipe) + }() + t.Cleanup(func() { + cancel() + <-closed + }) + return proto.NewDRPCProvisionerDaemonClient(clientPipe) +} + +// insertModuleFile inserts a system-created (CreatedBy=uuid.Nil) tar file and +// links it as the cached module files of a template version in the given +// organization, returning the file. +func insertModuleFile(t *testing.T, db database.Store, orgID uuid.UUID, data []byte) database.File { + t.Helper() + ctx := testutil.Context(t, testutil.WaitShort) + + user := dbgen.User(t, db, database.User{}) + template := dbgen.Template(t, db, database.Template{ + OrganizationID: orgID, + CreatedBy: user.ID, + }) + jobID := uuid.New() + version := dbgen.TemplateVersion(t, db, database.TemplateVersion{ + OrganizationID: orgID, + CreatedBy: user.ID, + TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true}, + JobID: jobID, + }) + // Insert the file directly rather than via dbgen.File: the helper treats a + // zero CreatedBy as "unset" and replaces it with a random UUID, but module + // files must be system-created (CreatedBy=uuid.Nil) to match the handler's + // metadata check. + file, err := db.InsertFile(ctx, database.InsertFileParams{ + ID: uuid.New(), + Hash: uuid.NewString(), + CreatedAt: dbtime.Now(), + CreatedBy: uuid.Nil, + Mimetype: "application/x-tar", + Data: data, + }) + require.NoError(t, err) + err = db.InsertTemplateVersionTerraformValuesByJobID(ctx, database.InsertTemplateVersionTerraformValuesByJobIDParams{ + JobID: version.JobID, + CachedPlan: []byte("{}"), + CachedModuleFiles: uuid.NullUUID{UUID: file.ID, Valid: true}, + UpdatedAt: dbtime.Now(), + }) + require.NoError(t, err) + return file +} + +// TestDownloadFile verifies that a provisioner daemon cannot download cached +// module archives belonging to other organizations (ANT-2026-22440), while +// still being able to download module files from its own organization. +func TestDownloadFile(t *testing.T) { + t.Parallel() + + t.Run("RejectsOtherOrgModuleFile", func(t *testing.T) { + t.Parallel() + + // The server is scoped to the default organization (org A). + srv, db, _, daemon := setup(t, false, &overrides{ + externalAuthConfigs: []*externalauth.Config{{}}, + }) + ctx := testutil.Context(t, testutil.WaitMedium) + client := serveProvisionerDaemon(t, srv) + + // Create a module file belonging to a different organization (org B). + otherOrg := dbgen.Organization(t, db, database.Organization{}) + require.NotEqual(t, daemon.OrganizationID, otherOrg.ID) + + moduleData := make([]byte, sdkproto.ChunkSize*2) + // crand.Read never returns an error as of Go 1.24. + _, _ = crand.Read(moduleData) + file := insertModuleFile(t, db, otherOrg.ID, moduleData) + + stream, err := client.DownloadFile(ctx, &proto.FileRequest{ + FileId: file.ID.String(), + UploadType: sdkproto.DataUploadType_UPLOAD_TYPE_MODULE_FILES, + }) + require.NoError(t, err) + + // The handler must reject the cross-org download with an error rather + // than streaming the file's contents. + _, err = provisionersdk.HandleReceivingDataUpload(stream) + require.Error(t, err) + require.ErrorContains(t, err, "is not a modules file") + }) + + t.Run("AllowsSameOrgModuleFile", func(t *testing.T) { + t.Parallel() + + // The server is scoped to the default organization (org A). + srv, db, _, daemon := setup(t, false, &overrides{ + externalAuthConfigs: []*externalauth.Config{{}}, + }) + ctx := testutil.Context(t, testutil.WaitMedium) + client := serveProvisionerDaemon(t, srv) + + moduleData := make([]byte, sdkproto.ChunkSize*2+512) + // crand.Read never returns an error as of Go 1.24. + _, _ = crand.Read(moduleData) + file := insertModuleFile(t, db, daemon.OrganizationID, moduleData) + + stream, err := client.DownloadFile(ctx, &proto.FileRequest{ + FileId: file.ID.String(), + UploadType: sdkproto.DataUploadType_UPLOAD_TYPE_MODULE_FILES, + }) + require.NoError(t, err) + + builder, err := provisionersdk.HandleReceivingDataUpload(stream) + require.NoError(t, err) + data, err := builder.Complete() + require.NoError(t, err) + require.Equal(t, moduleData, data) + }) +} From 877fbeb17f0371bf81ca42d77b8576968893de11 Mon Sep 17 00:00:00 2001 From: Denis Afonso Date: Mon, 10 Aug 2026 07:46:11 +0100 Subject: [PATCH 09/10] fix: update google.golang.org/grpc to v1.82.1 (#27928) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What Updates `google.golang.org/grpc` from `v1.81.1` → `v1.82.1` on `release/2.34`. ## Why `google.golang.org/grpc v1.81.1` is vulnerable to **GHSA-hrxh-6v49-42gf** (GO-2026-6061) — the relevant exposure is the HTTP/2 Rapid Reset-style DoS (the xDS RBAC auth-bypass half of the advisory isn't used by Coder). Flagged by the IronBank scan of Coder v2.35.3; `release/2.34` ships the same vulnerable version. Fixed in **v1.82.1** (matches `v2.36.0`; `main` is on v1.83.0). Companion to #27925 (the `release/2.35` backport). ## Change - `go.mod`: `google.golang.org/grpc v1.81.1` → `v1.82.1` (direct), plus the minimal indirect bumps grpc 1.82.1 requires on this branch: - `google.golang.org/genproto/googleapis/api` 20260319 → 20260414 - `GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp` v1.31.0 → v1.32.0 - `go.opentelemetry.io/contrib/detectors/gcp` v1.42.0 → v1.43.0 - `go.sum`: corresponding hashes (These three indirect bumps weren't needed on the 2.35 backport because that branch already had newer pins; on 2.34 they're pulled up by grpc 1.82.1's minimum-version requirements. All `// indirect`, all `go mod verify`-clean.) ## Validation (local; `golangci-lint` at the CI-pinned v1.64.8) - `go build ./...` — clean - `go vet ./tailnet/... ./codersdk/...` — clean - `golangci-lint run` (full repo) — 0 issues - `go run ./scripts/intxcheck ./...` — clean - `go mod tidy` stable; `go mod verify` OK DB-backed suites (`make test-postgres`) run in CI. Linear: ENT-144 --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 3b857381b29e4..a5ff12aebde2f 100644 --- a/go.mod +++ b/go.mod @@ -240,7 +240,7 @@ require ( golang.org/x/tools v0.45.0 golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da google.golang.org/api v0.280.0 - google.golang.org/grpc v1.81.1 + google.golang.org/grpc v1.82.1 google.golang.org/protobuf v1.36.11 gopkg.in/DataDog/dd-trace-go.v1 v1.74.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 @@ -478,7 +478,7 @@ require ( golang.zx2c4.com/wireguard/windows v0.5.3 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 // indirect gopkg.in/ini.v1 v1.67.1 // indirect howett.net/plist v1.0.1 // indirect @@ -541,7 +541,7 @@ require ( github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.64.2 // indirect github.com/DataDog/datadog-agent/pkg/version v0.64.2 // indirect github.com/DataDog/dd-trace-go/v2 v2.0.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect @@ -640,7 +640,7 @@ require ( github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect - go.opentelemetry.io/contrib/detectors/gcp v1.42.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.43.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect diff --git a/go.sum b/go.sum index 95741dbcf8d62..af26afa9a5c01 100644 --- a/go.sum +++ b/go.sum @@ -81,8 +81,8 @@ github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/attributes v0.26.0 h1:GlvoS github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/attributes v0.26.0/go.mod h1:mYQmU7mbHH6DrCaS8N6GZcxwPoeNfyuopUoLQltwSzs= github.com/DataDog/sketches-go v1.4.7 h1:eHs5/0i2Sdf20Zkj0udVFWuCrXGRFig2Dcfm5rtcTxc= github.com/DataDog/sketches-go v1.4.7/go.mod h1:eAmQ/EBmtSO+nQp7IZMZVRPT4BQTmIc5RZQ+deGlTPM= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 h1:rIkQfkCOVKc1OiRCNcSDD8ml5RJlZbH/Xsq7lbpynwc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0/go.mod h1:RD2SsorTmYhF6HkTmDw7KmPYQk8OBYwTkuasChwv7R4= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0/go.mod h1:IA1C1U7jO/ENqm/vhi7V9YYpBsp+IMyqNrEN94N7tVc= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0 h1:7t/qx5Ost0s0wbA/VDrByOooURhp+ikYwv20i9Y07TQ= @@ -1315,8 +1315,8 @@ go.opentelemetry.io/collector/semconv v0.123.0/go.mod h1:te6VQ4zZJO5Lp8dM2XIhDxD go.opentelemetry.io/contrib v1.0.0/go.mod h1:EH4yDYeNoaTqn/8yCWQmfNB78VHfGX2Jt2bvnvzBlGM= go.opentelemetry.io/contrib v1.19.0 h1:rnYI7OEPMWFeM4QCqWQ3InMJ0arWMR1i0Cx9A5hcjYM= go.opentelemetry.io/contrib v1.19.0/go.mod h1:gIzjwWFoGazJmtCaDgViqOSJPde2mCWzv60o0bWPcZs= -go.opentelemetry.io/contrib/detectors/gcp v1.42.0 h1:kpt2PEJuOuqYkPcktfJqWWDjTEd/FNgrxcniL7kQrXQ= -go.opentelemetry.io/contrib/detectors/gcp v1.42.0/go.mod h1:W9zQ439utxymRrXsUOzZbFX4JhLxXU4+ZnCt8GG7yA8= +go.opentelemetry.io/contrib/detectors/gcp v1.43.0 h1:62yY3dT7/ShwOxzA0RsKRgshBmfElKI4d/Myu2OxDFU= +go.opentelemetry.io/contrib/detectors/gcp v1.43.0/go.mod h1:RyaZMFY7yi1kAs45S6mbFGz8O8rqB0dTY14uzvG4LCs= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 h1:yI1/OhfEPy7J9eoa6Sj051C7n5dvpj0QX8g4sRchg04= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0/go.mod h1:NoUCKYWK+3ecatC4HjkRktREheMeEtrXoQxrqYFeHSc= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 h1:CqXxU8VOmDefoh0+ztfGaymYbhdB/tT3zs79QaZTNGY= @@ -1536,12 +1536,12 @@ google.golang.org/genai v1.51.0 h1:IZGuUqgfx40INv3hLFGCbOSGp0qFqm7LVmDghzNIYqg= google.golang.org/genai v1.51.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk= google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0= google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I= -google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 h1:41r6JMbpzBMen0R/4TZeeAmGXSJC7DftGINUodzTkPI= -google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y= +google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec= +google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 h1:seT2EwLWM78plQ7wcDfuWBc/4FAEAXDDiaSol4ku4qo= google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= -google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= +google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= From 7bd778d8815624fd2b598d9432092162437c06b3 Mon Sep 17 00:00:00 2001 From: Denis Afonso Date: Mon, 10 Aug 2026 08:14:15 +0100 Subject: [PATCH 10/10] fix: update github.com/DataDog/dd-trace-go/v2 to v2.8.1 (#27940) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What Updates `github.com/DataDog/dd-trace-go/v2` from `v2.0.0` → `v2.8.1` (indirect) on `release/2.34`. ## Why `github.com/DataDog/dd-trace-go/v2 v2.0.0` is vulnerable to **CVE-2026-50274**. It is an indirect dependency pulled in by the direct `gopkg.in/DataDog/dd-trace-go.v1 v1.74.0` shim that `coderd/tracing` uses. Flagged by the IronBank scan of Coder v2.35.3; `release/2.34` ships the same vulnerable version. Fixed in **v2.8.1** (matches `v2.36.0`/`main`). Companion to #27938 (the `release/2.35` backport). ## Change `go get github.com/DataDog/dd-trace-go/v2@v2.8.1 && go mod tidy`. This reproduces the DataDog dependency cluster as shipped on `v2.36.0`. Notable transitive effects: - **`go-libddwaf/v3` → `/v4`** (major-version module swap; v3 removed) - `datadog-agent/pkg/*` 0.64.2 → 0.77.0 (plus new `pkg/trace/{log,otel,stats,traceutil}`, `pkg/template`, `pkg/opentelemetry-mapping-go/otlp/attributes`) - `datadog-go/v5` 5.6.0→5.8.3, and bumps to `go-sqllexer`, `sketches-go`, `go-tuf`, `go-runtime-metrics-internal` - `go.opentelemetry.io/collector/{component,pdata,pdata/pprofile,featuregate}` 1.27 → 1.51; dropped `collector/semconv`, `appsec-internal-go`, `Masterminds/semver/v3`, `eapache/queue/v2`, `gogo/protobuf` Every changed module matches `v2.36.0`'s `go.mod` with one exception: `github.com/ebitengine/purego` resolves to `v0.10.0` here vs `v0.10.1` on `v2.36.0`. It is a patch-level grandchild of `go-libddwaf/v4`; MVS selects the minimal version this branch's graph requires (nothing on `release/2.34` demands v0.10.1, whereas 2.36's grpc-bumped graph does). Build and lint are clean with it. `go.mod` +35/−30, `go.sum` +112/−100. All new/changed entries are `// indirect`. ## Validation (local; `golangci-lint` at the CI-pinned v1.64.8) - `go build ./...` — clean - `go vet ./coderd/tracing/... ./codersdk/...` — clean - `go test ./coderd/tracing/...` — ok - `golangci-lint run` (full repo) — 0 issues - `go run ./scripts/intxcheck ./...` — clean - `go mod tidy` stable; `go mod verify` OK DB-backed suites (`make test-postgres`) run in CI. Linear: ENT-141 Co-authored-by: Marcin Tojek --- go.mod | 65 ++++++++++-------- go.sum | 212 ++++++++++++++++++++++++++++++--------------------------- 2 files changed, 147 insertions(+), 130 deletions(-) diff --git a/go.mod b/go.mod index a5ff12aebde2f..040ebefafb6c9 100644 --- a/go.mod +++ b/go.mod @@ -204,7 +204,7 @@ require ( github.com/prometheus/common v0.67.5 github.com/quasilyte/go-ruleguard/dsl v0.3.23 github.com/robfig/cron/v3 v3.0.1 - github.com/shirou/gopsutil/v4 v4.26.1 + github.com/shirou/gopsutil/v4 v4.26.2 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/spf13/afero v1.15.0 github.com/spf13/pflag v1.0.10 @@ -257,21 +257,18 @@ require ( dario.cat/mergo v1.0.2 // indirect filippo.io/edwards25519 v1.1.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect - github.com/DataDog/appsec-internal-go v1.11.2 // indirect - github.com/DataDog/datadog-agent/pkg/obfuscate v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/proto v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/trace v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/util/log v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/util/scrubber v0.64.2 // indirect - github.com/DataDog/datadog-go/v5 v5.6.0 // indirect - github.com/DataDog/go-libddwaf/v3 v3.5.4 // indirect - github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20250319104955-81009b9bad14 // indirect - github.com/DataDog/go-sqllexer v0.1.3 // indirect - github.com/DataDog/go-tuf v1.1.0-0.5.2 // indirect + github.com/DataDog/datadog-agent/pkg/obfuscate v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/proto v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/trace v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/util/log v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/util/scrubber v0.77.0 // indirect + github.com/DataDog/datadog-go/v5 v5.8.3 // indirect + github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20260217080614-b0f4edc38a6d // indirect + github.com/DataDog/go-sqllexer v0.1.13 // indirect + github.com/DataDog/go-tuf v1.1.1-0.5.2 // indirect github.com/DataDog/gostackparse v0.7.0 // indirect - github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/attributes v0.26.0 // indirect - github.com/DataDog/sketches-go v1.4.7 // indirect + github.com/DataDog/sketches-go v1.4.8 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/ProtonMail/go-crypto v1.4.1 // indirect @@ -319,8 +316,7 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd // indirect github.com/dustin/go-humanize v1.0.1 - github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 // indirect - github.com/ebitengine/purego v0.10.0-alpha.5 // indirect + github.com/ebitengine/purego v0.10.0 // indirect github.com/elastic/go-windows v1.0.0 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -342,7 +338,6 @@ require ( github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/ws v1.4.0 // indirect github.com/godbus/dbus/v5 v5.2.2 // indirect - github.com/gogo/protobuf v1.3.2 // indirect github.com/gohugoio/hashstructure v0.6.0 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -380,7 +375,7 @@ require ( github.com/kylelemons/godebug v1.1.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lucasb-eyer/go-colorful v1.4.0 // indirect - github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect + github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 // indirect github.com/mailru/easyjson v0.9.1 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-localereader v0.0.1 // indirect @@ -388,7 +383,7 @@ require ( github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/sdnotify v1.0.0 // indirect - github.com/mdlayher/socket v0.5.0 // indirect + github.com/mdlayher/socket v0.5.1 // indirect github.com/microcosm-cc/bluemonday v1.0.27 github.com/miekg/dns v1.1.72 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -410,7 +405,7 @@ require ( github.com/opencontainers/runc v1.2.8 // indirect github.com/outcaste-io/ristretto v0.2.3 // indirect github.com/pelletier/go-toml/v2 v2.3.1 // indirect - github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect + github.com/philhofer/fwd v1.2.0 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pion/transport/v2 v2.2.10 // indirect github.com/pion/transport/v3 v3.0.7 // indirect @@ -440,7 +435,7 @@ require ( github.com/tdewolff/parse/v2 v2.8.12 // indirect github.com/tidwall/match v1.2.0 // indirect github.com/tidwall/pretty v1.2.1 - github.com/tinylib/msgp v1.2.5 // indirect + github.com/tinylib/msgp v1.6.3 // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect github.com/tklauser/numcpus v0.11.0 // indirect github.com/u-root/uio v0.0.0-20240209044354-b3d14b93376a // indirect @@ -461,10 +456,9 @@ require ( github.com/zclconf/go-cty v1.18.1 github.com/zeebo/errs v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/collector/component v1.27.0 // indirect - go.opentelemetry.io/collector/pdata v1.27.0 // indirect - go.opentelemetry.io/collector/pdata/pprofile v0.121.0 // indirect - go.opentelemetry.io/collector/semconv v0.123.0 // indirect + go.opentelemetry.io/collector/component v1.51.1-0.20260205185216-81bc641f26c0 // indirect + go.opentelemetry.io/collector/pdata v1.51.1-0.20260205185216-81bc641f26c0 // indirect + go.opentelemetry.io/collector/pdata/pprofile v0.145.1-0.20260205185216-81bc641f26c0 // indirect go.opentelemetry.io/contrib v1.19.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 go.opentelemetry.io/otel/metric v1.43.0 // indirect @@ -491,12 +485,24 @@ require github.com/coder/clistat v1.2.1 require github.com/SherClockHolmes/webpush-go v1.4.0 require ( + github.com/DataDog/datadog-agent/pkg/opentelemetry-mapping-go/otlp/attributes v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/template v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/trace/log v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/trace/otel v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/trace/stats v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/trace/traceutil v0.77.0 // indirect + github.com/DataDog/go-libddwaf/v4 v4.9.0 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22 // indirect github.com/charmbracelet/colorprofile v0.4.1 // indirect github.com/charmbracelet/x/cellbuf v0.0.15 // indirect github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e // indirect github.com/golang-jwt/jwt/v5 v5.3.0 // indirect + github.com/linkdata/deadlock v0.5.5 // indirect + github.com/minio/simdjson-go v0.4.5 // indirect + github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 // indirect + github.com/trailofbits/go-mutexasserts v0.0.0-20250514102930-c1f3d2e37561 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + go.opentelemetry.io/collector/featuregate v1.51.1-0.20260205185216-81bc641f26c0 // indirect ) require ( @@ -538,13 +544,12 @@ require ( git.sr.ht/~jackmordaunt/go-toast v1.1.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect - github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.64.2 // indirect - github.com/DataDog/datadog-agent/pkg/version v0.64.2 // indirect - github.com/DataDog/dd-trace-go/v2 v2.0.0 // indirect + github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.77.0 // indirect + github.com/DataDog/datadog-agent/pkg/version v0.77.0 // indirect + github.com/DataDog/dd-trace-go/v2 v2.8.1 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect - github.com/Masterminds/semver/v3 v3.4.0 // indirect github.com/alecthomas/chroma v0.10.0 // indirect github.com/aquasecurity/go-version v0.0.1 // indirect github.com/aquasecurity/iamgo v0.0.10 // indirect diff --git a/go.sum b/go.sum index af26afa9a5c01..d0cb206516b0a 100644 --- a/go.sum +++ b/go.sum @@ -45,42 +45,50 @@ github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69 h1:+tu3HOoMXB7RX github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69/go.mod h1:L1AbZdiDllfyYH5l5OkAaZtk7VkWe89bPJFmnDBNHxg= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= -github.com/DataDog/appsec-internal-go v1.11.2 h1:Q00pPMQzqMIw7jT2ObaORIxBzSly+deS0Ely9OZ/Bj0= -github.com/DataDog/appsec-internal-go v1.11.2/go.mod h1:9YppRCpElfGX+emXOKruShFYsdPq7WEPq/Fen4tYYpk= -github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.64.2 h1:wEW+nwoLKubvnLLaxMScYO+rEuHGXmvDsrSV9M3aWdU= -github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.64.2/go.mod h1:lzCtnMSGZm/3RMk5RBRW/6IuK1TNbDXx1ttHTxN5Ykc= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.64.2 h1:xyKB0aTD0S0wp17Egqr8gNUL8btuaKC2WK08NT0pCFQ= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.64.2/go.mod h1:izbemZjqzBn9upkZj8SyT9igSGPMALaQYgswJ0408vY= -github.com/DataDog/datadog-agent/pkg/proto v0.64.2 h1:JGnb24mKLi+wEJg/bo5FPf1wli3ca2+owIkACl4mwl4= -github.com/DataDog/datadog-agent/pkg/proto v0.64.2/go.mod h1:q324yHcBN5hIeCU8eoinM7lP9c7MOA2FTj7oeWAl3Pc= -github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.64.2 h1:bCRz9YBvQTJNeE+eAPLEcuz4p/2aStxAO9lgf1HsivI= -github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.64.2/go.mod h1:1AAhFoEuoXs8jfpj7EiGW6lsqvCYgQc0B0pRpYAPEW4= -github.com/DataDog/datadog-agent/pkg/trace v0.64.2 h1:vuwxRGRVnlFYFUoSK5ZV0sHqskJwxknP5/lV+WfkSSw= -github.com/DataDog/datadog-agent/pkg/trace v0.64.2/go.mod h1:e0wLYMuXKwS/yorq1FqTDGR9WFj9RzwCMwUrli7mCAw= -github.com/DataDog/datadog-agent/pkg/util/log v0.64.2 h1:Sx+L6L2h/HN4UZwAFQMYt4eHkaLHe6THj6GUADLgkm0= -github.com/DataDog/datadog-agent/pkg/util/log v0.64.2/go.mod h1:XDJfRmc5FwFNLDFHtOKX8AW8W1N8Yk+V/wPwj98Zi6Q= -github.com/DataDog/datadog-agent/pkg/util/scrubber v0.64.2 h1:5jGvehYy2VVYJCMED3Dj6zIZds4g0O8PMf5uIMAwoAY= -github.com/DataDog/datadog-agent/pkg/util/scrubber v0.64.2/go.mod h1:uzxlZdxJ2yZZ9k+hDM4PyG3tYacoeneZuh+PVk+IVAw= -github.com/DataDog/datadog-agent/pkg/version v0.64.2 h1:clAPToUGyhFWJIfN6pBR808YigQsDP6hNcpEcu8qbtU= -github.com/DataDog/datadog-agent/pkg/version v0.64.2/go.mod h1:DgOVsfSRaNV4GZNl/qgoZjG3hJjoYUNWPPhbfTfTqtY= -github.com/DataDog/datadog-go/v5 v5.6.0 h1:2oCLxjF/4htd55piM75baflj/KoE6VYS7alEUqFvRDw= -github.com/DataDog/datadog-go/v5 v5.6.0/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw= -github.com/DataDog/dd-trace-go/v2 v2.0.0 h1:cHMEzD0Wcgtu+Rec9d1GuVgpIN5f+4vCaNzuFHJ0v+Y= -github.com/DataDog/dd-trace-go/v2 v2.0.0/go.mod h1:WBtf7TA9bWr5uA8DjOyw1qlSKe3bw9gN5nc0Ta9dHFE= -github.com/DataDog/go-libddwaf/v3 v3.5.4 h1:cLV5lmGhrUBnHG50EUXdqPQAlJdVCp9n3aQ5bDWJEAg= -github.com/DataDog/go-libddwaf/v3 v3.5.4/go.mod h1:HoLUHdj0NybsPBth/UppTcg8/DKA4g+AXuk8cZ6nuoo= -github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20250319104955-81009b9bad14 h1:tc5aVw7OcMyfVmJnrY4IOeiV1RTSaBuJBqF14BXxzIo= -github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20250319104955-81009b9bad14/go.mod h1:quaQJ+wPN41xEC458FCpTwyROZm3MzmTZ8q8XOXQiPs= -github.com/DataDog/go-sqllexer v0.1.3 h1:Kl2T6QVndMEZqQSY8rkoltYP+LVNaA54N+EwAMc9N5w= -github.com/DataDog/go-sqllexer v0.1.3/go.mod h1:KwkYhpFEVIq+BfobkTC1vfqm4gTi65skV/DpDBXtexc= -github.com/DataDog/go-tuf v1.1.0-0.5.2 h1:4CagiIekonLSfL8GMHRHcHudo1fQnxELS9g4tiAupQ4= -github.com/DataDog/go-tuf v1.1.0-0.5.2/go.mod h1:zBcq6f654iVqmkk8n2Cx81E1JnNTMOAx1UEO/wZR+P0= +github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.77.0 h1:Lu/HEo5svx/UwE7XWh8vOrEHCrVRsein9X1N0jGK5bo= +github.com/DataDog/datadog-agent/comp/core/tagger/origindetection v0.77.0/go.mod h1:+Ty3r23MjcmMSkr8JbFeqA3utgtc1wxsZ0KaQ9CzoWA= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.77.0 h1:mrHaNnDAIOFAVYhCqDpkenUtbadswHN68ZlG5krv40o= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.77.0/go.mod h1:E6RGAcEOr/d8wsV5/khYHvaHkijWex6dfNEvsBIgR7A= +github.com/DataDog/datadog-agent/pkg/opentelemetry-mapping-go/otlp/attributes v0.77.0 h1:g1d9d1CfG54WjXgvkysTFL9yjXexWeDbYssQaf1PG6c= +github.com/DataDog/datadog-agent/pkg/opentelemetry-mapping-go/otlp/attributes v0.77.0/go.mod h1:N/AB9VGpVwHxCcyX+7GLNYMfnTZvn65vp5cHb5Ed0ow= +github.com/DataDog/datadog-agent/pkg/proto v0.77.0 h1:21nDAKD+LdxZz2pMsLAQTZ+w9Z4JqecjKpt8xY1b7Ig= +github.com/DataDog/datadog-agent/pkg/proto v0.77.0/go.mod h1:g2QYJe1CheZdssiDQpSYWra9hORkh+S3WO8aOqDNLkg= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.77.0 h1:SxFGFN/Dd/uREaUTxuVTi0R7fRABzvUtu32YOXcjf6c= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.77.0/go.mod h1:TpW5ZwsQTrlRBPjtZH5/OFwpmOqxV/v2i9BiF4Xfcac= +github.com/DataDog/datadog-agent/pkg/template v0.77.0 h1:sUbTCoQyU9kXMc6/aDd4YTP2pe9PlNkgySM11ydMEbE= +github.com/DataDog/datadog-agent/pkg/template v0.77.0/go.mod h1:ZUjICHSlN0of0cmWrYk9Pof0DV0eqHSpTUK1NTnN26Y= +github.com/DataDog/datadog-agent/pkg/trace v0.77.0 h1:B7M6IW0sd60XnLfeP6HEneeR4lRnaNtI9bboU4R1cV0= +github.com/DataDog/datadog-agent/pkg/trace v0.77.0/go.mod h1:+7zMNPjHTDidiphECirrpq5jLK09S9kmLtGRv7di29Q= +github.com/DataDog/datadog-agent/pkg/trace/log v0.77.0 h1:2VY1byEA2XnYVg7+eLQSTgX2f76ZCf/AwpCBJDXCiDc= +github.com/DataDog/datadog-agent/pkg/trace/log v0.77.0/go.mod h1:thnxBOGfMU9uRlFUClXud6J7DdI8qWtElELSds5jqts= +github.com/DataDog/datadog-agent/pkg/trace/otel v0.77.0 h1:9zSto72E+wSETaKs47Yiq5D9du9H71IqWgbDJzGpzSs= +github.com/DataDog/datadog-agent/pkg/trace/otel v0.77.0/go.mod h1:IxBidgqUt8aBrKYq4VKynBHWYZYNoflk+0+m7w+lfbI= +github.com/DataDog/datadog-agent/pkg/trace/stats v0.77.0 h1:InA6JO5R8TFAUcKRxsdmIF1hJpVZqVO5Aqux+Iw/2V0= +github.com/DataDog/datadog-agent/pkg/trace/stats v0.77.0/go.mod h1:iZVotmInV8qaU6Q5h+tsKk4CBYupDcOgTzonzLlMi0k= +github.com/DataDog/datadog-agent/pkg/trace/traceutil v0.77.0 h1:b/2+uA/cG2xEV0LzgwnxloMFWe5sdJa3xtaQhSGN0+s= +github.com/DataDog/datadog-agent/pkg/trace/traceutil v0.77.0/go.mod h1:csT+8o3GOUjhKPs/GqWMb5Zh4iQpuZ/HZQ4Z5ls8Sak= +github.com/DataDog/datadog-agent/pkg/util/log v0.77.0 h1:YFa+8kIg2qQZca9zvowtwCPdHDhGMcTIF+PMIQsLSRs= +github.com/DataDog/datadog-agent/pkg/util/log v0.77.0/go.mod h1:DFK2U5RcB8/BcObgmVEZ4VxqXUi2t7y2svLTtJwQqeo= +github.com/DataDog/datadog-agent/pkg/util/scrubber v0.77.0 h1:dd0W9e39rv0R3DSgnaurVnQ43/jX/juqQPwLpGAJgFs= +github.com/DataDog/datadog-agent/pkg/util/scrubber v0.77.0/go.mod h1:nkhevws2pJvoXSGhjc8wuTbptNQ9ECRBjwVr4hSvoq0= +github.com/DataDog/datadog-agent/pkg/version v0.77.0 h1:fxpMWuoaRHS5vHzCNHftvJ6wdQrGhEmuozjjl8wZG5k= +github.com/DataDog/datadog-agent/pkg/version v0.77.0/go.mod h1:h9eJjfeTHlYYv+kzq6n3rQ07qXGirdCCacn1Ryu4TFQ= +github.com/DataDog/datadog-go/v5 v5.8.3 h1:s58CUJ9s8lezjhTNJO/SxkPBv2qZjS3ktpRSqGF5n0s= +github.com/DataDog/datadog-go/v5 v5.8.3/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw= +github.com/DataDog/dd-trace-go/v2 v2.8.1 h1:O/lPXXcJof4hqfcBGsL6p/PiVa5xTfvYzv5iv/4S66U= +github.com/DataDog/dd-trace-go/v2 v2.8.1/go.mod h1:IVkBpsq66Cw/YIRM/Te3pl2F0M9n4zguAB2ReGczWeo= +github.com/DataDog/go-libddwaf/v4 v4.9.0 h1:a788e37iuH7sR9uIYHkulvTnp2FkXTiZ3yY/kuaHgZE= +github.com/DataDog/go-libddwaf/v4 v4.9.0/go.mod h1:/AZqP6zw3qGJK5mLrA0PkfK3UQDk1zCI2fUNCt4xftE= +github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20260217080614-b0f4edc38a6d h1:cH9Bm0tJ8FEQbA4FRi0iRm7Zr/5Lata/Or31c+Dth0E= +github.com/DataDog/go-runtime-metrics-internal v0.0.4-0.20260217080614-b0f4edc38a6d/go.mod h1:yDuvU+Ak1TKwgd4K8DNcpJmUrrK8ONLkBMGNAppmBRk= +github.com/DataDog/go-sqllexer v0.1.13 h1:HhT2G21y7SDZYQx9i1b+3Sy/CHhESHet/YKMSm06XcE= +github.com/DataDog/go-sqllexer v0.1.13/go.mod h1:vOw7Ia7z+z6nl3zGZlLIZe0vQlPtCPR906WIPBJadxc= +github.com/DataDog/go-tuf v1.1.1-0.5.2 h1:YWvghV4ZvrQsPcUw8IOUMSDpqc3W5ruOIC+KJxPknv0= +github.com/DataDog/go-tuf v1.1.1-0.5.2/go.mod h1:zBcq6f654iVqmkk8n2Cx81E1JnNTMOAx1UEO/wZR+P0= github.com/DataDog/gostackparse v0.7.0 h1:i7dLkXHvYzHV308hnkvVGDL3BR4FWl7IsXNPz/IGQh4= github.com/DataDog/gostackparse v0.7.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM= -github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/attributes v0.26.0 h1:GlvoS6hJN0uANUC3fjx72rOgM4StAKYo2HtQGaasC7s= -github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/attributes v0.26.0/go.mod h1:mYQmU7mbHH6DrCaS8N6GZcxwPoeNfyuopUoLQltwSzs= -github.com/DataDog/sketches-go v1.4.7 h1:eHs5/0i2Sdf20Zkj0udVFWuCrXGRFig2Dcfm5rtcTxc= -github.com/DataDog/sketches-go v1.4.7/go.mod h1:eAmQ/EBmtSO+nQp7IZMZVRPT4BQTmIc5RZQ+deGlTPM= +github.com/DataDog/sketches-go v1.4.8 h1:pFk9BNn+Rzv8IMIoPUttoOpOr3bJOqU3P6EP5wK+Lv8= +github.com/DataDog/sketches-go v1.4.8/go.mod h1:a/wjRUqzqtGS8qRHRPDCs4EAQfmvPDZGDlMIF5mxXOE= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 h1:rIkQfkCOVKc1OiRCNcSDD8ml5RJlZbH/Xsq7lbpynwc= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0/go.mod h1:RD2SsorTmYhF6HkTmDw7KmPYQk8OBYwTkuasChwv7R4= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8= @@ -95,6 +103,7 @@ github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.1 h1:IpUgup6ucCE4wB59wAP0Y2 github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.1/go.mod h1:KUwy/WLgv9kv2yeBZkPCgDokHzg0M6EdRc17thnbVFw= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= @@ -440,10 +449,8 @@ github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd/go.mod h1:MxLav0peU43G github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 h1:8EXxF+tCLqaVk8AOC29zl2mnhQjwyLxxOTuhUazWRsg= -github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4/go.mod h1:I5sHm0Y0T1u5YjlyqC5GVArM7aNZRUYtTjmJ8mPJFds= -github.com/ebitengine/purego v0.10.0-alpha.5 h1:IUIZ1pu0wnpxrn7o6utj8AeoZBS2upI11kLcddBF414= -github.com/ebitengine/purego v0.10.0-alpha.5/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= +github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/elastic/go-sysinfo v1.15.1 h1:zBmTnFEXxIQ3iwcQuk7MzaUotmKRp3OabbbWM8TdzIQ= github.com/elastic/go-sysinfo v1.15.1/go.mod h1:jPSuTgXG+dhhh0GKIyI2Cso+w5lPJ5PvVqKlL8LV/Hk= github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= @@ -602,8 +609,6 @@ github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gohugoio/gift v0.2.0 h1:vA31pP0rTVmBxBrhpY3WEt+4zM4g+1sDqYeemwsYeqc= github.com/gohugoio/gift v0.2.0/go.mod h1:1Mrm5CjF33KpD749Dwj+UAjWZ3LC6cBXGuTMa5XwoP4= github.com/gohugoio/go-i18n/v2 v2.1.3-0.20251018145728-cfcc22d823c6 h1:pxlAea9eRwuAnt/zKbGqlFO2ZszpIe24YpOVLf+N+4I= @@ -798,8 +803,6 @@ github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4 github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f h1:dKccXx7xA56UNqOcFIbuqFjAWPVtP688j5QMgmo6OHU= github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDSfUAlBSyUjPG0JnaNGjf13JySHFeRdD/3dLP0= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= @@ -848,10 +851,12 @@ github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNB github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss= github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= +github.com/linkdata/deadlock v0.5.5 h1:d6O+rzEqasSfamGDA8u7bjtaq7hOX8Ha4Zn36Wxrkvo= +github.com/linkdata/deadlock v0.5.5/go.mod h1:tXb28stzAD3trzEEK0UJWC+rZKuobCoPktPYzebb1u0= github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4= github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc= -github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= +github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 h1:PTw+yKnXcOFCR6+8hHTyWBeQ/P4Nb7dd4/0ohEcWQuM= +github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= @@ -887,12 +892,14 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/ github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ3c= github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= -github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI= -github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI= +github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= +github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= +github.com/minio/simdjson-go v0.4.5 h1:r4IQwjRGmWCQ2VeMc7fGiilu1z5du0gJ/I/FsKwgo5A= +github.com/minio/simdjson-go v0.4.5/go.mod h1:eoNz0DcLQRyEDeaPr4Ru6JpjlZPzbA0IodxVJk8lO8E= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -971,10 +978,10 @@ github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVW github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= github.com/open-policy-agent/opa v1.11.0 h1:eOd/jJrbavakiX477yT4LrXZfUWViAot/AsKsjsfe7o= github.com/open-policy-agent/opa v1.11.0/go.mod h1:QimuJO4T3KYxWzrmAymqlFvsIanCjKrGjmmC8GgAdgE= -github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.120.1 h1:lK/3zr73guK9apbXTcnDnYrC0YCQ25V3CIULYz3k2xU= -github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.120.1/go.mod h1:01TvyaK8x640crO2iFwW/6CFCZgNsOvOGH3B5J239m0= -github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.120.1 h1:TCyOus9tym82PD1VYtthLKMVMlVyRwtDI4ck4SR2+Ok= -github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.120.1/go.mod h1:Z/S1brD5gU2Ntht/bHxBVnGxXKTvZDr0dNv/riUzPmY= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.145.0 h1:7rdLY2Ewa1WVnjMfJTEKwQ5uPDHYeA1tqNPNROi957U= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.145.0/go.mod h1:jYlQAaJO4ZyJAW2jcKAbjN+nt5BRCyu49mlZv4Rui7U= +github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.145.0 h1:12mxn+8YLeAjMZ1kLGulBcvHrdhRNUmxLVIDnaLkJbQ= +github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.145.0/go.mod h1:V87HYJpfmvCeQ6Cjy3Q4xylxfCn2wVSS80wvv5ECc0s= github.com/openai/openai-go v1.12.0 h1:NBQCnXzqOTv5wsgNC36PrFEiskGfO5wccfCWDo9S1U0= github.com/openai/openai-go v1.12.0/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -1001,8 +1008,11 @@ github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7ol github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY= -github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 h1:rh2lKw/P/EqHa724vYH2+VVQ1YnW4u6EOXl0PMAovZE= +github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +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.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= @@ -1079,8 +1089,8 @@ github.com/sergeymakinen/go-ico v1.0.0-beta.0 h1:m5qKH7uPKLdrygMWxbamVn+tl2HfiA3 github.com/sergeymakinen/go-ico v1.0.0-beta.0/go.mod h1:wQ47mTczswBO5F0NoDt7O0IXgnV4Xy3ojrroMQzyhUk= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/shirou/gopsutil/v4 v4.26.1 h1:TOkEyriIXk2HX9d4isZJtbjXbEjf5qyKPAzbzY0JWSo= -github.com/shirou/gopsutil/v4 v4.26.1/go.mod h1:medLI9/UNAb0dOI9Q3/7yWSqKkj00u+1tgY8nvv41pc= +github.com/shirou/gopsutil/v4 v4.26.2 h1:X8i6sicvUFih4BmYIGT1m2wwgw2VG9YgrDTi7cIRGUI= +github.com/shirou/gopsutil/v4 v4.26.2/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -1176,14 +1186,16 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po= -github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= +github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s= +github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= github.com/tmaxmax/go-sse v0.11.0 h1:nogmJM6rJUoOLoAwEKeQe5XlVpt9l7N82SS1jI7lWFg= github.com/tmaxmax/go-sse v0.11.0/go.mod h1:u/2kZQR1tyngo1lKaNCj1mJmhXGZWS1Zs5yiSOD+Eg8= +github.com/trailofbits/go-mutexasserts v0.0.0-20250514102930-c1f3d2e37561 h1:qqa3P9AtNn6RMe90l/lxd3eJWnIRxjI4eb5Rx8xqCLA= +github.com/trailofbits/go-mutexasserts v0.0.0-20250514102930-c1f3d2e37561/go.mod h1:GA3+Mq3kt3tYAfM0WZCu7ofy+GW9PuGysHfhr+6JX7s= github.com/u-root/gobusybox/src v0.0.0-20240225013946-a274a8d5d83a h1:eg5FkNoQp76ZsswyGZ+TjYqA/rhKefxK8BW7XOlQsxo= github.com/u-root/gobusybox/src v0.0.0-20240225013946-a274a8d5d83a/go.mod h1:e/8TmrdreH0sZOw2DFKBaUV7bvDWRq6SeM9PzkuVM68= github.com/u-root/u-root v0.14.0 h1:Ka4T10EEML7dQ5XDvO9c3MBN8z4nuSnGjcd1jmU2ivg= @@ -1256,8 +1268,6 @@ github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCO github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE= @@ -1284,34 +1294,40 @@ go.nhat.io/otelsql v0.16.0 h1:MUKhNSl7Vk1FGyopy04FBDimyYogpRFs0DBB9frQal0= go.nhat.io/otelsql v0.16.0/go.mod h1:YB2ocf0Q8+kK4kxzXYUOHj7P2Km8tNmE2QlRS0frUtc= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/collector/component v1.27.0 h1:6wk0K23YT9lSprX8BH9x5w8ssAORE109ekH/ix2S614= -go.opentelemetry.io/collector/component v1.27.0/go.mod h1:fIyBHoa7vDyZL3Pcidgy45cx24tBe7iHWne097blGgo= -go.opentelemetry.io/collector/component/componentstatus v0.120.0 h1:hzKjI9+AIl8A/saAARb47JqabWsge0kMp8NSPNiCNOQ= -go.opentelemetry.io/collector/component/componentstatus v0.120.0/go.mod h1:kbuAEddxvcyjGLXGmys3nckAj4jTGC0IqDIEXAOr3Ag= -go.opentelemetry.io/collector/component/componenttest v0.120.0 h1:vKX85d3lpxj/RoiFQNvmIpX9lOS80FY5svzOYUyeYX0= -go.opentelemetry.io/collector/component/componenttest v0.120.0/go.mod h1:QDLboWF2akEqAGyvje8Hc7GfXcrZvQ5FhmlWvD5SkzY= -go.opentelemetry.io/collector/consumer v1.26.0 h1:0MwuzkWFLOm13qJvwW85QkoavnGpR4ZObqCs9g1XAvk= -go.opentelemetry.io/collector/consumer v1.26.0/go.mod h1:I/ZwlWM0sbFLhbStpDOeimjtMbWpMFSoGdVmzYxLGDg= -go.opentelemetry.io/collector/consumer/consumertest v0.120.0 h1:iPFmXygDsDOjqwdQ6YZcTmpiJeQDJX+nHvrjTPsUuv4= -go.opentelemetry.io/collector/consumer/consumertest v0.120.0/go.mod h1:HeSnmPfAEBnjsRR5UY1fDTLlSrYsMsUjufg1ihgnFJ0= -go.opentelemetry.io/collector/consumer/xconsumer v0.120.0 h1:dzM/3KkFfMBIvad+NVXDV+mA+qUpHyu5c70TFOjDg68= -go.opentelemetry.io/collector/consumer/xconsumer v0.120.0/go.mod h1:eOf7RX9CYC7bTZQFg0z2GHdATpQDxI0DP36F9gsvXOQ= -go.opentelemetry.io/collector/pdata v1.27.0 h1:66yI7FYkUDia74h48Fd2/KG2Vk8DxZnGw54wRXykCEU= -go.opentelemetry.io/collector/pdata v1.27.0/go.mod h1:18e8/xDZsqyj00h/5HM5GLdJgBzzG9Ei8g9SpNoiMtI= -go.opentelemetry.io/collector/pdata/pprofile v0.121.0 h1:DFBelDRsZYxEaSoxSRtseAazsHJfqfC/Yl64uPicl2g= -go.opentelemetry.io/collector/pdata/pprofile v0.121.0/go.mod h1:j/fjrd7ybJp/PXkba92QLzx7hykUVmU8x/WJvI2JWSg= -go.opentelemetry.io/collector/pdata/testdata v0.120.0 h1:Zp0LBOv3yzv/lbWHK1oht41OZ4WNbaXb70ENqRY7HnE= -go.opentelemetry.io/collector/pdata/testdata v0.120.0/go.mod h1:PfezW5Rzd13CWwrElTZRrjRTSgMGUOOGLfHeBjj+LwY= -go.opentelemetry.io/collector/pipeline v0.123.0 h1:LDcuCrwhCTx2yROJZqhNmq2v0CFkCkUEvxvvcRW0+2c= -go.opentelemetry.io/collector/pipeline v0.123.0/go.mod h1:TO02zju/K6E+oFIOdi372Wk0MXd+Szy72zcTsFQwXl4= -go.opentelemetry.io/collector/processor v0.120.0 h1:No+I65ybBLVy4jc7CxcsfduiBrm7Z6kGfTnekW3hx1A= -go.opentelemetry.io/collector/processor v0.120.0/go.mod h1:4zaJGLZCK8XKChkwlGC/gn0Dj4Yke04gQCu4LGbJGro= -go.opentelemetry.io/collector/processor/processortest v0.120.0 h1:R+VSVSU59W0/mPAcyt8/h1d0PfWN6JI2KY5KeMICXvo= -go.opentelemetry.io/collector/processor/processortest v0.120.0/go.mod h1:me+IVxPsj4IgK99I0pgKLX34XnJtcLwqtgTuVLhhYDI= -go.opentelemetry.io/collector/processor/xprocessor v0.120.0 h1:mBznj/1MtNqmu6UpcoXz6a63tU0931oWH2pVAt2+hzo= -go.opentelemetry.io/collector/processor/xprocessor v0.120.0/go.mod h1:Nsp0sDR3gE+GAhi9d0KbN0RhOP+BK8CGjBRn8+9d/SY= -go.opentelemetry.io/collector/semconv v0.123.0 h1:hFjhLU1SSmsZ67pXVCVbIaejonkYf5XD/6u4qCQQPtc= -go.opentelemetry.io/collector/semconv v0.123.0/go.mod h1:te6VQ4zZJO5Lp8dM2XIhDxDiL45mwX0YAQQWRQ0Qr9U= +go.opentelemetry.io/collector/component v1.51.1-0.20260205185216-81bc641f26c0 h1:ZSlXxE90IY0Cl53RTqzyEgRgRPLTeTNBdGhaTmvj9eY= +go.opentelemetry.io/collector/component v1.51.1-0.20260205185216-81bc641f26c0/go.mod h1:944C7vEIdk13Pn1fBbyaU8C1qKf2XC0jRBlc69NAsRY= +go.opentelemetry.io/collector/component/componentstatus v0.145.0 h1:EwUZfSaagdpRXnlrb0TqReJXXW2p9HWBU5YiIeXPCAE= +go.opentelemetry.io/collector/component/componentstatus v0.145.0/go.mod h1:OiYb8rT4FtSJPFSGCKYvOaajdueDUTJZncixGrmy5aM= +go.opentelemetry.io/collector/component/componenttest v0.145.1-0.20260205185216-81bc641f26c0 h1:+VCK6wX/WN170dcaWJweRAkxpmAEyVucfrUV13NwUlY= +go.opentelemetry.io/collector/component/componenttest v0.145.1-0.20260205185216-81bc641f26c0/go.mod h1:U2wUjKMGwgqM49/q8ORkzzYzSWY2m6zpG/e606eK1wc= +go.opentelemetry.io/collector/consumer v1.51.1-0.20260205185216-81bc641f26c0 h1:WNkJ1bKnRVAEJtBm1bwEkoLG2x7GyANc3/OnErZJ338= +go.opentelemetry.io/collector/consumer v1.51.1-0.20260205185216-81bc641f26c0/go.mod h1:Erk6qdfVj+24QTrGCpurcrF+qdUlHkb4dgMy5wJxLvY= +go.opentelemetry.io/collector/consumer/consumertest v0.145.1-0.20260205185216-81bc641f26c0 h1:FHyDIlTbqt0Y6tDI9EbI3hr9uWthwkeLY7uGF1jZYqQ= +go.opentelemetry.io/collector/consumer/consumertest v0.145.1-0.20260205185216-81bc641f26c0/go.mod h1:IFc/FeaIHQClb8KK0aVn0tFDNMc+/MmfQ+aBT1cJNeo= +go.opentelemetry.io/collector/consumer/xconsumer v0.145.1-0.20260205185216-81bc641f26c0 h1:zg2Jqfy7n7o/LEmLsXB4sFhxWtOEMFCKRyQUFLFUS9M= +go.opentelemetry.io/collector/consumer/xconsumer v0.145.1-0.20260205185216-81bc641f26c0/go.mod h1:SryDCLP2ZaFeZJtA2CSksJ0XvjH8k3LmlfXvy/kC7Wc= +go.opentelemetry.io/collector/featuregate v1.51.1-0.20260205185216-81bc641f26c0 h1:fOXhfT2xKqNhfalTXaT/Wic9EBRK8+9ZH0y8phReQS4= +go.opentelemetry.io/collector/featuregate v1.51.1-0.20260205185216-81bc641f26c0/go.mod h1:/1bclXgP91pISaEeNulRxzzmzMTm4I5Xih2SnI4HRSo= +go.opentelemetry.io/collector/internal/componentalias v0.145.1-0.20260205185216-81bc641f26c0 h1:s4/vCxeIxgQpuWmX1AK1DRbZmEdmNBq925EKES8ebiI= +go.opentelemetry.io/collector/internal/componentalias v0.145.1-0.20260205185216-81bc641f26c0/go.mod h1:Z0TtMbzaMp2qhj1dw4toya8toyQzqoTF46/WhJXplVw= +go.opentelemetry.io/collector/internal/testutil v0.145.0 h1:H/KL0GH3kGqSMKxZvnQ0B0CulfO9xdTg4DZf28uV7fY= +go.opentelemetry.io/collector/internal/testutil v0.145.0/go.mod h1:YAD9EAkwh/l5asZNbEBEUCqEjoL1OKMjAMoPjPqH76c= +go.opentelemetry.io/collector/pdata v1.51.1-0.20260205185216-81bc641f26c0 h1:8tgf9W3aW3vFabyVxPNHKsaoyUytudfVOQbqZI9xBHQ= +go.opentelemetry.io/collector/pdata v1.51.1-0.20260205185216-81bc641f26c0/go.mod h1:GoX1bjKDR++mgFKdT7Hynv9+mdgQ1DDXbjs7/Ww209Q= +go.opentelemetry.io/collector/pdata/pprofile v0.145.1-0.20260205185216-81bc641f26c0 h1:MJcnK8txYZlqHZyfZ1rVf66kt5/kEveIdR6KX//BY1Y= +go.opentelemetry.io/collector/pdata/pprofile v0.145.1-0.20260205185216-81bc641f26c0/go.mod h1:a60GC7wQPhLAixWzKbbP51QLwwc+J0Cmp4SurOlhGUk= +go.opentelemetry.io/collector/pdata/testdata v0.145.0 h1:iFsxsCMtE3lnAc/5kZbhZHpRv1OMmM+O5ry46xdQHbg= +go.opentelemetry.io/collector/pdata/testdata v0.145.0/go.mod h1:0y2ERArdzqmYdJHdKLKue+AUubSEGlwK49F+23+Mbic= +go.opentelemetry.io/collector/pipeline v1.51.1-0.20260205185216-81bc641f26c0 h1:1KP5gXGF9qN1mEzJupZDUQVIND35qe/0Hy6Cptvdk0s= +go.opentelemetry.io/collector/pipeline v1.51.1-0.20260205185216-81bc641f26c0/go.mod h1:xUrAqiebzYbrgxyoXSkk6/Y3oi5Sy3im2iCA51LwUAI= +go.opentelemetry.io/collector/processor v1.51.0 h1:PKpCzkLQmqaW08TOVh/zM0qx07Ihq+DR5J/OBkPiL9o= +go.opentelemetry.io/collector/processor v1.51.0/go.mod h1:rtIPFS+EFRAkG+CSwtjxs2IsIkuZStObvALeueD02XI= +go.opentelemetry.io/collector/processor/processorhelper v0.145.0 h1:vXdv6lHz20Tm3ZEsg0i6jPZJBQgy9kzk/PuqWhHWiiM= +go.opentelemetry.io/collector/processor/processorhelper v0.145.0/go.mod h1:3Ecpe5jHRHGf24EvJHeJ/ekK/a1DLByyq0CSUxjjURg= +go.opentelemetry.io/collector/processor/processortest v0.145.0 h1:RDGBmyZnHk7XVK/EdLt/8iPWj+QLStbbVi1nFTNR01s= +go.opentelemetry.io/collector/processor/processortest v0.145.0/go.mod h1:WAvxAzSojkdoZB915Z1lsVHCPDJBb2fepjJBjenrzjg= +go.opentelemetry.io/collector/processor/xprocessor v0.145.0 h1:DaIE7MxRlg0OL1o2P0GQZtmZeExAmVso3qWv8S0RLps= +go.opentelemetry.io/collector/processor/xprocessor v0.145.0/go.mod h1:kUwRyKBU/kjCmXodd+0z7CpvcP0A9G9/QL+MaJt4U2o= go.opentelemetry.io/contrib v1.0.0/go.mod h1:EH4yDYeNoaTqn/8yCWQmfNB78VHfGX2Jt2bvnvzBlGM= go.opentelemetry.io/contrib v1.19.0 h1:rnYI7OEPMWFeM4QCqWQ3InMJ0arWMR1i0Cx9A5hcjYM= go.opentelemetry.io/contrib v1.19.0/go.mod h1:gIzjwWFoGazJmtCaDgViqOSJPde2mCWzv60o0bWPcZs= @@ -1332,8 +1348,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJK go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0 h1:ZrPRak/kS4xI3AVXy8F7pipuDXmDsrO8Lg+yQjBLjw0= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0/go.mod h1:3y6kQCWztq6hyW8Z9YxQDDm0Je9AJoFar2G0yDcmhRk= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0 h1:SNhVp/9q4Go/XHBkQ1/d5u9P/U+L1yaGPoi0x+mStaI= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0/go.mod h1:tx8OOlGH6R4kLV67YaYO44GFXloEjGPZuMjEkaaqIp4= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0 h1:8UPA4IbVZxpsD76ihGOQiFml99GPAEZLohDXvqHdi6U= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0/go.mod h1:MZ1T/+51uIVKlRzGw1Fo46KEWThjlCBZKl2LzY5nv4g= go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= @@ -1346,6 +1362,12 @@ go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09 go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= +go.opentelemetry.io/proto/slim/otlp v1.9.0 h1:fPVMv8tP3TrsqlkH1HWYUpbCY9cAIemx184VGkS6vlE= +go.opentelemetry.io/proto/slim/otlp v1.9.0/go.mod h1:xXdeJJ90Gqyll+orzUkY4bOd2HECo5JofeoLpymVqdI= +go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.2.0 h1:o13nadWDNkH/quoDomDUClnQBpdQQ2Qqv0lQBjIXjE8= +go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.2.0/go.mod h1:Gyb6Xe7FTi/6xBHwMmngGoHqL0w29Y4eW8TGFzpefGA= +go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.2.0 h1:EiUYvtwu6PMrMHVjcPfnsG3v+ajPkbUeH+IL93+QYyk= +go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.2.0/go.mod h1:mUUHKFiN2SST3AhJ8XhJxEoeVW12oqfXog0Bo8W3Ec4= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= @@ -1370,7 +1392,6 @@ go4.org/netipx v0.0.0-20230728180743-ad4cb58a6516/go.mod h1:TQvodOM+hJTioNQJilmL golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= @@ -1386,8 +1407,6 @@ golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJk golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= golang.org/x/image v0.41.0 h1:8wS72eGJMJaBxK6okTzd4WaXumUlTVlb753MlsSvTCo= golang.org/x/image v0.41.0/go.mod h1:uIc348UZMSvS5Z65CVZ7iDPaNobNFEPeJ4kbqTOszmA= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= @@ -1398,8 +1417,6 @@ golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= 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-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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -1416,8 +1433,6 @@ golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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= @@ -1437,7 +1452,6 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/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-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1504,8 +1518,6 @@ golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 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= @@ -1574,8 +1586,8 @@ gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM= howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apimachinery v0.35.1 h1:yxO6gV555P1YV0SANtnTjXYfiivaTPvCTKX6w6qdDsU= +k8s.io/apimachinery v0.35.1/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d h1:wAhiDyZ4Tdtt7e46e9M5ZSAJ/MnPGPs+Ki1gHw4w1R0= k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= kernel.org/pub/linux/libs/security/libcap/cap v1.2.73 h1:Th2b8jljYqkyZKS3aD3N9VpYsQpHuXLgea+SZUIfODA=