From 25bdbc94cb09ad5d70e12e7918724ca5f59f999a Mon Sep 17 00:00:00 2001 From: Callum Styan Date: Wed, 26 Nov 2025 19:12:45 +0000 Subject: [PATCH 1/4] the agentapi context needs to be a context with some amount of authorization attached to it via the context so that the cache refresh routine can fetch the workspace from the db via GetWorkspaceForAgentID Signed-off-by: Callum Styan --- coderd/workspaceagentsrpc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/workspaceagentsrpc.go b/coderd/workspaceagentsrpc.go index d5757786e474e..4a526ed8973ff 100644 --- a/coderd/workspaceagentsrpc.go +++ b/coderd/workspaceagentsrpc.go @@ -132,7 +132,7 @@ func (api *API) workspaceAgentRPC(rw http.ResponseWriter, r *http.Request) { WorkspaceID: workspace.ID, OrganizationID: workspace.OrganizationID, - Ctx: api.ctx, + Ctx: ctx, Log: logger, Clock: api.Clock, Database: api.Database, From f44448cfc955bfbb7086992195db26e6de4fc4d1 Mon Sep 17 00:00:00 2001 From: Callum Styan Date: Wed, 26 Nov 2025 20:49:01 +0000 Subject: [PATCH 2/4] Rename context to more accurately reflect the contexts use case Signed-off-by: Callum Styan --- coderd/agentapi/api.go | 7 ++++--- coderd/agentapi/metadata_test.go | 2 +- coderd/workspaceagentsrpc.go | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/coderd/agentapi/api.go b/coderd/agentapi/api.go index 8c8b1a00ae064..22ca737c3a20c 100644 --- a/coderd/agentapi/api.go +++ b/coderd/agentapi/api.go @@ -36,7 +36,7 @@ import ( "github.com/coder/quartz" ) -const workspaceCacheRefreshInterval = 5 * time.Minute +const workspaceCacheRefreshInterval = 1 * time.Minute // API implements the DRPC agent API interface from agent/proto. This struct is // instantiated once per agent connection and kept alive for the duration of the @@ -69,7 +69,7 @@ type Options struct { WorkspaceID uuid.UUID OrganizationID uuid.UUID - Ctx context.Context + AuthenticatedCtx context.Context Log slog.Logger Clock quartz.Clock Database database.Store @@ -220,7 +220,7 @@ func New(opts Options, workspace database.Workspace) *API { // Start background cache refresh loop to handle workspace changes // like prebuild claims where owner_id and other fields may be modified in the DB. - go api.startCacheRefreshLoop(opts.Ctx) + go api.startCacheRefreshLoop(opts.AuthenticatedCtx) return api } @@ -275,6 +275,7 @@ func (a *API) agent(ctx context.Context) (database.WorkspaceAgent, error) { // This ensures that changes like prebuild claims (which modify owner_id, name, etc.) // are eventually reflected in the cache without requiring agent reconnection. func (a *API) refreshCachedWorkspace(ctx context.Context) { + a.opts.Log.Debug(ctx, "refreshing cached workspace", slog.F("test", "test")) ws, err := a.opts.Database.GetWorkspaceByID(ctx, a.opts.WorkspaceID) if err != nil { a.opts.Log.Warn(ctx, "failed to refresh cached workspace fields", slog.Error(err)) diff --git a/coderd/agentapi/metadata_test.go b/coderd/agentapi/metadata_test.go index 23a6c4df4ad4a..8d6664cd9fad4 100644 --- a/coderd/agentapi/metadata_test.go +++ b/coderd/agentapi/metadata_test.go @@ -671,7 +671,7 @@ func TestBatchUpdateMetadata(t *testing.T) { // Create full API with cached workspace fields (initial state) api := agentapi.New(agentapi.Options{ - Ctx: ctxWithActor, + AuthenticatedCtx: ctxWithActor, AgentID: agentID, WorkspaceID: workspaceID, OwnerID: ownerID, diff --git a/coderd/workspaceagentsrpc.go b/coderd/workspaceagentsrpc.go index 4a526ed8973ff..50a14768c1b7d 100644 --- a/coderd/workspaceagentsrpc.go +++ b/coderd/workspaceagentsrpc.go @@ -132,7 +132,7 @@ func (api *API) workspaceAgentRPC(rw http.ResponseWriter, r *http.Request) { WorkspaceID: workspace.ID, OrganizationID: workspace.OrganizationID, - Ctx: ctx, + AuthenticatedCtx: ctx, Log: logger, Clock: api.Clock, Database: api.Database, From ff5a6a14612ea482c0a4e5db066ab005f7eb03b6 Mon Sep 17 00:00:00 2001 From: Callum Styan Date: Wed, 26 Nov 2025 20:57:04 +0000 Subject: [PATCH 3/4] lint/fmt Signed-off-by: Callum Styan --- coderd/agentapi/metadata_test.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/coderd/agentapi/metadata_test.go b/coderd/agentapi/metadata_test.go index 8d6664cd9fad4..1ba02d037fef5 100644 --- a/coderd/agentapi/metadata_test.go +++ b/coderd/agentapi/metadata_test.go @@ -671,15 +671,15 @@ func TestBatchUpdateMetadata(t *testing.T) { // Create full API with cached workspace fields (initial state) api := agentapi.New(agentapi.Options{ - AuthenticatedCtx: ctxWithActor, - AgentID: agentID, - WorkspaceID: workspaceID, - OwnerID: ownerID, - OrganizationID: orgID, - Database: dbauthz.New(dbM, auth, testutil.Logger(t), accessControlStore), - Log: testutil.Logger(t), - Clock: mClock, - Pubsub: pub, + AuthenticatedCtx: ctxWithActor, + AgentID: agentID, + WorkspaceID: workspaceID, + OwnerID: ownerID, + OrganizationID: orgID, + Database: dbauthz.New(dbM, auth, testutil.Logger(t), accessControlStore), + Log: testutil.Logger(t), + Clock: mClock, + Pubsub: pub, }, initialWorkspace) // Cache is initialized with 9am schedule and "my-workspace" name // Wait for ticker to be set up and release it so it can fire From 5fc6219a8011648e6747ad9c89f201091793d7b2 Mon Sep 17 00:00:00 2001 From: Callum Styan Date: Wed, 26 Nov 2025 22:29:19 +0000 Subject: [PATCH 4/4] back out unintentional changes Signed-off-by: Callum Styan --- coderd/agentapi/api.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/coderd/agentapi/api.go b/coderd/agentapi/api.go index 22ca737c3a20c..252e6b5c08449 100644 --- a/coderd/agentapi/api.go +++ b/coderd/agentapi/api.go @@ -36,7 +36,7 @@ import ( "github.com/coder/quartz" ) -const workspaceCacheRefreshInterval = 1 * time.Minute +const workspaceCacheRefreshInterval = 5 * time.Minute // API implements the DRPC agent API interface from agent/proto. This struct is // instantiated once per agent connection and kept alive for the duration of the @@ -275,7 +275,6 @@ func (a *API) agent(ctx context.Context) (database.WorkspaceAgent, error) { // This ensures that changes like prebuild claims (which modify owner_id, name, etc.) // are eventually reflected in the cache without requiring agent reconnection. func (a *API) refreshCachedWorkspace(ctx context.Context) { - a.opts.Log.Debug(ctx, "refreshing cached workspace", slog.F("test", "test")) ws, err := a.opts.Database.GetWorkspaceByID(ctx, a.opts.WorkspaceID) if err != nil { a.opts.Log.Warn(ctx, "failed to refresh cached workspace fields", slog.Error(err))