Skip to content

feat(coderd/agentapi): support terraform-defined subagent ids#21837

Merged
DanielleMaywood merged 6 commits intomainfrom
danielle/devcontainer-resources/agent
Feb 4, 2026
Merged

feat(coderd/agentapi): support terraform-defined subagent ids#21837
DanielleMaywood merged 6 commits intomainfrom
danielle/devcontainer-resources/agent

Conversation

@DanielleMaywood
Copy link
Contributor

@DanielleMaywood DanielleMaywood commented Feb 2, 2026

Relates to coder/internal#1243

Update coderd/agentapi to handle pre-created sub agents

@DanielleMaywood DanielleMaywood force-pushed the danielle/devcontainer-resources/agent branch from ca6855c to 2b48d69 Compare February 2, 2026 15:11
@DanielleMaywood DanielleMaywood changed the base branch from main to danielle/devcontainer-resources/agent-proto February 2, 2026 15:11
@DanielleMaywood DanielleMaywood force-pushed the danielle/devcontainer-resources/agent branch from 2b48d69 to fa0ccbc Compare February 3, 2026 11:36
Base automatically changed from danielle/devcontainer-resources/agent-proto to main February 3, 2026 12:37
@DanielleMaywood DanielleMaywood force-pushed the danielle/devcontainer-resources/agent branch 5 times, most recently from 7f95be2 to 9643b75 Compare February 3, 2026 15:51
@DanielleMaywood DanielleMaywood changed the title feat(agent): support terraform-defined subagent ids feat(coder/agentapi): support terraform-defined subagent ids Feb 3, 2026
@DanielleMaywood DanielleMaywood changed the title feat(coder/agentapi): support terraform-defined subagent ids feat(coderd/agentapi): support terraform-defined subagent ids Feb 3, 2026
@DanielleMaywood DanielleMaywood force-pushed the danielle/devcontainer-resources/agent branch from 9643b75 to ca54e30 Compare February 3, 2026 16:49
@DanielleMaywood DanielleMaywood marked this pull request as ready for review February 3, 2026 16:59
Copy link
Contributor

@coder-tasks coder-tasks bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Reviewed PR #21837: Support for terraform-defined subagent IDs. The changes enable updating pre-created subagents from terraform rather than always creating new ones. Found 3 issues requiring attention.

Summary

Strengths:

  • Good separation of create vs. update logic paths
  • Comprehensive test coverage with 6 test cases covering various scenarios
  • Proper authorization checks via dbauthz layer
  • Clear validation of parent-child relationships

Issues:

  1. Logic reordering breaks existing behavior (validation happens after operations)
  2. Missing validation when ID is provided in request
  3. Security: No validation that provided ID actually belongs to current workspace

General Comments

  • The new update path is well-designed and properly validates parent relationships
  • Test cases are thorough and test both success and error scenarios
  • Database query and authorization changes follow project patterns correctly

Copy link
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The agentapi look fine to me. 👍🏻 Only potential blocker I see is rbac.

Comment on lines +1933 to +1943
s.Run("UpdateWorkspaceAgentDisplayAppsByID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
w := testutil.Fake(s.T(), faker, database.Workspace{})
agt := testutil.Fake(s.T(), faker, database.WorkspaceAgent{})
arg := database.UpdateWorkspaceAgentDisplayAppsByIDParams{
ID: agt.ID,
DisplayApps: []database.DisplayApp{database.DisplayAppVscode},
}
dbm.EXPECT().GetWorkspaceByAgentID(gomock.Any(), agt.ID).Return(w, nil).AnyTimes()
dbm.EXPECT().UpdateWorkspaceAgentDisplayAppsByID(gomock.Any(), arg).Return(nil).AnyTimes()
check.Args(arg).Asserts(w, policy.ActionUpdate).Returns()
}))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a good place to ensure that we don't allow sub-agents to update across workspaces?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reading this, I'm unsure what you mean. Are these check.Args(...).Asserts(...) capable of testing this explicitly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right. I zoomed in on WithNotAuthorized() but appear to have misunderstood what it actually does.

@DanielleMaywood DanielleMaywood force-pushed the danielle/devcontainer-resources/agent branch from 4960519 to cf851aa Compare February 4, 2026 13:27
@DanielleMaywood DanielleMaywood force-pushed the danielle/devcontainer-resources/agent branch from cf851aa to 4e92897 Compare February 4, 2026 13:33
Comment on lines +5729 to +5740
func (q *querier) UpdateWorkspaceAgentDisplayAppsByID(ctx context.Context, arg database.UpdateWorkspaceAgentDisplayAppsByIDParams) error {
workspace, err := q.db.GetWorkspaceByAgentID(ctx, arg.ID)
if err != nil {
return err
}

if err := q.authorizeContext(ctx, policy.ActionUpdateAgent, workspace); err != nil {
return err
}

return q.db.UpdateWorkspaceAgentDisplayAppsByID(ctx, arg)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

APIKeyScopeWorkspaceDormantStart APIKeyScope = "workspace_dormant:start"
APIKeyScopeWorkspaceDormantStop APIKeyScope = "workspace_dormant:stop"
APIKeyScopeWorkspaceDormantUpdate APIKeyScope = "workspace_dormant:update"
APIKeyScopeWorkspaceDormantUpdateAgent APIKeyScope = "workspace_dormant:update_agent"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting question - when is this going to happen?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these scopes are internal by-default and have to be explicitly exported? I'm a little unsure about API Key Scopes, so I might need to do some reading to get more context.

Copy link
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! One last question/suggestion, but I leave it up to you as it's not a blocker.

check: func(t *testing.T, ctx context.Context, db database.Store, resp *proto.CreateSubAgentResponse, agent database.WorkspaceAgent) {
// Then: The response contains the original agent name, not the new one.
require.NotNil(t, resp.Agent)
require.Equal(t, baseChildAgent.Name, resp.Agent.Name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the client side see that some inputs were discarded? If not, that might lead to some confusion.

Should we consider introducing an errors field (like app creation errors)? Or perhaps erroring out if the name is changed? (Forcing the client to provide valid input for existing agents.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not at the moment, no.

I think I'll address this as a follow-up once the feature is fully implemented, and will follow the pattern introduced with app creation errors.

@DanielleMaywood DanielleMaywood merged commit af0e171 into main Feb 4, 2026
30 of 32 checks passed
@DanielleMaywood DanielleMaywood deleted the danielle/devcontainer-resources/agent branch February 4, 2026 15:33
@github-actions github-actions bot locked and limited conversation to collaborators Feb 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants